KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > ProxyClassLoader


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.netbeans;
21
22 import java.io.IOException JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.security.AccessController JavaDoc;
25 import java.security.PrivilegedAction JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Arrays JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Set JavaDoc;
35 import java.util.logging.Level JavaDoc;
36 import java.util.logging.Logger JavaDoc;
37 import org.openide.util.Enumerations;
38 import org.openide.util.Lookup;
39
40 /**
41  * A class loader that has multiple parents and uses them for loading
42  * classes and resources. It can be used in tree hierarchy, where it
43  * can exploit its capability to not throw ClassNotFoundException when
44  * communicating with other ProxyClassLoader.
45  * It itself doesn't load classes or resources, but allows subclasses
46  * to add such functionality.
47  *
48  * @author Petr Nejedly, Jesse Glick
49  */

50 public class ProxyClassLoader extends ClassLoader JavaDoc implements Util.PackageAccessibleClassLoader {
51
52     private static final Logger JavaDoc LOGGER = Logger.getLogger(ProxyClassLoader.class.getName());
53     
54     /**
55      * All known package owners.
56      * Packages are given in format <samp>org/netbeans/modules/foo/</samp>.
57      */

58     private final Map JavaDoc<String JavaDoc, ClassLoader JavaDoc> domainsByPackage = new HashMap JavaDoc<String JavaDoc, ClassLoader JavaDoc>();
59     /** All known packages */
60     private final Map JavaDoc<String JavaDoc, Package JavaDoc> packages = new HashMap JavaDoc<String JavaDoc, Package JavaDoc>();
61
62     /** All parents of this classloader, including their parents recursively */
63     private ClassLoader JavaDoc[] parents;
64
65     /** if true, we have been destroyed */
66     private boolean dead = false;
67     
68     private final boolean transitive;
69     
70     /** Create a multi-parented classloader.
71      * Loads recursively from parents.
72      * @param parents list of parent classloaders.
73      * @throws IllegalArgumentException if there are any nulls or duplicate
74      * parent loaders or cycles.
75      */

76     public ProxyClassLoader( ClassLoader JavaDoc[] parents ) {
77         this(parents, true);
78     }
79     
80     /** Create a multi-parented classloader.
81      * @param parents list of parent classloaders.
82      * @param transitive whether other PCLs depending on this one will
83      * automatically search through its parent list
84      * @throws IllegalArgumentException if there are any nulls or duplicate
85      * parent loaders or cycles.
86      * @since org.netbeans.core/1 > 1.6
87      */

88     public ProxyClassLoader(ClassLoader JavaDoc[] parents, boolean transitive) {
89         if (parents.length == 0) {
90             throw new IllegalArgumentException JavaDoc ("ProxyClassLoader must have a parent"); // NOI18N
91
}
92         
93         this.transitive = transitive;
94         
95         Set JavaDoc<ClassLoader JavaDoc> check = new HashSet JavaDoc<ClassLoader JavaDoc>(Arrays.asList(parents));
96         if (check.size() < parents.length) throw new IllegalArgumentException JavaDoc("duplicate parents"); // NOI18N
97
if (check.contains(null)) throw new IllegalArgumentException JavaDoc("null parent in " + check); // NOI18N
98

99         this.parents = coalesceParents(parents);
100     }
101     
102     // this is used only by system classloader, maybe we can redesign it a bit
103
// to live without this functionality, then destroy may also go away
104
/** Add new parents dynamically.
105      * @param nueparents the new parents to add (append to list)
106      * @throws IllegalArgumentException in case of a null or cyclic parent (duplicate OK)
107      */

108     public void append(ClassLoader JavaDoc[] nueparents) throws IllegalArgumentException JavaDoc {
109         if (nueparents == null) throw new IllegalArgumentException JavaDoc("null parents array"); // NOI18N
110
for (int i = 0; i < nueparents.length; i++) {
111             if (nueparents[i] == null) throw new IllegalArgumentException JavaDoc("null parent"); // NOI18N
112
}
113         ClassLoader JavaDoc[] resParents = null;
114         ModuleFactory moduleFactory = Lookup.getDefault().lookup(ModuleFactory.class);
115         if (moduleFactory != null && moduleFactory.removeBaseClassLoader()) {
116             // this hack is here to prevent having the application classloader
117
// as parent to all module classloaders.
118
resParents = coalesceAppend(new ClassLoader JavaDoc[0], nueparents);
119         } else {
120             resParents = coalesceAppend(parents, nueparents);
121         }
122         synchronized (this) {
123             // synchronized because we don't want to mess up potentially running
124
// classloading
125
parents = resParents;
126         }
127     }
128     
129     /** Try to destroy this classloader.
130      * Subsequent attempts to use it will log an error (at most one though).
131      */

132     public void destroy() {
133         dead = true;
134     }
135
136     private void zombieCheck(String JavaDoc hint) {
137         if (dead) {
138             /* suppress this warning for now, more confusing than useful
139             LOGGER.log(Level.WARNING, "WARNING - attempting to use a zombie classloader " + this + " on " + hint + ". This means classes from a disabled module are still active. May or may not be a problem.", new IllegalStateException());
140              */

141             // don't warn again for same loader... this was enough
142
dead = false;
143         }
144     }
145
146     /**
147      * Loads the class with the specified name. The implementation of
148      * this method searches for classes in the following order:<p>
149      * <ol>
150      * <li> Calls {@link #findLoadedClass(String)} to check if the class has
151      * already been loaded.
152      * <li> Checks the caches whether another class from the same package
153      * was already loaded and uses the same classloader
154      * <li> Tries to find the class using parent loaders in their order.
155      * <li> Calls the {@link #simpleFindClass} method to find
156      * the class using this class loader.
157      * </ol>
158      *
159      * @param name the name of the class
160      * @param resolve if <code>true</code> then resolve the class
161      * @return the resulting <code>Class</code> object
162      * @exception ClassNotFoundException if the class could not be found
163      */

164     protected synchronized final Class JavaDoc<?> loadClass(String JavaDoc name, boolean resolve)
165                                             throws ClassNotFoundException JavaDoc {
166         zombieCheck(name);
167         String JavaDoc filename = name.replace('.', '/').concat(".class"); // NOI18N
168
int idx = filename.lastIndexOf('/'); // NOI18N
169
if (idx == -1) {
170             throw new ClassNotFoundException JavaDoc("Will not load classes from default package (" + name + ")"); // NOI18N
171
}
172         String JavaDoc pkg = filename.substring(0, idx + 1); // "org/netbeans/modules/foo/"
173
Class JavaDoc c = smartLoadClass(name, filename, pkg);
174         if(c == null) {
175             throw new ClassNotFoundException JavaDoc(name + " from " + this);
176         }
177         if (resolve) resolveClass(c);
178         return c;
179     }
180     
181     /** This ClassLoader can't load anything itself. Subclasses
182      * may override this method to do some class loading themselves. The
183      * implementation should not throw any exception, just return
184      * <CODE>null</CODE> if it can't load required class.
185      *
186      * @param name the name of the class
187      * @param fileName the expected filename of the classfile, like
188      * <CODE>java/lang/Object.class</CODE> for <CODE>java.lang.Object</CODE>
189      * The ClassLoader implementation may or may not use it, depending
190      * whether it is usefull to it.
191      * @param pkg the package name, in the format org/netbeans/modules/foo/
192      * @return the resulting <code>Class</code> object or <code>null</code>
193      */

194     protected Class JavaDoc simpleFindClass(String JavaDoc name, String JavaDoc fileName, String JavaDoc pkg) {
195         return null;
196     }
197     
198     private String JavaDoc stripInitialSlash(String JavaDoc resource) { // #90310
199
if (resource.startsWith("/")) {
200             LOGGER.log(Level.WARNING, "Should not use initial '/' in calls to ClassLoader.getResource(s): {0}", resource);
201             return resource.substring(1);
202         } else {
203             return resource;
204         }
205     }
206
207     /**
208      * Finds the resource with the given name. The implementation of
209      * this method searches for resources in the following order:<p>
210      * <ol>
211      * <li> Checks the caches whether another resource or class from the same
212      * package was already loaded and uses the same classloader.
213      * <li> Tries to find the resources using parent loaders in their order.
214      * <li> Calls the {@link #findResource(String)} method to find
215      * the resources using this class loader.
216      * </ol>
217      *
218      * @param name a "/"-separated path name that identifies the resource.
219      * @return a URL for reading the resource, or <code>null</code> if
220      * the resource could not be found.
221      * @see #findResource(String)
222      */

223     public final URL JavaDoc getResource(String JavaDoc name) {
224         zombieCheck(name);
225         
226         name = stripInitialSlash(name);
227         
228         final int slashIdx = name.lastIndexOf('/');
229         if (slashIdx == -1) {
230             printDefaultPackageWarning(name);
231         }
232         final String JavaDoc pkg = name.substring(0, slashIdx + 1);
233
234         if (isSpecialResource(pkg)) {
235             // Disable domain cache for this one, do a simple check.
236
for (int i = 0; i < parents.length; i++) {
237                 if (!shouldDelegateResource(pkg, parents[i])) continue;
238                 URL JavaDoc u;
239                 if (parents[i] instanceof ProxyClassLoader) {
240                     u = ((ProxyClassLoader)parents[i]).findResource(name);
241                 } else {
242                     u = parents[i].getResource(name);
243                 }
244                 if (u != null) return u;
245             }
246             return findResource(name);
247         }
248         
249         ClassLoader JavaDoc owner = domainsByPackage.get(pkg);
250
251         if (owner != null) { // known package
252
// Note that shouldDelegateResource should already be true for this!
253
if (owner instanceof ProxyClassLoader) {
254                 return ((ProxyClassLoader)owner).findResource(name); // we have its parents, skip them
255
} else {
256                 return owner.getResource(name); // know nothing about this loader and his structure
257
}
258         }
259         
260         // virgin package
261
URL JavaDoc retVal = null;
262         for (int i = 0; i < parents.length; i++) {
263             owner = parents[i];
264             if (!shouldDelegateResource(pkg, owner)) continue;
265             if (owner instanceof ProxyClassLoader) {
266                 retVal = ((ProxyClassLoader)owner).findResource(name); // skip parents (checked already)
267
} else {
268                 retVal = owner.getResource(name); // know nothing about this loader and his structure
269
}
270             if (retVal != null) {
271                 String JavaDoc p = new String JavaDoc(pkg).intern(); // NOPMD
272
domainsByPackage.put(p, owner);
273         if (owner instanceof ProxyClassLoader) {
274                     ((ProxyClassLoader)owner).domainsByPackage.put(p, owner);
275         }
276                 return retVal;
277             }
278         }
279         
280         // try it ourself
281
retVal = findResource(name);
282         if (retVal != null) {
283             domainsByPackage.put(new String JavaDoc(pkg).intern(), this); // NOPMD
284
}
285         return retVal;
286     }
287
288     /** This ClassLoader can't load anything itself. Subclasses
289      * may override this method to do some resource loading themselves.
290      *
291      * @param name the resource name
292      * @return a URL for reading the resource, or <code>null</code>
293      * if the resource could not be found.
294      */

295     protected URL JavaDoc findResource(String JavaDoc name) {
296     return null;
297     }
298
299     /**
300      * Finds all the resource with the given name. The implementation of
301      * this method uses the {@link #simpleFindResources(String)} method to find
302      * all the resources available from this classloader and adds all the
303      * resources from all the parents.
304      *
305      * @param name the resource name
306      * @return an Enumeration of URLs for the resources
307      * @throws IOException if I/O errors occur
308      */

309     protected final synchronized Enumeration JavaDoc<URL JavaDoc> findResources(String JavaDoc name) throws IOException JavaDoc {
310         zombieCheck(name);
311         name = stripInitialSlash(name);
312         final int slashIdx = name.lastIndexOf('/');
313         if (slashIdx == -1) {
314             printDefaultPackageWarning(name);
315         }
316         final String JavaDoc pkg = name.substring(0, slashIdx + 1);
317
318         // Don't bother optimizing this call by domains.
319
// It is mostly used for resources for which isSpecialResource would be true anyway.
320
List JavaDoc<Enumeration JavaDoc<URL JavaDoc>> es = new ArrayList JavaDoc<Enumeration JavaDoc<URL JavaDoc>>(parents.length + 1);
321         for (ClassLoader JavaDoc parent : parents) {
322             if (!shouldDelegateResource(pkg, parent)) {
323                 continue;
324             }
325             if (parent instanceof ProxyClassLoader) {
326                 es.add(((ProxyClassLoader) parent).simpleFindResources(name));
327             } else {
328                 es.add(parent.getResources(name));
329             }
330         }
331         es.add(simpleFindResources(name));
332         // Should not be duplicates, assuming the parent loaders are properly distinct
333
// from one another and do not overlap in JAR usage, which they ought not.
334
// Anyway MetaInfServicesLookup, the most important client of this method, does
335
// its own duplicate filtering already.
336
return Enumerations.concat(Collections.enumeration(es));
337     }
338
339     /** This ClassLoader can't load anything itself. Subclasses
340      * may override this method to do some resource loading themselves, this
341      * implementation simply delegates to findResources method of the superclass
342      * that should return empty Enumeration.
343      *
344      * @param name the resource name
345      * @return an Enumeration of URLs for the resources
346      * @throws IOException if I/O errors occur
347      */

348     protected Enumeration JavaDoc<URL JavaDoc> simpleFindResources(String JavaDoc name) throws IOException JavaDoc {
349         return super.findResources(name);
350     }
351
352     
353     /**
354      * Returns a Package that has been defined by this class loader or any
355      * of its parents.
356      *
357      * @param name the package name
358      * @return the Package corresponding to the given name, or null if not found
359      */

360     protected Package JavaDoc getPackage(String JavaDoc name) {
361         zombieCheck(name);
362         return getPackageFast(name, name.replace('.', '/') + '/', true);
363     }
364     
365     /**
366      * Faster way to find a package.
367      * @param name package name in org.netbeans.modules.foo format
368      * @param sname package name in org/netbeans/modules/foo/ format
369      * @param recurse whether to also ask parents
370      * @return located package, or null
371      */

372     protected Package JavaDoc getPackageFast(String JavaDoc name, String JavaDoc sname, boolean recurse) {
373         synchronized (packages) {
374             Package JavaDoc pkg = packages.get(name);
375             if (pkg != null) {
376                 return pkg;
377             }
378             if (!recurse) {
379                 return null;
380             }
381             for (int i = 0; i < parents.length; i++) {
382                 ClassLoader JavaDoc par = parents[i];
383                 if (par instanceof ProxyClassLoader && shouldDelegateResource(sname, par)) {
384                     pkg = ((ProxyClassLoader)par).getPackageFast(name, sname, false);
385                     if (pkg != null) {
386                         break;
387                     }
388                 }
389             }
390             if (pkg == null && /* #30093 */shouldDelegateResource(sname, getParent())) {
391                 // Cannot access either Package.getSystemPackage nor ClassLoader.getPackage
392
// from here, so do the best we can though it will cause unnecessary
393
// duplication of the package cache (PCL.packages vs. CL.packages):
394
pkg = super.getPackage(name);
395             }
396             if (pkg != null) {
397                 packages.put(name, pkg);
398             }
399             return pkg;
400         }
401     }
402
403     /** This is here just for locking serialization purposes.
404      * Delegates to super.definePackage with proper locking.
405      * Also tracks the package in our private cache, since
406      * getPackageFast(...,...,false) will not call super.getPackage.
407      */

408     protected Package JavaDoc definePackage(String JavaDoc name, String JavaDoc specTitle,
409                 String JavaDoc specVersion, String JavaDoc specVendor, String JavaDoc implTitle,
410         String JavaDoc implVersion, String JavaDoc implVendor, URL JavaDoc sealBase )
411         throws IllegalArgumentException JavaDoc {
412     synchronized (packages) {
413             Package JavaDoc pkg = super.definePackage (name, specTitle, specVersion, specVendor, implTitle,
414             implVersion, implVendor, sealBase);
415             packages.put(name, pkg);
416             return pkg;
417     }
418     }
419
420     /**
421      * Returns all of the Packages defined by this class loader and its parents.
422      *
423      * @return the array of <code>Package</code> objects defined by this
424      * <code>ClassLoader</code>
425      */

426     protected synchronized Package JavaDoc[] getPackages() {
427         return getPackages(new HashSet JavaDoc<ClassLoader JavaDoc>());
428     }
429     
430     /**
431      * Returns all of the Packages defined by this class loader and its parents.
432      * Do not recurse to parents in addedParents set. It speeds up execution
433      * time significantly.
434      * @return the array of <code>Package</code> objects defined by this
435      * <code>ClassLoader</code>
436      */

437     private synchronized Package JavaDoc[] getPackages(Set JavaDoc<ClassLoader JavaDoc> addedParents) {
438         zombieCheck(null);
439         Map JavaDoc<String JavaDoc,Package JavaDoc> all = new HashMap JavaDoc<String JavaDoc, Package JavaDoc>();
440         // XXX call shouldDelegateResource on each?
441
addPackages(all, super.getPackages());
442         for (int i = 0; i < parents.length; i++) {
443             ClassLoader JavaDoc par = parents[i];
444             if (par instanceof ProxyClassLoader && addedParents.add(par)) {
445                 // XXX should ideally use shouldDelegateResource here...
446
addPackages(all, ((ProxyClassLoader)par).getPackages(addedParents));
447             }
448         }
449         synchronized (packages) {
450             all.keySet().removeAll(packages.keySet());
451             packages.putAll(all);
452         }
453         return packages.values().toArray(new Package JavaDoc[packages.size()]);
454     }
455     
456     public Package JavaDoc getPackageAccessibly(String JavaDoc name) {
457         return getPackage(name);
458     }
459     
460     public Package JavaDoc[] getPackagesAccessibly() {
461         return getPackages();
462     }
463
464     /**
465      * #38368: Warn that the default package should not be used.
466      */

467     private static void printDefaultPackageWarning(String JavaDoc name) {
468         // #42201 - commons-logging lib tries to read its config from this file, ignore
469
if (!"commons-logging.properties".equals(name) &&
470             !"jndi.properties".equals(name)) { // NOI18N
471
LOGGER.log(Level.INFO, null, new IllegalStateException JavaDoc("You are trying to access file: " + name + " from the default package. Please see http://www.netbeans.org/download/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/classpath.html#default_package"));
472         }
473     }
474     
475     /** Coalesce parent classloaders into an optimized set.
476      * This means that all parents of the specified classloaders
477      * are also added recursively, removing duplicates along the way.
478      * Search order should be preserved (parents before children, stable w.r.t. inputs).
479      * @param loaders list of suggested parents (no nulls or duplicates permitted)
480      * @return optimized list of parents (no nulls or duplicates)
481      * @throws IllegalArgumentException if there are cycles
482      */

483     private ClassLoader JavaDoc[] coalesceParents(ClassLoader JavaDoc[] loaders) throws IllegalArgumentException JavaDoc {
484         int likelySize = loaders.length * 5 + 10;
485         Set JavaDoc<ClassLoader JavaDoc> resultingUnique = new HashSet JavaDoc<ClassLoader JavaDoc>(likelySize);
486         List JavaDoc<ClassLoader JavaDoc> resulting = new ArrayList JavaDoc<ClassLoader JavaDoc>(likelySize);
487         for (int i = 0; i < loaders.length; i++) {
488             addRec(resultingUnique, resulting, loaders[i]);
489         }
490         ClassLoader JavaDoc[] ret = resulting.toArray(new ClassLoader JavaDoc[resulting.size()]);
491         return ret;
492     }
493     
494     /** Coalesce a new set of loaders into the existing ones.
495      */

496     private ClassLoader JavaDoc[] coalesceAppend(ClassLoader JavaDoc[] existing, ClassLoader JavaDoc[] appended) throws IllegalArgumentException JavaDoc {
497         int likelySize = existing.length + 3;
498         Set JavaDoc<ClassLoader JavaDoc> resultingUnique = new HashSet JavaDoc<ClassLoader JavaDoc>(likelySize);
499         List JavaDoc<ClassLoader JavaDoc> existingL = Arrays.asList(existing);
500         resultingUnique.addAll(existingL);
501         if (resultingUnique.containsAll(Arrays.asList(appended))) {
502             // No change required.
503
return existing;
504         }
505         List JavaDoc<ClassLoader JavaDoc> resulting = new ArrayList JavaDoc<ClassLoader JavaDoc>(likelySize);
506         resulting.addAll(existingL);
507         for (int i = 0; i < appended.length; i++) {
508             addRec(resultingUnique, resulting, appended[i]);
509         }
510         ClassLoader JavaDoc[] ret = resulting.toArray(new ClassLoader JavaDoc[resulting.size()]);
511         return ret;
512     }
513     
514     private void addRec(Set JavaDoc<ClassLoader JavaDoc> resultingUnique, List JavaDoc<ClassLoader JavaDoc> resulting, ClassLoader JavaDoc loader) throws IllegalArgumentException JavaDoc {
515         if (loader == this) throw new IllegalArgumentException JavaDoc("cycle in parents"); // NOI18N
516
if (resultingUnique.contains(loader)) return;
517         if (loader instanceof ProxyClassLoader && ((ProxyClassLoader)loader).transitive) {
518             ClassLoader JavaDoc[] parents = ((ProxyClassLoader)loader).parents;
519             for (int i = 0; i < parents.length; i++) {
520                 addRec(resultingUnique, resulting, parents[i]);
521             }
522         }
523         resultingUnique.add(loader);
524         resulting.add(loader);
525     }
526
527     /** A method that finds a class either in itself or in parents.
528      * It uses dual signaling for class not found: it can either return null
529      * or throw CNFE itself.
530      * @param name class name, e.g. "org.netbeans.modules.foo.Clazz"
531      * @param fileName resource name, e.g. "org/netbeans/modules/foo/Clazz.class"
532      * @param pkg package component, e.g. "org/netbeans/modules/foo/"
533      * @return a class or null if not found. It can also throw an exception.
534      * @throws ClassNotFoundException in case it doesn't found a class
535      * and a parent eglible for loading it thrown it already.
536      */

537     private final Class JavaDoc smartLoadClass(String JavaDoc name, String JavaDoc fileName, String JavaDoc pkg) throws ClassNotFoundException JavaDoc {
538     // First, check if the class has already been loaded
539
Class JavaDoc c = findLoadedClass(name);
540     if(c != null) return c;
541         
542         final ClassLoader JavaDoc owner = isSpecialResource(pkg) ? null : domainsByPackage.get(pkg);
543         if (owner == this) {
544             return simpleFindClass(name, fileName, pkg);
545         }
546         if (owner != null) {
547             // Note that shouldDelegateResource should already be true as we hit this pkg before.
548
if (owner instanceof ProxyClassLoader) {
549                 return ((ProxyClassLoader)owner).fullFindClass(name, fileName, pkg);
550             } else {
551                 return owner.loadClass(name); // May throw CNFE, will be propagated
552
}
553         }
554         
555         // Virgin package, do the parent scan
556
c = loadInOrder(name, fileName, pkg);
557
558         if (c != null) {
559             final ClassLoader JavaDoc owner2 = getClassClassLoader(c); // who got it?
560
domainsByPackage.put(new String JavaDoc(pkg).intern(), owner2); // NOPMD
561
}
562         return c;
563     }
564
565     // #29844 run as privileged as it may get called by loadClassInternal() used
566
// during class resolving by JVM with arbitrary ProtectionDomain context stack
567
private static ClassLoader JavaDoc getClassClassLoader(final Class JavaDoc c) {
568         return AccessController.doPrivileged(new PrivilegedAction JavaDoc<ClassLoader JavaDoc>() {
569             public ClassLoader JavaDoc run() {
570                 return c.getClassLoader();
571             }
572         });
573     }
574
575     private final Class JavaDoc loadInOrder( String JavaDoc name, String JavaDoc fileName, String JavaDoc pkg ) throws ClassNotFoundException JavaDoc {
576         ClassNotFoundException JavaDoc cached = null;
577         for (int i = 0; i < parents.length; i++) {
578         ClassLoader JavaDoc par = parents[i];
579             if (!shouldDelegateResource(pkg, par)) continue;
580         if ((par instanceof ProxyClassLoader) &&
581                 ((ProxyClassLoader)par).shouldBeCheckedAsParentProxyClassLoader()) {
582                 ProxyClassLoader pcl = (ProxyClassLoader)par;
583         Class JavaDoc c = pcl.fullFindClass(name, fileName, pkg);
584                 // pcl might have have c in its already-loaded classes even though
585
// it was not the defining class loader. In that case, if pcl was
586
// not transitive (should not expose its own parents), reject this.
587
if (c != null && (pcl.transitive || getClassClassLoader(c) == pcl)) return c;
588         } else {
589                 // The following is an optimization, it should not affect semantics:
590
boolean skip = false;
591                 if (optimizeNBLoading()) {
592                     if (name.startsWith("org.netbeans.") || // NOI18N
593
name.startsWith("org.openide.") || // NOI18N
594
name.endsWith(".Bundle") || // NOI18N
595
name.endsWith("BeanInfo") || // NOI18N
596
name.endsWith("Editor")) { // NOI18N
597
if (par.getResource(fileName) == null) {
598                             // We would just throw CNFE anyway, don't bother!
599
// Avg. (over ten runs after primer, w/ netbeans.close):
600
// before: 13.87s after: 13.40s saved: 1.3%
601
skip = true;
602                         }
603                     }
604                 }
605                 if (!skip) {
606                     try {
607                         return par.loadClass(name);
608                     } catch( ClassNotFoundException JavaDoc cnfe ) {
609                         cached = cnfe;
610                     }
611                 }
612         }
613     }
614
615         Class JavaDoc c = simpleFindClass(name, fileName, pkg); // Try it ourselves
616
if (c != null) return c;
617         if (cached != null) throw cached;
618     return null;
619     }
620
621     private synchronized Class JavaDoc fullFindClass(String JavaDoc name, String JavaDoc fileName, String JavaDoc pkg) {
622     Class JavaDoc c = findLoadedClass(name);
623         if (c == null) {
624             c = simpleFindClass(name, fileName, pkg);
625             if (c != null) {
626                 domainsByPackage.put(new String JavaDoc(pkg).intern(), this); // NOPMD
627
}
628         }
629     return c;
630     }
631
632     private void addPackages(Map JavaDoc<String JavaDoc,Package JavaDoc> all, Package JavaDoc[] pkgs) {
633         // Would be easier if Package.equals() was just defined sensibly...
634
for (int i = 0; i < pkgs.length; i++) {
635             all.put(pkgs[i].getName(), pkgs[i]);
636         }
637     }
638     
639     /**
640      * Can be overridden by special classloaders
641      * (see project installer/jnlp/modules).
642      * @see #loadInOrder
643      */

644     protected boolean shouldBeCheckedAsParentProxyClassLoader() {
645         return true;
646     }
647
648     /**
649      * Allows turning off the optimization in {@link #loadInOrder}.
650      */

651     protected boolean optimizeNBLoading() {
652         return true;
653     }
654     
655     /** Test whether a given resource name is something that any JAR might
656      * have, and for which the domain cache should be disabled.
657      * The result must not change from one call to the next with the same argument.
658      * By default the domain cache is disabled only for META-INF/* JAR information.
659      * @param pkg the package component of the resource path ending with a slash,
660      * e.g. "org/netbeans/modules/foo/"
661      * @return true if it is a special resource, false for normal domain-cached resource
662      * @since org.netbeans.core/1 1.3
663      */

664     protected boolean isSpecialResource(String JavaDoc pkg) {
665         if (pkg.startsWith("META-INF/")) return true; // NOI18N
666

667         // #38368: do not cache the default package
668
if (pkg.length() == 0) return true;
669         
670         return false;
671     }
672     
673     /** Test whether a given resource request (for a class or not) should be
674      * searched for in the specified parent classloader or not.
675      * The result must not change from one call to the next with the same arguments.
676      * By default, always true. Subclasses may override to "mask" certain
677      * packages from view, possibly according to the classloader chain.
678      * @param pkg the package component of the resource path ending with a slash,
679      * e.g. "org/netbeans/modules/foo/"
680      * @param parent a classloader which is a direct or indirect parent of this one
681      * @return true if the request should be delegated to this parent; false to
682      * only search elsewhere (other parents, this loader's own namespace)
683      * @since org.netbeans.core/1 1.3
684      */

685     protected boolean shouldDelegateResource(String JavaDoc pkg, ClassLoader JavaDoc parent) {
686         return true;
687     }
688     
689 }
690
Popular Tags