/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package org.apache.tools.ant.taskdefs.rmic;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import java.util.stream.Collectors;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Rmic;
import org.apache.tools.ant.types.Commandline;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.JavaEnvUtils;
import org.apache.tools.ant.util.StringUtils;

This is the default implementation for the RmicAdapter interface. Currently, this is a cut-and-paste of the original rmic task and DefaultCompilerAdapter.
Since:Ant 1.4
/** * This is the default implementation for the RmicAdapter interface. * Currently, this is a cut-and-paste of the original rmic task and * DefaultCompilerAdapter. * * @since Ant 1.4 */
public abstract class DefaultRmicAdapter implements RmicAdapter { private static final Random RAND = new Random();
suffix denoting a stub file: "_Stub"
/** suffix denoting a stub file: {@value} */
public static final String RMI_STUB_SUFFIX = "_Stub";
suffix denoting a skel file: "_Skel"
/** suffix denoting a skel file: {@value} */
public static final String RMI_SKEL_SUFFIX = "_Skel";
suffix denoting a tie file: "_Tie"
/** suffix denoting a tie file: {@value} */
public static final String RMI_TIE_SUFFIX = "_Tie";
arg for compat: "-vcompat"
/** arg for compat: {@value} */
public static final String STUB_COMPAT = "-vcompat";
arg for 1.1: "-v1.1"
/** arg for 1.1: {@value} */
public static final String STUB_1_1 = "-v1.1";
arg for 1.2: "-v1.2"
/** arg for 1.2: {@value} */
public static final String STUB_1_2 = "-v1.2";
option for stub 1.1 in the rmic task: "1.1"
/** * option for stub 1.1 in the rmic task: {@value} */
public static final String STUB_OPTION_1_1 = "1.1";
option for stub 1.2 in the rmic task: "1.2"
/** * option for stub 1.2 in the rmic task: {@value} */
public static final String STUB_OPTION_1_2 = "1.2";
option for stub compat in the rmic task: "compat"
/** * option for stub compat in the rmic task: {@value} */
public static final String STUB_OPTION_COMPAT = "compat"; private Rmic attributes; private FileNameMapper mapper;
Sets Rmic attributes
Params:
  • attributes – the rmic attributes
/** * Sets Rmic attributes * @param attributes the rmic attributes */
@Override public void setRmic(final Rmic attributes) { this.attributes = attributes; mapper = new RmicFileNameMapper(); }
Get the Rmic attributes
Returns:the attributes as a Rmic taskdef
/** * Get the Rmic attributes * @return the attributes as a Rmic taskdef */
public Rmic getRmic() { return attributes; }
Gets the stub class suffix
Returns:the stub suffix "_Stub"
/** * Gets the stub class suffix * @return the stub suffix "_Stub" */
protected String getStubClassSuffix() { return RMI_STUB_SUFFIX; }
Gets the skeleton class suffix
Returns:the skeleton suffix "_Skel"
/** * Gets the skeleton class suffix * @return the skeleton suffix "_Skel" */
protected String getSkelClassSuffix() { return RMI_SKEL_SUFFIX; }
Gets the tie class suffix
Returns:the tie suffix "_Tie"
/** * Gets the tie class suffix * @return the tie suffix "_Tie" */
protected String getTieClassSuffix() { return RMI_TIE_SUFFIX; }
This implementation returns a mapper that may return up to two file names.
  • for JRMP it will return *_getStubClassSuffix (and *_getSkelClassSuffix if JDK 1.1 is used)
  • for IDL it will return a random name, causing <rmic> to always recompile.
  • for IIOP it will return _*_getStubClassSuffix for interfaces and _*_getStubClassSuffix for non-interfaces (and determine the interface and create _*_Stub from that).
Returns:a FileNameMapper
/** * This implementation returns a mapper that may return up to two * file names. * * <ul> * <li>for JRMP it will return *_getStubClassSuffix (and * *_getSkelClassSuffix if JDK 1.1 is used)</li> * * <li>for IDL it will return a random name, causing &lt;rmic&gt; to * always recompile.</li> * * <li>for IIOP it will return _*_getStubClassSuffix for * interfaces and _*_getStubClassSuffix for non-interfaces (and * determine the interface and create _*_Stub from that).</li> * </ul> * @return a <code>FileNameMapper</code> */
@Override public FileNameMapper getMapper() { return mapper; }
Gets the CLASSPATH this rmic process will use.
Returns:the classpath
/** * Gets the CLASSPATH this rmic process will use. * @return the classpath */
@Override public Path getClasspath() { return getCompileClasspath(); }
Builds the compilation classpath.
Returns:the classpath
/** * Builds the compilation classpath. * @return the classpath */
protected Path getCompileClasspath() { Path classpath = new Path(attributes.getProject()); // add dest dir to classpath so that previously compiled and // untouched classes are on classpath classpath.setLocation(attributes.getBase()); // Combine the build classpath with the system classpath, in an // order determined by the value of build.sysclasspath Path cp = attributes.getClasspath(); if (cp == null) { cp = new Path(attributes.getProject()); } if (attributes.getIncludeantruntime()) { classpath.addExisting(cp.concatSystemClasspath("last")); } else { classpath.addExisting(cp.concatSystemClasspath("ignore")); } if (attributes.getIncludejavaruntime()) { classpath.addJavaRuntime(); } return classpath; }
Whether the iiop and idl switches are supported.

This implementation returns false if running on Java 11 onwards and true otherwise.

Returns:true if the iiop and idl switches are supported
Since:Ant 1.10.3
/** * Whether the iiop and idl switches are supported. * * <p>This implementation returns false if running on Java 11 * onwards and true otherwise.</p> * @return true if the iiop and idl switches are supported * @since Ant 1.10.3 */
protected boolean areIiopAndIdlSupported() { return !JavaEnvUtils.isAtLeastJavaVersion("11"); }
Setup rmic argument for rmic.
Returns:the command line
/** * Setup rmic argument for rmic. * @return the command line */
protected Commandline setupRmicCommand() { return setupRmicCommand(null); }
Setup rmic argument for rmic.
Params:
  • options – additional parameters needed by a specific implementation.
Returns:the command line
/** * Setup rmic argument for rmic. * @param options additional parameters needed by a specific * implementation. * @return the command line */
protected Commandline setupRmicCommand(String[] options) { Commandline cmd = new Commandline(); if (options != null) { for (String option : options) { cmd.createArgument().setValue(option); } } Path classpath = getCompileClasspath(); cmd.createArgument().setValue("-d"); cmd.createArgument().setFile(attributes.getOutputDir()); if (attributes.getExtdirs() != null) { cmd.createArgument().setValue("-extdirs"); cmd.createArgument().setPath(attributes.getExtdirs()); } cmd.createArgument().setValue("-classpath"); cmd.createArgument().setPath(classpath); String stubOption = addStubVersionOptions(); if (stubOption != null) { //set the non-null stubOption cmd.createArgument().setValue(stubOption); } if (null != attributes.getSourceBase()) { cmd.createArgument().setValue("-keepgenerated"); } if (attributes.getIiop()) { if (!areIiopAndIdlSupported()) { throw new BuildException("this rmic implementation doesn't support the -iiop switch"); } attributes.log("IIOP has been turned on.", Project.MSG_INFO); cmd.createArgument().setValue("-iiop"); if (attributes.getIiopopts() != null) { attributes.log("IIOP Options: " + attributes.getIiopopts(), Project.MSG_INFO); cmd.createArgument().setValue(attributes.getIiopopts()); } } if (attributes.getIdl()) { if (!areIiopAndIdlSupported()) { throw new BuildException("this rmic implementation doesn't support the -idl switch"); } cmd.createArgument().setValue("-idl"); attributes.log("IDL has been turned on.", Project.MSG_INFO); if (attributes.getIdlopts() != null) { cmd.createArgument().setValue(attributes.getIdlopts()); attributes.log("IDL Options: " + attributes.getIdlopts(), Project.MSG_INFO); } } if (attributes.getDebug()) { cmd.createArgument().setValue("-g"); } String[] compilerArgs = attributes.getCurrentCompilerArgs(); compilerArgs = preprocessCompilerArgs(compilerArgs); cmd.addArguments(compilerArgs); verifyArguments(cmd); logAndAddFilesToCompile(cmd); return cmd; }
This is an override point; get the stub version off the rmic command and translate that into a compiler-specific argument
Returns:a string to use for the stub version; can be null
Since:Ant1.7.1
/** * This is an override point; get the stub version off the rmic command and * translate that into a compiler-specific argument * @return a string to use for the stub version; can be null * @since Ant1.7.1 */
protected String addStubVersionOptions() { //handle the many different stub options. String stubVersion = attributes.getStubVersion(); //default is compatibility String stubOption = null; if (null != stubVersion) { if (STUB_OPTION_1_1.equals(stubVersion)) { stubOption = STUB_1_1; } else if (STUB_OPTION_1_2.equals(stubVersion)) { stubOption = STUB_1_2; } else if (STUB_OPTION_COMPAT.equals(stubVersion)) { stubOption = STUB_COMPAT; } else { //anything else attributes.log("Unknown stub option " + stubVersion); //do nothing with the value? or go -v+stubVersion?? } } //for java1.5+, we generate compatible stubs, that is, unless //the caller asked for IDL or IIOP support. if (stubOption == null && !attributes.getIiop() && !attributes.getIdl()) { stubOption = STUB_COMPAT; } return stubOption; }
Preprocess the compiler arguments in any way you see fit. This is to allow compiler adapters to validate or filter the arguments. The base implementation returns the original compiler arguments unchanged.
Params:
  • compilerArgs – the original compiler arguments
Returns:the filtered set.
/** * Preprocess the compiler arguments in any way you see fit. * This is to allow compiler adapters to validate or filter the arguments. * The base implementation returns the original compiler arguments unchanged. * @param compilerArgs the original compiler arguments * @return the filtered set. */
protected String[] preprocessCompilerArgs(String[] compilerArgs) { return compilerArgs; }
Strip out all -J args from the command list. Invoke this from preprocessCompilerArgs(String[]) if you have a non-forking compiler.
Params:
  • compilerArgs – the original compiler arguments
Returns:the filtered set.
/** * Strip out all -J args from the command list. Invoke this from * {@link #preprocessCompilerArgs(String[])} if you have a non-forking * compiler. * @param compilerArgs the original compiler arguments * @return the filtered set. */
protected String[] filterJvmCompilerArgs(String[] compilerArgs) { int len = compilerArgs.length; List<String> args = new ArrayList<>(len); for (String arg : compilerArgs) { if (arg.startsWith("-J")) { attributes.log("Dropping " + arg + " from compiler arguments"); } else { args.add(arg); } } return args.toArray(new String[args.size()]); }
Logs the compilation parameters, adds the files to compile and logs the "niceSourceList"
Params:
  • cmd – the commandline args
/** * Logs the compilation parameters, adds the files to compile and logs the * &quot;niceSourceList&quot; * @param cmd the commandline args */
protected void logAndAddFilesToCompile(Commandline cmd) { Vector<String> compileList = attributes.getCompileList(); attributes.log("Compilation " + cmd.describeArguments(), Project.MSG_VERBOSE); String niceSourceList = (compileList.size() == 1 ? "File" : "Files") + " to be compiled:" + compileList.stream().peek(arg -> cmd.createArgument().setValue(arg)) .collect(Collectors.joining(" ")); attributes.log(niceSourceList, Project.MSG_VERBOSE); } private void verifyArguments(Commandline cmd) { if (JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_9)) { for (String arg : cmd.getArguments()) { if ("-Xnew".equals(arg)) { throw new BuildException("JDK9 has removed support for -Xnew"); } } } }
Mapper that may return up to two file names.
  • for JRMP it will return *_getStubClassSuffix (and *_getSkelClassSuffix if JDK 1.1 is used)
  • for IDL it will return a random name, causing to always recompile.
  • for IIOP it will return _*_getStubClassSuffix for interfaces and _*_getStubClassSuffix for non-interfaces (and determine the interface and create _*_Stub from that).
/** * Mapper that may return up to two file names. * * <ul> * <li>for JRMP it will return *_getStubClassSuffix (and * *_getSkelClassSuffix if JDK 1.1 is used)</li> * * <li>for IDL it will return a random name, causing <rmic> to * always recompile.</li> * * <li>for IIOP it will return _*_getStubClassSuffix for * interfaces and _*_getStubClassSuffix for non-interfaces (and * determine the interface and create _*_Stub from that).</li> * </ul> */
private class RmicFileNameMapper implements FileNameMapper {
Empty implementation.
/** * Empty implementation. */
@Override public void setFrom(String s) { }
Empty implementation.
/** * Empty implementation. */
@Override public void setTo(String s) { } @Override public String[] mapFileName(String name) { if (name == null || !name.endsWith(".class") || name.endsWith(getStubClassSuffix() + ".class") || name.endsWith(getSkelClassSuffix() + ".class") || name.endsWith(getTieClassSuffix() + ".class")) { // Not a .class file or the one we'd generate return null; } // we know that name.endsWith(".class") String base = StringUtils.removeSuffix(name, ".class"); String classname = base.replace(File.separatorChar, '.'); if (attributes.getVerify() && !attributes.isValidRmiRemote(classname)) { return null; } /* * fallback in case we have trouble loading the class or * don't know how to handle it (there is no easy way to * know what IDL mode would generate. * * This is supposed to make Ant always recompile the * class, as a file of that name should not exist. */ String[] target = new String[] {name + ".tmp." + RAND.nextLong()}; if (!attributes.getIiop() && !attributes.getIdl()) { // JRMP with simple naming convention if (STUB_OPTION_1_2.equals(attributes.getStubVersion())) { target = new String[] { base + getStubClassSuffix() + ".class" }; } else { target = new String[] { base + getStubClassSuffix() + ".class", base + getSkelClassSuffix() + ".class", }; } } else if (!attributes.getIdl()) { int lastSlash = base.lastIndexOf(File.separatorChar); String dirname; /* * I know, this is not necessary, but I prefer it explicit (SB) */ int index = -1; if (lastSlash == -1) { // no package index = 0; dirname = ""; } else { index = lastSlash + 1; dirname = base.substring(0, index); } String filename = base.substring(index); try { Class<?> c = attributes.getLoader().loadClass(classname); if (c.isInterface()) { // only stub, no tie target = new String[] { dirname + "_" + filename + getStubClassSuffix() + ".class" }; } else { /* * stub is derived from implementation, * tie from interface name. */ Class<?> interf = attributes.getRemoteInterface(c); String iName = interf.getName(); String iDir; int iIndex; int lastDot = iName.lastIndexOf('.'); if (lastDot == -1) { // no package iIndex = 0; iDir = ""; } else { iIndex = lastDot + 1; iDir = iName.substring(0, iIndex); iDir = iDir.replace('.', File.separatorChar); } target = new String[] { dirname + "_" + filename + getTieClassSuffix() + ".class", iDir + "_" + iName.substring(iIndex) + getStubClassSuffix() + ".class" }; } } catch (ClassNotFoundException e) { attributes.log("Unable to verify class " + classname + ". It could not be found.", Project.MSG_WARN); } catch (NoClassDefFoundError e) { attributes.log("Unable to verify class " + classname + ". It is not defined.", Project.MSG_WARN); } catch (Throwable t) { attributes.log("Unable to verify class " + classname + ". Loading caused Exception: " + t.getMessage(), Project.MSG_WARN); } } return target; } } }