bodewig 2003/04/14 00:06:55
Added: src/main/org/apache/tools/ant/util ClasspathUtils.java Log: Utility class to centralize all classloader and "instante from custom classloader" related actions. PR: 18906 Submitted by: Marc Portier <mpo at apache dot org> Revision Changes Path 1.1 ant/src/main/org/apache/tools/ant/util/ClasspathUtils.java Index: ClasspathUtils.java =================================================================== /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 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 "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 [EMAIL PROTECTED] * * 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 * <http://www.apache.org/>. */ package org.apache.tools.ant.util; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; /** * Offers some helper methods on the Path structure in ant. * * <p>Basic idea behind this utility class is to use it from inside the * different ant objects (and user defined objects) that need dclassLoading * for their operation. * Normally those would have a setClasspathRef() {for the @@classpathref} * and/or a createClasspath() {for the nested <classpath>} * Typically one would have</p> * * <pre><code> * public void setClasspathRef(Reference r) { * this.classpathId = r.getRefId(); * createClasspath().setRefid(r); * } * * public Path createClasspath() { * if (this.classpath == null) { * this.classpath = new Path(getProject()); * } * return this.classpath.createPath(); * } * * public void setClassname(String fqcn) { * this.classname = fqcn; * } * </code></pre> * * <p>when you actually need the classloading you can just:</p> * * <pre><code> * ClassLoader cl = ClasspathUtils.getClassLoaderForPath(this.classpath, this.classpathId); * Object o = ClasspathUtils.newInstance(this.classname, cl); * </code></pre> * * @since Ant 1.6 */ public class ClasspathUtils { private static final String LOADER_ID_PREFIX = "ant.loader."; public static final String REUSE_LOADER_REF = "ant.reuse.loader"; /** * Convenience overloaded version of [EMAIL PROTECTED] * #getClassLoaderForPath(Project, Reference, boolean)}. * * <p>Assumes the logical 'false' for the reverseLoader.</p> * * @param path * @param pathId * @return */ public static ClassLoader getClassLoaderForPath(Project p, Reference ref) { return getClassLoaderForPath(p, ref, false); } /** * Convenience overloaded version of [EMAIL PROTECTED] #geClassLoader(Path, * String, boolean)}. * * <p>Delegates to the other one after extracting the referenced * Path from the Project This checks also that the passed * Reference is pointing to a Path all right.</p> * @param p current ant project * @param ref Reference to Path structure * @param reverseLoader if set to true this new loader will take * precedence over it's parent (which is contra the regular * classloader behaviour) * @return */ public static ClassLoader getClassLoaderForPath(Project p, Reference ref, boolean reverseLoader) { String pathId = ref.getRefId(); Object path = p.getReference(pathId); if (!(path instanceof Path)){ throw new BuildException ("The specified classpathref " + pathId + " does not reference a Path."); } return getClassLoaderForPath((Path)path, pathId, reverseLoader); } /** * Convenience overloaded version of [EMAIL PROTECTED] * #getClassLoaderForPath(Path, String, boolean)}. * * <p>Assumes the logical 'false' for the reverseLoader.</p> * * @param path * @param pathId * @return */ public static ClassLoader getClassLoaderForPath(Path path, String pathId){ return getClassLoaderForPath(path, pathId, false); } /** * Gets a classloader that loads classes from the classpath * defined in the path argument. * * <p>Based on the setting of the magic property * 'ant.reuse.loader' this will try to reuse the perviously * created loader with that id, and of course store it there upon * creation.</p> * @param path Path object to be used as classpath for this classloader * @param pathId identification for this Path, will be used to * identify the classLoader as well. * @param reverseLoader if set to true this new loader will take * precedence over it's parent (which is contra the regular * classloader behaviour) * @return ClassLoader that uses the Path as its classpath. */ public static ClassLoader getClassLoaderForPath(Path path, String pathId, boolean reverseLoader) { ClassLoader cl = null; Project p = path.getProject(); String loaderId = LOADER_ID_PREFIX + pathId; // code stolen from o.a.t.a.taskdefs.Definer, might be a todo // to remove it there didn't look at the reverse loader stuff // however (todo that first) // magic property if (p.getProperty(REUSE_LOADER_REF) != null) { //chose not to do the extra instanceof checking here, consider it // a programming error and not a config error if this fails // so I assume the RuntimeException is OK cl = (ClassLoader)p.getReference(loaderId); } if (cl == null){ cl = getUniqueClassLoaderForPath(path, reverseLoader); p.addReference(loaderId, cl); } return cl; } /** * Gets a fresh, different, not used before classloader that uses the * passed path as it's classpath. * * <p>This method completely ignores the ant.reuse.loader magic * property and should be used with caution.</p> * @param path the classpath for this loader * @param reverseLoader * @return */ public static ClassLoader getUniqueClassLoaderForPath(Path path, boolean reverseLoader) { ClassLoader cl = null; Project p = path.getProject(); AntClassLoader acl = p.createClassLoader(Path.systemClasspath); if (reverseLoader) { acl.setParentFirst(false); acl.addJavaLibraries(); } return cl; } public static Object newInstance(String className, ClassLoader userDefinedLoader){ try { Class clazz = userDefinedLoader.loadClass(className); Object o = clazz.newInstance(); return o; } catch (ClassNotFoundException e) { throw new BuildException("Class " + className + " not found by the specific classLoader.", e); } catch (InstantiationException e) { throw new BuildException("Could not instantiate " + className + ". Specified class should have a no " + "argument constructor.", e); } catch (IllegalAccessException e) { throw new BuildException("Could not instantiate " + className + ". Specified class should have a " + "public constructor.", e); } } }
