001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.taskdefs;
020:
021: import org.apache.tools.ant.Project;
022: import org.apache.tools.ant.Task;
023: import org.apache.tools.ant.MagicNames;
024: import org.apache.tools.ant.BuildException;
025: import org.apache.tools.ant.AntClassLoader;
026: import org.apache.tools.ant.types.Reference;
027: import org.apache.tools.ant.types.Path;
028:
029: import java.io.File;
030:
031: /**
032: * EXPERIMENTAL
033: * Create or modifies ClassLoader. The required pathRef parameter
034: * will be used to add classpath elements.
035: *
036: * The classpath is a regular path. Currently only file components are
037: * supported (future extensions may allow URLs).
038: *
039: * You can modify the core loader by not specifying any name or using
040: * "ant.coreLoader". (the core loader is used to load system ant
041: * tasks and for taskdefs that don't specify an explicit path).
042: *
043: * Taskdef and typedef can use the loader you create if the name follows
044: * the "ant.loader.NAME" pattern. NAME will be used as a pathref when
045: * calling taskdef.
046: *
047: * This tasks will not modify the core loader if "build.sysclasspath=only"
048: *
049: * The typical use is:
050: * <pre>
051: * <path id="ant.deps" >
052: * <fileset dir="myDir" >
053: * <include name="junit.jar, bsf.jar, js.jar, etc"/>
054: * </fileset>
055: * </path>
056: *
057: * <classloader pathRef="ant.deps" />
058: *
059: * </pre>
060: *
061: */
062: public class Classloader extends Task {
063: /** @see MagicNames#SYSTEM_LOADER_REF */
064: public static final String SYSTEM_LOADER_REF = MagicNames.SYSTEM_LOADER_REF;
065:
066: private String name = null;
067: private Path classpath;
068: private boolean reset = false;
069: private boolean parentFirst = true;
070: private String parentName = null;
071:
072: /**
073: * Default constructor
074: */
075: public Classloader() {
076: }
077:
078: /** Name of the loader. If none, the default loader will be modified
079: *
080: * @param name the name of this loader
081: */
082: public void setName(String name) {
083: this .name = name;
084: }
085:
086: /**
087: * Reset the classloader, if it already exists. A new loader will
088: * be created and all the references to the old one will be removed.
089: * (it is not possible to remove paths from a loader). The new
090: * path will be used.
091: *
092: * @param b true if the loader is to be reset.
093: */
094: public void setReset(boolean b) {
095: this .reset = b;
096: }
097:
098: /**
099: * Set reverse attribute.
100: * @param b if true reverse the normal classloader lookup.
101: */
102: public void setReverse(boolean b) {
103: this .parentFirst = !b;
104: }
105:
106: /**
107: * Set reverse attribute.
108: * @param b if true reverse the normal classloader lookup.
109: */
110: public void setParentFirst(boolean b) {
111: this .parentFirst = b;
112: }
113:
114: /**
115: * Set the name of the parent.
116: * @param name the parent name.
117: */
118: public void setParentName(String name) {
119: this .parentName = name;
120: }
121:
122: /** Specify which path will be used. If the loader already exists
123: * and is an AntClassLoader (or any other loader we can extend),
124: * the path will be added to the loader.
125: * @param pathRef a reference to a path.
126: * @throws BuildException if there is a problem.
127: */
128: public void setClasspathRef(Reference pathRef)
129: throws BuildException {
130: classpath = (Path) pathRef.getReferencedObject(getProject());
131: }
132:
133: /**
134: * Set the classpath to be used when searching for component being defined
135: *
136: * @param classpath an Ant Path object containing the classpath.
137: */
138: public void setClasspath(Path classpath) {
139: if (this .classpath == null) {
140: this .classpath = classpath;
141: } else {
142: this .classpath.append(classpath);
143: }
144: }
145:
146: /**
147: * Create a classpath.
148: * @return a path for configuration.
149: */
150: public Path createClasspath() {
151: if (this .classpath == null) {
152: this .classpath = new Path(null);
153: }
154: return this .classpath.createPath();
155: }
156:
157: /**
158: * do the classloader manipulation.
159: */
160: public void execute() {
161: try {
162: // Gump friendly - don't mess with the core loader if only classpath
163: if ("only".equals(getProject().getProperty(
164: "build.sysclasspath"))
165: && (name == null || SYSTEM_LOADER_REF.equals(name))) {
166: log("Changing the system loader is disabled "
167: + "by build.sysclasspath=only",
168: Project.MSG_WARN);
169: return;
170: }
171:
172: String loaderName = (name == null) ? SYSTEM_LOADER_REF
173: : name;
174:
175: Object obj = getProject().getReference(loaderName);
176: if (reset) {
177: // Are any other references held ? Can we 'close' the loader
178: // so it removes the locks on jars ?
179: obj = null; // a new one will be created.
180: }
181:
182: // XXX maybe use reflection to addPathElement (other patterns ?)
183: if (obj != null && !(obj instanceof AntClassLoader)) {
184: log("Referenced object is not an AntClassLoader",
185: Project.MSG_ERR);
186: return;
187: }
188:
189: AntClassLoader acl = (AntClassLoader) obj;
190:
191: if (acl == null) {
192: // Construct a new class loader
193: Object parent = null;
194: if (parentName != null) {
195: parent = getProject().getReference(parentName);
196: if (!(parent instanceof ClassLoader)) {
197: parent = null;
198: }
199: }
200: // TODO: allow user to request the system or no parent
201: if (parent == null) {
202: parent = this .getClass().getClassLoader();
203: }
204:
205: if (name == null) {
206: // The core loader must be reverse
207: //reverse=true;
208: }
209: getProject().log(
210: "Setting parent loader " + name + " " + parent
211: + " " + parentFirst, Project.MSG_DEBUG);
212:
213: // The param is "parentFirst"
214: acl = new AntClassLoader((ClassLoader) parent,
215: getProject(), classpath, parentFirst);
216:
217: getProject().addReference(loaderName, acl);
218:
219: if (name == null) {
220: // This allows the core loader to load optional tasks
221: // without delegating
222: acl
223: .addLoaderPackageRoot("org.apache.tools.ant.taskdefs.optional");
224: getProject().setCoreLoader(acl);
225: }
226: }
227: if (classpath != null) {
228: String[] list = classpath.list();
229: for (int i = 0; i < list.length; i++) {
230: File f = new File(list[i]);
231: if (f.exists()) {
232: acl.addPathElement(f.getAbsolutePath());
233: log("Adding to class loader " + acl + " "
234: + f.getAbsolutePath(),
235: Project.MSG_DEBUG);
236: }
237: }
238: }
239:
240: // XXX add exceptions
241:
242: } catch (Exception ex) {
243: ex.printStackTrace();
244: }
245: }
246: }
|