KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > module > bridge > AntBridge


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.apache.tools.ant.module.bridge;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.io.File JavaDoc;
25 import java.io.FilenameFilter JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.io.PrintStream JavaDoc;
29 import java.lang.ref.Reference JavaDoc;
30 import java.lang.ref.SoftReference JavaDoc;
31 import java.lang.reflect.Method JavaDoc;
32 import java.net.URL JavaDoc;
33 import java.net.URLClassLoader JavaDoc;
34 import java.security.AllPermission JavaDoc;
35 import java.security.CodeSource JavaDoc;
36 import java.security.PermissionCollection JavaDoc;
37 import java.security.Permissions JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.Arrays JavaDoc;
40 import java.util.Collection JavaDoc;
41 import java.util.Collections JavaDoc;
42 import java.util.Enumeration JavaDoc;
43 import java.util.HashMap JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.LinkedHashSet JavaDoc;
46 import java.util.List JavaDoc;
47 import java.util.Locale JavaDoc;
48 import java.util.Map JavaDoc;
49 import javax.swing.event.ChangeEvent JavaDoc;
50 import javax.swing.event.ChangeListener JavaDoc;
51 import org.apache.tools.ant.module.AntSettings;
52 import org.openide.ErrorManager;
53 import org.openide.modules.InstalledFileLocator;
54 import org.openide.modules.ModuleInfo;
55 import org.openide.util.Lookup;
56 import org.openide.util.LookupEvent;
57 import org.openide.util.LookupListener;
58 import org.openide.util.io.NullOutputStream;
59 import org.openide.xml.XMLUtil;
60 import org.w3c.dom.Document JavaDoc;
61 import org.w3c.dom.Element JavaDoc;
62 import org.w3c.dom.Node JavaDoc;
63 import org.w3c.dom.NodeList JavaDoc;
64 import org.xml.sax.InputSource JavaDoc;
65 import org.xml.sax.SAXException JavaDoc;
66
67 /**
68  * Utility class providing entry points to the bridging functionality.
69  * @author Jesse Glick
70  */

71 public final class AntBridge {
72     
73     private static final ErrorManager err = ErrorManager.getDefault().getInstance(AntBridge.class.getName());
74     
75     private AntBridge() {}
76
77     private static final class AntInstance {
78         public final String JavaDoc mainClassPath;
79         public final ClassLoader JavaDoc mainClassLoader;
80         public final ClassLoader JavaDoc bridgeClassLoader;
81         public final BridgeInterface bridge;
82         public final Map JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>> customDefs;
83         public final Map JavaDoc<String JavaDoc,ClassLoader JavaDoc> customDefClassLoaders;
84         public AntInstance(String JavaDoc mainClassPath, ClassLoader JavaDoc mainClassLoader,
85                 ClassLoader JavaDoc bridgeClassLoader, BridgeInterface bridge,
86                 Map JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>> customDefs,
87                 Map JavaDoc<String JavaDoc,ClassLoader JavaDoc> customDefClassLoaders) {
88             this.mainClassPath = mainClassPath;
89             this.mainClassLoader = mainClassLoader;
90             this.bridgeClassLoader = bridgeClassLoader;
91             this.bridge = bridge;
92             this.customDefs = customDefs;
93             this.customDefClassLoaders = customDefClassLoaders;
94         }
95     }
96     private static Reference JavaDoc<AntInstance> antInstance = null;
97     
98     private static List JavaDoc<ChangeListener JavaDoc> listeners = new ArrayList JavaDoc<ChangeListener JavaDoc>();
99     
100     private static final class MiscListener implements PropertyChangeListener JavaDoc, LookupListener {
101         MiscListener() {}
102         private ModuleInfo[] modules = null;
103         public void propertyChange(PropertyChangeEvent JavaDoc ev) {
104             String JavaDoc prop = ev.getPropertyName();
105             if (AntSettings.PROP_ANT_HOME.equals(prop) ||
106                     AntSettings.PROP_EXTRA_CLASSPATH.equals(prop) ||
107                     AntSettings.PROP_AUTOMATIC_EXTRA_CLASSPATH.equals(prop)) {
108                 err.log("AntBridge got settings change in " + prop);
109                 fireChange();
110             } else if (ModuleInfo.PROP_ENABLED.equals(prop)) {
111                 err.log("AntBridge got module enablement change on " + ev.getSource());
112                 fireChange();
113             }
114         }
115         public void resultChanged(LookupEvent ev) {
116             err.log("AntModule got ModuleInfo change");
117             synchronized (this) {
118                 if (modules != null) {
119                     for (ModuleInfo module : modules) {
120                         module.removePropertyChangeListener(this);
121                     }
122                     modules = null;
123                 }
124             }
125             fireChange();
126         }
127         public synchronized ModuleInfo[] getEnabledModules() {
128             if (modules == null) {
129                 Collection JavaDoc<? extends ModuleInfo> c = modulesResult.allInstances();
130                 modules = c.toArray(new ModuleInfo[c.size()]);
131                 for (ModuleInfo module : modules) {
132                     module.addPropertyChangeListener(this);
133                 }
134             }
135             List JavaDoc<ModuleInfo> enabledModules = new ArrayList JavaDoc<ModuleInfo>(modules.length);
136             for (ModuleInfo module : modules) {
137                 if (module.isEnabled()) {
138                     enabledModules.add(module);
139                 }
140             }
141             return enabledModules.toArray(new ModuleInfo[enabledModules.size()]);
142         }
143     }
144     private static MiscListener miscListener = new MiscListener();
145     private static Lookup.Result<ModuleInfo> modulesResult = Lookup.getDefault().lookupResult(ModuleInfo.class);
146     static {
147         AntSettings.addPropertyChangeListener(miscListener);
148         modulesResult.addLookupListener(miscListener);
149     }
150     
151     /**
152      * Listen for changes in the contents of the bridge, as e.g. after changing the
153      * location of the installed copy of Ant.
154      */

155     public static synchronized void addChangeListener(ChangeListener JavaDoc l) {
156         listeners.add(l);
157     }
158     
159     /**
160      * Stop listening for changes in the contents of the bridge.
161      */

162     public static synchronized void removeChangeListener(ChangeListener JavaDoc l) {
163         listeners.remove(l);
164     }
165     
166     private static void fireChange() {
167         antInstance = null;
168         ChangeEvent JavaDoc ev = new ChangeEvent JavaDoc(AntBridge.class);
169         ChangeListener JavaDoc[] ls;
170         synchronized (AntBridge.class) {
171             ls = listeners.toArray(new ChangeListener JavaDoc[listeners.size()]);
172         }
173         for (ChangeListener JavaDoc l : ls) {
174             l.stateChanged(ev);
175         }
176     }
177     
178     /**
179      * Get the loader responsible for loading Ant together with any
180      * user-defined classpath.
181      */

182     public static ClassLoader JavaDoc getMainClassLoader() {
183         return getAntInstance().mainClassLoader;
184     }
185     
186     /**
187      * Get any custom task/type definitions stored in $nbhome/ant/nblib/*.jar.
188      * Some of the classes might not be fully resolvable, so beware.
189      * The names will include namespace prefixes.
190      * <p>
191      * Only minimal antlib syntax is currently interpreted here:
192      * only <code>&lt;taskdef&gt;</code> and <code>&lt;typedef&gt;</code>,
193      * and only the <code>name</code> and <code>classname</code> attributes.
194      */

195     public static Map JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>> getCustomDefsWithNamespace() {
196         return getAntInstance().customDefs;
197     }
198     
199     /**
200      * Same as {@link #getCustomDefsWithNamespace} but without any namespace prefixes.
201      */

202     public static Map JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>> getCustomDefsNoNamespace() {
203         Map JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>> m = new HashMap JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>>();
204         for (Map.Entry JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>> entry : getCustomDefsWithNamespace().entrySet()) {
205             String JavaDoc type = entry.getKey();
206             Map JavaDoc<String JavaDoc,Class JavaDoc> defs = entry.getValue();
207             Map JavaDoc<String JavaDoc,Class JavaDoc> m2 = new HashMap JavaDoc<String JavaDoc,Class JavaDoc>();
208             for (Map.Entry JavaDoc<String JavaDoc,Class JavaDoc> entry2 : defs.entrySet()) {
209                 String JavaDoc fqn = entry2.getKey();
210                 Class JavaDoc clazz = entry2.getValue();
211                 String JavaDoc name;
212                 int idx = fqn.lastIndexOf(':');
213                 if (idx != -1) {
214                     name = fqn.substring(idx + 1);
215                 } else {
216                     name = fqn;
217                 }
218                 m2.put(name, clazz);
219             }
220             m.put(type, m2);
221         }
222         return m;
223     }
224     
225     /**
226      * Get a map from enabled module code name bases to class loaders containing
227      * JARs from ant/nblib/*.jar.
228      */

229     // XXX does not have to be here, used only by BridgeImpl
230
public static Map JavaDoc<String JavaDoc,ClassLoader JavaDoc> getCustomDefClassLoaders() throws IOException JavaDoc {
231         return getAntInstance().customDefClassLoaders;
232     }
233     
234     /**
235      * Get the bridge interface.
236      */

237     public static BridgeInterface getInterface() {
238         return getAntInstance().bridge;
239     }
240     
241     private synchronized static AntInstance getAntInstance() {
242         AntInstance ai;
243         if (antInstance != null) {
244             ai = antInstance.get();
245         } else {
246             ai = null;
247         }
248         if (ai == null) {
249             ai = createAntInstance();
250             // XXX would be more accurate to stuff this struct into by BridgeImpl
251
// so that it all lives or dies iff that class loader is still alive
252
// (current impl is just workaround for JDK #6389107)
253
antInstance = new SoftReference JavaDoc<AntInstance>(ai);
254         }
255         return ai;
256     }
257     
258     private static AntInstance createAntInstance() {
259         err.log("AntBridge.createAntInstance - loading Ant installation...");
260         try {
261             List JavaDoc<File JavaDoc> mainClassPath = createMainClassPath();
262             err.log("mainClassPath=" + mainClassPath);
263             ClassLoader JavaDoc main = createMainClassLoader(mainClassPath);
264             ClassLoader JavaDoc bridgeLoader = createBridgeClassLoader(main);
265             // Ensures that the loader is functional, and that it is at least 1.5.x
266
// so that our classes can link against it successfully, and that
267
// we are really loading Ant from the right place:
268
Class JavaDoc ihClazz = Class.forName("org.apache.tools.ant.input.InputHandler", false, bridgeLoader); // NOI18N
269
Class JavaDoc<? extends BridgeInterface> impl = bridgeLoader.loadClass("org.apache.tools.ant.module.bridge.impl.BridgeImpl").asSubclass(BridgeInterface.class); // NOI18N
270
if (AntSettings.getAntHome() != null) {
271                 ClassLoader JavaDoc loaderUsedForAnt = ihClazz.getClassLoader();
272                 if (loaderUsedForAnt != main) {
273                     throw new IllegalStateException JavaDoc("Wrong class loader is finding Ant: " + loaderUsedForAnt); // NOI18N
274
}
275                 Class JavaDoc ihClazz2 = Class.forName("org.apache.tools.ant.input.InputHandler", false, main); // NOI18N
276
if (ihClazz2 != ihClazz) {
277                     throw new IllegalStateException JavaDoc("Main and bridge class loaders do not agree on version of Ant: " + ihClazz2.getClassLoader()); // NOI18N
278
}
279                 try {
280                     Class JavaDoc alClazz = Class.forName("org.apache.tools.ant.taskdefs.Antlib", false, bridgeLoader); // NOI18N
281
if (alClazz.getClassLoader() != main) {
282                         throw new IllegalStateException JavaDoc("Bridge loader is loading stuff from elsewhere: " + alClazz.getClassLoader()); // NOI18N
283
}
284                     Class JavaDoc alClazz2 = Class.forName("org.apache.tools.ant.taskdefs.Antlib", false, main); // NOI18N
285
if (alClazz2 != alClazz) {
286                         throw new IllegalStateException JavaDoc("Main and bridge class loaders do not agree on version of Ant: " + alClazz2.getClassLoader()); // NOI18N
287
}
288                 } catch (ClassNotFoundException JavaDoc cnfe) {
289                     // Fine, it was added in Ant 1.6.
290
}
291                 if (impl.getClassLoader() != bridgeLoader) {
292                     throw new IllegalStateException JavaDoc("Wrong class loader is finding bridge impl: " + impl.getClassLoader()); // NOI18N
293
}
294             } // in classpath mode, these checks do not apply
295
Map JavaDoc<String JavaDoc,ClassLoader JavaDoc> cDCLs = createCustomDefClassLoaders(main);
296             return new AntInstance(classPathToString(mainClassPath), main, bridgeLoader, impl.newInstance(), createCustomDefs(cDCLs), cDCLs);
297         } catch (Exception JavaDoc e) {
298             return fallback(e);
299         } catch (LinkageError JavaDoc e) {
300             return fallback(e);
301         }
302     }
303     
304     private static AntInstance fallback(Throwable JavaDoc e) {
305         ClassLoader JavaDoc dummy = ClassLoader.getSystemClassLoader();
306         Map JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>> defs = new HashMap JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>>();
307         defs.put("task", new HashMap JavaDoc<String JavaDoc,Class JavaDoc>()); // NOI18N
308
defs.put("type", new HashMap JavaDoc<String JavaDoc,Class JavaDoc>()); // NOI18N
309
return new AntInstance("", dummy, dummy, new DummyBridgeImpl(e), defs, Collections.<String JavaDoc,ClassLoader JavaDoc>emptyMap());
310     }
311     
312     private static final class JarFilter implements FilenameFilter JavaDoc {
313         JarFilter() {}
314         public boolean accept(File JavaDoc dir, String JavaDoc name) {
315             return name.toLowerCase(Locale.US).endsWith(".jar"); // NOI18N
316
}
317     }
318     
319     private static String JavaDoc classPathToString(List JavaDoc<File JavaDoc> cp) {
320         StringBuffer JavaDoc b = new StringBuffer JavaDoc();
321         Iterator JavaDoc<File JavaDoc> it = cp.iterator();
322         while (it.hasNext()) {
323             b.append(it.next().getAbsolutePath());
324             if (it.hasNext()) {
325                 b.append(File.pathSeparator);
326             }
327         }
328         return b.toString();
329     }
330     
331     private static String JavaDoc originalJavaClassPath = System.getProperty("java.class.path"); // NOI18N
332
/**
333      * Get the equivalent of java.class.path for the main Ant loader.
334      * Includes everything in the main class loader,
335      * plus the regular system class path (for tools.jar etc.).
336      */

337     public static String JavaDoc getMainClassPath() {
338         return getAntInstance().mainClassPath + File.pathSeparatorChar + originalJavaClassPath;
339     }
340     
341     private static List JavaDoc<File JavaDoc> createMainClassPath() throws Exception JavaDoc {
342         // Use LinkedHashSet to automatically suppress duplicates.
343
Collection JavaDoc<File JavaDoc> cp = new LinkedHashSet JavaDoc<File JavaDoc>();
344         File JavaDoc antHome = AntSettings.getAntHome();
345         if (antHome != null) {
346             File JavaDoc libdir = new File JavaDoc(antHome, "lib"); // NOI18N
347
if (!libdir.isDirectory()) {
348                 throw new IOException JavaDoc("No such Ant library dir: " + libdir); // NOI18N
349
}
350             err.log("Creating main class loader from " + libdir);
351             // First look for ${ant.home}/patches/*.jar, to support e.g. patching #47708:
352
File JavaDoc[] patches = new File JavaDoc(libdir.getParentFile(), "patches").listFiles(new JarFilter()); // NOI18N
353
if (patches != null) {
354                 cp.addAll(Arrays.asList(patches));
355             }
356             // Now continue with regular classpath.
357
File JavaDoc[] libs = libdir.listFiles(new JarFilter());
358             if (libs == null) {
359                 throw new IOException JavaDoc("Listing: " + libdir); // NOI18N
360
}
361             cp.addAll(Arrays.asList(libs));
362         } else {
363             // Classpath mode. Try to add in tools.jar if we can find it somewhere.
364
File JavaDoc toolsJar = new File JavaDoc(new File JavaDoc(new File JavaDoc(System.getProperty("java.home")).getParentFile(), "lib"), "tools.jar");
365             if (toolsJar.isFile()) {
366                 cp.add(toolsJar);
367             }
368         }
369         // XXX consider adding ${user.home}/.ant/lib/*.jar (org.apache.tools.ant.launch.Launcher.USER_LIBDIR)
370
cp.addAll(AntSettings.getExtraClasspath());
371         cp.addAll(AntSettings.getAutomaticExtraClasspath());
372         // XXX note that systemClassLoader will include boot.jar, and perhaps anything else
373
// in lib/ext/*.jar, like rmi-ext.jar. Would be nicer to exclude everything NB-specific.
374
// However the simplest way - to use the parent loader (JRE ext loader) - does not work
375
// well because Ant assumes that tools.jar is in its classpath (for <javac> etc.).
376
// Manually readding the JDK JARs would be possible, but then they would not be shared
377
// with the versions used inside NB, which may cause inefficiencies or more memory usage.
378
// On the other hand, if ant.jar is in ${java.class.path} (e.g. from a unit test), we
379
// have to explicitly mask it out. What a mess...
380
//org.openide.DialogDisplayer.getDefault().notify(new org.openide.NotifyDescriptor.Message("cp=" + cp));
381
return new ArrayList JavaDoc<File JavaDoc>(cp);
382     }
383     
384     private static ClassLoader JavaDoc createMainClassLoader(List JavaDoc<File JavaDoc> mainClassPath) throws Exception JavaDoc {
385         URL JavaDoc[] cp = new URL JavaDoc[mainClassPath.size()];
386         Iterator JavaDoc<File JavaDoc> it = mainClassPath.iterator();
387         int i = 0;
388         while (it.hasNext()) {
389             cp[i++] = it.next().toURI().toURL();
390         }
391         if (AntSettings.getAntHome() != null) {
392             ClassLoader JavaDoc parent = ClassLoader.getSystemClassLoader();
393             if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
394                 List JavaDoc<URL JavaDoc> parentURLs;
395                 if (parent instanceof URLClassLoader JavaDoc) {
396                     parentURLs = Arrays.asList(((URLClassLoader JavaDoc) parent).getURLs());
397                 } else {
398                     parentURLs = null;
399                 }
400                 err.log("AntBridge.createMainClassLoader: cp=" + Arrays.asList(cp) + " parent.urls=" + parentURLs);
401             }
402             return new MaskedClassLoader(cp, parent);
403         } else {
404             // Run-in-classpath mode.
405
ClassLoader JavaDoc existing = AntBridge.class.getClassLoader();
406             if (existing instanceof URLClassLoader JavaDoc) {
407                 try {
408                     // Need to insert resources into it.
409
// We could also try making a fresh loader which masks the parent
410
// yet delegates findResource to it, so as to be initiating loader
411
// for everything Ant. Might be safer.
412
Method JavaDoc addURL = URLClassLoader JavaDoc.class.getDeclaredMethod("addURL", URL JavaDoc.class);
413                     addURL.setAccessible(true);
414                     for (URL JavaDoc u : cp) {
415                         addURL.invoke(existing, u);
416                     }
417                     return existing;
418                 } catch (Exception JavaDoc e) {
419                     // Problem. Don't do it, I guess.
420
err.notify(ErrorManager.WARNING, e);
421                 }
422             }
423             // Probably won't work as desired, but just in case:
424
return new AllPermissionURLClassLoader(cp, existing);
425         }
426     }
427     
428     private static ClassLoader JavaDoc createBridgeClassLoader(ClassLoader JavaDoc main) throws Exception JavaDoc {
429         File JavaDoc bridgeJar = InstalledFileLocator.getDefault().locate("ant/nblib/bridge.jar", "org.apache.tools.ant.module", false); // NOI18N
430
if (bridgeJar == null) {
431             // Run-in-classpath mode.
432
return main;
433         }
434         return createAuxClassLoader(bridgeJar, main, AntBridge.class.getClassLoader());
435     }
436     
437     private static ClassLoader JavaDoc createAuxClassLoader(File JavaDoc lib, ClassLoader JavaDoc main, ClassLoader JavaDoc moduleLoader) throws IOException JavaDoc {
438         return new AuxClassLoader(moduleLoader, main, lib.toURI().toURL());
439     }
440     
441     /**
442      * Get a map from enabled module code name bases to class loaders containing
443      * JARs from ant/nblib/*.jar.
444      */

445     private static Map JavaDoc<String JavaDoc,ClassLoader JavaDoc> createCustomDefClassLoaders(ClassLoader JavaDoc main) throws IOException JavaDoc {
446         Map JavaDoc<String JavaDoc,ClassLoader JavaDoc> m = new HashMap JavaDoc<String JavaDoc,ClassLoader JavaDoc>();
447         ModuleInfo[] modules = miscListener.getEnabledModules();
448         InstalledFileLocator ifl = InstalledFileLocator.getDefault();
449         for (ModuleInfo module : modules) {
450             String JavaDoc cnb = module.getCodeNameBase();
451             String JavaDoc cnbDashes = cnb.replace('.', '-');
452             File JavaDoc lib = ifl.locate("ant/nblib/" + cnbDashes + ".jar", cnb, false); // NOI18N
453
if (lib == null) {
454                 if (main.getResource(cnb.replace('.', '/') + "/antlib.xml") != null) { // NOI18N
455
// Run-in-classpath mode.
456
m.put(cnb, main);
457                 }
458                 continue;
459             }
460             ClassLoader JavaDoc l = createAuxClassLoader(lib, main, module.getClassLoader());
461             m.put(cnb, l);
462         }
463         return m;
464     }
465     
466     private static Map JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>> createCustomDefs(Map JavaDoc<String JavaDoc,ClassLoader JavaDoc> cDCLs) throws IOException JavaDoc {
467         Map JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>> m = new HashMap JavaDoc<String JavaDoc,Map JavaDoc<String JavaDoc,Class JavaDoc>>();
468         Map JavaDoc<String JavaDoc,Class JavaDoc> tasks = new HashMap JavaDoc<String JavaDoc,Class JavaDoc>();
469         Map JavaDoc<String JavaDoc,Class JavaDoc> types = new HashMap JavaDoc<String JavaDoc,Class JavaDoc>();
470         // XXX #36776: should eventually support <macrodef>s here
471
m.put("task", tasks); // NOI18N
472
m.put("type", types); // NOI18N
473
for (Map.Entry JavaDoc<String JavaDoc,ClassLoader JavaDoc> entry : cDCLs.entrySet()) {
474             String JavaDoc cnb = entry.getKey();
475             ClassLoader JavaDoc l = entry.getValue();
476             String JavaDoc resource = cnb.replace('.', '/') + "/antlib.xml"; // NOI18N
477
URL JavaDoc antlib = l.getResource(resource);
478             if (antlib == null) {
479                 throw new IOException JavaDoc("Could not find " + resource + " in ant/nblib/" + cnb.replace('.', '-') + ".jar"); // NOI18N
480
}
481             Document JavaDoc doc;
482             try {
483                 doc = XMLUtil.parse(new InputSource JavaDoc(antlib.toExternalForm()), false, true, /*XXX needed?*/null, null);
484             } catch (SAXException JavaDoc e) {
485                 throw (IOException JavaDoc)new IOException JavaDoc(e.toString()).initCause(e);
486             }
487             Element JavaDoc docEl = doc.getDocumentElement();
488             if (!docEl.getLocalName().equals("antlib")) { // NOI18N
489
throw new IOException JavaDoc("Bad root element for " + antlib + ": " + docEl); // NOI18N
490
}
491             NodeList JavaDoc nl = docEl.getChildNodes();
492             Map JavaDoc<String JavaDoc,String JavaDoc> newTaskDefs = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
493             Map JavaDoc<String JavaDoc,String JavaDoc> newTypeDefs = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
494             for (int i = 0; i < nl.getLength(); i++) {
495                 Node JavaDoc n = nl.item(i);
496                 if (n.getNodeType() != Node.ELEMENT_NODE) {
497                     continue;
498                 }
499                 Element JavaDoc def = (Element JavaDoc)n;
500                 boolean type;
501                 if (def.getNodeName().equals("taskdef")) { // NOI18N
502
type = false;
503                 } else if (def.getNodeName().equals("typedef")) { // NOI18N
504
type = true;
505                 } else {
506                     err.log(ErrorManager.WARNING, "Warning: unrecognized definition " + def + " in " + antlib);
507                     continue;
508                 }
509                 String JavaDoc name = def.getAttribute("name"); // NOI18N
510
if (name == null) {
511                     // Not a hard error since there might be e.g. <taskdef resource="..."/> here
512
// which we do not parse but which is permitted in antlib by Ant.
513
err.log(ErrorManager.WARNING, "Warning: skipping definition " + def + " with no 'name' in " + antlib);
514                     continue;
515                 }
516                 String JavaDoc classname = def.getAttribute("classname"); // NOI18N
517
if (classname == null) {
518                     // But this is a hard error.
519
throw new IOException JavaDoc("No 'classname' attr on def of " + name + " in " + antlib); // NOI18N
520
}
521                 // XXX would be good to handle at least onerror attr too
522
String JavaDoc nsname = "antlib:" + cnb + ":" + name; // NOI18N
523
(type ? newTypeDefs : newTaskDefs).put(nsname, classname);
524             }
525             loadDefs(newTaskDefs, tasks, l);
526             loadDefs(newTypeDefs, types, l);
527         }
528         return m;
529     }
530     
531     private static void loadDefs(Map JavaDoc<String JavaDoc,String JavaDoc> p, Map JavaDoc<String JavaDoc,Class JavaDoc> defs, ClassLoader JavaDoc l) throws IOException JavaDoc {
532         // Similar to IntrospectedInfo.load, after having parsed the properties.
533
for (Map.Entry JavaDoc<String JavaDoc,String JavaDoc> entry : p.entrySet()) {
534             String JavaDoc name = entry.getKey();
535             String JavaDoc clazzname = entry.getValue();
536             try {
537                 Class JavaDoc clazz = l.loadClass(clazzname);
538                 defs.put(name, clazz);
539             } catch (ClassNotFoundException JavaDoc cnfe) {
540                 // This is not normal. If the class is mentioned, it should be there.
541
throw (IOException JavaDoc) new IOException JavaDoc("Could not load class " + clazzname + ": " + cnfe).initCause(cnfe); // NOI18N
542
} catch (NoClassDefFoundError JavaDoc ncdfe) {
543                 // Normal for e.g. tasks dumped there by disabled modules.
544
// Cf. #36702 for possible better solution.
545
err.log("AntBridge.loadDefs: skipping " + clazzname + ": " + ncdfe);
546             } catch (LinkageError JavaDoc e) {
547                 // Not normal; if it is there it ought to be resolvable etc.
548
throw (IOException JavaDoc) new IOException JavaDoc("Could not load class " + clazzname + ": " + e).initCause(e); // NOI18N
549
}
550         }
551     }
552     
553     static class AllPermissionURLClassLoader extends URLClassLoader JavaDoc {
554         
555         private static PermissionCollection JavaDoc allPermission;
556         private static synchronized PermissionCollection JavaDoc getAllPermissions() {
557             if (allPermission == null) {
558                 allPermission = new Permissions JavaDoc();
559                 allPermission.add(new AllPermission JavaDoc());
560             }
561             return allPermission;
562         }
563         
564         public AllPermissionURLClassLoader(URL JavaDoc[] urls, ClassLoader JavaDoc parent) {
565             super(urls, parent);
566         }
567         
568         @Override JavaDoc
569         protected final PermissionCollection JavaDoc getPermissions(CodeSource JavaDoc cs) {
570             return getAllPermissions();
571         }
572         
573         @Override JavaDoc
574         public String JavaDoc toString() {
575             return super.toString() + "[parent=" + getParent() + ",urls=" + Arrays.asList(getURLs()) + "]";
576         }
577
578         @Override JavaDoc
579         public URL JavaDoc getResource(String JavaDoc name) {
580             URL JavaDoc u = super.getResource(name);
581             if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
582                 err.log("APURLCL.gR: " + name + " -> " + u + " [" + this + "]");
583             }
584             return u;
585         }
586         
587         @Override JavaDoc
588         public Enumeration JavaDoc<URL JavaDoc> findResources(String JavaDoc name) throws IOException JavaDoc {
589             try {
590                 Enumeration JavaDoc<URL JavaDoc> us = super.findResources(name);
591                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
592                     // Make a copy so it can be logged:
593
List JavaDoc<URL JavaDoc> resources = Collections.list(us);
594                     us = Collections.enumeration(resources);
595                     err.log("APURLCL.fRs: " + name + " -> " + resources + " [" + this + "]");
596                 }
597                 return us;
598             } catch (IOException JavaDoc e) {
599                 if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
600                     err.notify(ErrorManager.INFORMATIONAL, e);
601                 }
602                 throw e;
603             }
604         }
605
606         /*
607         public Class loadClass(String name) throws ClassNotFoundException {
608             try {
609                 Class c = super.loadClass(name);
610                 java.security.CodeSource s = c.getProtectionDomain().getCodeSource();
611                 System.err.println("ACL.lC: " + name + " from " + (s != null ? s.getLocation() : null) + " [" + this + "]");
612                 return c;
613             } catch (ClassNotFoundException e) {
614                 System.err.println("ACL.lC: CNFE on " + name + " [" + this + "]");
615                 throw e;
616             }
617         }
618          */

619         
620     }
621     
622     private static boolean masked(String JavaDoc clazz) {
623         return clazz.startsWith("org.apache.tools.") ||
624                 clazz.startsWith("org.netbeans.") ||
625                 clazz.startsWith("org.openide.") ||
626                 clazz.startsWith("org.openidex."); // NOI18N
627
}
628
629     /**
630      * Special class loader that refuses to load Ant or NetBeans classes from its parent.
631      * Necessary in order to be able to load the intended Ant distro from a unit test.
632      */

633     private static final class MaskedClassLoader extends AllPermissionURLClassLoader {
634         
635         public MaskedClassLoader(URL JavaDoc[] urls, ClassLoader JavaDoc parent) {
636             super(urls, parent);
637         }
638         
639         @Override JavaDoc
640         protected synchronized Class JavaDoc<?> loadClass(String JavaDoc name, boolean resolve) throws ClassNotFoundException JavaDoc {
641             if (masked(name)) {
642                 Class JavaDoc c = findLoadedClass(name);
643                 // Careful with that parent loader Eugene!
644
if (c == null) {
645                     c = findClass(name);
646                 }
647                 if (resolve) {
648                     resolveClass(c);
649                 }
650                 return c;
651             } else {
652                 return super.loadClass(name, resolve);
653             }
654         }
655         
656     }
657     
658     // I/O redirection impl. Keyed by thread group (each Ant process has its own TG).
659
// Various Ant tasks (e.g. <java fork="false" output="..." ...>) need the system
660
// I/O streams to be redirected to the demux streams of the project so they can
661
// be handled properly. Ideally nothing would try to read directly from stdin
662
// or print directly to stdout/stderr but in fact some tasks do.
663
// Could also pass a custom InputOutput to ExecutionEngine, perhaps, but this
664
// seems a lot simpler and probably has the same effect.
665

666     private static int delegating = 0;
667     private static InputStream JavaDoc origIn;
668     private static PrintStream JavaDoc origOut, origErr;
669     private static Map JavaDoc<ThreadGroup JavaDoc,InputStream JavaDoc> delegateIns = new HashMap JavaDoc<ThreadGroup JavaDoc,InputStream JavaDoc>();
670     private static Map JavaDoc<ThreadGroup JavaDoc,PrintStream JavaDoc> delegateOuts = new HashMap JavaDoc<ThreadGroup JavaDoc,PrintStream JavaDoc>();
671     private static Map JavaDoc<ThreadGroup JavaDoc,PrintStream JavaDoc> delegateErrs = new HashMap JavaDoc<ThreadGroup JavaDoc,PrintStream JavaDoc>();
672     /** list, not set, so can be reentrant - treated as a multiset */
673     private static List JavaDoc<Thread JavaDoc> suspendedDelegationTasks = new ArrayList JavaDoc<Thread JavaDoc>();
674     
675     /**
676      * Handle I/O scoping for overlapping project runs.
677      * You must call {@link #restoreSystemInOutErr} in a finally block.
678      * @param in new temporary input stream for this thread group
679      * @param out new temporary output stream for this thread group
680      * @param err new temporary error stream for this thread group
681      * @see "#36396"
682      */

683     public static synchronized void pushSystemInOutErr(InputStream JavaDoc in, PrintStream JavaDoc out, PrintStream JavaDoc err) {
684         if (delegating++ == 0) {
685             origIn = System.in;
686             origOut = System.out;
687             origErr = System.err;
688             System.setIn(new MultiplexInputStream());
689             System.setOut(new MultiplexPrintStream(false));
690             System.setErr(new MultiplexPrintStream(true));
691         }
692         ThreadGroup JavaDoc tg = Thread.currentThread().getThreadGroup();
693         delegateIns.put(tg, in);
694         delegateOuts.put(tg, out);
695         delegateErrs.put(tg, err);
696     }
697     
698     /**
699      * Restore original I/O streams after a call to {@link #pushSystemInOutErr}.
700      */

701     public static synchronized void restoreSystemInOutErr() {
702         assert delegating > 0;
703         if (--delegating == 0) {
704             System.setIn(origIn);
705             System.setOut(origOut);
706             System.setErr(origErr);
707             origIn = null;
708             origOut = null;
709             origErr = null;
710         }
711         ThreadGroup JavaDoc tg = Thread.currentThread().getThreadGroup();
712         delegateIns.remove(tg);
713         delegateOuts.remove(tg);
714         delegateErrs.remove(tg);
715     }
716
717     /**
718      * Temporarily suspend delegation of system I/O streams for the current thread.
719      * Useful when running callbacks to IDE code that might try to print to stderr etc.
720      * Must be matched in a finally block by {@link #resumeDelegation}.
721      * Safe to call when not actually delegating; in that case does nothing.
722      * Safe to call in reentrant but not overlapping fashion.
723      */

724     public static synchronized void suspendDelegation() {
725         Thread JavaDoc t = Thread.currentThread();
726         //assert delegateOuts.containsKey(t.getThreadGroup()) : "Not currently delegating in " + t;
727
// #58394: do *not* check that it does not yet contain t. It is OK if it does; need to
728
// be able to call suspendDelegation reentrantly.
729
suspendedDelegationTasks.add(t);
730     }
731     
732     /**
733      * Resume delegation of system I/O streams for the current thread group
734      * after a call to {@link #suspendDelegation}.
735      */

736     public static synchronized void resumeDelegation() {
737         Thread JavaDoc t = Thread.currentThread();
738         //assert delegateOuts.containsKey(t.getThreadGroup()) : "Not currently delegating in " + t;
739
// This is still valid: suspendedDelegationTasks must have *at least one* copy of t.
740
assert suspendedDelegationTasks.contains(t) : "Have not suspended delegation in " + t;
741         suspendedDelegationTasks.remove(t);
742     }
743     
744     private static final class MultiplexInputStream extends InputStream JavaDoc {
745         
746         public MultiplexInputStream() {}
747         
748         private InputStream JavaDoc delegate() {
749             Thread JavaDoc t = Thread.currentThread();
750             ThreadGroup JavaDoc tg = t.getThreadGroup();
751             while (tg != null && !delegateIns.containsKey(tg)) {
752                 tg = tg.getParent();
753             }
754             InputStream JavaDoc is = delegateIns.get(tg);
755             if (is != null && !suspendedDelegationTasks.contains(t)) {
756                 return is;
757             } else if (delegating > 0) {
758                 assert origIn != null;
759                 return origIn;
760             } else {
761                 // Probably should not happen? But not sure.
762
return System.in;
763             }
764         }
765         
766         @Override JavaDoc
767         public int read() throws IOException JavaDoc {
768             return delegate().read();
769         }
770         
771         @Override JavaDoc
772         public int read(byte[] b) throws IOException JavaDoc {
773             return delegate().read(b);
774         }
775         
776         @Override JavaDoc
777         public int read(byte[] b, int off, int len) throws IOException JavaDoc {
778             return delegate().read(b, off, len);
779         }
780         
781         @Override JavaDoc
782         public int available() throws IOException JavaDoc {
783             return delegate().available();
784         }
785         
786         @Override JavaDoc
787         public boolean markSupported() {
788             return delegate().markSupported();
789         }
790         
791         @Override JavaDoc
792         public void mark(int readlimit) {
793             delegate().mark(readlimit);
794         }
795         
796         @Override JavaDoc
797         public void close() throws IOException JavaDoc {
798             delegate().close();
799         }
800         
801         @Override JavaDoc
802         public long skip(long n) throws IOException JavaDoc {
803             return delegate().skip(n);
804         }
805         
806         @Override JavaDoc
807         public void reset() throws IOException JavaDoc {
808             delegate().reset();
809         }
810         
811     }
812     
813     private static final class MultiplexPrintStream extends PrintStream JavaDoc {
814         
815         private final boolean err;
816         
817         public MultiplexPrintStream(boolean err) {
818             this(new NullOutputStream(), err);
819         }
820         
821         private MultiplexPrintStream(NullOutputStream nos, boolean err) {
822             super(nos);
823             nos.throwException = true;
824             this.err = err;
825         }
826         
827         private PrintStream JavaDoc delegate() {
828             Thread JavaDoc t = Thread.currentThread();
829             ThreadGroup JavaDoc tg = t.getThreadGroup();
830             Map JavaDoc<ThreadGroup JavaDoc,PrintStream JavaDoc> delegates = err ? delegateErrs : delegateOuts;
831             while (tg != null && !delegates.containsKey(tg)) {
832                 tg = tg.getParent();
833             }
834             PrintStream JavaDoc ps = delegates.get(tg);
835             if (ps != null && !suspendedDelegationTasks.contains(t)) {
836                 assert !(ps instanceof MultiplexPrintStream);
837                 return ps;
838             } else if (delegating > 0) {
839                 PrintStream JavaDoc orig = err ? origErr : origOut;
840                 assert orig != null;
841                 assert !(orig instanceof MultiplexPrintStream);
842                 return orig;
843             } else {
844                 // Probably should not happen? But not sure.
845
PrintStream JavaDoc stream = err ? System.err : System.out;
846                 assert !(stream instanceof MultiplexPrintStream); // #89020
847
return stream;
848             }
849         }
850         
851         @Override JavaDoc
852         public boolean checkError() {
853             return delegate().checkError();
854         }
855         
856         @Override JavaDoc
857         public void close() {
858             delegate().close();
859         }
860         
861         @Override JavaDoc
862         public void flush() {
863             delegate().flush();
864         }
865         
866         @Override JavaDoc
867         public void print(long l) {
868             delegate().print(l);
869         }
870         
871         @Override JavaDoc
872         public void print(char[] s) {
873             delegate().print(s);
874         }
875         
876         @Override JavaDoc
877         public void print(int i) {
878             delegate().print(i);
879         }
880         
881         @Override JavaDoc
882         public void print(boolean b) {
883             delegate().print(b);
884         }
885         
886         @Override JavaDoc
887         public void print(char c) {
888             delegate().print(c);
889         }
890         
891         @Override JavaDoc
892         public void print(float f) {
893             delegate().print(f);
894         }
895         
896         @Override JavaDoc
897         public void print(double d) {
898             delegate().print(d);
899         }
900         
901         @Override JavaDoc
902         public void print(Object JavaDoc obj) {
903             delegate().print(obj);
904         }
905         
906         @Override JavaDoc
907         public void print(String JavaDoc s) {
908             delegate().print(s);
909         }
910         
911         @Override JavaDoc
912         public void println(double x) {
913             delegate().println(x);
914         }
915         
916         @Override JavaDoc
917         public void println(Object JavaDoc x) {
918             delegate().println(x);
919         }
920         
921         @Override JavaDoc
922         public void println(float x) {
923             delegate().println(x);
924         }
925         
926         @Override JavaDoc
927         public void println(int x) {
928             delegate().println(x);
929         }
930         
931         @Override JavaDoc
932         public void println(char x) {
933             delegate().println(x);
934         }
935         
936         @Override JavaDoc
937         public void println(boolean x) {
938             delegate().println(x);
939         }
940         
941         @Override JavaDoc
942         public void println(String JavaDoc x) {
943             delegate().println(x);
944         }
945         
946         @Override JavaDoc
947         public void println(char[] x) {
948             delegate().println(x);
949         }
950         
951         @Override JavaDoc
952         public void println() {
953             delegate().println();
954         }
955         
956         @Override JavaDoc
957         public void println(long x) {
958             delegate().println(x);
959         }
960         
961         @Override JavaDoc
962         public void write(int b) {
963             delegate().write(b);
964         }
965         
966         @Override JavaDoc
967         public void write(byte[] b) throws IOException JavaDoc {
968             delegate().write(b);
969         }
970         
971         @Override JavaDoc
972         public void write(byte[] b, int off, int len) {
973             delegate().write(b, off, len);
974         }
975         
976         // XXX printf/format with varargs cannot be overridden here (JDK 1.5 specific)
977
// nor can append(char,CharSequence)
978
// probably does not matter however...
979

980     }
981     
982     // Faking the system property java.class.path for the benefit of a few tasks
983
// that expect it to be equal to the Ant class loader path.
984

985     private static int fakingJavaClassPath = 0;
986     
987     /**
988      * Fake the system property java.class.path temporarily.
989      * Must be followed by {@link unfakeJavaClassPath} in a finally block.
990      * Reentrant.
991      */

992     public static synchronized void fakeJavaClassPath() {
993         if (fakingJavaClassPath++ == 0) {
994             String JavaDoc cp = getMainClassPath();
995             err.log("Faking java.class.path=" + cp);
996             System.setProperty("java.class.path", cp); // NOI18N
997
}
998     }
999     
1000    /**
1001     * Reverse the effect of {@link fakeJavaClassPath}.
1002     */

1003    public static synchronized void unfakeJavaClassPath() {
1004        if (--fakingJavaClassPath == 0) {
1005            err.log("Restoring java.class.path=" + originalJavaClassPath);
1006            System.setProperty("java.class.path", originalJavaClassPath); // NOI18N
1007
}
1008    }
1009
1010}
1011
Popular Tags