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 |
* </fileset> |
59 |
* </fileset> |
54 |
* </path> |
60 |
* </path> |
55 |
* |
61 |
* |
56 |
* <classloader pathRef="ant.deps" /> |
62 |
* <classloader loader="project" classpathRef="ant.deps" /> |
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 |
} |