diff --git a/docs/index.html b/docs/index.html index b735cd9e5..d46a634b9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2360,6 +2360,19 @@ in selected file.
Runs the rmic compiler for a certain class.
+Rmic can be run on a single class (as specified with the classname +attribute) or a number of classes at once (all classes below base that +are neither _Stub nor _Skel classes).
+It is possible to refine the set of files that are being rmiced. This can be +done with the includes, includesfile, excludes, excludesfile and defaultexcludes +attributes. With the includes or includesfile attribute you specify the files you want to +have included by using patterns. The exclude or excludesfile attribute is used to specify +the files you want to have excluded. This is also done with patterns. And +finally with the defaultexcludes attribute, you can specify whether you +want to use default exclusions or not. See the section on directory based tasks, on how the +inclusion/exclusion of files works, and how to write patterns. The patterns are +relative to the base directory.
classname | the class for which to run rmic . |
- Yes | +No |
filtering | @@ -2399,11 +2412,52 @@ in selected file.The classpath to use during compilation | No | |
includes | +comma separated list of patterns of files that must be + included. All files are included when omitted. | +No | +|
includesfile | +the name of a file. Each line of this file is + taken to be an include pattern | +No | +|
excludes | +comma separated list of patterns of files that must be + excluded. No files (except default excludes) are excluded when omitted. | +No | +|
excludesfile | +the name of a file. Each line of this file is + taken to be an exclude pattern | +No | +|
defaultexcludes | +indicates whether default excludes should be used or not + ("yes"/"no"). Default excludes are used when omitted. | +No | +|
verify | +check that classes implement Remote before handing them + to rmic (default is false) | +No | +
<rmic classname="com.xyz.FooBar" base="${build}/classes" />
runs the rmic compiler for the class com.xyz.FooBar
. The
compiled files will be stored in the directory ${build}/classes
.
<rmic base="${build}/classes" includes="**/Remote*.class" />+
runs the rmic compiler for all classes with .class
+files below ${build}/classes
whose classname starts with
+Remote. The compiled files will be stored in the directory
+${build}/classes
.
+ * If classname is specified then only that classname will be compiled. If it + * is absent, then base is traversed for classes according to patterns. *
* * @author duncan@x180.com * @author ludovic.claude@websitewatchers.co.uk + * @author David Maclean david@cm.co.za */ -public class Rmic extends Task { +public class Rmic extends MatchingTask { private String base; private String classname; private String sourceBase; private String stubVersion; private String compileClasspath; + private boolean verify = false; private boolean filtering = false; + private Vector compileList = new Vector(); + public void setBase(String base) { this.base = base; } @@ -118,26 +127,55 @@ public class Rmic extends Task { compileClasspath = project.translatePath(classpath); } + /** + * Indicates that the classes found by the directory match should be + * checked to see if they implement java.rmi.Remote. + * This defaults to false if not set. + */ + public void setVerify(String verify) { + this.verify = Project.toBoolean(verify); + } + public void execute() throws BuildException { - File baseFile = project.resolveFile(base); + File baseDir = project.resolveFile(base); + if (baseDir == null) { + throw new BuildException("base attribute must be set!", location); + } + if (!baseDir.exists()) { + throw new BuildException("base does not exist!", location); + } + + if (verify) { + project.log("Verify has been turned on.", Project.MSG_INFO); + } File sourceBaseFile = null; - if (null != sourceBase) + if (null != sourceBase) { sourceBaseFile = project.resolveFile(sourceBase); - String classpath = getCompileClasspath(baseFile); + } + String classpath = getCompileClasspath(baseDir); + + // scan base dirs to build up compile lists + + DirectoryScanner ds = this.getDirectoryScanner(baseDir); + + String[] files = ds.getIncludedFiles(); + + scanDir(baseDir, files, verify); + // XXX // need to provide an input stream that we read in from! sun.rmi.rmic.Main compiler = new sun.rmi.rmic.Main(System.out, "rmic"); - int argCount = 5; + int argCount = 5; int i = 0; if (null != stubVersion) argCount++; if (null != sourceBase) argCount++; + if (compileList.size() > 0) argCount += compileList.size() - 1; String[] args = new String[argCount]; args[i++] = "-d"; - args[i++] = baseFile.getAbsolutePath(); + args[i++] = baseDir.getAbsolutePath(); args[i++] = "-classpath"; args[i++] = classpath; - args[i++] = classname; if (null != stubVersion) { if ("1.1".equals(stubVersion)) args[i++] = "-v1.1"; @@ -148,35 +186,162 @@ public class Rmic extends Task { } if (null != sourceBase) args[i++] = "-keepgenerated"; - compiler.compile(args); + if (classname != null) { + if (shouldCompile(new File(baseDir, classname.replace('.', File.separatorChar)))) { + args[i++] = classname; + compiler.compile(args); + } + } else { + if (compileList.size() > 0) { + project.log("RMI Compiling " + compileList.size() + + " classes to " + baseDir, Project.MSG_INFO); + + for (int j = 0; j < compileList.size(); j++) { + args[i++] = (String) compileList.elementAt(j); + } + compiler.compile(args); + } + } // Move the generated source file to the base directory if (null != sourceBase) { - String stubFileName = classname.replace('.', '/') + "_Stub.java"; - File oldStubFile = new File(baseFile, stubFileName); - File newStubFile = new File(sourceBaseFile, stubFileName); + if (classname != null) { + moveGeneratedFile(baseDir, sourceBaseFile, classname); + } else { + for (int j = 0; j < compileList.size(); j++) { + moveGeneratedFile(baseDir, sourceBaseFile, (String) compileList.elementAt(j)); + } + } + } + } + + /** + * Move the generated source file(s) to the base directory + * + * @exception org.apache.tools.ant.BuildException When error copying/removing files. + */ + private void moveGeneratedFile (File baseDir, File sourceBaseFile, String classname) + throws BuildException { + String stubFileName = classname.replace('.', File.separatorChar) + "_Stub.java"; + File oldStubFile = new File(baseDir, stubFileName); + File newStubFile = new File(sourceBaseFile, stubFileName); + try { + project.copyFile(oldStubFile, newStubFile, filtering); + oldStubFile.delete(); + } catch (IOException ioe) { + String msg = "Failed to copy " + oldStubFile + " to " + + newStubFile + " due to " + ioe.getMessage(); + throw new BuildException(msg, ioe, location); + } + if (!"1.2".equals(stubVersion)) { + String skelFileName = classname.replace('.', '/') + "_Skel.java"; + File oldSkelFile = new File(baseDir, skelFileName); + File newSkelFile = new File(sourceBaseFile, skelFileName); try { - project.copyFile(oldStubFile, newStubFile, filtering); - oldStubFile.delete(); + project.copyFile(oldSkelFile, newSkelFile, filtering); + oldSkelFile.delete(); } catch (IOException ioe) { - String msg = "Failed to copy " + oldStubFile + " to " + - newStubFile + " due to " + ioe.getMessage(); - throw new BuildException(msg); + String msg = "Failed to copy " + oldSkelFile + " to " + + newSkelFile + " due to " + ioe.getMessage(); + throw new BuildException(msg, ioe, location); } - if (!"1.2".equals(stubVersion)) { - String skelFileName = classname.replace('.', '/') + "_Skel.java"; - File oldSkelFile = new File(baseFile, skelFileName); - File newSkelFile = new File(sourceBaseFile, skelFileName); - try { - project.copyFile(oldSkelFile, newSkelFile, filtering); - oldSkelFile.delete(); - } catch (IOException ioe) { - String msg = "Failed to copy " + oldSkelFile + " to " + - newSkelFile + " due to " + ioe.getMessage(); - throw new BuildException(msg); + } + } + + /** + * Scans the directory looking for class files to be compiled. + * The result is returned in the class variable compileList. + */ + + protected void scanDir(File baseDir, String files[], boolean shouldVerify) { + compileList.removeAllElements(); + for (int i = 0; i < files.length; i++) { + File baseFile = new File(baseDir, files[i]); + if (files[i].endsWith(".class") && + !files[i].endsWith("_Stub.class") && + !files[i].endsWith("_Skel.class")) { + if (shouldCompile(baseFile)) { + String classname = files[i].replace(File.separatorChar, '.'); + classname = classname.substring(0, classname.indexOf(".class")); + boolean shouldAdd = true; + if (shouldVerify) { + try { + Class testClass = Class.forName(classname); + // One cannot RMIC an interface + if (testClass.isInterface() || !isValidRmiRemote(testClass)) { + shouldAdd = false; + } + } catch (ClassNotFoundException e) { + project.log("Unable to verify class " + classname + + ". It could not be found.", Project.MSG_WARN); + } catch (NoClassDefFoundError e) { + project.log("Unable to verify class " + classname + + ". It is not defined.", Project.MSG_WARN); + } + } + if (shouldAdd) { + project.log("Adding: " + classname + " to compile list", + Project.MSG_VERBOSE); + compileList.addElement(classname); + } + } + } + } + } + + + /** + * Check to see if the class or superclasses/interfaces implement + * java.rmi.Remote. + */ + private boolean isValidRmiRemote (Class testClass) { + Class rmiRemote = java.rmi.Remote.class; + + if (rmiRemote.equals(testClass)) { + // This class is java.rmi.Remote + return true; + } + + Class [] interfaces = testClass.getInterfaces(); + if (interfaces != null) { + for (int i = 0; i < interfaces.length; i++) { + if (rmiRemote.equals(interfaces[i])) { + // This class directly implements java.rmi.Remote + return true; } + if (isValidRmiRemote(interfaces[i])) { + return true; + } + } + } + return false; + } + + /** + * Determine whether the class needs to be RMI compiled. It looks at the _Stub.class + * and _Skel.class files' last modification date and compares it with the class' class file. + */ + private boolean shouldCompile (File classFile) { + long now = (new Date()).getTime(); + File stubFile = new File(classFile.getAbsolutePath().substring(0, + classFile.getAbsolutePath().indexOf(".class")) + "_Stub.class"); + File skelFile = new File(classFile.getAbsolutePath().substring(0, + classFile.getAbsolutePath().indexOf(".class")) + "_Skel.class"); + if (classFile.exists()) { + if (classFile.lastModified() > now) { + project.log("Warning: file modified in the future: " + + classFile, Project.MSG_WARN); + } + + if (classFile.lastModified() > stubFile.lastModified()) { + return true; + } else if (classFile.lastModified() > skelFile.lastModified()) { + return true; + } else { + return false; } } + return true; } /** @@ -235,7 +400,7 @@ public class Rmic extends Task { target.append(f.getAbsolutePath()); } else { project.log("Dropping from classpath: "+ - f.getAbsolutePath(),project.MSG_VERBOSE); + f.getAbsolutePath(), Project.MSG_VERBOSE); } }