0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: *
0017: */
0018:
0019: package org.apache.tools.ant;
0020:
0021: import java.io.ByteArrayOutputStream;
0022: import java.io.File;
0023: import java.io.FileInputStream;
0024: import java.io.IOException;
0025: import java.io.InputStream;
0026: import java.io.InputStreamReader;
0027: import java.io.Reader;
0028: import java.lang.reflect.Constructor;
0029: import java.net.MalformedURLException;
0030: import java.net.URL;
0031: import java.util.Collections;
0032: import java.util.Enumeration;
0033: import java.util.HashMap;
0034: import java.util.Hashtable;
0035: import java.util.Map;
0036: import java.util.StringTokenizer;
0037: import java.util.Vector;
0038: import java.util.jar.Attributes;
0039: import java.util.jar.Attributes.Name;
0040: import java.util.jar.JarFile;
0041: import java.util.jar.Manifest;
0042: import java.util.zip.ZipEntry;
0043: import java.util.zip.ZipFile;
0044: import org.apache.tools.ant.types.Path;
0045: import org.apache.tools.ant.util.CollectionUtils;
0046: import org.apache.tools.ant.util.FileUtils;
0047: import org.apache.tools.ant.util.JavaEnvUtils;
0048: import org.apache.tools.ant.util.LoaderUtils;
0049: import org.apache.tools.ant.launch.Locator;
0050:
0051: /**
0052: * Used to load classes within ant with a different classpath from
0053: * that used to start ant. Note that it is possible to force a class
0054: * into this loader even when that class is on the system classpath by
0055: * using the forceLoadClass method. Any subsequent classes loaded by that
0056: * class will then use this loader rather than the system class loader.
0057: *
0058: * <p>
0059: * Note that this classloader has a feature to allow loading
0060: * in reverse order and for "isolation".
0061: * Due to the fact that a number of
0062: * methods in java.lang.ClassLoader are final (at least
0063: * in java 1.4 getResources) this means that the
0064: * class has to fake the given parent.
0065: * </p>
0066: *
0067: */
0068: public class AntClassLoader extends ClassLoader implements
0069: SubBuildListener {
0070:
0071: private static final FileUtils FILE_UTILS = FileUtils
0072: .getFileUtils();
0073:
0074: /**
0075: * An enumeration of all resources of a given name found within the
0076: * classpath of this class loader. This enumeration is used by the
0077: * ClassLoader.findResources method, which is in
0078: * turn used by the ClassLoader.getResources method.
0079: *
0080: * @see AntClassLoader#findResources(String)
0081: * @see java.lang.ClassLoader#getResources(String)
0082: */
0083: private class ResourceEnumeration implements Enumeration {
0084: /**
0085: * The name of the resource being searched for.
0086: */
0087: private String resourceName;
0088:
0089: /**
0090: * The index of the next classpath element to search.
0091: */
0092: private int pathElementsIndex;
0093:
0094: /**
0095: * The URL of the next resource to return in the enumeration. If this
0096: * field is <code>null</code> then the enumeration has been completed,
0097: * i.e., there are no more elements to return.
0098: */
0099: private URL nextResource;
0100:
0101: /**
0102: * Constructs a new enumeration of resources of the given name found
0103: * within this class loader's classpath.
0104: *
0105: * @param name the name of the resource to search for.
0106: */
0107: ResourceEnumeration(String name) {
0108: this .resourceName = name;
0109: this .pathElementsIndex = 0;
0110: findNextResource();
0111: }
0112:
0113: /**
0114: * Indicates whether there are more elements in the enumeration to
0115: * return.
0116: *
0117: * @return <code>true</code> if there are more elements in the
0118: * enumeration; <code>false</code> otherwise.
0119: */
0120: public boolean hasMoreElements() {
0121: return (this .nextResource != null);
0122: }
0123:
0124: /**
0125: * Returns the next resource in the enumeration.
0126: *
0127: * @return the next resource in the enumeration
0128: */
0129: public Object nextElement() {
0130: URL ret = this .nextResource;
0131: findNextResource();
0132: return ret;
0133: }
0134:
0135: /**
0136: * Locates the next resource of the correct name in the classpath and
0137: * sets <code>nextResource</code> to the URL of that resource. If no
0138: * more resources can be found, <code>nextResource</code> is set to
0139: * <code>null</code>.
0140: */
0141: private void findNextResource() {
0142: URL url = null;
0143: while ((pathElementsIndex < pathComponents.size())
0144: && (url == null)) {
0145: try {
0146: File pathComponent = (File) pathComponents
0147: .elementAt(pathElementsIndex);
0148: url = getResourceURL(pathComponent,
0149: this .resourceName);
0150: pathElementsIndex++;
0151: } catch (BuildException e) {
0152: // ignore path elements which are not valid relative to the
0153: // project
0154: }
0155: }
0156: this .nextResource = url;
0157: }
0158: }
0159:
0160: /**
0161: * The size of buffers to be used in this classloader.
0162: */
0163: private static final int BUFFER_SIZE = 8192;
0164: /**
0165: * Number of array elements in a test array of strings
0166: */
0167: private static final int NUMBER_OF_STRINGS = 256;
0168:
0169: /**
0170: * The components of the classpath that the classloader searches
0171: * for classes.
0172: */
0173: private Vector pathComponents = new Vector();
0174:
0175: /**
0176: * The project to which this class loader belongs.
0177: */
0178: private Project project;
0179:
0180: /**
0181: * Indicates whether the parent class loader should be
0182: * consulted before trying to load with this class loader.
0183: */
0184: private boolean parentFirst = true;
0185:
0186: /**
0187: * These are the package roots that are to be loaded by the parent class
0188: * loader regardless of whether the parent class loader is being searched
0189: * first or not.
0190: */
0191: private Vector systemPackages = new Vector();
0192:
0193: /**
0194: * These are the package roots that are to be loaded by this class loader
0195: * regardless of whether the parent class loader is being searched first
0196: * or not.
0197: */
0198: private Vector loaderPackages = new Vector();
0199:
0200: /**
0201: * Whether or not this classloader will ignore the base
0202: * classloader if it can't find a class.
0203: *
0204: * @see #setIsolated(boolean)
0205: */
0206: private boolean ignoreBase = false;
0207:
0208: /**
0209: * The parent class loader, if one is given or can be determined.
0210: */
0211: private ClassLoader parent = null;
0212:
0213: /**
0214: * A hashtable of zip files opened by the classloader (File to ZipFile).
0215: */
0216: private Hashtable zipFiles = new Hashtable();
0217:
0218: /** Static map of jar file/time to manifiest class-path entries */
0219: private static Map/*<String,String>*/pathMap = Collections
0220: .synchronizedMap(new HashMap());
0221:
0222: /**
0223: * The context loader saved when setting the thread's current
0224: * context loader.
0225: */
0226: private ClassLoader savedContextLoader = null;
0227: /**
0228: * Whether or not the context loader is currently saved.
0229: */
0230: private boolean isContextLoaderSaved = false;
0231:
0232: /**
0233: * Create an Ant ClassLoader for a given project, with
0234: * a parent classloader and an initial classpath.
0235: * @since Ant 1.7.
0236: * @param parent the parent for this classloader.
0237: * @param project The project to which this classloader is to
0238: * belong.
0239: * @param classpath The classpath to use to load classes.
0240: */
0241: public AntClassLoader(ClassLoader parent, Project project,
0242: Path classpath) {
0243: setParent(parent);
0244: setClassPath(classpath);
0245: setProject(project);
0246: }
0247:
0248: /**
0249: * Create an Ant Class Loader
0250: */
0251: public AntClassLoader() {
0252: setParent(null);
0253: }
0254:
0255: /**
0256: * Creates a classloader for the given project using the classpath given.
0257: *
0258: * @param project The project to which this classloader is to belong.
0259: * Must not be <code>null</code>.
0260: * @param classpath The classpath to use to load the classes. This
0261: * is combined with the system classpath in a manner
0262: * determined by the value of ${build.sysclasspath}.
0263: * May be <code>null</code>, in which case no path
0264: * elements are set up to start with.
0265: */
0266: public AntClassLoader(Project project, Path classpath) {
0267: setParent(null);
0268: setProject(project);
0269: setClassPath(classpath);
0270: }
0271:
0272: /**
0273: * Creates a classloader for the given project using the classpath given.
0274: *
0275: * @param parent The parent classloader to which unsatisfied loading
0276: * attempts are delegated. May be <code>null</code>,
0277: * in which case the classloader which loaded this
0278: * class is used as the parent.
0279: * @param project The project to which this classloader is to belong.
0280: * Must not be <code>null</code>.
0281: * @param classpath the classpath to use to load the classes.
0282: * May be <code>null</code>, in which case no path
0283: * elements are set up to start with.
0284: * @param parentFirst If <code>true</code>, indicates that the parent
0285: * classloader should be consulted before trying to
0286: * load the a class through this loader.
0287: */
0288: public AntClassLoader(ClassLoader parent, Project project,
0289: Path classpath, boolean parentFirst) {
0290: this (project, classpath);
0291: if (parent != null) {
0292: setParent(parent);
0293: }
0294: setParentFirst(parentFirst);
0295: addJavaLibraries();
0296: }
0297:
0298: /**
0299: * Creates a classloader for the given project using the classpath given.
0300: *
0301: * @param project The project to which this classloader is to belong.
0302: * Must not be <code>null</code>.
0303: * @param classpath The classpath to use to load the classes. May be
0304: * <code>null</code>, in which case no path
0305: * elements are set up to start with.
0306: * @param parentFirst If <code>true</code>, indicates that the parent
0307: * classloader should be consulted before trying to
0308: * load the a class through this loader.
0309: */
0310: public AntClassLoader(Project project, Path classpath,
0311: boolean parentFirst) {
0312: this (null, project, classpath, parentFirst);
0313: }
0314:
0315: /**
0316: * Creates an empty class loader. The classloader should be configured
0317: * with path elements to specify where the loader is to look for
0318: * classes.
0319: *
0320: * @param parent The parent classloader to which unsatisfied loading
0321: * attempts are delegated. May be <code>null</code>,
0322: * in which case the classloader which loaded this
0323: * class is used as the parent.
0324: * @param parentFirst If <code>true</code>, indicates that the parent
0325: * classloader should be consulted before trying to
0326: * load the a class through this loader.
0327: */
0328: public AntClassLoader(ClassLoader parent, boolean parentFirst) {
0329: setParent(parent);
0330: project = null;
0331: this .parentFirst = parentFirst;
0332: }
0333:
0334: /**
0335: * Set the project associated with this class loader
0336: *
0337: * @param project the project instance
0338: */
0339: public void setProject(Project project) {
0340: this .project = project;
0341: if (project != null) {
0342: project.addBuildListener(this );
0343: }
0344: }
0345:
0346: /**
0347: * Set the classpath to search for classes to load. This should not be
0348: * changed once the classloader starts to server classes
0349: *
0350: * @param classpath the search classpath consisting of directories and
0351: * jar/zip files.
0352: */
0353: public void setClassPath(Path classpath) {
0354: pathComponents.removeAllElements();
0355: if (classpath != null) {
0356: Path actualClasspath = classpath
0357: .concatSystemClasspath("ignore");
0358: String[] pathElements = actualClasspath.list();
0359: for (int i = 0; i < pathElements.length; ++i) {
0360: try {
0361: addPathElement(pathElements[i]);
0362: } catch (BuildException e) {
0363: // ignore path elements which are invalid
0364: // relative to the project
0365: }
0366: }
0367: }
0368: }
0369:
0370: /**
0371: * Set the parent for this class loader. This is the class loader to which
0372: * this class loader will delegate to load classes
0373: *
0374: * @param parent the parent class loader.
0375: */
0376: public void setParent(ClassLoader parent) {
0377: if (parent == null) {
0378: this .parent = AntClassLoader.class.getClassLoader();
0379: } else {
0380: this .parent = parent;
0381: }
0382: }
0383:
0384: /**
0385: * Control whether class lookup is delegated to the parent loader first
0386: * or after this loader. Use with extreme caution. Setting this to
0387: * false violates the class loader hierarchy and can lead to Linkage errors
0388: *
0389: * @param parentFirst if true, delegate initial class search to the parent
0390: * classloader.
0391: */
0392: public void setParentFirst(boolean parentFirst) {
0393: this .parentFirst = parentFirst;
0394: }
0395:
0396: /**
0397: * Logs a message through the project object if one has been provided.
0398: *
0399: * @param message The message to log.
0400: * Should not be <code>null</code>.
0401: *
0402: * @param priority The logging priority of the message.
0403: */
0404: protected void log(String message, int priority) {
0405: if (project != null) {
0406: project.log(message, priority);
0407: }
0408: // else {
0409: // System.out.println(message);
0410: // }
0411: }
0412:
0413: /**
0414: * Sets the current thread's context loader to this classloader, storing
0415: * the current loader value for later resetting.
0416: */
0417: public void setThreadContextLoader() {
0418: if (isContextLoaderSaved) {
0419: throw new BuildException(
0420: "Context loader has not been reset");
0421: }
0422: if (LoaderUtils.isContextLoaderAvailable()) {
0423: savedContextLoader = LoaderUtils.getContextClassLoader();
0424: ClassLoader loader = this ;
0425: if (project != null
0426: && "only".equals(project
0427: .getProperty("build.sysclasspath"))) {
0428: loader = this .getClass().getClassLoader();
0429: }
0430: LoaderUtils.setContextClassLoader(loader);
0431: isContextLoaderSaved = true;
0432: }
0433: }
0434:
0435: /**
0436: * Resets the current thread's context loader to its original value.
0437: */
0438: public void resetThreadContextLoader() {
0439: if (LoaderUtils.isContextLoaderAvailable()
0440: && isContextLoaderSaved) {
0441: LoaderUtils.setContextClassLoader(savedContextLoader);
0442: savedContextLoader = null;
0443: isContextLoaderSaved = false;
0444: }
0445: }
0446:
0447: /**
0448: * Adds an element to the classpath to be searched.
0449: *
0450: * @param pathElement The path element to add. Must not be
0451: * <code>null</code>.
0452: *
0453: * @exception BuildException if the given path element cannot be resolved
0454: * against the project.
0455: */
0456: public void addPathElement(String pathElement)
0457: throws BuildException {
0458: File pathComponent = project != null ? project
0459: .resolveFile(pathElement) : new File(pathElement);
0460: try {
0461: addPathFile(pathComponent);
0462: } catch (IOException e) {
0463: throw new BuildException(e);
0464: }
0465: }
0466:
0467: /**
0468: * Add a file to the path.
0469: * Reads the manifest, if available, and adds any additional class path jars
0470: * specified in the manifest.
0471: *
0472: * @param pathComponent the file which is to be added to the path for
0473: * this class loader
0474: *
0475: * @throws IOException if data needed from the file cannot be read.
0476: */
0477: protected void addPathFile(File pathComponent) throws IOException {
0478: pathComponents.addElement(pathComponent);
0479: if (pathComponent.isDirectory()) {
0480: return;
0481: }
0482:
0483: String absPathPlusTimeAndLength = pathComponent
0484: .getAbsolutePath()
0485: + pathComponent.lastModified()
0486: + "-"
0487: + pathComponent.length();
0488: String classpath = (String) pathMap
0489: .get(absPathPlusTimeAndLength);
0490: if (classpath == null) {
0491: ZipFile jarFile = null;
0492: InputStream manifestStream = null;
0493: try {
0494: jarFile = new ZipFile(pathComponent);
0495: manifestStream = jarFile.getInputStream(new ZipEntry(
0496: "META-INF/MANIFEST.MF"));
0497:
0498: if (manifestStream == null) {
0499: return;
0500: }
0501: Reader manifestReader = new InputStreamReader(
0502: manifestStream, "UTF-8");
0503: org.apache.tools.ant.taskdefs.Manifest manifest = new org.apache.tools.ant.taskdefs.Manifest(
0504: manifestReader);
0505: classpath = manifest.getMainSection()
0506: .getAttributeValue("Class-Path");
0507:
0508: } catch (org.apache.tools.ant.taskdefs.ManifestException e) {
0509: // ignore
0510: } finally {
0511: if (manifestStream != null) {
0512: manifestStream.close();
0513: }
0514: if (jarFile != null) {
0515: jarFile.close();
0516: }
0517: }
0518: if (classpath == null) {
0519: classpath = "";
0520: }
0521: pathMap.put(absPathPlusTimeAndLength, classpath);
0522: }
0523:
0524: if (!"".equals(classpath)) {
0525: URL baseURL = FILE_UTILS.getFileURL(pathComponent);
0526: StringTokenizer st = new StringTokenizer(classpath);
0527: while (st.hasMoreTokens()) {
0528: String classpathElement = st.nextToken();
0529: URL libraryURL = new URL(baseURL, classpathElement);
0530: if (!libraryURL.getProtocol().equals("file")) {
0531: log(
0532: "Skipping jar library "
0533: + classpathElement
0534: + " since only relative URLs are supported by this"
0535: + " loader", Project.MSG_VERBOSE);
0536: continue;
0537: }
0538: String decodedPath = Locator.decodeUri(libraryURL
0539: .getFile());
0540: File libraryFile = new File(decodedPath);
0541: if (libraryFile.exists() && !isInPath(libraryFile)) {
0542: addPathFile(libraryFile);
0543: }
0544: }
0545: }
0546: }
0547:
0548: /**
0549: * Returns the classpath this classloader will consult.
0550: *
0551: * @return the classpath used for this classloader, with elements
0552: * separated by the path separator for the system.
0553: */
0554: public String getClasspath() {
0555: StringBuffer sb = new StringBuffer();
0556: boolean firstPass = true;
0557: Enumeration componentEnum = pathComponents.elements();
0558: while (componentEnum.hasMoreElements()) {
0559: if (!firstPass) {
0560: sb.append(System.getProperty("path.separator"));
0561: } else {
0562: firstPass = false;
0563: }
0564: sb.append(((File) componentEnum.nextElement())
0565: .getAbsolutePath());
0566: }
0567: return sb.toString();
0568: }
0569:
0570: /**
0571: * Sets whether this classloader should run in isolated mode. In
0572: * isolated mode, classes not found on the given classpath will
0573: * not be referred to the parent class loader but will cause a
0574: * ClassNotFoundException.
0575: *
0576: * @param isolated Whether or not this classloader should run in
0577: * isolated mode.
0578: */
0579: public synchronized void setIsolated(boolean isolated) {
0580: ignoreBase = isolated;
0581: }
0582:
0583: /**
0584: * Forces initialization of a class in a JDK 1.1 compatible, albeit hacky
0585: * way.
0586: *
0587: * @param theClass The class to initialize.
0588: * Must not be <code>null</code>.
0589: *
0590: * @deprecated since 1.6.x.
0591: * Use Class.forName with initialize=true instead.
0592: */
0593: public static void initializeClass(Class theClass) {
0594: // ***HACK*** We ask the VM to create an instance
0595: // by voluntarily providing illegal arguments to force
0596: // the VM to run the class' static initializer, while
0597: // at the same time not running a valid constructor.
0598:
0599: final Constructor[] cons = theClass.getDeclaredConstructors();
0600: //At least one constructor is guaranteed to be there, but check anyway.
0601: if (cons != null) {
0602: if (cons.length > 0 && cons[0] != null) {
0603: final String[] strs = new String[NUMBER_OF_STRINGS];
0604: try {
0605: cons[0].newInstance((Object[]) strs);
0606: // Expecting an exception to be thrown by this call:
0607: // IllegalArgumentException: wrong number of Arguments
0608: } catch (Exception e) {
0609: // Ignore - we are interested only in the side
0610: // effect - that of getting the static initializers
0611: // invoked. As we do not want to call a valid
0612: // constructor to get this side effect, an
0613: // attempt is made to call a hopefully
0614: // invalid constructor - come on, nobody
0615: // would have a constructor that takes in
0616: // 256 String arguments ;-)
0617: // (In fact, they can't - according to JVM spec
0618: // section 4.10, the number of method parameters is limited
0619: // to 255 by the definition of a method descriptor.
0620: // Constructors count as methods here.)
0621: }
0622: }
0623: }
0624: }
0625:
0626: /**
0627: * Adds a package root to the list of packages which must be loaded on the
0628: * parent loader.
0629: *
0630: * All subpackages are also included.
0631: *
0632: * @param packageRoot The root of all packages to be included.
0633: * Should not be <code>null</code>.
0634: */
0635: public void addSystemPackageRoot(String packageRoot) {
0636: systemPackages.addElement(packageRoot
0637: + (packageRoot.endsWith(".") ? "" : "."));
0638: }
0639:
0640: /**
0641: * Adds a package root to the list of packages which must be loaded using
0642: * this loader.
0643: *
0644: * All subpackages are also included.
0645: *
0646: * @param packageRoot The root of all packages to be included.
0647: * Should not be <code>null</code>.
0648: */
0649: public void addLoaderPackageRoot(String packageRoot) {
0650: loaderPackages.addElement(packageRoot
0651: + (packageRoot.endsWith(".") ? "" : "."));
0652: }
0653:
0654: /**
0655: * Loads a class through this class loader even if that class is available
0656: * on the parent classpath.
0657: *
0658: * This ensures that any classes which are loaded by the returned class
0659: * will use this classloader.
0660: *
0661: * @param classname The name of the class to be loaded.
0662: * Must not be <code>null</code>.
0663: *
0664: * @return the required Class object
0665: *
0666: * @exception ClassNotFoundException if the requested class does not exist
0667: * on this loader's classpath.
0668: */
0669: public Class forceLoadClass(String classname)
0670: throws ClassNotFoundException {
0671: log("force loading " + classname, Project.MSG_DEBUG);
0672:
0673: Class theClass = findLoadedClass(classname);
0674:
0675: if (theClass == null) {
0676: theClass = findClass(classname);
0677: }
0678:
0679: return theClass;
0680: }
0681:
0682: /**
0683: * Loads a class through this class loader but defer to the parent class
0684: * loader.
0685: *
0686: * This ensures that instances of the returned class will be compatible
0687: * with instances which have already been loaded on the parent
0688: * loader.
0689: *
0690: * @param classname The name of the class to be loaded.
0691: * Must not be <code>null</code>.
0692: *
0693: * @return the required Class object
0694: *
0695: * @exception ClassNotFoundException if the requested class does not exist
0696: * on this loader's classpath.
0697: */
0698: public Class forceLoadSystemClass(String classname)
0699: throws ClassNotFoundException {
0700: log("force system loading " + classname, Project.MSG_DEBUG);
0701:
0702: Class theClass = findLoadedClass(classname);
0703:
0704: if (theClass == null) {
0705: theClass = findBaseClass(classname);
0706: }
0707:
0708: return theClass;
0709: }
0710:
0711: /**
0712: * Returns a stream to read the requested resource name.
0713: *
0714: * @param name The name of the resource for which a stream is required.
0715: * Must not be <code>null</code>.
0716: *
0717: * @return a stream to the required resource or <code>null</code> if the
0718: * resource cannot be found on the loader's classpath.
0719: */
0720: public InputStream getResourceAsStream(String name) {
0721:
0722: InputStream resourceStream = null;
0723: if (isParentFirst(name)) {
0724: resourceStream = loadBaseResource(name);
0725: if (resourceStream != null) {
0726: log("ResourceStream for " + name
0727: + " loaded from parent loader",
0728: Project.MSG_DEBUG);
0729:
0730: } else {
0731: resourceStream = loadResource(name);
0732: if (resourceStream != null) {
0733: log("ResourceStream for " + name
0734: + " loaded from ant loader",
0735: Project.MSG_DEBUG);
0736: }
0737: }
0738: } else {
0739: resourceStream = loadResource(name);
0740: if (resourceStream != null) {
0741: log("ResourceStream for " + name
0742: + " loaded from ant loader", Project.MSG_DEBUG);
0743:
0744: } else {
0745: resourceStream = loadBaseResource(name);
0746: if (resourceStream != null) {
0747: log("ResourceStream for " + name
0748: + " loaded from parent loader",
0749: Project.MSG_DEBUG);
0750: }
0751: }
0752: }
0753:
0754: if (resourceStream == null) {
0755: log("Couldn't load ResourceStream for " + name,
0756: Project.MSG_DEBUG);
0757: }
0758:
0759: return resourceStream;
0760: }
0761:
0762: /**
0763: * Returns a stream to read the requested resource name from this loader.
0764: *
0765: * @param name The name of the resource for which a stream is required.
0766: * Must not be <code>null</code>.
0767: *
0768: * @return a stream to the required resource or <code>null</code> if
0769: * the resource cannot be found on the loader's classpath.
0770: */
0771: private InputStream loadResource(String name) {
0772: // we need to search the components of the path to see if we can
0773: // find the class we want.
0774: InputStream stream = null;
0775:
0776: Enumeration e = pathComponents.elements();
0777: while (e.hasMoreElements() && stream == null) {
0778: File pathComponent = (File) e.nextElement();
0779: stream = getResourceStream(pathComponent, name);
0780: }
0781: return stream;
0782: }
0783:
0784: /**
0785: * Finds a system resource (which should be loaded from the parent
0786: * classloader).
0787: *
0788: * @param name The name of the system resource to load.
0789: * Must not be <code>null</code>.
0790: *
0791: * @return a stream to the named resource, or <code>null</code> if
0792: * the resource cannot be found.
0793: */
0794: private InputStream loadBaseResource(String name) {
0795: if (parent == null) {
0796: return getSystemResourceAsStream(name);
0797: } else {
0798: return parent.getResourceAsStream(name);
0799: }
0800: }
0801:
0802: /**
0803: * Returns an inputstream to a given resource in the given file which may
0804: * either be a directory or a zip file.
0805: *
0806: * @param file the file (directory or jar) in which to search for the
0807: * resource. Must not be <code>null</code>.
0808: * @param resourceName The name of the resource for which a stream is
0809: * required. Must not be <code>null</code>.
0810: *
0811: * @return a stream to the required resource or <code>null</code> if
0812: * the resource cannot be found in the given file.
0813: */
0814: private InputStream getResourceStream(File file, String resourceName) {
0815: try {
0816: if (!file.exists()) {
0817: return null;
0818: }
0819:
0820: if (file.isDirectory()) {
0821: File resource = new File(file, resourceName);
0822:
0823: if (resource.exists()) {
0824: return new FileInputStream(resource);
0825: }
0826: } else {
0827: // is the zip file in the cache
0828: ZipFile zipFile = (ZipFile) zipFiles.get(file);
0829: if (zipFile == null) {
0830: zipFile = new ZipFile(file);
0831: zipFiles.put(file, zipFile);
0832: }
0833: ZipEntry entry = zipFile.getEntry(resourceName);
0834: if (entry != null) {
0835: return zipFile.getInputStream(entry);
0836: }
0837: }
0838: } catch (Exception e) {
0839: log("Ignoring Exception " + e.getClass().getName() + ": "
0840: + e.getMessage() + " reading resource "
0841: + resourceName + " from " + file,
0842: Project.MSG_VERBOSE);
0843: }
0844:
0845: return null;
0846: }
0847:
0848: /**
0849: * Tests whether or not the parent classloader should be checked for
0850: * a resource before this one. If the resource matches both the
0851: * "use parent classloader first" and the "use this classloader first"
0852: * lists, the latter takes priority.
0853: *
0854: * @param resourceName The name of the resource to check.
0855: * Must not be <code>null</code>.
0856: *
0857: * @return whether or not the parent classloader should be checked for a
0858: * resource before this one is.
0859: */
0860: private boolean isParentFirst(String resourceName) {
0861: // default to the global setting and then see
0862: // if this class belongs to a package which has been
0863: // designated to use a specific loader first
0864: // (this one or the parent one)
0865:
0866: // XXX - shouldn't this always return false in isolated mode?
0867:
0868: boolean useParentFirst = parentFirst;
0869:
0870: for (Enumeration e = systemPackages.elements(); e
0871: .hasMoreElements();) {
0872: String packageName = (String) e.nextElement();
0873: if (resourceName.startsWith(packageName)) {
0874: useParentFirst = true;
0875: break;
0876: }
0877: }
0878:
0879: for (Enumeration e = loaderPackages.elements(); e
0880: .hasMoreElements();) {
0881: String packageName = (String) e.nextElement();
0882: if (resourceName.startsWith(packageName)) {
0883: useParentFirst = false;
0884: break;
0885: }
0886: }
0887:
0888: return useParentFirst;
0889: }
0890:
0891: /**
0892: * Used for isolated resource seaching.
0893: * @return the root classloader of AntClassLoader.
0894: */
0895: private ClassLoader getRootLoader() {
0896: ClassLoader ret = getClass().getClassLoader();
0897: while (ret != null && ret.getParent() != null) {
0898: ret = ret.getParent();
0899: }
0900: return ret;
0901: }
0902:
0903: /**
0904: * Finds the resource with the given name. A resource is
0905: * some data (images, audio, text, etc) that can be accessed by class
0906: * code in a way that is independent of the location of the code.
0907: *
0908: * @param name The name of the resource for which a stream is required.
0909: * Must not be <code>null</code>.
0910: *
0911: * @return a URL for reading the resource, or <code>null</code> if the
0912: * resource could not be found or the caller doesn't have
0913: * adequate privileges to get the resource.
0914: */
0915: public URL getResource(String name) {
0916: // we need to search the components of the path to see if
0917: // we can find the class we want.
0918: URL url = null;
0919: if (isParentFirst(name)) {
0920: url = (parent == null) ? super .getResource(name) : parent
0921: .getResource(name);
0922: }
0923:
0924: if (url != null) {
0925: log("Resource " + name + " loaded from parent loader",
0926: Project.MSG_DEBUG);
0927:
0928: } else {
0929: // try and load from this loader if the parent either didn't find
0930: // it or wasn't consulted.
0931: Enumeration e = pathComponents.elements();
0932: while (e.hasMoreElements() && url == null) {
0933: File pathComponent = (File) e.nextElement();
0934: url = getResourceURL(pathComponent, name);
0935: if (url != null) {
0936: log("Resource " + name + " loaded from ant loader",
0937: Project.MSG_DEBUG);
0938: }
0939: }
0940: }
0941:
0942: if (url == null && !isParentFirst(name)) {
0943: // this loader was first but it didn't find it - try the parent
0944: if (ignoreBase) {
0945: url = (getRootLoader() == null) ? null
0946: : getRootLoader().getResource(name);
0947: } else {
0948: url = (parent == null) ? super .getResource(name)
0949: : parent.getResource(name);
0950: }
0951: if (url != null) {
0952: log("Resource " + name + " loaded from parent loader",
0953: Project.MSG_DEBUG);
0954: }
0955: }
0956:
0957: if (url == null) {
0958: log("Couldn't load Resource " + name, Project.MSG_DEBUG);
0959: }
0960:
0961: return url;
0962: }
0963:
0964: /**
0965: * Returns an enumeration of URLs representing all the resources with the
0966: * given name by searching the class loader's classpath.
0967: *
0968: * @param name The resource name to search for.
0969: * Must not be <code>null</code>.
0970: * @return an enumeration of URLs for the resources
0971: * @exception IOException if I/O errors occurs (can't happen)
0972: */
0973: protected Enumeration/*<URL>*/findResources(String name)
0974: throws IOException {
0975: Enumeration/*<URL>*/mine = new ResourceEnumeration(name);
0976: Enumeration/*<URL>*/base;
0977: if (parent != null && parent != getParent()) {
0978: // Delegate to the parent:
0979: base = parent.getResources(name);
0980: // Note: could cause overlaps in case ClassLoader.this.parent has matches.
0981: } else {
0982: // ClassLoader.this.parent is already delegated to from
0983: // ClassLoader.getResources, no need:
0984: base = new CollectionUtils.EmptyEnumeration();
0985: }
0986: if (isParentFirst(name)) {
0987: // Normal case.
0988: return CollectionUtils.append(base, mine);
0989: } else if (ignoreBase) {
0990: return getRootLoader() == null ? mine : CollectionUtils
0991: .append(mine, getRootLoader().getResources(name));
0992: } else {
0993: // Inverted.
0994: return CollectionUtils.append(mine, base);
0995: }
0996: }
0997:
0998: /**
0999: * Returns the URL of a given resource in the given file which may
1000: * either be a directory or a zip file.
1001: *
1002: * @param file The file (directory or jar) in which to search for
1003: * the resource. Must not be <code>null</code>.
1004: * @param resourceName The name of the resource for which a stream
1005: * is required. Must not be <code>null</code>.
1006: *
1007: * @return a stream to the required resource or <code>null</code> if the
1008: * resource cannot be found in the given file object.
1009: */
1010: protected URL getResourceURL(File file, String resourceName) {
1011: try {
1012: if (!file.exists()) {
1013: return null;
1014: }
1015:
1016: if (file.isDirectory()) {
1017: File resource = new File(file, resourceName);
1018:
1019: if (resource.exists()) {
1020: try {
1021: return FILE_UTILS.getFileURL(resource);
1022: } catch (MalformedURLException ex) {
1023: return null;
1024: }
1025: }
1026: } else {
1027: ZipFile zipFile = (ZipFile) zipFiles.get(file);
1028: if (zipFile == null) {
1029: zipFile = new ZipFile(file);
1030: zipFiles.put(file, zipFile);
1031: }
1032:
1033: ZipEntry entry = zipFile.getEntry(resourceName);
1034: if (entry != null) {
1035: try {
1036: return new URL("jar:"
1037: + FILE_UTILS.getFileURL(file) + "!/"
1038: + entry);
1039: } catch (MalformedURLException ex) {
1040: return null;
1041: }
1042: }
1043: }
1044: } catch (Exception e) {
1045: e.printStackTrace();
1046: }
1047:
1048: return null;
1049: }
1050:
1051: /**
1052: * Loads a class with this class loader.
1053: *
1054: * This class attempts to load the class in an order determined by whether
1055: * or not the class matches the system/loader package lists, with the
1056: * loader package list taking priority. If the classloader is in isolated
1057: * mode, failure to load the class in this loader will result in a
1058: * ClassNotFoundException.
1059: *
1060: * @param classname The name of the class to be loaded.
1061: * Must not be <code>null</code>.
1062: * @param resolve <code>true</code> if all classes upon which this class
1063: * depends are to be loaded.
1064: *
1065: * @return the required Class object
1066: *
1067: * @exception ClassNotFoundException if the requested class does not exist
1068: * on the system classpath (when not in isolated mode) or this loader's
1069: * classpath.
1070: */
1071: protected synchronized Class loadClass(String classname,
1072: boolean resolve) throws ClassNotFoundException {
1073: // 'sync' is needed - otherwise 2 threads can load the same class
1074: // twice, resulting in LinkageError: duplicated class definition.
1075: // findLoadedClass avoids that, but without sync it won't work.
1076:
1077: Class theClass = findLoadedClass(classname);
1078: if (theClass != null) {
1079: return theClass;
1080: }
1081:
1082: if (isParentFirst(classname)) {
1083: try {
1084: theClass = findBaseClass(classname);
1085: log("Class " + classname
1086: + " loaded from parent loader "
1087: + "(parentFirst)", Project.MSG_DEBUG);
1088: } catch (ClassNotFoundException cnfe) {
1089: theClass = findClass(classname);
1090: log("Class " + classname + " loaded from ant loader "
1091: + "(parentFirst)", Project.MSG_DEBUG);
1092: }
1093: } else {
1094: try {
1095: theClass = findClass(classname);
1096: log("Class " + classname + " loaded from ant loader",
1097: Project.MSG_DEBUG);
1098: } catch (ClassNotFoundException cnfe) {
1099: if (ignoreBase) {
1100: throw cnfe;
1101: }
1102: theClass = findBaseClass(classname);
1103: log(
1104: "Class " + classname
1105: + " loaded from parent loader",
1106: Project.MSG_DEBUG);
1107: }
1108: }
1109:
1110: if (resolve) {
1111: resolveClass(theClass);
1112: }
1113:
1114: return theClass;
1115: }
1116:
1117: /**
1118: * Converts the class dot notation to a filesystem equivalent for
1119: * searching purposes.
1120: *
1121: * @param classname The class name in dot format (eg java.lang.Integer).
1122: * Must not be <code>null</code>.
1123: *
1124: * @return the classname in filesystem format (eg java/lang/Integer.class)
1125: */
1126: private String getClassFilename(String classname) {
1127: return classname.replace('.', '/') + ".class";
1128: }
1129:
1130: /**
1131: * Define a class given its bytes
1132: *
1133: * @param container the container from which the class data has been read
1134: * may be a directory or a jar/zip file.
1135: *
1136: * @param classData the bytecode data for the class
1137: * @param classname the name of the class
1138: *
1139: * @return the Class instance created from the given data
1140: *
1141: * @throws IOException if the class data cannot be read.
1142: */
1143: protected Class defineClassFromData(File container,
1144: byte[] classData, String classname) throws IOException {
1145: definePackage(container, classname);
1146: // XXX should instead make a new ProtectionDomain with a CodeSource
1147: // corresponding to container.toURI().toURL() and the same
1148: // PermissionCollection as Project.class.protectionDomain had
1149: return defineClass(classname, classData, 0, classData.length,
1150: Project.class.getProtectionDomain());
1151: }
1152:
1153: /**
1154: * Define the package information associated with a class.
1155: *
1156: * @param container the file containing the class definition.
1157: * @param className the class name of for which the package information
1158: * is to be determined.
1159: *
1160: * @exception IOException if the package information cannot be read from the
1161: * container.
1162: */
1163: protected void definePackage(File container, String className)
1164: throws IOException {
1165: int classIndex = className.lastIndexOf('.');
1166: if (classIndex == -1) {
1167: return;
1168: }
1169:
1170: String packageName = className.substring(0, classIndex);
1171: if (getPackage(packageName) != null) {
1172: // already defined
1173: return;
1174: }
1175:
1176: // define the package now
1177: Manifest manifest = getJarManifest(container);
1178:
1179: if (manifest == null) {
1180: definePackage(packageName, null, null, null, null, null,
1181: null, null);
1182: } else {
1183: definePackage(container, packageName, manifest);
1184: }
1185: }
1186:
1187: /**
1188: * Get the manifest from the given jar, if it is indeed a jar and it has a
1189: * manifest
1190: *
1191: * @param container the File from which a manifest is required.
1192: *
1193: * @return the jar's manifest or null is the container is not a jar or it
1194: * has no manifest.
1195: *
1196: * @exception IOException if the manifest cannot be read.
1197: */
1198: private Manifest getJarManifest(File container) throws IOException {
1199: if (container.isDirectory()) {
1200: return null;
1201: }
1202: JarFile jarFile = null;
1203: try {
1204: jarFile = new JarFile(container);
1205: return jarFile.getManifest();
1206: } finally {
1207: if (jarFile != null) {
1208: jarFile.close();
1209: }
1210: }
1211: }
1212:
1213: /**
1214: * Define the package information when the class comes from a
1215: * jar with a manifest
1216: *
1217: * @param container the jar file containing the manifest
1218: * @param packageName the name of the package being defined.
1219: * @param manifest the jar's manifest
1220: */
1221: protected void definePackage(File container, String packageName,
1222: Manifest manifest) {
1223: String sectionName = packageName.replace('.', '/') + "/";
1224:
1225: String specificationTitle = null;
1226: String specificationVendor = null;
1227: String specificationVersion = null;
1228: String implementationTitle = null;
1229: String implementationVendor = null;
1230: String implementationVersion = null;
1231: String sealedString = null;
1232: URL sealBase = null;
1233:
1234: Attributes sectionAttributes = manifest
1235: .getAttributes(sectionName);
1236: if (sectionAttributes != null) {
1237: specificationTitle = sectionAttributes
1238: .getValue(Name.SPECIFICATION_TITLE);
1239: specificationVendor = sectionAttributes
1240: .getValue(Name.SPECIFICATION_VENDOR);
1241: specificationVersion = sectionAttributes
1242: .getValue(Name.SPECIFICATION_VERSION);
1243: implementationTitle = sectionAttributes
1244: .getValue(Name.IMPLEMENTATION_TITLE);
1245: implementationVendor = sectionAttributes
1246: .getValue(Name.IMPLEMENTATION_VENDOR);
1247: implementationVersion = sectionAttributes
1248: .getValue(Name.IMPLEMENTATION_VERSION);
1249: sealedString = sectionAttributes.getValue(Name.SEALED);
1250: }
1251:
1252: Attributes mainAttributes = manifest.getMainAttributes();
1253: if (mainAttributes != null) {
1254: if (specificationTitle == null) {
1255: specificationTitle = mainAttributes
1256: .getValue(Name.SPECIFICATION_TITLE);
1257: }
1258: if (specificationVendor == null) {
1259: specificationVendor = mainAttributes
1260: .getValue(Name.SPECIFICATION_VENDOR);
1261: }
1262: if (specificationVersion == null) {
1263: specificationVersion = mainAttributes
1264: .getValue(Name.SPECIFICATION_VERSION);
1265: }
1266: if (implementationTitle == null) {
1267: implementationTitle = mainAttributes
1268: .getValue(Name.IMPLEMENTATION_TITLE);
1269: }
1270: if (implementationVendor == null) {
1271: implementationVendor = mainAttributes
1272: .getValue(Name.IMPLEMENTATION_VENDOR);
1273: }
1274: if (implementationVersion == null) {
1275: implementationVersion = mainAttributes
1276: .getValue(Name.IMPLEMENTATION_VERSION);
1277: }
1278: if (sealedString == null) {
1279: sealedString = mainAttributes.getValue(Name.SEALED);
1280: }
1281: }
1282:
1283: if (sealedString != null
1284: && sealedString.equalsIgnoreCase("true")) {
1285: try {
1286: sealBase = new URL(FileUtils.getFileUtils().toURI(
1287: container.getAbsolutePath()));
1288: } catch (MalformedURLException e) {
1289: // ignore
1290: }
1291: }
1292:
1293: definePackage(packageName, specificationTitle,
1294: specificationVersion, specificationVendor,
1295: implementationTitle, implementationVersion,
1296: implementationVendor, sealBase);
1297: }
1298:
1299: /**
1300: * Reads a class definition from a stream.
1301: *
1302: * @param stream The stream from which the class is to be read.
1303: * Must not be <code>null</code>.
1304: * @param classname The name of the class in the stream.
1305: * Must not be <code>null</code>.
1306: * @param container the file or directory containing the class.
1307: *
1308: * @return the Class object read from the stream.
1309: *
1310: * @exception IOException if there is a problem reading the class from the
1311: * stream.
1312: * @exception SecurityException if there is a security problem while
1313: * reading the class from the stream.
1314: */
1315: private Class getClassFromStream(InputStream stream,
1316: String classname, File container) throws IOException,
1317: SecurityException {
1318: ByteArrayOutputStream baos = new ByteArrayOutputStream();
1319: int bytesRead = -1;
1320: byte[] buffer = new byte[BUFFER_SIZE];
1321:
1322: while ((bytesRead = stream.read(buffer, 0, BUFFER_SIZE)) != -1) {
1323: baos.write(buffer, 0, bytesRead);
1324: }
1325:
1326: byte[] classData = baos.toByteArray();
1327: return defineClassFromData(container, classData, classname);
1328: }
1329:
1330: /**
1331: * Searches for and load a class on the classpath of this class loader.
1332: *
1333: * @param name The name of the class to be loaded. Must not be
1334: * <code>null</code>.
1335: *
1336: * @return the required Class object
1337: *
1338: * @exception ClassNotFoundException if the requested class does not exist
1339: * on this loader's classpath.
1340: */
1341: public Class findClass(String name) throws ClassNotFoundException {
1342: log("Finding class " + name, Project.MSG_DEBUG);
1343:
1344: return findClassInComponents(name);
1345: }
1346:
1347: /**
1348: * Indicate if the given file is in this loader's path
1349: *
1350: * @param component the file which is to be checked
1351: *
1352: * @return true if the file is in the class path
1353: */
1354: protected boolean isInPath(File component) {
1355: for (Enumeration e = pathComponents.elements(); e
1356: .hasMoreElements();) {
1357: File pathComponent = (File) e.nextElement();
1358: if (pathComponent.equals(component)) {
1359: return true;
1360: }
1361: }
1362: return false;
1363: }
1364:
1365: /**
1366: * Finds a class on the given classpath.
1367: *
1368: * @param name The name of the class to be loaded. Must not be
1369: * <code>null</code>.
1370: *
1371: * @return the required Class object
1372: *
1373: * @exception ClassNotFoundException if the requested class does not exist
1374: * on this loader's classpath.
1375: */
1376: private Class findClassInComponents(String name)
1377: throws ClassNotFoundException {
1378: // we need to search the components of the path to see if
1379: // we can find the class we want.
1380: InputStream stream = null;
1381: String classFilename = getClassFilename(name);
1382: try {
1383: Enumeration e = pathComponents.elements();
1384: while (e.hasMoreElements()) {
1385: File pathComponent = (File) e.nextElement();
1386: try {
1387: stream = getResourceStream(pathComponent,
1388: classFilename);
1389: if (stream != null) {
1390: log("Loaded from " + pathComponent + " "
1391: + classFilename, Project.MSG_DEBUG);
1392: return getClassFromStream(stream, name,
1393: pathComponent);
1394: }
1395: } catch (SecurityException se) {
1396: throw se;
1397: } catch (IOException ioe) {
1398: // ioe.printStackTrace();
1399: log("Exception reading component " + pathComponent
1400: + " (reason: " + ioe.getMessage() + ")",
1401: Project.MSG_VERBOSE);
1402: }
1403: }
1404:
1405: throw new ClassNotFoundException(name);
1406: } finally {
1407: try {
1408: if (stream != null) {
1409: stream.close();
1410: }
1411: } catch (IOException e) {
1412: //ignore
1413: }
1414: }
1415: }
1416:
1417: /**
1418: * Finds a system class (which should be loaded from the same classloader
1419: * as the Ant core).
1420: *
1421: * For JDK 1.1 compatibility, this uses the findSystemClass method if
1422: * no parent classloader has been specified.
1423: *
1424: * @param name The name of the class to be loaded.
1425: * Must not be <code>null</code>.
1426: *
1427: * @return the required Class object
1428: *
1429: * @exception ClassNotFoundException if the requested class does not exist
1430: * on this loader's classpath.
1431: */
1432: private Class findBaseClass(String name)
1433: throws ClassNotFoundException {
1434: if (parent == null) {
1435: return findSystemClass(name);
1436: } else {
1437: return parent.loadClass(name);
1438: }
1439: }
1440:
1441: /**
1442: * Cleans up any resources held by this classloader. Any open archive
1443: * files are closed.
1444: */
1445: public synchronized void cleanup() {
1446: for (Enumeration e = zipFiles.elements(); e.hasMoreElements();) {
1447: ZipFile zipFile = (ZipFile) e.nextElement();
1448: try {
1449: zipFile.close();
1450: } catch (IOException ioe) {
1451: // ignore
1452: }
1453: }
1454: zipFiles = new Hashtable();
1455: if (project != null) {
1456: project.removeBuildListener(this );
1457: }
1458: project = null;
1459: }
1460:
1461: /**
1462: * Empty implementation to satisfy the BuildListener interface.
1463: *
1464: * @param event the buildStarted event
1465: */
1466: public void buildStarted(BuildEvent event) {
1467: // Not significant for the class loader.
1468: }
1469:
1470: /**
1471: * Cleans up any resources held by this classloader at the end
1472: * of a build.
1473: *
1474: * @param event the buildFinished event
1475: */
1476: public void buildFinished(BuildEvent event) {
1477: cleanup();
1478: }
1479:
1480: /**
1481: * Cleans up any resources held by this classloader at the end of
1482: * a subbuild if it has been created for the subbuild's project
1483: * instance.
1484: *
1485: * @param event the buildFinished event
1486: *
1487: * @since Ant 1.6.2
1488: */
1489: public void subBuildFinished(BuildEvent event) {
1490: if (event.getProject() == project) {
1491: cleanup();
1492: }
1493: }
1494:
1495: /**
1496: * Empty implementation to satisfy the BuildListener interface.
1497: *
1498: * @param event the buildStarted event
1499: *
1500: * @since Ant 1.6.2
1501: */
1502: public void subBuildStarted(BuildEvent event) {
1503: // Not significant for the class loader.
1504: }
1505:
1506: /**
1507: * Empty implementation to satisfy the BuildListener interface.
1508: *
1509: * @param event the targetStarted event
1510: */
1511: public void targetStarted(BuildEvent event) {
1512: // Not significant for the class loader.
1513: }
1514:
1515: /**
1516: * Empty implementation to satisfy the BuildListener interface.
1517: *
1518: * @param event the targetFinished event
1519: */
1520: public void targetFinished(BuildEvent event) {
1521: // Not significant for the class loader.
1522: }
1523:
1524: /**
1525: * Empty implementation to satisfy the BuildListener interface.
1526: *
1527: * @param event the taskStarted event
1528: */
1529: public void taskStarted(BuildEvent event) {
1530: // Not significant for the class loader.
1531: }
1532:
1533: /**
1534: * Empty implementation to satisfy the BuildListener interface.
1535: *
1536: * @param event the taskFinished event
1537: */
1538: public void taskFinished(BuildEvent event) {
1539: // Not significant for the class loader.
1540: }
1541:
1542: /**
1543: * Empty implementation to satisfy the BuildListener interface.
1544: *
1545: * @param event the messageLogged event
1546: */
1547: public void messageLogged(BuildEvent event) {
1548: // Not significant for the class loader.
1549: }
1550:
1551: /**
1552: * add any libraries that come with different java versions
1553: * here
1554: */
1555: public void addJavaLibraries() {
1556: Vector packages = JavaEnvUtils.getJrePackages();
1557: Enumeration e = packages.elements();
1558: while (e.hasMoreElements()) {
1559: String packageName = (String) e.nextElement();
1560: addSystemPackageRoot(packageName);
1561: }
1562: }
1563:
1564: /**
1565: * Returns a <code>String</code> representing this loader.
1566: * @return the path that this classloader has.
1567: */
1568: public String toString() {
1569: return "AntClassLoader[" + getClasspath() + "]";
1570: }
1571:
1572: }
|