diff --git a/src/main/org/apache/tools/ant/AntClassLoader.java b/src/main/org/apache/tools/ant/AntClassLoader.java index ab958cf84..e9cedf16b 100644 --- a/src/main/org/apache/tools/ant/AntClassLoader.java +++ b/src/main/org/apache/tools/ant/AntClassLoader.java @@ -57,6 +57,7 @@ package org.apache.tools.ant; import java.util.*; import java.util.zip.*; import java.io.*; +import org.apache.tools.ant.types.Path; /** * Used to load classes within ant with a different claspath from that used to start ant. @@ -75,7 +76,7 @@ public class AntClassLoader extends ClassLoader { /** * The classpath that is to be used when loading classes using this class loader. */ - private org.apache.tools.ant.types.Path classpath; + private Path classpath; /** * The project to which this class loader belongs. @@ -83,9 +84,22 @@ public class AntClassLoader extends ClassLoader { private Project project; /** - * The File components of the path. Typically these will be directories or jar files. + * Indicates whether the system class loader should be + * consulted before trying to load with this class loader. */ - private Vector components = null; + private boolean systemFirst = true; + + /** + * These are the package roots that are to be loaded by the system class loader + * regardless of whether the system class loader is being searched first or not. + */ + private Vector systemPackages = new Vector(); + + /** + * These are the package roots that are to be loaded by this class loader + * regardless of whether the system class loader is being searched first or not. + */ + private Vector loaderPackages = new Vector(); /** * Create a classloader for the given project using the classpath given. @@ -93,28 +107,47 @@ public class AntClassLoader extends ClassLoader { * @param project the project to ehich this classloader is to belong. * @param classpath the classpath to use to load the classes. */ - public AntClassLoader(Project project, - org.apache.tools.ant.types.Path classpath) { + public AntClassLoader(Project project, Path classpath) { this.project = project; this.classpath = classpath; } /** - * Set up this classloader for the first time. + * Create a classloader for the given project using the classpath given. * - * This method will set up the components field with the components from the - * given classpath. + * @param project the project to ehich this classloader is to belong. + * @param classpath the classpath to use to load the classes. */ - private void setup() { - // We iterate through the class path, resolving each element. - components = new Vector(); - - String[] pathElements = classpath.list(); - for (int i = 0; i < pathElements.length; ++i) { - File element = project.resolveFile(pathElements[i]); - components.addElement(element); - } + public AntClassLoader(Project project, Path classpath, boolean systemFirst) { + this(project, classpath); + this.systemFirst = systemFirst; } + + /** + * Add a package root to the list of packages which must be loaded on the + * system loader. + * + * All subpackages are also included. + * + * @param packageRoot the root of akll packages to be included. + */ + public void addSystemPackageRoot(String packageRoot) { + systemPackages.addElement(packageRoot + "."); + } + + /** + * Add a package root to the list of packages which must be loaded using + * this loader. + * + * All subpackages are also included. + * + * @param packageRoot the root of akll packages to be included. + */ + public void addLoaderPackageRoot(String packageRoot) { + loaderPackages.addElement(packageRoot + "."); + } + + /** * Load a class through this class loader even if that class is available on the @@ -131,6 +164,7 @@ public class AntClassLoader extends ClassLoader { * this loader's classpath. */ public Class forceLoadClass(String classname) throws ClassNotFoundException { + project.log("force loading " + classname, Project.MSG_VERBOSE); Class theClass = findLoadedClass(classname); if (theClass == null) { @@ -140,6 +174,30 @@ public class AntClassLoader extends ClassLoader { return theClass; } + /** + * Load a class through this class loader but defer to the system class loader + * + * This ensures that instances of the returned class will be compatible with instances which + * which have already been loaded on the system loader. + * + * @param classname the classname to be loaded. + * + * @return the required Class object + * + * @throws ClassNotFoundException if the requested class does not exist on + * this loader's classpath. + */ + public Class forceLoadSystemClass(String classname) throws ClassNotFoundException { + project.log("force system loading " + classname, Project.MSG_VERBOSE); + Class theClass = findLoadedClass(classname); + + if (theClass == null) { + theClass = findSystemClass(classname); + } + + return theClass; + } + /** * Get a stream to read the requested resource name. * @@ -149,17 +207,13 @@ public class AntClassLoader extends ClassLoader { * found on the loader's classpath. */ public InputStream getResourceAsStream(String name) { - if (components == null) { - // we haven't set up the list of directories and jars yet. - setup(); - } - // we need to search the components of the path to see if we can find the // class we want. InputStream stream = null; - - for (Enumeration e = components.elements(); e.hasMoreElements() && stream == null; ) { - File pathComponent = (File)e.nextElement(); + + String[] pathElements = classpath.list(); + for (int i = 0; i < pathElements.length && stream == null; ++i) { + File pathComponent = project.resolveFile((String)pathElements[i]); stream = getResourceStream(pathComponent, name); } @@ -168,7 +222,7 @@ public class AntClassLoader extends ClassLoader { /** * Get an inputstream to a given resource in the given file which may - * either be a directory or a jar type file. + * either be a directory or a zip file. * * @param file the file (directory or jar) in which to search for the resource. * @param resourceName the name of the resource for which a stream is required. @@ -184,6 +238,7 @@ public class AntClassLoader extends ClassLoader { if (file.isDirectory()) { File resource = new File(file, resourceName); + if (resource.exists()) { return new FileInputStream(resource); } @@ -238,14 +293,49 @@ public class AntClassLoader extends ClassLoader { * the system classpath or this loader's classpath. */ protected Class loadClass(String classname, boolean resolve) throws ClassNotFoundException { - + + // default to the global setting and then see + // if this class belongs to a package which has been + // designated to use a specific loader first (this one or the system one) + boolean useSystemFirst = systemFirst; + + for (Enumeration e = systemPackages.elements(); e.hasMoreElements();) { + String packageName = (String)e.nextElement(); + if (classname.startsWith(packageName)) { + useSystemFirst = true; + break; + } + } + + for (Enumeration e = loaderPackages.elements(); e.hasMoreElements();) { + String packageName = (String)e.nextElement(); + if (classname.startsWith(packageName)) { + useSystemFirst = false; + break; + } + } + Class theClass = findLoadedClass(classname); if (theClass == null) { - try { - theClass = findSystemClass(classname); + if (useSystemFirst) { + try { + theClass = findSystemClass(classname); + project.log("Class " + classname + " loaded from system loader", Project.MSG_VERBOSE); + } + catch (ClassNotFoundException cnfe) { + theClass = findClass(classname); + project.log("Class " + classname + " loaded from ant loader", Project.MSG_VERBOSE); + } } - catch (ClassNotFoundException cnfe) { - theClass = findClass(classname); + else { + try { + theClass = findClass(classname); + project.log("Class " + classname + " loaded from ant loader", Project.MSG_VERBOSE); + } + catch (ClassNotFoundException cnfe) { + theClass = findSystemClass(classname); + project.log("Class " + classname + " loaded from system loader", Project.MSG_VERBOSE); + } } } @@ -294,6 +384,7 @@ public class AntClassLoader extends ClassLoader { return defineClass(classname, classData, 0, classData.length); } + /** * Search for and load a class on the classpath of this class loader. * @@ -305,18 +396,29 @@ public class AntClassLoader extends ClassLoader { * this loader's classpath. */ public Class findClass(String name) throws ClassNotFoundException { - if (components == null) { - // we haven't set up the list of directories and jars yet. - setup(); + project.log("Finding class " + name, Project.MSG_VERBOSE); + + try { + return findClass(name, classpath); + } + catch (ClassNotFoundException e) { + throw e; } + } + + /** + * Find a class on the given classpath. + */ + private Class findClass(String name, Path path) throws ClassNotFoundException { // we need to search the components of the path to see if we can find the // class we want. InputStream stream = null; String classFilename = getClassFilename(name); try { - for (Enumeration e = components.elements(); e.hasMoreElements() && stream == null; ) { - File pathComponent = (File)e.nextElement(); + String[] pathElements = path.list(); + for (int i = 0; i < pathElements.length && stream == null; ++i) { + File pathComponent = project.resolveFile((String)pathElements[i]); stream = getResourceStream(pathComponent, classFilename); } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ejb/Ejbc.java b/src/main/org/apache/tools/ant/taskdefs/optional/ejb/Ejbc.java index 2f6844d2c..dfc34be11 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/ejb/Ejbc.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/ejb/Ejbc.java @@ -54,9 +54,7 @@ package org.apache.tools.ant.taskdefs.optional.ejb; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.DirectoryScanner; -import org.apache.tools.ant.Project; +import org.apache.tools.ant.*; import org.apache.tools.ant.taskdefs.*; import org.apache.tools.ant.types.Path; @@ -70,6 +68,19 @@ import java.io.File; * @author Conor MacNeill, Cortex ebusiness Pty Limited */ public class Ejbc extends MatchingTask { + static public interface Helper { + public void initialize(Ejbc ejbcTask); + public void setDescriptorDir(File dir); + public void setDest(File dir); + public void setManifest(File manifestFile); + public void setClasspath(Path classpath); + public void setSrc(File dir); + public void setDescriptors(String[] descriptors); + public void execute(); + } + + + /** * The root directory of the tree containing the serialised deployment desciptors. The actual * deployment descriptor files are selected using include and exclude constructs @@ -91,7 +102,7 @@ public class Ejbc extends MatchingTask { * The classpath to be used in the weblogic ejbc calls. It must contain the weblogic * classes and the implementation classes of the home and remote interfaces. */ - private String classpath; + private Path classpath; /** * The source directory for the home and remote interfaces. This is used to determine if @@ -129,49 +140,53 @@ public class Ejbc extends MatchingTask { } String systemClassPath = System.getProperty("java.class.path"); - String execClassPath = project.translatePath(systemClassPath + ":" + classpath + - ":" + generatedFilesDirectory); + Path execClassPath = new Path(project, classpath + ":" + generatedFilesDirectory + ":" + systemClassPath); + // get all the files in the descriptor directory DirectoryScanner ds = super.getDirectoryScanner(descriptorDirectory); - String[] files = ds.getIncludedFiles(); + String[] descriptorNames = ds.getIncludedFiles(); + - Java helperTask = (Java)project.createTask("java"); - helperTask.setFork(true); - helperTask.setClassname("org.apache.tools.ant.taskdefs.optional.ejb.EjbcHelper"); - String args = ""; - args += " " + descriptorDirectory; - args += " " + generatedFilesDirectory; - args += " " + sourceDirectory; - args += " " + generatedManifestFile; - for (int i = 0; i < files.length; ++i) { - args += " " + files[i]; + // create an class loader + AntClassLoader loader = new AntClassLoader(project, execClassPath, false); + loader.addSystemPackageRoot("org.apache.tools.ant"); + loader.addSystemPackageRoot("javax"); + try { + Helper helper = (Helper)(loader.forceLoadClass("org.apache.tools.ant.taskdefs.optional.ejb.EjbcHelper").newInstance()); + helper.initialize(this); + helper.setDescriptorDir(descriptorDirectory); + helper.setDest(generatedFilesDirectory); + helper.setManifest(generatedManifestFile); + helper.setSrc(sourceDirectory); + helper.setDescriptors(descriptorNames); + helper.setClasspath(execClassPath); + helper.execute(); + helper = null; } - - helperTask.setArgs(args); - helperTask.setClasspath(new Path(project, execClassPath)); - if (helperTask.executeJava() != 0) { - throw new BuildException("Execution of ejbc helper failed"); + catch (Exception e) { + throw new BuildException(e); } + loader = null; } /** * Set the directory from where the serialised deployment descriptors are * to be read. * - * @param dirName the name of the directory containing the serialised deployment descriptors. + * @param dir the directory containing the serialised deployment descriptors. */ - public void setDescriptors(String dirName) { - descriptorDirectory = new File(dirName); + public void setDescriptors(File dir) { + descriptorDirectory = dir; } /** * Set the directory into which the support classes, RMI stubs, etc are to be written * - * @param dirName the name of the directory into which code is generated + * @param dir the directory into which code is generated */ - public void setDest(String dirName) { - generatedFilesDirectory = new File(dirName); + public void setDest(File dir) { + generatedFilesDirectory = dir; } /** @@ -180,27 +195,27 @@ public class Ejbc extends MatchingTask { * For each EJB that is processed an entry is created in this file. This can then be used * to create a jar file for dploying the beans. * - * @param manfestFilename the name of the manifest file to be generated. + * @param manfestFilename the manifest file to be generated. */ - public void setManifest(String manifestFilename) { - generatedManifestFile = new File(manifestFilename); + public void setManifest(File manifestFile) { + generatedManifestFile = manifestFile; } /** * Set the classpath to be used for this compilation. */ - public void setClasspath(String s) { - this.classpath = project.translatePath(s); + public void setClasspath(Path classpath) { + this.classpath = classpath; } /** * Set the directory containing the source code for the home interface, remote interface * and public key class definitions. * - * @param dirName the directory containg the source tree for the EJB's interface classes. + * @param dir the directory containg the source tree for the EJB's interface classes. */ - public void setSrc(String dirName) { - sourceDirectory = new File(dirName); + public void setSrc(File dir) { + sourceDirectory = dir; } } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbcHelper.java b/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbcHelper.java index 262ff887a..f68345f83 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbcHelper.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbcHelper.java @@ -53,16 +53,13 @@ */ package org.apache.tools.ant.taskdefs.optional.ejb; -import java.io.File; -import java.io.FileInputStream; -import java.io.ObjectInputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.FileWriter; +import java.io.*; import javax.ejb.deployment.EntityDescriptor; import javax.ejb.deployment.DeploymentDescriptor; +import org.apache.tools.ant.*; +import org.apache.tools.ant.types.Path; /** * A helper class which performs the actual work of the ejbc task. @@ -72,7 +69,7 @@ import javax.ejb.deployment.DeploymentDescriptor; * * @author Conor MacNeill, Cortex ebusiness Pty Limited */ -public class EjbcHelper { +public class EjbcHelper implements Ejbc.Helper { /** * The root directory of the tree containing the serialised deployment desciptors. */ @@ -92,43 +89,127 @@ public class EjbcHelper { * The classpath to be used in the weblogic ejbc calls. It must contain the weblogic * classes and the implementation classes of the home and remote interfaces. */ - private String classpath; + private Path classpath; /** * The source directory for the home and remote interfaces. This is used to determine if * the generated deployment classes are out of date. */ private File sourceDirectory; + + /** + * The array of descriptor filenames to be processed + */ + private String[] files; + + /** + * The Ejbc task that this helper is helping + */ + private Ejbc ejbcTask; /** * The names of the serialised deployment descriptors */ String[] descriptors; + public EjbcHelper() { + } + + public void initialize(Ejbc ejbcTask) { + this.ejbcTask = ejbcTask; + } + /** - * Command line interface for the ejbc helper task. - */ - public static void main(String[] args) throws Exception { - EjbcHelper helper = new EjbcHelper(args); - helper.process(); + * Set the directory from where the serialised deployment descriptors are + * to be read. + * + * @param dir the directory containing the serialised deployment descriptors. + */ + public void setDescriptorDir(File dir) { + descriptorDirectory = dir; + } + + /** + * Set the directory into which the support classes, RMI stubs, etc are to be written + * + * @param dir the directory into which code is generated + */ + public void setDest(File dir) { + generatedFilesDirectory = dir; } /** - * Initialise the EjbcHelper by reading the command arguments. - */ - private EjbcHelper(String[] args) { - int index = 0; - descriptorDirectory = new File(args[index++]); - generatedFilesDirectory = new File(args[index++]); - sourceDirectory = new File(args[index++]); - manifestFile = new File(args[index++]); - - descriptors = new String[args.length - index]; - for (int i = 0; index < args.length; ++i) { - descriptors[i] = args[index++]; + * Set the generated manifest file. + * + * For each EJB that is processed an entry is created in this file. This can then be used + * to create a jar file for dploying the beans. + * + * @param manfestFilename the manifest file to be generated. + */ + public void setManifest(File manifestFile) { + this.manifestFile = manifestFile; + } + + /** + * Set the classpath to be used for this compilation. + */ + public void setClasspath(Path classpath) { + this.classpath = classpath; + } + + /** + * Set the list of desciptors which ar eto be processed. + * + * @param descriptors an array of serialised deployment descriptor filenames to be processed. + */ + public void setDescriptors(String[] descriptors) { + this.descriptors = descriptors; + } + + + + /** + * Set the directory containing the source code for the home interface, remote interface + * and public key class definitions. + * + * @param dir the directory containg the source tree for the EJB's interface classes. + */ + public void setSrc(File dir) { + sourceDirectory = dir; + } + + /** + * Perform the weblogic compiles. + */ + public void execute() throws BuildException { + try { + String manifest = "Manifest-Version: 1.0\n\n"; + for (int i = 0; i < descriptors.length; ++i) { + String descriptorName = descriptors[i]; + File descriptorFile = new File(descriptorDirectory, descriptorName); + + if (isRegenRequired(descriptorFile)) { + ejbcTask.log("Running ejbc for " + descriptorFile.getName(), Project.MSG_INFO); + regenerateSupportClasses(descriptorFile); + } + else { + ejbcTask.log(descriptorFile.getName() + " is up to date", Project.MSG_VERBOSE); + } + manifest += "Name: " + descriptorFile.getName() + "\nEnterprise-Bean: True\n\n"; + } + + FileWriter fw = new FileWriter(manifestFile); + PrintWriter pw = new PrintWriter(fw); + pw.print(manifest); + fw.flush(); + fw.close(); + } + catch (IOException e) { + throw new BuildException(e); } } + /** * Determine if the weblogic EJB support classes need to be regenerated * for a given deployment descriptor. @@ -210,7 +291,8 @@ public class EjbcHelper { } } catch (Throwable descriptorLoadException) { - System.out.println("Exception occurred reading " + descriptorFile.getName() + " - continuing"); + ejbcTask.log("Exception occurred reading " + descriptorFile.getName() + " - continuing", + Project.MSG_WARN); // any problems - just regenerate return true; } @@ -223,56 +305,57 @@ public class EjbcHelper { return false; } - /** - * Process the descriptors in turn generating support classes for each and a manifest - * file for all of the beans. - */ - private void process() throws Exception { - String manifest = "Manifest-Version: 1.0\n\n"; - for (int i = 0; i < descriptors.length; ++i) { - String descriptorName = descriptors[i]; - File descriptorFile = new File(descriptorDirectory, descriptorName); - - if (isRegenRequired(descriptorFile)) { - System.out.println("Running ejbc for " + descriptorFile.getName()); - regenerateSupportClasses(descriptorFile); - } - else { - System.out.println(descriptorFile.getName() + " is up to date"); - } - manifest += "Name: " + descriptorFile.getName() + "\nEnterprise-Bean: True\n\n"; - } - - FileWriter fw = new FileWriter(manifestFile); - PrintWriter pw = new PrintWriter(fw); - pw.print(manifest); - fw.flush(); - fw.close(); - } - /** * Perform the weblogic.ejbc call to regenerate the support classes. * * Note that this method relies on an undocumented -noexit option to the * ejbc tool to stop the ejbc tool exiting the VM altogether. */ - private void regenerateSupportClasses(File descriptorFile) throws Exception { - // create a Java task to do the rebuild + private void regenerateSupportClasses(File descriptorFile) { + Project project = ejbcTask.getProject(); + String javaHome = System.getProperty("java.home"); - String[] args = {"-noexit", - "-keepgenerated", - "-d", generatedFilesDirectory.getPath(), - descriptorFile.getPath()}; + String compiler = project.getProperty("build.compiler"); + String[] args = null; + if (compiler.equalsIgnoreCase("jikes")) { + Path execClassPath = new Path(project); + if (Project.getJavaVersion() == Project.JAVA_1_1) { + execClassPath.addExisting(new Path(project, System.getProperty("java.home") + + "/lib/classes.zip")); + } else { + execClassPath.addExisting(new Path(project, + System.getProperty("java.home") + + "/lib/rt.jar")); + // Just keep the old version as well and let addExisting + // sort it out. + execClassPath.addExisting(new Path(project, + System.getProperty("java.home") + + "/jre/lib/rt.jar")); + } + execClassPath.append(classpath); + + args = new String[] {"-noexit", + "-keepgenerated", + "-compiler", "Jikes", + "-d", generatedFilesDirectory.getPath(), + "-classpath", execClassPath.toString(), + descriptorFile.getPath()}; + } + else { + args = new String[]{"-noexit", + "-keepgenerated", + "-d", generatedFilesDirectory.getPath(), + "-classpath", classpath.toString(), + descriptorFile.getPath()}; + } + try { weblogic.ejbc.main(args); } catch (Exception e) { - // run with no exit for better reporting - String[] newArgs = {"-keepgenerated", - "-d", generatedFilesDirectory.getPath(), - descriptorFile.getPath()}; - weblogic.ejbc.main(newArgs); + e.printStackTrace(); + throw new BuildException(e); } } }