View | Details | Raw Unified | Return to bug 28228
Collapse All | Expand All

(-)CONTRIBUTORS (+1 lines)
Lines 150-155 Link Here
150
Pierre Dittgen
150
Pierre Dittgen
151
Raphael Pierquin
151
Raphael Pierquin
152
R Handerson
152
R Handerson
153
Rainer Noack
153
Richard Evans
154
Richard Evans
154
Rick Beton
155
Rick Beton
155
Robert Anderson
156
Robert Anderson
(-)docs/manual/coretasklist.html (+1 lines)
Lines 26-31 Link Here
26
<a href="CoreTasks/pack.html">BZip2</a><br>
26
<a href="CoreTasks/pack.html">BZip2</a><br>
27
<a href="CoreTasks/checksum.html">Checksum</a><br>
27
<a href="CoreTasks/checksum.html">Checksum</a><br>
28
<a href="CoreTasks/chmod.html">Chmod</a><br>
28
<a href="CoreTasks/chmod.html">Chmod</a><br>
29
<a href="CoreTasks/classloader.html">Classloader</a><br>
29
<a href="CoreTasks/concat.html">Concat</a><br>
30
<a href="CoreTasks/concat.html">Concat</a><br>
30
<a href="CoreTasks/condition.html">Condition</a><br>
31
<a href="CoreTasks/condition.html">Condition</a><br>
31
&nbsp;&nbsp;<a href="CoreTasks/conditions.html">Supported conditions</a><br>
32
&nbsp;&nbsp;<a href="CoreTasks/conditions.html">Supported conditions</a><br>
(-)src/etc/testcases/taskdefs/classloader.xml (-14 / +110 lines)
Lines 1-23 Link Here
1
<project name="classloader-test" default="main" basedir=".">
1
<project name="classloader-test" default="test-system2prop" basedir=".">
2
2
3
  <target name="init">
3
  <target name="test.system2prop">
4
    <classloader loader="system" property="test.cl.system2prop" />
5
    <condition property="test.system2prop">
6
    	<isset property="test.cl.system2prop"/>
7
    </condition>
8
  </target>
9
  
10
  <target name="test.report">
11
    <classloader report="true"/>
12
  </target>
4
13
5
    <path id="myJars" >
14
  <target name="test.system2prop">
6
      <!-- both ant-junit.jar and junit.jar must be loaded from the same path -->
15
    <classloader loader="system" property="test.cl.system2prop" />
7
      <pathelement path="${ant.home}/lib/ant-junit.jar" />
16
    <condition property="test.system2prop">
8
      <pathelement path="${junit.jar}" />
17
    	<isset property="test.cl.system2prop"/>
9
    </path>
18
    </condition>
19
  </target>
10
20
11
    <classloader classpathRef="myJars" 
21
  <target name="test.createURL">
12
                 reverse="true" >
22
    <classloader loader="test.cl.createURL">
13
      
23
      <classpath>
24
         <urlpathelement location="http://my.domain/my.1st.jar"/>
25
         <urlpathelement path="http://my.domain/my.2nd.jar;http://my.domain/my.3rd.jar"/>
26
      </classpath>
14
    </classloader>
27
    </classloader>
15
    <junit />
28
    <classloader loader="test.cl.createURL" property="test.cl.createURL"/>
16
  
29
    <condition property="test.createURL">
30
    	<equals arg1="http://my.domain/my.1st.jar;http://my.domain/my.2nd.jar;http://my.domain/my.3rd.jar" 
31
    	        arg2="${test.cl.createURL}"/>
32
    </condition>
33
    
34
  </target>
35
36
  <target name="test.updateURL">
37
    <classloader loader="test.cl.updateURL">
38
      <classpath>
39
         <urlpathelement location="http://my.domain/my.1st.jar"/>
40
      </classpath>
41
    </classloader>
42
    <classloader loader="test.cl.updateURL" property="test.cl.updateURL">
43
      <classpath>
44
         <urlpathelement location="http://my.domain/my.2nd.jar"/>
45
      </classpath>
46
    </classloader>
47
    <condition property="test.updateURL">
48
    	<equals arg1="http://my.domain/my.1st.jar;http://my.domain/my.2nd.jar" 
49
    	        arg2="${test.cl.updateURL}"/>
50
    </condition>
51
    
52
  </target>
53
54
  <target name="test.createAnt">
55
    <classloader loader="test.cl.createAnt">
56
      <classpath>
57
         <pathelement location="classloader/path1"/>
58
      </classpath>
59
     <antparameters/>
60
    </classloader>
61
    <classloader loader="test.cl.createAnt" property="test.cl.createAnt"/>
62
    <condition property="test.createAnt">
63
    	<equals arg1="${basedir}${file.separator}classloader${file.separator}path1" 
64
    	        arg2="${test.cl.createAnt}"/>
65
    </condition>
66
  </target>
67
68
  <target name="test.updateAnt">
69
    <classloader loader="test.cl.updateAnt">
70
      <classpath>
71
         <pathelement location="classloader/path1"/>
72
      </classpath>
73
     <antparameters/>
74
    </classloader>
75
    <classloader loader="test.cl.updateAnt" property="test.cl.updateAnt">
76
      <classpath>
77
         <pathelement location="classloader/path2"/>
78
      </classpath>
79
    </classloader>
80
    <condition property="test.updateAnt">
81
    	<equals arg1="${basedir}${file.separator}classloader${file.separator}path1${path.separator}${basedir}${file.separator}classloader${file.separator}path2" 
82
    	        arg2="${test.cl.updateAnt}"/>
83
    </condition>
17
  </target>
84
  </target>
18
85
19
  <target name="main" depends="init">
86
  <target name="test.updateSystem">
20
    <echo message="Found JUNIT" />
87
    <condition property="test.updateSystem.previous">
88
        <not>
89
    		<available resource="classloadertest.properties"/>
90
        </not>
91
    </condition>
92
    <classloader loader="system">
93
      <classpath>
94
         <pathelement location="classloader/path1"/>
95
      </classpath>
96
     <antparameters/>
97
    </classloader>
98
    <condition property="test.updateSystem">
99
        <and>
100
	   	  <available resource="classloadertest.properties"/>
101
	   	  <equals arg1="${test.updateSystem.previous}" arg2="true"/>
102
	   	</and>
103
    </condition>
21
  </target>
104
  </target>
22
105
106
  <target name="test.types" description="just checks whether buildIn types are available">
107
    <loaderhandler id="test.types.handler" loader="dummyloader" adapter="dummyadapter"/>
108
    <loaderhandlerset id="test.types.handlerset"/>
109
    <loaderparameters id="test.types.loaderparameters"/>
110
    <antloaderparameters id="test.types.antloaderparameters"/>
111
    <loaderref id="test.types.loaderref" loader="project"/>
112
    <urlpath id="test.types.urlpath" location="http://ant.apache.org"/>
113
    <property name="test.types" value="true"/>
114
  </target>
115
116
  <!-- future use -->
117
  <target name="cleanup">
118
  </target>
23
</project>
119
</project>
(-)src/main/org/apache/tools/ant/taskdefs/Classloader.java (-144 / +793 lines)
Lines 17-49 Link Here
17
17
18
package org.apache.tools.ant.taskdefs;
18
package org.apache.tools.ant.taskdefs;
19
19
20
import java.io.PrintStream;
21
import java.net.URL;
22
import java.util.ArrayList;
23
import java.util.Arrays;
24
import java.util.HashMap;
25
import java.util.Map;
26
27
import org.apache.tools.ant.AntTypeDefinition;
28
import org.apache.tools.ant.ComponentHelper;
29
import org.apache.tools.ant.Location;
20
import org.apache.tools.ant.Project;
30
import org.apache.tools.ant.Project;
21
import org.apache.tools.ant.Task;
31
import org.apache.tools.ant.Task;
22
import org.apache.tools.ant.MagicNames;
23
import org.apache.tools.ant.BuildException;
32
import org.apache.tools.ant.BuildException;
24
import org.apache.tools.ant.AntClassLoader;
33
import org.apache.tools.ant.types.AntLoaderParameters;
34
import org.apache.tools.ant.types.LoaderParameters;
35
import org.apache.tools.ant.types.LoaderHandler;
36
import org.apache.tools.ant.types.LoaderHandlerSet;
37
import org.apache.tools.ant.types.LoaderRef;
25
import org.apache.tools.ant.types.Reference;
38
import org.apache.tools.ant.types.Reference;
26
import org.apache.tools.ant.types.Path;
39
import org.apache.tools.ant.types.URLPath;
27
40
28
import java.io.File;
41
import sun.misc.Launcher;
42
import sun.misc.URLClassPath;
29
43
30
/**
44
/**
31
 * EXPERIMENTAL
45
 * Create or modifies ClassLoader.
32
 * Create or modifies ClassLoader. The required pathRef parameter
33
 * will be used to add classpath elements.
34
 *
35
 * The classpath is a regular path. Currently only file components are
36
 * supported (future extensions may allow URLs).
37
 *
38
 * You can modify the core loader by not specifying any name or using
39
 * "ant.coreLoader". (the core loader is used to load system ant
40
 * tasks and for taskdefs that don't specify an explicit path).
41
 *
42
 * Taskdef and typedef can use the loader you create if the name follows
43
 * the "ant.loader.NAME" pattern. NAME will be used as a pathref when
44
 * calling taskdef.
45
 *
46
 *
46
 * This tasks will not modify the core loader if "build.sysclasspath=only"
47
 * The classpath is a regular path.
48
 *
49
 * Taskdef and typedef can use the loader you create with the loaderRef attribute.
50
 *
51
 * This tasks will not modify the core loader, the project loader
52
 * or the system loader if "build.sysclasspath=only"
47
 *
53
 *
48
 * The typical use is:
54
 * The typical use is:
49
 * <pre>
55
 * <pre>
Lines 53-222 Link Here
53
 *     &lt;/fileset&gt;
59
 *     &lt;/fileset&gt;
54
 *  &lt;/path&gt;
60
 *  &lt;/path&gt;
55
 *
61
 *
56
 *  &lt;classloader pathRef="ant.deps" /&gt;
62
 *  &lt;classloader loader="project" classpathRef="ant.deps" /&gt;
57
 *
63
 *
58
 * </pre>
64
 * </pre>
59
 *
65
 *
66
 * @since Ant 1.7
60
 */
67
 */
61
public class Classloader extends Task {
68
public class Classloader extends Task {
62
    /** @see MagicNames#SYSTEM_LOADER_REF */
69
    /**
63
    public static final String SYSTEM_LOADER_REF = MagicNames.SYSTEM_LOADER_REF;
70
     * Actions for ClassLoaderAdapter.
71
     */
72
    public static final class Action {
73
        private static final int IDCREATE = 1;
74
        private static final int IDAPPEND = 2;
75
        private static final int IDGETPATH = 3;
76
        private static final int IDREPORT = 4;
77
        /**
78
         * Append Path to an existing ClassLoader instance.
79
         */
80
        public static final Action APPEND = new Action(IDAPPEND);
81
        /**
82
         * Create a new ClassLoader instance.
83
         */
84
        public static final Action CREATE = new Action(IDCREATE);
85
        /**
86
         * Get the path of an existing ClassLoader instance.
87
         */
88
        public static final Action GETPATH = new Action(IDGETPATH);
89
        /**
90
         * Get additional Report information.
91
         */
92
        public static final Action REPORT = new Action(IDREPORT);
93
94
        private final int value;
95
        private Action(int value) {
96
            this.value = value;
97
        }
98
    }
99
    /**
100
     * ClassLoaderAdapter used to define classloader interaction.
101
     */
102
    public static interface ClassLoaderAdapter {
103
        /**
104
         * add classloader to the report queue.
105
         * the adapter should call task.addLoaderToReport to add a loader.
106
         * @param task the calling Classloader-task.
107
         * @param classloader the classloader to analyze.
108
         * @param name the name of the classloader instance.
109
         * @param loaderStack loaderStack to pass to Classloader.addLoaderToReport.
110
         * @param loaderNames loaderNames to pass to Classloader.addLoaderToReport.
111
         */
112
        void addReportable(
113
            Classloader task,
114
            ClassLoader classloader,
115
            String name,
116
            Map loaderStack,
117
            Map loaderNames);
118
        /**
119
         * Appends a classpath to an existing classloader instance.
120
         * @param task the calling Classloader-task.
121
         * @param classloader the classloader instance to append the path to.
122
         * @return The ClassLoader instance or null if an error occured.
123
         */
124
        boolean appendClasspath(Classloader task, ClassLoader classloader);
125
        /**
126
         * Creates a classloader instance.
127
         * @param task the calling Classloader-task.
128
         * @return the newly created ClassLoader instance or null if an error occured.
129
         */
130
        ClassLoader createClassLoader(Classloader task);
131
        /**
132
         * returns the actual classpath of a classloader instance.
133
         * @param task the calling Classloader-task.
134
         * @param classloader the classloader instance to get the path from.
135
         * @param defaultToFile if true, returned url-elements with file protocol
136
         *         should trim the leading 'file:/' prefix.
137
         * @return the path or null if an error occured
138
         */
139
        String[] getClasspath(
140
            Classloader task,
141
            ClassLoader classloader,
142
            boolean defaultToFile);
143
        /**
144
         * Checks whether the adapter supports an action.
145
         * @param action the action to check.
146
         * @return true, if action is supported.
147
         */
148
        boolean isSupported(Action action);
149
        /**
150
         * performs additional reporting.
151
         * @param to the Reporter Object to report to.
152
         * @param task the calling Classloader-task.
153
         * @param classloader the classloader instance to report about.
154
         * @param name the name of the classloader instance.
155
         */
156
        void report(
157
            Reporter to,
158
            Classloader task,
159
            ClassLoader classloader,
160
            String name);
161
    }
162
    /**
163
     * Mandatory Interface for ClassLoaderParameters.
164
     */
165
    public static interface ClassLoaderParameters {
166
        /**
167
         * returns the default handler for this descriptor.
168
         * @return handler.
169
         */
170
        LoaderHandler getDefaultHandler();
171
        /**
172
         * returns the valuable parameter object which is either the instance itself
173
         * or the resolved referenced parameters.
174
         * @return parameters.
175
         */
176
        ClassLoaderParameters getParameters();
177
    }
178
    /**
179
     * makes reporting destination transparent for reporting objects.
180
     */
181
    public static class Reporter {
182
        private PrintStream stream;
183
        private Classloader task;
184
        Reporter(Classloader task, PrintStream stream) {
185
            this.task = task;
186
            this.stream = stream;
187
        }
188
        /**
189
         * writes a message line to the reporting dest.
190
         * @param s the message line to report.
191
         */
192
        public void report(String s) {
193
            if (stream != null) {
194
                stream.println(s);
195
            } else {
196
                task.log(s, Project.MSG_INFO);
197
            }
198
        }
199
    }
64
200
65
    private String name = null;
201
    private URLPath classpath = null;
66
    private Path classpath;
202
    private ClassLoaderParameters parameters = null;
203
    private boolean failOnError;
204
    private LoaderHandler handler = null;
205
    private LoaderHandlerSet handlerSet = null;
206
    private LoaderRef loader = null;
207
    private String loaderName = null;
208
    private LoaderRef parentLoader = null;
209
    private String property = null;
210
    private boolean report = false;
211
    private boolean reportPackages = false;
67
    private boolean reset = false;
212
    private boolean reset = false;
68
    private boolean parentFirst = true;
213
    private LoaderRef superLoader = null;
69
    private String parentName = null;
70
71
    /**
214
    /**
72
     * Default constructor
215
     * Default constructor
73
     */
216
     */
74
    public Classloader() {
217
    public Classloader() {
75
    }
218
    }
76
219
    /**
77
    /** Name of the loader. If none, the default loader will be modified
220
     * Sets a nested Descriptor element for an AntClassLoader.
78
     *
221
     * @param desc the parameters.
79
     * @param name the name of this loader
80
     */
222
     */
81
    public void setName(String name) {
223
    public void addAntParameters(AntLoaderParameters desc) {
82
        this.name = name;
224
        parameters = desc;
83
    }
225
    }
84
85
    /**
226
    /**
86
     * Reset the classloader, if it already exists. A new loader will
227
     * sets a nested LoaderHandler element.
87
     * be created and all the references to the old one will be removed.
228
     * @param handler the loaderHandler.
88
     * (it is not possible to remove paths from a loader). The new
89
     * path will be used.
90
     *
91
     * @param b true if the loader is to be reset.
92
     */
229
     */
93
    public void setReset(boolean b) {
230
    public void addConfiguredHandler(LoaderHandler handler) {
94
        this.reset = b;
231
        handler.check();
232
        if (this.handler != null) {
233
            throw new BuildException("nested element handler can only specified once");
234
        }
235
        this.handler = handler;
95
    }
236
    }
96
237
    /**
97
    public void setReverse(boolean b) {
238
     * sets a nested LoaderHandler element.
98
        this.parentFirst = !b;
239
     * @param handler the loaderHandler.
240
     */
241
    public void setHandler(LoaderHandler handler) {
242
        handler.check();
243
        this.handler = handler;
244
    }
245
    /**
246
     * sets a nested ClassLoaderParameters element.
247
     * @param desc the parameters.
248
     */
249
    public void addParameters(LoaderParameters desc) {
250
        parameters = desc;
251
    }
252
    /**
253
     * sets a nested HandlerSet element.
254
     * @param handlerSet the handlerSet
255
     */
256
    public void addHandlerSet(LoaderHandlerSet handlerSet) {
257
        if (this.handlerSet != null) {
258
            throw new BuildException("nested element handlerSet may only specified once");
259
        }
260
        this.handlerSet = handlerSet;
261
    }
262
    /**
263
     * sets a HandlerSet ref.
264
     * @param handlerSet the handlerSet
265
     */
266
    public void setHandlerSet(LoaderHandlerSet handlerSet) {
267
        this.handlerSet = handlerSet;
99
    }
268
    }
269
    /**
270
     * sets a nested loader element.
271
     * @param x the loader definition.
272
     */
273
    public void addLoader(LoaderRef x) {
274
        if (x.isStandardLoader(LoaderRef.LoaderSpec.NONE)) {
275
            throw new BuildException("nested element loader can not be 'none'");
276
        }
277
        this.loader = x;
278
    }
279
    /**
280
     * Callback method for ClassLoaderAdapters to add classloaders
281
     * to the list of loaders to report.
282
     * @param cl the classloader instance to add.
283
     * @param name the name of the classloader instance.
284
     * @param loaderStack a list of loader names by instance.
285
     * @param loaderNames a list of loader instances by name.
286
     * @return true, if successfully executed, false otherwise.
287
     */
288
    public boolean addLoaderToReport(
289
        ClassLoader cl,
290
        String name,
291
        Map loaderStack,
292
        Map loaderNames) {
293
        if (cl == null) {
294
            Object old = loaderNames.put(name, null);
295
            if (old != null) {
296
                throw new BuildException("duplicate classloader name " + name);
297
            }
298
        } else {
299
            Object old = loaderNames.put(name, cl);
300
            if (old != null) {
301
                throw new BuildException("duplicate classloader name " + name);
302
            }
303
            old = loaderStack.get(cl);
304
            boolean isNew = (old == null);
305
            if (old == null) {
306
                old = new ArrayList();
307
                loaderStack.put(cl, old);
308
            }
309
            ((ArrayList) old).add(name);
100
310
101
    public void setParentFirst(boolean b) {
311
            if (isNew) {
102
        this.parentFirst = b;
312
                addLoaderToReport(
313
                    cl.getParent(),
314
                    name + "->parent",
315
                    loaderStack,
316
                    loaderNames);
317
318
                LoaderHandlerSet handlerSet = getHandlerSet();
319
                if (handlerSet == null) {
320
                    return false;
321
                }
322
                LoaderHandler handler =
323
                    handlerSet.getHandler(this, cl, Action.REPORT);
324
                if (handler == null) {
325
                    return false;
326
                }
327
                ClassLoaderAdapter adapter = handler.getAdapter(this);
328
                if (adapter == null) {
329
                    return false;
330
                }
331
                adapter.addReportable(this, cl, name, loaderStack, loaderNames);
332
            }
333
        }
334
        return true;
335
    }
336
    /**
337
     * sets the nested parentLoader element.
338
     * @param x the parentLoader
339
     */
340
    public void addParentLoader(LoaderRef x) {
341
        this.parentLoader = x;
103
    }
342
    }
343
    /**
344
     * sets the nested superLoader element.
345
     * @param x the superLoader.
346
     */
347
    public void addSuperLoader(LoaderRef x) {
348
        this.parentLoader = x;
349
    }
350
    /**
351
     * creates a nested classpath element.
352
     * @return the classpath.
353
     */
354
    public URLPath createClasspath() {
355
        if (this.classpath == null) {
356
            this.classpath = new URLPath(getProject());
357
        }
358
        return this.classpath.createUrlpath();
359
    }
360
    /**
361
     * executes this task.
362
     */
363
    public void execute() {
364
        if (report) {
365
            executeReport();
366
            return;
367
        }
368
        if (loader == null) {
369
            throw new BuildException("no loader specified");
370
        }
371
        if (!executeCreateModify()) {
372
            return;
373
        }
374
        if (property != null) {
375
            this.executeProperty();
376
        }
377
    }
378
    private boolean executeCreateModify() {
379
        URLPath cp = getClasspath();
380
        ClassLoader cl = null;
381
        // Are any other references held ? Can we 'close' the loader
382
        // so it removes the locks on jars ?
383
        // Can we replace the system classloader by just changing the
384
        // referenced object?
385
        // however, is reset really useful?
386
        if (!reset) {
387
            cl = loader.getClassLoader(null, false, true);
388
        }
389
390
        boolean create = (cl == null);
391
        boolean modify = ((cl != null) && (cp != null));
392
        if (!(create || modify)) {
393
            return true;
394
        }
104
395
105
    // TODO: add exceptions for delegation or reverse
396
        // Gump friendly - don't mess with the core loader if only classpath
397
        if ("only".equals(getProject().getProperty("build.sysclasspath"))
398
         && loader.equalsSysLoader()) {
399
            log("Changing " + loader.getName() + " is disabled "
400
                    + "by build.sysclasspath=only",
401
                Project.MSG_WARN);
402
            return true;
403
        }
106
404
107
    // TODO
405
        if (reset && !loader.isResetPossible()) {
108
    public void setParentName(String name) {
406
            this.handleError("reseting " + loader.getName() + " is not possible");
109
        this.parentName = name;
407
            return false;
408
        }
409
        if (create && !loader.isResetPossible()) {
410
            this.handleError("creating " + loader.getName() + " is not possible");
411
            return false;
412
        }
413
        log(
414
            "handling "
415
                + this.getLoaderName()
416
                + ": "
417
                + ((cl == null) ? "not " : "")
418
                + "found, cp="
419
                + this.getClasspath(),
420
            Project.MSG_DEBUG);
421
        LoaderHandlerSet handlerSet = null;
422
        if (cl == null) {
423
            LoaderHandler handler = getHandler();
424
            if (handler == null) {
425
                throw new BuildException("internal error: handler is null");
426
            }
427
            ClassLoaderAdapter adapter = handler.getAdapter(this);
428
            if (adapter == null) {
429
                return false;
430
            }
431
            cl = adapter.createClassLoader(this);
432
            if (cl == null) {
433
                return false;
434
            }
435
            loader.setClassLoader(cl);
436
        } else if (cp != null) {
437
            handlerSet = getHandlerSet();
438
            if (handlerSet == null) {
439
                throw new BuildException("internal error: handlerset is null");
440
            }
441
            LoaderHandler handler =
442
                handlerSet.getHandler(this, cl, Action.APPEND);
443
            if (handler == null) {
444
                log("NO HANDLER", Project.MSG_DEBUG);
445
                return false;
446
            }
447
            ClassLoaderAdapter adapter = handler.getAdapter(this);
448
            if (adapter == null) {
449
                log("NO ADAPTER", Project.MSG_DEBUG);
450
                return false;
451
            }
452
            if (!adapter.appendClasspath(this, cl)) {
453
                log("NO APPEND", Project.MSG_DEBUG);
454
                return false;
455
            }
456
        }
457
        return true;
458
    }
459
    private boolean executeProperty() {
460
        ClassLoader cl = loader.getClassLoader(null);
461
        LoaderHandlerSet handlerSet = getHandlerSet();
462
        if (handlerSet == null) {
463
            throw new BuildException("internal error: handlerset is null");
464
        }
465
        LoaderHandler handler =
466
            handlerSet.getHandler(this, cl, Action.GETPATH);
467
        if (handler == null) {
468
            return false;
469
        }
470
        ClassLoaderAdapter adapter = handler.getAdapter(this);
471
        if (adapter == null) {
472
            return false;
473
        }
474
        String[] propPath = adapter.getClasspath(this, cl, true);
475
        if (propPath == null) {
476
            return false;
477
        }
478
        StringBuffer propValue = new StringBuffer();
479
        if (propPath.length > 0) {
480
            propValue.append(propPath[0]);
481
        }
482
        for (int i = 1; i < propPath.length; i++) {
483
            propValue.append(';').append(propPath[i]);
484
        }
485
        getProject().setProperty(property, propValue.toString());
486
        return true;
110
    }
487
    }
488
    private String formatIndex(int i) {
489
        String x = String.valueOf(i + 1);
490
        if (x.length() == 1) {
491
            return " " + x;
492
        }
493
        return x;
494
    }
495
    /**
496
     * gets the classpath to add to a classloader.
497
     * @return the classpath.
498
     */
499
    public URLPath getClasspath() {
500
        return classpath;
501
    }
502
    /**
503
     * gets the parameters for a newly created classloader.
504
     * @return the parameters
505
     */
506
    public ClassLoaderParameters getParameters() {
507
        if (parameters == null) {
508
            parameters = new LoaderParameters(getProject());
509
        }
510
        return parameters;
511
    }
512
    /**
513
     * gets the handler to create a new classloader.
514
     * @return the handler
515
     */
516
    public LoaderHandler getHandler() {
517
        if (handler == null) {
518
            handler = getParameters().getDefaultHandler();
519
        }
520
        return handler;
521
    }
522
    /**
523
     * gets the handlerset to analyze a given classloader with.
524
     * @return the handlerset.
525
     */
526
    public LoaderHandlerSet getHandlerSet() {
527
        if (handlerSet == null) {
528
            handlerSet = new LoaderHandlerSet(getProject());
529
            handlerSet.addConfiguredHandler(getHandler());
530
        }
531
        return handlerSet;
532
    }
533
    /**
534
     * gets the name of the described classloader for logging and report purposes.
535
     * @return the name.
536
     */
537
    public String getLoaderName() {
538
        if (loaderName == null) {
539
            loaderName = loader.getName();
540
        }
541
        return loaderName;
542
    }
543
    /**
544
     * gets the parent ClassLoader as defined via the parentLoader attribute.
545
     * @return parent ClassLoader or null if not defined.
546
     */
547
    public ClassLoader getParentLoader() {
548
        if (parentLoader == null) {
549
            return null;
550
        }
551
        return parentLoader.getClassLoader(null, failOnError, false);
552
    }
553
    /**
554
     * gets the super classloader to create a new classloader with.
555
     * @return the super loader.
556
     */
557
    public ClassLoader getSuperLoader() {
558
        if (superLoader == null) {
559
            return getClass().getClassLoader();
560
        }
561
        return superLoader.getClassLoader(null, failOnError, false);
562
    }
563
    /**
564
     * indicates whether packages should been reported
565
     * @return true, if packages should been reported, else false.
566
     */
567
    public boolean isReportPackages() {
568
        return reportPackages;
569
    }
570
    /**
571
     * handles an error with respect to the failonerror attribute.
572
     * @param msg error message.
573
     */
574
    public void handleError(String msg) {
575
        handleError(msg, null, null);
576
    }
577
    /**
578
     * handles an error with respect to the failonerror attribute.
579
     * @param msg error message.
580
     * @param ex causing exception.
581
     */
582
    public void handleError(String msg, Throwable ex) {
583
        handleError(msg, ex, null);
584
    }
585
    /**
586
     * handles an error with respect to the failonerror attribute.
587
     * @param msg error message.
588
     * @param ex causing exception.
589
     * @param loc loaction.
590
     */
591
    public void handleError(String msg, Throwable ex, Location loc) {
592
        if (loc == null) {
593
            loc = this.getLocation();
594
        }
595
        if ((msg == null) && (ex != null)) {
596
            msg = ex.getMessage();
597
        }
598
        if (failOnError) {
599
            throw new BuildException(msg, ex, loc);
600
        } else {
601
            log(loc + "Error: " + msg, Project.MSG_ERR);
602
        }
603
    }
604
    /**
605
     * handle the report.
606
     */
607
    protected void executeReport() {
608
        //let's hope, that no classloader implementation overrides
609
        // equals/hashCode
610
        //for 1.4 IdentityHashMap should be used for loaderStack
611
        HashMap loaderStack = new HashMap();
612
        HashMap loaderNames = new HashMap();
613
        boolean addSuccess = true;
614
        if (!addLoaderToReport(
615
            ClassLoader.getSystemClassLoader(),
616
            "1-SystemClassLoader",
617
            loaderStack,
618
            loaderNames)) {
619
            addSuccess = false;
620
        }
621
        if (!addLoaderToReport(
622
            getProject().getClass().getClassLoader(),
623
            "2-ProjectClassLoader",
624
            loaderStack,
625
            loaderNames)) {
626
            addSuccess = false;
627
        }
628
        if (!addLoaderToReport(
629
            getClass().getClassLoader(),
630
            "3-CurrentClassLoader",
631
            loaderStack,
632
            loaderNames)) {
633
            addSuccess = false;
634
        }
635
        if (!addLoaderToReport(
636
            Thread.currentThread().getContextClassLoader(),
637
            "4-ThreadContextClassLoader",
638
            loaderStack,
639
            loaderNames)) {
640
            addSuccess = false;
641
        }
642
        if (!addLoaderToReport(
643
            getProject().getCoreLoader(),
644
            "5-CoreLoader",
645
            loaderStack,
646
            loaderNames)) {
647
            addSuccess = false;
648
        }
649
        String[] rNames =
650
            (String[]) getProject().getReferences().keySet().toArray(
651
                new String[getProject().getReferences().size()]);
652
        Arrays.sort(rNames);
653
        for (int i = 0; i < rNames.length; i++) {
654
            Object val = getProject().getReference(rNames[i]);
655
            if (val instanceof ClassLoader) {
656
                if (!addLoaderToReport(
657
                    (ClassLoader) val,
658
                    "6-id=" + rNames[i],
659
                    loaderStack,
660
                    loaderNames)) {
661
                    addSuccess = false;
662
                }
663
            }
664
        }
665
        ComponentHelper ch = ComponentHelper.getComponentHelper(getProject());
666
        Map types = ch.getAntTypeTable();
667
        rNames = (String[]) types.keySet().toArray(new String[types.size()]);
668
        Arrays.sort(rNames);
669
        for (int i = 0; i < rNames.length; i++) {
670
            AntTypeDefinition val = ch.getDefinition(rNames[i]);
671
            if (val.getClassLoader() != null) {
672
                if (!addLoaderToReport(
673
                    val.getClassLoader(),
674
                    "7-def=" + rNames[i],
675
                    loaderStack,
676
                    loaderNames)) {
677
                    addSuccess = false;
678
                }
679
            }
680
        }
681
        rNames = null;
682
        String[] names =
683
            (String[]) loaderNames.keySet().toArray(
684
                new String[loaderNames.size()]);
685
        Arrays.sort(names);
686
        for (int i = names.length - 1; i >= 0; i--) {
687
            Object cl = loaderNames.get(names[i]);
688
            if (cl != null) {
689
                loaderStack.put(cl, names[i]);
690
            }
691
        }
692
        //fileoutput and xml-format to be implemented.
693
        Reporter to = new Reporter(this, null);
111
694
695
        to.report("---------- ClassLoader Report ----------");
696
        if (!addSuccess) {
697
            to.report("WARNING: As of missing Loaderhandlers, this report might not be complete.");
698
        }
699
        URLClassPath bscp = Launcher.getBootstrapClassPath();
700
        URL[] urls = bscp.getURLs();
701
        to.report(" ");
702
        to.report(" 0. bootstrap classpath: " + urls.length + " elements");
703
        for (int i = 0; i < urls.length; i++) {
704
            to.report("         > " + urls[i]);
705
        }
112
706
113
    /** Specify which path will be used. If the loader already exists
707
        for (int i = 0; i < names.length; i++) {
114
     *  and is an AntClassLoader (or any other loader we can extend),
708
            to.report(" ");
115
     *  the path will be added to the loader.
709
            ClassLoader cl = (ClassLoader) loaderNames.get(names[i]);
710
            if (cl == null) {
711
                to.report(
712
                    formatIndex(i)
713
                        + ". "
714
                        + names[i].substring(2)
715
                        + " is not assigned.");
716
            } else {
717
                Object n = loaderStack.get(cl);
718
                if (names[i].equals(n)) {
719
                    to.report(formatIndex(i) + ". " + names[i].substring(2));
720
                    report(to, cl, names[i].substring(2));
721
                } else {
722
                    to.report(
723
                        formatIndex(i)
724
                            + ". "
725
                            + names[i].substring(2)
726
                            + " = "
727
                            + ((String) n).substring(2)
728
                            + ". (See above.)");
729
                }
730
            }
731
        }
732
        to.report("---------- End Of ClassLoader Report ----------");
733
    }
734
    /**
735
     * handle the report for a single classloader
736
     * @param to Reporter to report
737
     * @param cl Classloader instance to report
738
     * @param name name of the classloader instance.
116
     */
739
     */
117
    public void setClasspathRef(Reference pathRef) throws BuildException {
740
    public void report(Reporter to, ClassLoader cl, String name) {
118
        classpath = (Path) pathRef.getReferencedObject(getProject());
741
        to.report("    class: " + cl.getClass().getName());
742
        LoaderHandlerSet handlerSet = getHandlerSet();
743
        if (handlerSet == null) {
744
            throw new BuildException("internal error: handlerset is null");
745
        }
746
        LoaderHandler handler = handlerSet.getHandler(this, cl, Action.GETPATH);
747
        ClassLoaderAdapter adapter;
748
        if (handler == null) {
749
            to.report("    path:  - not investigatable (no Loaderhandler found) -");
750
        } else {
751
            adapter = handler.getAdapter(this);
752
            if (adapter == null) {
753
                to.report("    path:  - not investigatable (Loaderhandler retrieves no adapter) -");
754
            } else {
755
                String[] cp = adapter.getClasspath(this, cl, false);
756
                if (cp == null) {
757
                    to.report("    path:  - not investigatable (adapter retrieves no path) -");
758
                } else {
759
                    to.report("    path:  " + cp.length + " elements");
760
                    for (int i = 0; i < cp.length; i++) {
761
                        to.report("         > " + cp[i]);
762
                    }
763
                }
764
            }
765
        }
766
        handler = handlerSet.getHandler(this, cl, Action.REPORT);
767
        if (handler == null) {
768
            to.report("    - additional parameters not investigatable (no Loaderhandler found) -");
769
            return;
770
        }
771
        adapter = handler.getAdapter(this);
772
        if (adapter == null) {
773
            to.report("    - additional parameters not investigatable "
774
                    + "(Loaderhandler retrieves no adapter) -");
775
            return;
776
        }
777
        adapter.report(to, this, cl, name);
119
    }
778
    }
120
779
121
    /**
780
    /**
122
     * Set the classpath to be used when searching for component being defined
781
     * Specify which path will be used. If the loader already exists
123
     *
782
     *  the path will be added to the loader.
124
     * @param classpath an Ant Path object containing the classpath.
783
     * @param classpath an Ant Path object containing the classpath.
125
     */
784
     */
126
    public void setClasspath(Path classpath) {
785
    public void setClasspath(URLPath classpath) {
127
        if (this.classpath == null) {
786
        if (this.classpath == null) {
128
            this.classpath = classpath;
787
            this.classpath = classpath;
129
        } else {
788
        } else {
130
            this.classpath.append(classpath);
789
            this.classpath.append(classpath);
131
        }
790
        }
132
    }
791
    }
133
792
    /**
134
    public Path createClasspath() {
793
     * Specify which path will be used. If the loader already exists
135
        if (this.classpath == null) {
794
     *  the path will be added to the loader.
136
            this.classpath = new Path(null);
795
     * @param pathRef reference to a path defined elsewhere
796
     */
797
    public void setClasspathRef(Reference pathRef) {
798
        createClasspath().addReference(pathRef);
799
    }
800
    /**
801
     * sets the failonerror attribute
802
     * @param onOff value
803
     */
804
    public void setFailonerror(boolean onOff) {
805
        this.failOnError = onOff;
806
    }
807
    /**
808
     * sets the loader attribute
809
     * @param x the loader
810
     */
811
    public void setLoader(LoaderRef x) {
812
        if (x.isStandardLoader(LoaderRef.LoaderSpec.NONE)) {
813
            throw new BuildException("attribute loader can not be 'none'");
137
        }
814
        }
138
        return this.classpath.createPath();
815
        this.loader = x;
816
    }
817
    /**
818
     * sets the parameters attribute.
819
     * @param desc the parameters.
820
     */
821
    public void setParameters(LoaderParameters desc) {
822
        parameters = desc;
823
    }
824
    /**
825
     * sets the parentLoader attribute
826
     * @param x the parent loader
827
     */
828
    public void setParentLoader(LoaderRef x) {
829
        this.parentLoader = x;
830
    }
831
    /**
832
     * sets the property to put the ClassLoaders path into.
833
     * @param property name of the property.
834
     */
835
    public void setProperty(String property) {
836
        this.property = property;
837
    }
838
    /**
839
     * sets the report attribute.
840
     * @param onOff indicates whether to generate a report or not. defaults to false.
841
     */
842
    public void setReport(boolean onOff) {
843
        report = onOff;
844
    }
845
    /**
846
     * sets the reportPackages attribute.
847
     * @param onOff indicates whether to generate a report or not. defaults to false.
848
     */
849
    public void setReportpackages(boolean onOff) {
850
        reportPackages = onOff;
139
    }
851
    }
140
852
141
853
    /**
142
    public void execute() {
854
     * Reset the classloader, if it already exists. A new loader will
143
        try {
855
     * be created and all the references to the old one will be removed.
144
            // Gump friendly - don't mess with the core loader if only classpath
856
     * (it is not possible to remove paths from a loader). The new
145
            if ("only".equals(getProject().getProperty("build.sysclasspath"))
857
     * path will be used.
146
                && (name == null || SYSTEM_LOADER_REF.equals(name))) {
858
     *
147
                log("Changing the system loader is disabled "
859
     * @param b true if the loader is to be reset.
148
                    + "by build.sysclasspath=only", Project.MSG_WARN);
860
     */
149
                return;
861
    public void setReset(boolean b) {
150
            }
862
        this.reset = b;
151
863
    }
152
            String loaderName = (name == null) ? SYSTEM_LOADER_REF : name;
864
    /**
153
865
     * sets the superLoader attribute.
154
            Object obj = getProject().getReference(loaderName);
866
     * @param x the superLoader.
155
            if (reset) {
867
     */
156
                // Are any other references held ? Can we 'close' the loader
868
    public void setSuperLoader(LoaderRef x) {
157
                // so it removes the locks on jars ?
869
        this.parentLoader = x;
158
                obj = null; // a new one will be created.
159
            }
160
161
            // XXX maybe use reflection to addPathElement (other patterns ?)
162
            if (obj != null && !(obj instanceof AntClassLoader)) {
163
                log("Referenced object is not an AntClassLoader",
164
                        Project.MSG_ERR);
165
                return;
166
            }
167
168
            AntClassLoader acl = (AntClassLoader) obj;
169
170
            if (acl == null) {
171
                // Construct a new class loader
172
                Object parent = null;
173
                if (parentName != null) {
174
                    parent = getProject().getReference(parentName);
175
                    if (!(parent instanceof ClassLoader)) {
176
                        parent = null;
177
                    }
178
                }
179
                // TODO: allow user to request the system or no parent
180
                if (parent == null) {
181
                    parent = this.getClass().getClassLoader();
182
                }
183
184
                if (name == null) {
185
                    // The core loader must be reverse
186
                    //reverse=true;
187
                }
188
                getProject().log("Setting parent loader " + name + " "
189
                    + parent + " " + parentFirst, Project.MSG_DEBUG);
190
191
                // The param is "parentFirst"
192
                acl = new AntClassLoader((ClassLoader) parent,
193
                         getProject(), classpath, parentFirst);
194
195
                getProject().addReference(loaderName, acl);
196
197
                if (name == null) {
198
                    // This allows the core loader to load optional tasks
199
                    // without delegating
200
                    acl.addLoaderPackageRoot("org.apache.tools.ant.taskdefs.optional");
201
                    getProject().setCoreLoader(acl);
202
                }
203
            }
204
            if (classpath != null) {
205
                String[] list = classpath.list();
206
                for (int i = 0; i < list.length; i++) {
207
                    File f = new File(list[i]);
208
                    if (f.exists()) {
209
                        acl.addPathElement(f.getAbsolutePath());
210
                        log("Adding to class loader " +  acl + " " + f.getAbsolutePath(),
211
                                Project.MSG_DEBUG);
212
                    }
213
                }
214
            }
215
216
            // XXX add exceptions
217
218
        } catch (Exception ex) {
219
            ex.printStackTrace();
220
        }
221
    }
870
    }
222
}
871
}
(-)src/main/org/apache/tools/ant/types/defaults.properties (+6 lines)
Lines 32-34 Link Here
32
propertyset=org.apache.tools.ant.types.PropertySet
32
propertyset=org.apache.tools.ant.types.PropertySet
33
assertions=org.apache.tools.ant.types.Assertions
33
assertions=org.apache.tools.ant.types.Assertions
34
concatfilter=org.apache.tools.ant.filters.ConcatFilter
34
concatfilter=org.apache.tools.ant.filters.ConcatFilter
35
loaderhandler=org.apache.tools.ant.types.LoaderHandler
36
loaderhandlerset=org.apache.tools.ant.types.LoaderHandlerSet
37
loaderparameters=org.apache.tools.ant.types.LoaderParameters
38
antloaderparameters=org.apache.tools.ant.types.AntLoaderParameters
39
loaderref=org.apache.tools.ant.types.LoaderRef
40
urlpath=org.apache.tools.ant.types.URLPath

Return to bug 28228