From 598017b1cdec8da5d9ac7002f6625561aca80ac7 Mon Sep 17 00:00:00 2001 From: Conor MacNeill Date: Mon, 11 Mar 2002 09:40:21 +0000 Subject: [PATCH] Restore 1.1 operation Refactor context class loader methods into a utility class Add URL method to FileUtils (still need to pick that up in Project) Rename xcatalog to XMLCatalog git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271813 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/tools/ant/AntClassLoader.java | 163 +++++++++--------- .../org/apache/tools/ant/ProjectHelper.java | 28 +-- .../tools/ant/taskdefs/XSLTProcess.java | 18 +- .../types/{XCatalog.java => XMLCatalog.java} | 38 ++-- .../tools/ant/types/defaults.properties | 2 +- .../org/apache/tools/ant/util/FileUtils.java | 21 +++ .../apache/tools/ant/util/LoaderUtils.java | 150 ++++++++++++++++ 7 files changed, 289 insertions(+), 131 deletions(-) rename src/main/org/apache/tools/ant/types/{XCatalog.java => XMLCatalog.java} (89%) create mode 100644 src/main/org/apache/tools/ant/util/LoaderUtils.java diff --git a/src/main/org/apache/tools/ant/AntClassLoader.java b/src/main/org/apache/tools/ant/AntClassLoader.java index 893decbb8..403abcbc4 100644 --- a/src/main/org/apache/tools/ant/AntClassLoader.java +++ b/src/main/org/apache/tools/ant/AntClassLoader.java @@ -70,6 +70,7 @@ import java.io.ByteArrayOutputStream; import java.net.URL; import java.net.MalformedURLException; import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.util.LoaderUtils; /** * Used to load classes within ant with a different claspath from @@ -181,8 +182,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { * The components of the classpath that the classloader searches * for classes. */ - // XXX: Any reason this shouldn't be private? - Vector pathComponents = new Vector(); + private Vector pathComponents = new Vector(); /** * The project to which this class loader belongs. @@ -228,7 +228,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { private Hashtable zipFiles = new Hashtable(); /** - * The context loader saved when setting the thread's current context loader. + * The context loader saved when setting the thread's current + * context loader. */ private ClassLoader savedContextLoader = null; /** @@ -248,29 +249,18 @@ public class AntClassLoader extends ClassLoader implements BuildListener { */ private static Method defineClassProtectionDomain = null; - /** - * Reflection method reference for getContextClassLoader; - * used to avoid 1.1-compatibility problems. - */ - private static Method getContextClassLoader = null; - - /** - * Reflection method reference for setContextClassLoader; - * used to avoid 1.1-compatibility problems. - */ - private static Method setContextClassLoader = null; // Set up the reflection-based Java2 methods if possible static { try { - getProtectionDomain = Class.class.getMethod("getProtectionDomain", new Class[0]); - Class protectionDomain = Class.forName("java.security.ProtectionDomain"); - Class[] args = new Class[] {String.class, byte[].class, Integer.TYPE, Integer.TYPE, protectionDomain}; - defineClassProtectionDomain = ClassLoader.class.getDeclaredMethod("defineClass", args); - - getContextClassLoader = Thread.class.getMethod("getContextClassLoader", new Class[0]); - args = new Class[] {ClassLoader.class}; - setContextClassLoader = Thread.class.getMethod("setContextClassLoader", args); + getProtectionDomain + = Class.class.getMethod("getProtectionDomain", new Class[0]); + Class protectionDomain + = Class.forName("java.security.ProtectionDomain"); + Class[] args = new Class[] {String.class, byte[].class, + Integer.TYPE, Integer.TYPE, protectionDomain}; + defineClassProtectionDomain + = ClassLoader.class.getDeclaredMethod("defineClass", args); } catch (Exception e) {} } @@ -299,7 +289,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { addPathElement(pathElements[i]); } catch (BuildException e) { - // ignore path elements which are invalid relative to the project + // ignore path elements which are invalid + // relative to the project } } } @@ -345,7 +336,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { * classloader should be consulted before trying to * load the a class through this loader. */ - public AntClassLoader(Project project, Path classpath, boolean parentFirst) { + public AntClassLoader(Project project, Path classpath, + boolean parentFirst) { this(null, project, classpath, parentFirst); } @@ -398,26 +390,10 @@ public class AntClassLoader extends ClassLoader implements BuildListener { if (isContextLoaderSaved) { throw new BuildException("Context loader has not been reset"); } - if (getContextClassLoader != null && setContextClassLoader != null) { - try { - savedContextLoader - = (ClassLoader)getContextClassLoader.invoke(Thread.currentThread(), new Object[0]); - Object[] args = null; - if ("only".equals(project.getProperty("build.sysclasspath"))) { - args = new Object[] {this.getClass().getClassLoader()}; - } else { - args = new Object[] {this}; - } - setContextClassLoader.invoke(Thread.currentThread(), args); - isContextLoaderSaved = true; - } - catch (InvocationTargetException ite) { - Throwable t = ite.getTargetException(); - throw new BuildException(t.toString()); - } - catch (Exception e) { - throw new BuildException(e.toString()); - } + if (LoaderUtils.isContextLoaderAvailable()) { + savedContextLoader = LoaderUtils.getContextClassLoader(); + LoaderUtils.setContextClassLoader(this); + isContextLoaderSaved = true; } } @@ -425,21 +401,11 @@ public class AntClassLoader extends ClassLoader implements BuildListener { * Resets the current thread's context loader to its original value. */ public void resetThreadContextLoader() { - if (isContextLoaderSaved && - getContextClassLoader != null && setContextClassLoader != null) { - try { - Object[] args = new Object[] {savedContextLoader}; - setContextClassLoader.invoke(Thread.currentThread(), args); - savedContextLoader = null; - isContextLoaderSaved = false; - } - catch (InvocationTargetException ite) { - Throwable t = ite.getTargetException(); - throw new BuildException(t.toString()); - } - catch (Exception e) { - throw new BuildException(e.toString()); - } + if (LoaderUtils.isContextLoaderAvailable() + && isContextLoaderSaved) { + LoaderUtils.setContextClassLoader(savedContextLoader); + savedContextLoader = null; + isContextLoaderSaved = false; } } @@ -575,7 +541,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { * @exception ClassNotFoundException if the requested class does not exist * on this loader's classpath. */ - public Class forceLoadClass(String classname) throws ClassNotFoundException { + public Class forceLoadClass(String classname) + throws ClassNotFoundException { log("force loading " + classname, Project.MSG_DEBUG); Class theClass = findLoadedClass(classname); @@ -603,7 +570,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { * @exception ClassNotFoundException if the requested class does not exist * on this loader's classpath. */ - public Class forceLoadSystemClass(String classname) throws ClassNotFoundException { + public Class forceLoadSystemClass(String classname) + throws ClassNotFoundException { log("force system loading " + classname, Project.MSG_DEBUG); Class theClass = findLoadedClass(classname); @@ -674,8 +642,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { * the resource cannot be found on the loader's classpath. */ private InputStream loadResource(String name) { - // we need to search the components of the path to see if we can find the - // class we want. + // 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 = pathComponents.elements(); e.hasMoreElements() && stream == null; ) { @@ -743,8 +711,9 @@ public class AntClassLoader extends ClassLoader implements BuildListener { } } catch (Exception e) { - log("Ignoring Exception " + e.getClass().getName() + ": " + e.getMessage() + - " reading resource " + resourceName + " from " + file, Project.MSG_VERBOSE); + log("Ignoring Exception " + e.getClass().getName() + + ": " + e.getMessage() + " reading resource " + resourceName + + " from " + file, Project.MSG_VERBOSE); } return null; @@ -765,7 +734,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { private boolean isParentFirst(String resourceName) { // 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 parent one) + // designated to use a specific loader first + // (this one or the parent one) // XXX - shouldn't this always return false in isolated mode? @@ -803,11 +773,12 @@ public class AntClassLoader extends ClassLoader implements BuildListener { * adequate privileges to get the resource. */ public URL getResource(String name) { - // we need to search the components of the path to see if we can find the - // class we want. + // we need to search the components of the path to see if + // we can find the class we want. URL url = null; if (isParentFirst(name)) { - url = (parent == null) ? super.getResource(name) : parent.getResource(name); + url = (parent == null) ? super.getResource(name) + : parent.getResource(name); } if (url != null) { @@ -881,7 +852,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { if (resource.exists()) { try { - return new URL("file:"+resource.toString()); + return new URL("file:" + resource.toString()); } catch (MalformedURLException ex) { return null; } @@ -897,7 +868,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { ZipEntry entry = zipFile.getEntry(resourceName); if (entry != null) { try { - return new URL("jar:file:"+file.toString()+"!/"+entry); + return new URL("jar:file:" + file.toString() + + "!/" + entry); } catch (MalformedURLException ex) { return null; } @@ -931,7 +903,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { * on the system classpath (when not in isolated mode) or this loader's * classpath. */ - protected Class loadClass(String classname, boolean resolve) throws ClassNotFoundException { + protected Class loadClass(String classname, boolean resolve) + throws ClassNotFoundException { Class theClass = findLoadedClass(classname); if (theClass != null) { @@ -941,24 +914,28 @@ public class AntClassLoader extends ClassLoader implements BuildListener { if (isParentFirst(classname)) { try { theClass = findBaseClass(classname); - log("Class " + classname + " loaded from parent loader", Project.MSG_DEBUG); + log("Class " + classname + " loaded from parent loader", + Project.MSG_DEBUG); } catch (ClassNotFoundException cnfe) { theClass = findClass(classname); - log("Class " + classname + " loaded from ant loader", Project.MSG_DEBUG); + log("Class " + classname + " loaded from ant loader", + Project.MSG_DEBUG); } } else { try { theClass = findClass(classname); - log("Class " + classname + " loaded from ant loader", Project.MSG_DEBUG); + log("Class " + classname + " loaded from ant loader", + Project.MSG_DEBUG); } catch (ClassNotFoundException cnfe) { if (ignoreBase) { throw cnfe; } theClass = findBaseClass(classname); - log("Class " + classname + " loaded from parent loader", Project.MSG_DEBUG); + log("Class " + classname + " loaded from parent loader", + Project.MSG_DEBUG); } } @@ -1008,12 +985,16 @@ public class AntClassLoader extends ClassLoader implements BuildListener { byte[] classData = baos.toByteArray(); // Simply put: - // defineClass(classname, classData, 0, classData.length, Project.class.getProtectionDomain()); + // defineClass(classname, classData, 0, classData.length, + // Project.class.getProtectionDomain()); // Made more elaborate to be 1.1-safe. if (defineClassProtectionDomain != null) { try { - Object domain = getProtectionDomain.invoke(Project.class, new Object[0]); - Object[] args = new Object[] {classname, classData, new Integer(0), new Integer(classData.length), domain}; + Object domain + = getProtectionDomain.invoke(Project.class, new Object[0]); + Object[] args + = new Object[] {classname, classData, new Integer(0), + new Integer(classData.length), domain}; return (Class)defineClassProtectionDomain.invoke(this, args); } catch (InvocationTargetException ite) { @@ -1066,9 +1047,10 @@ public class AntClassLoader extends ClassLoader implements BuildListener { * @exception ClassNotFoundException if the requested class does not exist * on this loader's classpath. */ - private Class findClassInComponents(String name) throws ClassNotFoundException { - // we need to search the components of the path to see if we can find the - // class we want. + private Class findClassInComponents(String name) + 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 { @@ -1082,7 +1064,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { } catch (IOException ioe) { // ioe.printStackTrace(); - log("Exception reading component " + pathComponent , Project.MSG_VERBOSE); + log("Exception reading component " + pathComponent , + Project.MSG_VERBOSE); } } @@ -1143,6 +1126,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { /** * Empty implementation to satisfy the BuildListener interface. + * + * @param event the buildStarted event */ public void buildStarted(BuildEvent event) { } @@ -1150,6 +1135,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { /** * Cleans up any resources held by this classloader at the end * of a build. + * + * @param event the buildFinished event */ public void buildFinished(BuildEvent event) { cleanup(); @@ -1157,30 +1144,40 @@ public class AntClassLoader extends ClassLoader implements BuildListener { /** * Empty implementation to satisfy the BuildListener interface. + * + * @param event the targetStarted event */ public void targetStarted(BuildEvent event) { } /** * Empty implementation to satisfy the BuildListener interface. + * + * @param event the targetFinished event */ public void targetFinished(BuildEvent event) { } /** * Empty implementation to satisfy the BuildListener interface. + * + * @param event the taskStarted event */ public void taskStarted(BuildEvent event) { } /** * Empty implementation to satisfy the BuildListener interface. + * + * @param event the taskFinished event */ public void taskFinished(BuildEvent event) { } /** * Empty implementation to satisfy the BuildListener interface. + * + * @param event the messageLogged event */ public void messageLogged(BuildEvent event) { } diff --git a/src/main/org/apache/tools/ant/ProjectHelper.java b/src/main/org/apache/tools/ant/ProjectHelper.java index d3d5ec0f4..5b9657464 100644 --- a/src/main/org/apache/tools/ant/ProjectHelper.java +++ b/src/main/org/apache/tools/ant/ProjectHelper.java @@ -70,6 +70,7 @@ import java.lang.reflect.Method; import org.xml.sax.AttributeList; import org.apache.tools.ant.helper.ProjectHelperImpl; +import org.apache.tools.ant.util.LoaderUtils; /** * Configures a Project (complete with Targets and Tasks) based on @@ -236,30 +237,11 @@ public class ProjectHelper { public static ClassLoader getContextClassLoader() throws BuildException { - // Are we running on a JDK 1.2 or later system? - Method method = null; - try { - method = Thread.class.getMethod("getContextClassLoader", null); - } catch (NoSuchMethodException e) { - // we are running on JDK 1.1 - return null; - } - - // Get the thread context class loader (if there is one) - ClassLoader classLoader = null; - try { - classLoader = (ClassLoader) - method.invoke(Thread.currentThread(), null); - } catch (IllegalAccessException e) { - throw new BuildException - ("Unexpected IllegalAccessException", e); - } catch (InvocationTargetException e) { - throw new BuildException - ("Unexpected InvocationTargetException", e); + if (!LoaderUtils.isContextLoaderAvailable()) { + return null; } - - // Return the selected class loader - return (classLoader); + + return LoaderUtils.getContextClassLoader(); } // -------------------- Static utils, used by most helpers -------------------- diff --git a/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java b/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java index e15a8ee46..1ab56536d 100644 --- a/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java +++ b/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java @@ -65,7 +65,7 @@ import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.util.FileUtils; -import org.apache.tools.ant.types.XCatalog; +import org.apache.tools.ant.types.XMLCatalog; import org.xml.sax.EntityResolver; /** @@ -142,7 +142,7 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { private String outputtype = null; /** for resolving entities such as dtds */ - private XCatalog xcatalog; + private XMLCatalog xmlCatalog; /** Name of the TRAX Liason class */ private static final String TRAX_LIAISON_CLASS = @@ -344,12 +344,12 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { } /** - * store the xcatalog for resolving entities + * store the xml catalog for resolving entities * - * @param xcatalog the xcatalog instance to use to look up DTDs + * @param xmlCatalog the XMLCatalog instance to use to look up DTDs */ - public void addXcatalog(XCatalog xcatalog) { - this.xcatalog = xcatalog; + public void addXMLcatalog(XMLCatalog xmlCatalog) { + this.xmlCatalog = xmlCatalog; } /** @@ -660,16 +660,16 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { Param p = (Param)e.nextElement(); liaison.addParam( p.getName(), p.getExpression() ); } - // if liaison is a TraxLiason, use XCatalog as the entity + // if liaison is a TraxLiason, use XMLCatalog as the entity // resolver if (liaison.getClass().getName().equals(TRAX_LIAISON_CLASS) && - xcatalog != null) { + xmlCatalog != null) { log("Configuring TraxLiaison and calling entity resolver", Project.MSG_DEBUG); Method resolver = liaison.getClass() .getDeclaredMethod("setEntityResolver", new Class[] {EntityResolver.class}); - resolver.invoke(liaison, new Object[] {xcatalog}); + resolver.invoke(liaison, new Object[] {xmlCatalog}); } } catch (Exception ex) { log("Failed to read stylesheet " + stylesheet, Project.MSG_INFO); diff --git a/src/main/org/apache/tools/ant/types/XCatalog.java b/src/main/org/apache/tools/ant/types/XMLCatalog.java similarity index 89% rename from src/main/org/apache/tools/ant/types/XCatalog.java rename to src/main/org/apache/tools/ant/types/XMLCatalog.java index 5f1ae3871..f95a5160a 100644 --- a/src/main/org/apache/tools/ant/types/XCatalog.java +++ b/src/main/org/apache/tools/ant/types/XMLCatalog.java @@ -59,13 +59,15 @@ import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.net.URL; -import java.util.Enumeration; +import java.util.Iterator; import java.util.Vector; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.apache.tools.ant.util.LoaderUtils; +import org.apache.tools.ant.util.FileUtils; /** * This data type provides a catalog of DTD locations @@ -90,7 +92,9 @@ import org.xml.sax.SAXException; * @author dIon Gillard * @version $Id$ */ -public class XCatalog extends DataType implements Cloneable, EntityResolver { +public class XMLCatalog extends DataType implements Cloneable, EntityResolver { + + private FileUtils fileUtils = FileUtils.newFileUtils(); //-- Fields ---------------------------------------------------------------- @@ -121,7 +125,7 @@ public class XCatalog extends DataType implements Cloneable, EntityResolver { * @param aDTD the DTDLocation instance to be aded to the catalog */ private void addElement(DTDLocation aDTD) { - getElements().addElement(aDTD); + getElements().add(aDTD); } /** @@ -135,7 +139,7 @@ public class XCatalog extends DataType implements Cloneable, EntityResolver { if (isReference()) { throw noChildrenAllowed(); } - getElements().addElement(dtd); + getElements().add(dtd); } /** @@ -165,9 +169,9 @@ public class XCatalog extends DataType implements Cloneable, EntityResolver { // change this to get the objects from the other reference Object o = r.getReferencedObject(getProject()); // we only support references to other XCatalogs - if (o instanceof XCatalog) { + if (o instanceof XMLCatalog) { // set all elements from referenced catalog to this one - XCatalog catalog = (XCatalog) o; + XMLCatalog catalog = (XMLCatalog) o; setElements(catalog.getElements()); } else { String msg = r.getRefId() + " doesn\'t refer to an XCatalog"; @@ -191,16 +195,20 @@ public class XCatalog extends DataType implements Cloneable, EntityResolver { Project.MSG_DEBUG); File dtdFile = new File(matchingDTD.getLocation()); if (dtdFile.exists() && dtdFile.canRead()) { - source = new InputSource( new FileInputStream(dtdFile) ); - source.setSystemId(dtdFile.toURL().toExternalForm()); + source = new InputSource(new FileInputStream(dtdFile)); + URL dtdFileURL = fileUtils.getFileURL(dtdFile); + source.setSystemId(dtdFileURL.toExternalForm()); log("matched a readable file", Project.MSG_DEBUG); } else { // check if publicId is a resource // FIXME: ClassLoader: should this be context? - ClassLoader loader - = Thread.currentThread().getContextClassLoader(); - InputStream is = loader.getResourceAsStream( - matchingDTD.getLocation() ); + ClassLoader loader = LoaderUtils.getContextClassLoader(); + if (loader == null) { + loader = getClass().getClassLoader(); + } + + InputStream is + = loader.getResourceAsStream(matchingDTD.getLocation()); if (is != null) { source = new InputSource(is); source.setSystemId(loader.getResource( @@ -242,10 +250,10 @@ public class XCatalog extends DataType implements Cloneable, EntityResolver { * of the DTD or null if no such information is available */ private DTDLocation findMatchingDTD(String publicId) { - Enumeration elements = getElements().elements(); + Iterator elements = getElements().iterator(); DTDLocation element = null; - while (elements.hasMoreElements()) { - element = (DTDLocation)elements.nextElement(); + while (elements.hasNext()) { + element = (DTDLocation)elements.next(); if (element.getPublicId().equals(publicId)) { return element; } diff --git a/src/main/org/apache/tools/ant/types/defaults.properties b/src/main/org/apache/tools/ant/types/defaults.properties index 3deff353d..3fb5f1c31 100644 --- a/src/main/org/apache/tools/ant/types/defaults.properties +++ b/src/main/org/apache/tools/ant/types/defaults.properties @@ -8,5 +8,5 @@ description=org.apache.tools.ant.types.Description classfileset=org.apache.tools.ant.types.optional.depend.ClassfileSet substitution=org.apache.tools.ant.types.Substitution regexp=org.apache.tools.ant.types.RegularExpression -xcatalog=org.apache.tools.ant.types.XCatalog +xmlcatalog=org.apache.tools.ant.types.XMLCatalog diff --git a/src/main/org/apache/tools/ant/util/FileUtils.java b/src/main/org/apache/tools/ant/util/FileUtils.java index 84a4d7a05..804fed50e 100644 --- a/src/main/org/apache/tools/ant/util/FileUtils.java +++ b/src/main/org/apache/tools/ant/util/FileUtils.java @@ -74,6 +74,8 @@ import java.util.Random; import java.util.Stack; import java.util.StringTokenizer; import java.util.Vector; +import java.net.URL; +import java.net.MalformedURLException; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; @@ -115,6 +117,25 @@ public class FileUtils { */ protected FileUtils() {} + /** + * Get the URL for a file taking into account # characters + * + * @param file the file whose URL representation is required. + * @return The FileURL value + * @throws MalformedURLException if the URL representation cannot be + * formed. + */ + public URL getFileURL(File file) throws MalformedURLException { + String uri = "file:" + file.getAbsolutePath().replace('\\', '/'); + for (int i = uri.indexOf('#'); i != -1; i = uri.indexOf('#')) { + uri = uri.substring(0, i) + "%23" + uri.substring(i + 1); + } + if (file.isDirectory()) { + uri += "/"; + } + return new URL(uri); + } + /** * Convienence method to copy a file from a source to a destination. * No filtering is performed. diff --git a/src/main/org/apache/tools/ant/util/LoaderUtils.java b/src/main/org/apache/tools/ant/util/LoaderUtils.java new file mode 100644 index 000000000..d72ef44c5 --- /dev/null +++ b/src/main/org/apache/tools/ant/util/LoaderUtils.java @@ -0,0 +1,150 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.tools.ant.util; + +import java.lang.reflect.InvocationTargetException; + +import java.lang.reflect.Method; +import org.apache.tools.ant.BuildException; + +/** + * ClassLoader utility methods + * + * @author Conor MacNeill + * @created 11 March 2002 + */ +public class LoaderUtils { + /** The getContextClassLoader method */ + private static Method getContextClassLoader; + /** The setContextClassLoader method */ + private static Method setContextClassLoader; + + // Set up the reflection-based Java2 methods if possible + static { + try { + getContextClassLoader + = Thread.class.getMethod("getContextClassLoader", + new Class[0]); + Class[] setContextArgs = new Class[]{ClassLoader.class}; + setContextClassLoader + = Thread.class.getMethod("setContextClassLoader", + setContextArgs); + } catch (Exception e) { + // ignore any problems accessing the methods - probably JDK 1.1 + } + } + + /** + * JDK1.1 compatible access to get the context class loader. Has no + * effect on JDK 1.1 + * + * @param loader the ClassLoader to be used as the context class loader + * on the current thread. + */ + public static void setContextClassLoader(ClassLoader loader) { + if (setContextClassLoader == null) { + return; + } + + try { + Thread currentThread = Thread.currentThread(); + setContextClassLoader.invoke(currentThread, + new Object[]{loader}); + } catch (IllegalAccessException e) { + throw new BuildException + ("Unexpected IllegalAccessException", e); + } catch (InvocationTargetException e) { + throw new BuildException + ("Unexpected InvocationTargetException", e); + } + + } + + + /** + * JDK1.1 compatible access to set the context class loader. + * + * @return the ClassLoader instance being used as the context + * classloader on the current thread. Returns null on JDK 1.1 + */ + public static ClassLoader getContextClassLoader() { + if (getContextClassLoader == null) { + return null; + } + + try { + Thread currentThread = Thread.currentThread(); + return (ClassLoader)getContextClassLoader.invoke(currentThread, + new Object[0]); + } catch (IllegalAccessException e) { + throw new BuildException + ("Unexpected IllegalAccessException", e); + } catch (InvocationTargetException e) { + throw new BuildException + ("Unexpected InvocationTargetException", e); + } + } + + /** + * Indicates if the context class loader methods are available + * + * @return true if the get and set methods dealing with the context + * classloader are available. + */ + public static boolean isContextLoaderAvailable() { + return getContextClassLoader != null && + setContextClassLoader != null; + } +} +