Most of the changes here are actually adding tests, which was surprisingly hard work. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276755 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -37,6 +37,7 @@ attribute. <a name="compilervalues">There are three choices</a>:</p> | |||
| <li>sun (the standard compiler of the JDK)</li> | |||
| <li>kaffe (the standard compiler of <a href="http://www.kaffe.org" target="_top">Kaffe</a>)</li> | |||
| <li>weblogic</li> | |||
| <li>forking - the sun compiler forked into a separate process</li> | |||
| </ul> | |||
| <p>The <a href="http://dione.zcu.cz/~toman40/miniRMI/">miniRMI</a> | |||
| @@ -0,0 +1,89 @@ | |||
| <?xml version="1.0"?> | |||
| <project name="rmic" default="teardown" basedir="."> | |||
| <property name="rmic.dir" location="." /> | |||
| <property name="src.dir" location="${rmic.dir}/src"/> | |||
| <property name="build.dir" location="${rmic.dir}/build"/> | |||
| <target name="teardown"> | |||
| <delete dir="${build.dir}"/> | |||
| </target> | |||
| <!-- init builds the java source --> | |||
| <target name="init" depends="probe-rmic"> | |||
| <mkdir dir="${build.dir}"/> | |||
| <javac | |||
| destdir="${build.dir}" | |||
| srcdir="${src.dir}" > | |||
| </javac> | |||
| <presetdef name="base-rmic"> | |||
| <rmic | |||
| base="${build.dir}" | |||
| verify="true" | |||
| includes="**/*.class"/> | |||
| </presetdef> | |||
| </target> | |||
| <target name="probe-rmic"> | |||
| <available property="kaffe.present" classname="jkaffe.rmi.rmic.RMIC"/> | |||
| <available property="rmic.present" classname="sun.rmi.rmic.Main"/> | |||
| <available property="wlrmic.present" classname="weblogic.rmic"/> | |||
| </target> | |||
| <target name="testRmic" if="rmic.present" depends="init"> | |||
| <base-rmic /> | |||
| </target> | |||
| <target name="testKaffe" if="kaffe.present" depends="init"> | |||
| <base-rmic | |||
| compiler="kaffe" | |||
| /> | |||
| </target> | |||
| <target name="testWlrmic" if="wlrmic.present" depends="init"> | |||
| <base-rmic | |||
| compiler="wlrmic" | |||
| /> | |||
| </target> | |||
| <target name="testForking" if="rmic.present" depends="init"> | |||
| <base-rmic | |||
| compiler="forking" | |||
| /> | |||
| </target> | |||
| <target name="testBadName" if="rmic.present" depends="init"> | |||
| <base-rmic | |||
| compiler="no-such-compiler" | |||
| /> | |||
| </target> | |||
| <target name="testWrongClass" if="rmic.present" depends="init"> | |||
| <base-rmic | |||
| compiler="org.apache.tools.ant.BuildException" | |||
| /> | |||
| </target> | |||
| <target name="testNoBase" depends="init"> | |||
| <rmic | |||
| verify="true" | |||
| includes="**/*.class"/> | |||
| </target> | |||
| <target name="testBaseDoesntExist" depends="init"> | |||
| <rmic | |||
| base="${build.dir}/classes" | |||
| verify="true" | |||
| includes="**/*.class"/> | |||
| </target> | |||
| <target name="testBaseIsntDir" depends="init"> | |||
| <rmic | |||
| base="${ant.file}" | |||
| verify="true" | |||
| includes="**/*.class"/> | |||
| </target> | |||
| </project> | |||
| @@ -0,0 +1,10 @@ | |||
| import java.rmi.Remote; | |||
| import java.rmi.RemoteException; | |||
| /** | |||
| * this is the interface we remote | |||
| */ | |||
| public interface RemoteTimestamp extends Remote { | |||
| long when() throws RemoteException ; | |||
| } | |||
| @@ -0,0 +1,12 @@ | |||
| import java.rmi.Remote; | |||
| import java.rmi.RemoteException; | |||
| /** | |||
| * this is the implementation | |||
| */ | |||
| public class RemoteTimestampImpl implements RemoteTimestamp { | |||
| public long when() throws RemoteException { | |||
| return System.currentTimeMillis(); | |||
| } | |||
| } | |||
| @@ -26,6 +26,7 @@ import org.apache.tools.ant.DirectoryScanner; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.taskdefs.rmic.RmicAdapter; | |||
| import org.apache.tools.ant.taskdefs.rmic.RmicAdapterFactory; | |||
| import org.apache.tools.ant.taskdefs.rmic.KaffeRmic; | |||
| import org.apache.tools.ant.types.FilterSetCollection; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.Reference; | |||
| @@ -106,14 +107,17 @@ public class Rmic extends MatchingTask { | |||
| private FileUtils fileUtils = FileUtils.newFileUtils(); | |||
| private FacadeTaskHelper facade; | |||
| public static final String ERROR_UNABLE_TO_VERIFY_CLASS = "Unable to verify class "; | |||
| public static final String ERROR_NOT_FOUND = ". It could not be found."; | |||
| public static final String ERROR_NOT_DEFINED = ". It is not defined."; | |||
| public static final String ERROR_LOADING_CAUSED_EXCEPTION = ". Loading caused Exception: "; | |||
| public static final String ERROR_NO_BASE_EXISTS = "base does not exist: "; | |||
| public static final String ERROR_NOT_A_DIR = "base is not a directory:"; | |||
| public static final String ERROR_BASE_NOT_SET = "base attribute must be set!"; | |||
| public Rmic() { | |||
| try { | |||
| Class.forName("kaffe.rmi.rmic.RMIC"); | |||
| facade = new FacadeTaskHelper("kaffe"); | |||
| } catch (ClassNotFoundException cnfe) { | |||
| facade = new FacadeTaskHelper("sun"); | |||
| } | |||
| String facadeName=KaffeRmic.isAvailable()?"kaffe":"sun"; | |||
| facade = new FacadeTaskHelper(facadeName); | |||
| } | |||
| /** | |||
| @@ -433,12 +437,14 @@ public class Rmic extends MatchingTask { | |||
| */ | |||
| public void execute() throws BuildException { | |||
| if (baseDir == null) { | |||
| throw new BuildException("base attribute must be set!", getLocation()); | |||
| throw new BuildException(ERROR_BASE_NOT_SET, getLocation()); | |||
| } | |||
| if (!baseDir.exists()) { | |||
| throw new BuildException("base does not exist!", getLocation()); | |||
| throw new BuildException(ERROR_NO_BASE_EXISTS+baseDir, getLocation()); | |||
| } | |||
| if ( !baseDir.isDirectory() ) { | |||
| throw new BuildException(ERROR_NOT_A_DIR+baseDir, getLocation()); | |||
| } | |||
| if (verify) { | |||
| log("Verify has been turned on.", Project.MSG_VERBOSE); | |||
| } | |||
| @@ -595,14 +601,14 @@ public class Rmic extends MatchingTask { | |||
| } | |||
| return isValidRmiRemote(testClass); | |||
| } catch (ClassNotFoundException e) { | |||
| log("Unable to verify class " + classname | |||
| + ". It could not be found.", Project.MSG_WARN); | |||
| log(ERROR_UNABLE_TO_VERIFY_CLASS + classname | |||
| + ERROR_NOT_FOUND, Project.MSG_WARN); | |||
| } catch (NoClassDefFoundError e) { | |||
| log("Unable to verify class " + classname | |||
| + ". It is not defined.", Project.MSG_WARN); | |||
| log(ERROR_UNABLE_TO_VERIFY_CLASS + classname | |||
| + ERROR_NOT_DEFINED, Project.MSG_WARN); | |||
| } catch (Throwable t) { | |||
| log("Unable to verify class " + classname | |||
| + ". Loading caused Exception: " | |||
| log(ERROR_UNABLE_TO_VERIFY_CLASS + classname | |||
| + ERROR_LOADING_CAUSED_EXCEPTION | |||
| + t.getMessage(), Project.MSG_WARN); | |||
| } | |||
| // we only get here if an exception has been thrown | |||
| @@ -0,0 +1,74 @@ | |||
| /** (C) Copyright 2004 Hewlett-Packard Development Company, LP | |||
| This library is free software; you can redistribute it and/or | |||
| modify it under the terms of the GNU Lesser General Public | |||
| License as published by the Free Software Foundation; either | |||
| version 2.1 of the License, or (at your option) any later version. | |||
| This library is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public | |||
| License along with this library; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| For more information: www.smartfrog.org | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.rmic; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.taskdefs.Rmic; | |||
| import org.apache.tools.ant.taskdefs.Java; | |||
| import org.apache.tools.ant.taskdefs.Execute; | |||
| import org.apache.tools.ant.taskdefs.LogStreamHandler; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| import java.io.IOException; | |||
| /** | |||
| * This is an extension of the sun rmic compiler, which forks rather than | |||
| * executes it inline. Why so? Because rmic is dog slow, but if you fork the | |||
| * compiler you can have multiple copies compiling different bits of your project | |||
| * at the same time. Which, on a multi-cpu system results in significant speedups. | |||
| * | |||
| * @since ant1.7 | |||
| */ | |||
| public class ForkingSunRmic extends DefaultRmicAdapter { | |||
| /** | |||
| * exec by creating a new command | |||
| * @return | |||
| * @throws BuildException | |||
| */ | |||
| public boolean execute() throws BuildException { | |||
| Rmic owner=getRmic(); | |||
| Commandline cmd = setupRmicCommand(); | |||
| Project project=owner.getProject(); | |||
| //rely on RMIC being on the path | |||
| cmd.setExecutable(SunRmic.RMIC_EXECUTABLE); | |||
| //set up the args | |||
| String[] args=cmd.getCommandline(); | |||
| try { | |||
| Execute exe = new Execute(new LogStreamHandler(owner, | |||
| Project.MSG_INFO, | |||
| Project.MSG_WARN)); | |||
| exe.setAntRun(project); | |||
| exe.setWorkingDirectory(project.getBaseDir()); | |||
| exe.setCommandline(args); | |||
| exe.execute(); | |||
| return exe.getExitValue()==0; | |||
| } catch (IOException exception) { | |||
| throw new BuildException("Error running "+ SunRmic.RMIC_EXECUTABLE | |||
| +" -maybe it is not on the path" , | |||
| exception); | |||
| } | |||
| } | |||
| } | |||
| @@ -21,6 +21,7 @@ import java.lang.reflect.Constructor; | |||
| import java.lang.reflect.Method; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.util.facade.FacadeTaskHelper; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| /** | |||
| @@ -29,6 +30,7 @@ import org.apache.tools.ant.types.Commandline; | |||
| * @since Ant 1.4 | |||
| */ | |||
| public class KaffeRmic extends DefaultRmicAdapter { | |||
| public static final String RMIC_CLASSNAME = "kaffe.rmi.rmic.RMIC"; | |||
| public boolean execute() throws BuildException { | |||
| getRmic().log("Using Kaffe rmic", Project.MSG_VERBOSE); | |||
| @@ -36,7 +38,7 @@ public class KaffeRmic extends DefaultRmicAdapter { | |||
| try { | |||
| Class c = Class.forName("kaffe.rmi.rmic.RMIC"); | |||
| Class c = Class.forName(RMIC_CLASSNAME); | |||
| Constructor cons = c.getConstructor(new Class[] {String[].class}); | |||
| Object rmic = cons.newInstance(new Object[] {cmd.getArguments()}); | |||
| Method doRmic = c.getMethod("run", null); | |||
| @@ -58,4 +60,17 @@ public class KaffeRmic extends DefaultRmicAdapter { | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * test for kaffe being on the system | |||
| * @return | |||
| */ | |||
| public static boolean isAvailable() { | |||
| try { | |||
| Class.forName(RMIC_CLASSNAME); | |||
| return true; | |||
| } catch (ClassNotFoundException cnfe) { | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| @@ -23,7 +23,7 @@ import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.util.FileNameMapper; | |||
| /** | |||
| * The interface that all rmic adapters must adher to. | |||
| * The interface that all rmic adapters must adhere to. | |||
| * | |||
| * <p>A rmic adapter is an adapter that interprets the rmic's | |||
| * parameters in preperation to be passed off to the compiler this | |||
| @@ -27,6 +27,8 @@ import org.apache.tools.ant.Task; | |||
| * @since 1.4 | |||
| */ | |||
| public class RmicAdapterFactory { | |||
| public static final String ERROR_UNKNOWN_COMPILER = "Cannot find the compiler or class: "; | |||
| public static final String ERROR_NOT_RMIC_ADAPTER = "Not an rmic adapter: "; | |||
| /** This is a singleton -- can't create instances!! */ | |||
| private RmicAdapterFactory() { | |||
| @@ -41,6 +43,8 @@ public class RmicAdapterFactory { | |||
| * <li>kaffe = Kaffe's rmic | |||
| * <li><i>a fully quallified classname</i> = the name of a rmic | |||
| * adapter | |||
| * <li>weblogic = weblogic compiler | |||
| * <li>forking = Sun's RMIC by forking a new JVM | |||
| * </ul> | |||
| * | |||
| * @param rmicType either the name of the desired rmic, or the | |||
| @@ -57,6 +61,8 @@ public class RmicAdapterFactory { | |||
| return new KaffeRmic(); | |||
| } else if (rmicType.equalsIgnoreCase("weblogic")) { | |||
| return new WLRmic(); | |||
| } else if (rmicType.equalsIgnoreCase("forking")) { | |||
| return new ForkingSunRmic(); | |||
| } | |||
| return resolveClassName(rmicType); | |||
| } | |||
| @@ -76,10 +82,11 @@ public class RmicAdapterFactory { | |||
| Object o = c.newInstance(); | |||
| return (RmicAdapter) o; | |||
| } catch (ClassNotFoundException cnfe) { | |||
| throw new BuildException(className + " can\'t be found.", cnfe); | |||
| throw new BuildException(ERROR_UNKNOWN_COMPILER+className, | |||
| cnfe); | |||
| } catch (ClassCastException cce) { | |||
| throw new BuildException(className + " isn\'t the classname of " | |||
| + "a rmic adapter.", cce); | |||
| throw new BuildException(ERROR_NOT_RMIC_ADAPTER+className, | |||
| cce); | |||
| } catch (Throwable t) { | |||
| // for all other possibilities | |||
| throw new BuildException(className + " caused an interesting " | |||
| @@ -33,6 +33,21 @@ import org.apache.tools.ant.types.Commandline; | |||
| */ | |||
| public class SunRmic extends DefaultRmicAdapter { | |||
| /** | |||
| * name of the class | |||
| */ | |||
| public static final String RMIC_CLASSNAME = "sun.rmi.rmic.Main"; | |||
| /** | |||
| * name of the executable | |||
| */ | |||
| public static final String RMIC_EXECUTABLE = "rmic"; | |||
| public static final String ERROR_NO_RMIC_ON_CLASSPATH = "Cannot use SUN rmic, as it is not " | |||
| + "available. A common solution is to " | |||
| + "set the environment variable " | |||
| + "JAVA_HOME or CLASSPATH."; | |||
| public static final String ERROR_RMIC_FAILED = "Error starting SUN rmic: "; | |||
| public boolean execute() throws BuildException { | |||
| getRmic().log("Using SUN rmic compiler", Project.MSG_VERBOSE); | |||
| Commandline cmd = setupRmicCommand(); | |||
| @@ -43,7 +58,7 @@ public class SunRmic extends DefaultRmicAdapter { | |||
| Project.MSG_WARN); | |||
| try { | |||
| Class c = Class.forName("sun.rmi.rmic.Main"); | |||
| Class c = Class.forName(RMIC_CLASSNAME); | |||
| Constructor cons | |||
| = c.getConstructor(new Class[] {OutputStream.class, String.class}); | |||
| Object rmic = cons.newInstance(new Object[] {logstr, "rmic"}); | |||
| @@ -55,16 +70,13 @@ public class SunRmic extends DefaultRmicAdapter { | |||
| (new Object[] {cmd.getArguments()})); | |||
| return ok.booleanValue(); | |||
| } catch (ClassNotFoundException ex) { | |||
| throw new BuildException("Cannot use SUN rmic, as it is not " | |||
| + "available. A common solution is to " | |||
| + "set the environment variable " | |||
| + "JAVA_HOME or CLASSPATH.", | |||
| throw new BuildException(ERROR_NO_RMIC_ON_CLASSPATH, | |||
| getRmic().getLocation()); | |||
| } catch (Exception ex) { | |||
| if (ex instanceof BuildException) { | |||
| throw (BuildException) ex; | |||
| } else { | |||
| throw new BuildException("Error starting SUN rmic: ", | |||
| throw new BuildException(ERROR_RMIC_FAILED, | |||
| ex, getRmic().getLocation()); | |||
| } | |||
| } finally { | |||
| @@ -29,6 +29,12 @@ import org.apache.tools.ant.types.Commandline; | |||
| * @since Ant 1.4 | |||
| */ | |||
| public class WLRmic extends DefaultRmicAdapter { | |||
| public static final String WLRMIC_CLASSNAME = "weblogic.rmic"; | |||
| public static final String ERROR_NO_WLRMIC_ON_CLASSPATH = "Cannot use WebLogic rmic, as it is not " | |||
| + "available. A common solution is to " | |||
| + "set the environment variable " | |||
| + "CLASSPATH."; | |||
| public static final String ERROR_WLRMIC_FAILED = "Error starting WebLogic rmic: "; | |||
| public boolean execute() throws BuildException { | |||
| getRmic().log("Using WebLogic rmic", Project.MSG_VERBOSE); | |||
| @@ -39,26 +45,23 @@ public class WLRmic extends DefaultRmicAdapter { | |||
| // Create an instance of the rmic | |||
| Class c = null; | |||
| if (getRmic().getClasspath() == null) { | |||
| c = Class.forName("weblogic.rmic"); | |||
| c = Class.forName(WLRMIC_CLASSNAME); | |||
| } else { | |||
| loader | |||
| = getRmic().getProject().createClassLoader(getRmic().getClasspath()); | |||
| c = Class.forName("weblogic.rmic", true, loader); | |||
| c = Class.forName(WLRMIC_CLASSNAME, true, loader); | |||
| } | |||
| Method doRmic = c.getMethod("main", | |||
| new Class [] {String[].class}); | |||
| doRmic.invoke(null, new Object[] {cmd.getArguments()}); | |||
| return true; | |||
| } catch (ClassNotFoundException ex) { | |||
| throw new BuildException("Cannot use WebLogic rmic, as it is not " | |||
| + "available. A common solution is to " | |||
| + "set the environment variable " | |||
| + "CLASSPATH.", getRmic().getLocation()); | |||
| throw new BuildException(ERROR_NO_WLRMIC_ON_CLASSPATH, getRmic().getLocation()); | |||
| } catch (Exception ex) { | |||
| if (ex instanceof BuildException) { | |||
| throw (BuildException) ex; | |||
| } else { | |||
| throw new BuildException("Error starting WebLogic rmic: ", ex, | |||
| throw new BuildException(ERROR_WLRMIC_FAILED, ex, | |||
| getRmic().getLocation()); | |||
| } | |||
| } finally { | |||
| @@ -0,0 +1,98 @@ | |||
| /** (C) Copyright 2004 Hewlett-Packard Development Company, LP | |||
| This library is free software; you can redistribute it and/or | |||
| modify it under the terms of the GNU Lesser General Public | |||
| License as published by the Free Software Foundation; either | |||
| version 2.1 of the License, or (at your option) any later version. | |||
| This library is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public | |||
| License along with this library; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| For more information: www.smartfrog.org | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import org.apache.tools.ant.BuildFileTest; | |||
| import org.apache.tools.ant.taskdefs.rmic.RmicAdapterFactory; | |||
| /** | |||
| * Date: 04-Aug-2004 | |||
| * Time: 22:15:46 | |||
| */ | |||
| public class RmicAdvancedTest extends BuildFileTest { | |||
| public RmicAdvancedTest(String name) { | |||
| super(name); | |||
| } | |||
| private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/rmic/"; | |||
| /** | |||
| * The JUnit setup method | |||
| */ | |||
| public void setUp() { | |||
| configureProject(TASKDEFS_DIR + "rmic.xml"); | |||
| } | |||
| /** | |||
| * The teardown method for JUnit | |||
| */ | |||
| public void tearDown() { | |||
| executeTarget("teardown"); | |||
| } | |||
| /** | |||
| * A unit test for JUnit | |||
| */ | |||
| public void testRmic() throws Exception { | |||
| executeTarget("testRmic"); | |||
| } | |||
| /** | |||
| * A unit test for JUnit | |||
| */ | |||
| public void testKaffe() throws Exception { | |||
| executeTarget("testKaffe"); | |||
| } | |||
| /** | |||
| * A unit test for JUnit | |||
| */ | |||
| public void testWlrmic() throws Exception { | |||
| executeTarget("testWlrmic"); | |||
| } | |||
| /** | |||
| * A unit test for JUnit | |||
| */ | |||
| public void testForking() throws Exception { | |||
| executeTarget("testForking"); | |||
| } | |||
| /** | |||
| * A unit test for JUnit | |||
| */ | |||
| public void testBadName() throws Exception { | |||
| expectBuildExceptionContaining("testBadName", | |||
| "compiler not known", | |||
| RmicAdapterFactory.ERROR_UNKNOWN_COMPILER); | |||
| } | |||
| /** | |||
| * A unit test for JUnit | |||
| */ | |||
| public void testWrongClass() throws Exception { | |||
| expectBuildExceptionContaining("testWrongClass", | |||
| "class not an RMIC adapter", | |||
| RmicAdapterFactory.ERROR_NOT_RMIC_ADAPTER); | |||
| } | |||
| } | |||
| @@ -18,9 +18,9 @@ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import org.apache.tools.ant.Project; | |||
| import junit.framework.TestCase; | |||
| /** | |||
| * Testcase for <rmic>. | |||
| * | |||
| @@ -43,6 +43,19 @@ public class RmicTest extends TestCase { | |||
| rmic.setProject(project); | |||
| } | |||
| /** | |||
| * test for a compiler class existing | |||
| * @param compilerClass | |||
| * @return | |||
| */ | |||
| private boolean hasCompiler(String compilerClass) { | |||
| try { | |||
| Class.forName(compilerClass); | |||
| return true; | |||
| } catch (ClassNotFoundException cnfe) { | |||
| return false; | |||
| } | |||
| } | |||
| /** | |||
| * Test nested compiler args. | |||
| */ | |||
| @@ -99,5 +112,4 @@ public class RmicTest extends TestCase { | |||
| assertNotNull(compiler); | |||
| assertEquals("kaffe", compiler); | |||
| } | |||
| } | |||