aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ClasspathUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ClasspathUtils.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ClasspathUtils.java463
1 files changed, 463 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ClasspathUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ClasspathUtils.java
new file mode 100644
index 00000000..309860e9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ClasspathUtils.java
@@ -0,0 +1,463 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * Offers some helper methods on the Path structure in ant.
+ *
+ * <p>The basic idea behind this utility class is to use it from inside the
+ * different Ant objects (and user defined objects) that need classLoading
+ * for their operation.
+ * Normally those would have a setClasspathRef() {for the @classpathref}
+ * and/or a createClasspath() {for the nested &lt;classpath&gt;}
+ * Typically one would have in your Ant Task or DataType</p>
+ *
+ * <pre><code>
+ * ClasspathUtils.Delegate cpDelegate;
+ *
+ * public void init() {
+ * this.cpDelegate = ClasspathUtils.getDelegate(this);
+ * super.init();
+ * }
+ *
+ * public void setClasspathRef(Reference r) {
+ * this.cpDelegate.setClasspathRef(r);
+ * }
+ *
+ * public Path createClasspath() {
+ * return this.cpDelegate.createClasspath();
+ * }
+ *
+ * public void setClassname(String fqcn) {
+ * this.cpDelegate.setClassname(fqcn);
+ * }
+ * </code></pre>
+ *
+ * <p>At execution time, when you actually need the classloading
+ * you can just:</p>
+ *
+ * <pre><code>
+ * Object o = this.cpDelegate.newInstance();
+ * </code></pre>
+ *
+ * @since Ant 1.6
+ */
+public class ClasspathUtils {
+
+ /**
+ * Name of the magic property that controls classloader reuse in Ant 1.4.
+ */
+ public static final String REUSE_LOADER_REF = MagicNames.REFID_CLASSPATH_REUSE_LOADER;
+
+ /**
+ * Convenience overloaded version of {@link
+ * #getClassLoaderForPath(Project, Reference, boolean)}.
+ *
+ * <p>Assumes the logical 'false' for the reverseLoader.</p>
+ *
+ * @param p the project
+ * @param ref the reference
+ * @return The class loader
+ */
+ public static ClassLoader getClassLoaderForPath(Project p, Reference ref) {
+ return getClassLoaderForPath(p, ref, false);
+ }
+
+ /**
+ * Convenience overloaded version of {@link #getClassLoaderForPath(Project, 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 its parent (which is contra the regular
+ * classloader behaviour)
+ * @return The class loader
+ */
+ 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.");
+ }
+ String loaderId = MagicNames.REFID_CLASSPATH_LOADER_PREFIX + pathId;
+ return getClassLoaderForPath(p, (Path) path, loaderId, reverseLoader);
+ }
+
+ /**
+ * Convenience overloaded version of {@link
+ * #getClassLoaderForPath(Project, Path, String, boolean)}.
+ *
+ * <p>Assumes the logical 'false' for the reverseLoader.</p>
+ *
+ * @param p current Ant project
+ * @param path the path
+ * @param loaderId the loader id string
+ * @return The class loader
+ */
+ public static ClassLoader getClassLoaderForPath(Project p, Path path, String loaderId) {
+ return getClassLoaderForPath(p, path, loaderId, false);
+ }
+
+ /**
+ * Convenience overloaded version of {@link
+ * #getClassLoaderForPath(Project, Path, String, boolean, boolean)}.
+ *
+ * <p>Sets value for 'reuseLoader' to true if the magic property
+ * has been set.</p>
+ *
+ * @param p the project
+ * @param path the path
+ * @param loaderId the loader id string
+ * @param reverseLoader if set to true this new loader will take
+ * precedence over its parent (which is contra the regular
+ * classloader behaviour)
+ * @return The class loader
+ */
+ public static ClassLoader getClassLoaderForPath(
+ Project p, Path path, String loaderId, boolean reverseLoader) {
+ return getClassLoaderForPath(p, path, loaderId, reverseLoader, isMagicPropertySet(p));
+ }
+
+ /**
+ * 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 previously
+ * created loader with that id, and of course store it there upon
+ * creation.</p>
+ * @param p Ant Project where the handled components are living in.
+ * @param path Path object to be used as classpath for this classloader
+ * @param loaderId identification for this Loader,
+ * @param reverseLoader if set to true this new loader will take
+ * precedence over its parent (which is contra the regular
+ * classloader behaviour)
+ * @param reuseLoader if true reuse the loader if it is found
+ * @return ClassLoader that uses the Path as its classpath.
+ */
+ public static ClassLoader getClassLoaderForPath(
+ Project p, Path path, String loaderId, boolean reverseLoader, boolean reuseLoader) {
+ ClassLoader cl = null;
+
+ // magic property
+ if (loaderId != null && reuseLoader) {
+ Object reusedLoader = p.getReference(loaderId);
+ if (reusedLoader != null && !(reusedLoader instanceof ClassLoader)) {
+ throw new BuildException("The specified loader id " + loaderId
+ + " does not reference a class loader");
+ }
+ cl = (ClassLoader) reusedLoader;
+ }
+ if (cl == null) {
+ cl = getUniqueClassLoaderForPath(p, path, reverseLoader);
+ if (loaderId != null && reuseLoader) {
+ p.addReference(loaderId, cl);
+ }
+ }
+ return cl;
+ }
+
+ /**
+ * Gets a fresh, different, previously unused classloader that uses the
+ * passed path as its classpath.
+ *
+ * <p>This method completely ignores the ant.reuse.loader magic
+ * property and should be used with caution.</p>
+ * @param p Ant Project where the handled components are living in.
+ * @param path the classpath for this loader
+ * @param reverseLoader if set to true this new loader will take
+ * precedence over its parent (which is contra the regular
+ * classloader behaviour)
+ * @return The fresh, different, previously unused class loader.
+ */
+ public static ClassLoader getUniqueClassLoaderForPath(Project p, Path path,
+ boolean reverseLoader) {
+ AntClassLoader acl = p.createClassLoader(path);
+ if (reverseLoader) {
+ acl.setParentFirst(false);
+ acl.addJavaLibraries();
+ }
+ return acl;
+ }
+
+ /**
+ * Creates a fresh object instance of the specified classname.
+ *
+ * <p> This uses the userDefinedLoader to load the specified class,
+ * and then makes an instance using the default no-argument constructor.
+ * </p>
+ *
+ * @param className the full qualified class name to load.
+ * @param userDefinedLoader the classloader to use.
+ * @return The fresh object instance
+ * @throws BuildException when loading or instantiation failed.
+ */
+ public static Object newInstance(String className, ClassLoader userDefinedLoader) {
+ return newInstance(className, userDefinedLoader, Object.class);
+ }
+
+ /**
+ * Creates a fresh object instance of the specified classname.
+ *
+ * <p> This uses the userDefinedLoader to load the specified class,
+ * and then makes an instance using the default no-argument constructor.
+ * </p>
+ *
+ * @param className the full qualified class name to load.
+ * @param userDefinedLoader the classloader to use.
+ * @param expectedType the Class that the result should be assignment
+ * compatible with. (No ClassCastException will be thrown in case
+ * the result of this method is casted to the expectedType)
+ * @return The fresh object instance
+ * @throws BuildException when loading or instantiation failed.
+ * @since Ant 1.7
+ */
+ public static Object newInstance(String className, ClassLoader userDefinedLoader,
+ Class expectedType) {
+ try {
+ Class clazz = Class.forName(className, true, userDefinedLoader);
+ Object o = clazz.newInstance();
+ if (!expectedType.isInstance(o)) {
+ throw new BuildException("Class of unexpected Type: " + className + " expected :"
+ + expectedType);
+ }
+ return o;
+ } catch (ClassNotFoundException e) {
+ throw new BuildException("Class not found: " + className, 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);
+ } catch (LinkageError e) {
+ throw new BuildException("Class " + className
+ + " could not be loaded because of an invalid dependency.", e);
+ }
+ }
+
+ /**
+ * Obtains a delegate that helps out with classic classpath configuration.
+ *
+ * @param component your projectComponent that needs the assistence
+ * @return the helper, delegate.
+ * @see ClasspathUtils.Delegate
+ */
+ public static Delegate getDelegate(ProjectComponent component) {
+ return new Delegate(component);
+ }
+
+ /**
+ * Checks for the magic property that enables class loader reuse
+ * for <taskdef> and <typedef> in Ant 1.5 and earlier.
+ */
+ private static boolean isMagicPropertySet(Project p) {
+ return p.getProperty(REUSE_LOADER_REF) != null;
+ }
+
+ /**
+ * Delegate that helps out any specific ProjectComponent that needs
+ * dynamic classloading.
+ *
+ * <p>Ant ProjectComponents that need a to be able to dynamically load
+ * Classes and instantiate them often expose the following ant syntax
+ * sugar: </p>
+ *
+ * <ul><li> nested &lt;classpath&gt; </li>
+ * <li> attribute @classpathref </li>
+ * <li> attribute @classname </li></ul>
+ *
+ * <p> This class functions as a delegate handling the configuration
+ * issues for this recurring pattern. Its usage pattern, as the name
+ * suggests, is delegation rather than inheritance. </p>
+ *
+ * @since Ant 1.6
+ */
+ public static class Delegate {
+ private final ProjectComponent component;
+ private Path classpath;
+ private String classpathId;
+ private String className;
+ private String loaderId;
+ private boolean reverseLoader = false;
+
+ /**
+ * Construct a Delegate
+ * @param component the ProjectComponent this delegate is for.
+ */
+ Delegate(ProjectComponent component) {
+ this.component = component;
+ }
+
+ /**
+ * This method is a Delegate method handling the @classpath attribute.
+ *
+ * <p>This attribute can set a path to add to the classpath.</p>
+ *
+ * @param classpath the path to use for the classpath.
+ */
+ public void setClasspath(Path classpath) {
+ if (this.classpath == null) {
+ this.classpath = classpath;
+ } else {
+ this.classpath.append(classpath);
+ }
+ }
+
+ /**
+ * Delegate method handling the &lt;classpath&gt; tag.
+ *
+ * <p>This nested path-like structure can set a path to add to the
+ * classpath.</p>
+ *
+ * @return the created path.
+ */
+ public Path createClasspath() {
+ if (this.classpath == null) {
+ this.classpath = new Path(component.getProject());
+ }
+ return this.classpath.createPath();
+ }
+
+ /**
+ * Delegate method handling the @classname attribute.
+ *
+ * <p>This attribute sets the full qualified class name of the class
+ * to load and instantiate.</p>
+ *
+ * @param fcqn the name of the class to load.
+ */
+ public void setClassname(String fcqn) {
+ this.className = fcqn;
+ }
+
+ /**
+ * Delegate method handling the @classpathref attribute.
+ *
+ * <p>This attribute can add a referenced path-like structure to the
+ * classpath.</p>
+ *
+ * @param r the reference to the classpath.
+ */
+ public void setClasspathref(Reference r) {
+ this.classpathId = r.getRefId();
+ createClasspath().setRefid(r);
+ }
+
+ /**
+ * Delegate method handling the @reverseLoader attribute.
+ *
+ * <p>This attribute can set a boolean indicating that the used
+ * classloader should NOT follow the classical parent-first scheme.
+ * </p>
+ *
+ * <p>By default this is supposed to be false.</p>
+ *
+ * <p>Caution: this behaviour is contradictory to the normal way
+ * classloaders work. Do not let your ProjectComponent use it if
+ * you are not really sure.</p>
+ *
+ * @param reverseLoader if true reverse the order of looking up a class.
+ */
+ public void setReverseLoader(boolean reverseLoader) {
+ this.reverseLoader = reverseLoader;
+ }
+
+ /**
+ * Sets the loaderRef.
+ * @param r the reference to the loader.
+ */
+ public void setLoaderRef(Reference r) {
+ this.loaderId = r.getRefId();
+ }
+
+
+ /**
+ * Finds or creates the classloader for this object.
+ * @return The class loader.
+ */
+ public ClassLoader getClassLoader() {
+ return getClassLoaderForPath(getContextProject(), classpath, getClassLoadId(),
+ reverseLoader, loaderId != null || isMagicPropertySet(getContextProject()));
+ }
+
+ /**
+ * The project of the ProjectComponent we are working for.
+ */
+ private Project getContextProject() {
+ return component.getProject();
+ }
+
+ /**
+ * Computes the loaderId based on the configuration of the component.
+ * @return a loader identifier.
+ */
+ public String getClassLoadId() {
+ if (loaderId == null && classpathId != null) {
+ return MagicNames.REFID_CLASSPATH_LOADER_PREFIX + classpathId;
+ } else {
+ return loaderId;
+ }
+ }
+
+ /**
+ * Helper method obtaining a fresh instance of the class specified
+ * in the @classname and using the specified classpath.
+ *
+ * @return the fresh instantiated object.
+ */
+ public Object newInstance() {
+ return ClasspathUtils.newInstance(this.className, getClassLoader());
+ }
+
+ /**
+ * The classpath.
+ * @return the classpath.
+ */
+ public Path getClasspath() {
+ return classpath;
+ }
+
+ /**
+ * Get the reverseLoader setting.
+ * @return true if looking up in reverse order.
+ */
+ public boolean isReverseLoader() {
+ return reverseLoader;
+ }
+
+ //TODO no methods yet for getClassname
+ //TODO no method for newInstance using a reverse-classloader
+ }
+}