KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > StandardModule


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 // THIS CLASS OUGHT NOT USE NbBundle NOR org.openide CLASSES
23
// OUTSIDE OF openide-util.jar! UI AND FILESYSTEM/DATASYSTEM
24
// INTERACTIONS SHOULD GO ELSEWHERE.
25
// (NbBundle.getLocalizedValue is OK here.)
26

27 import java.io.File JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.InputStream JavaDoc;
30 import java.security.AllPermission JavaDoc;
31 import java.security.CodeSource JavaDoc;
32 import java.security.PermissionCollection JavaDoc;
33 import java.security.Permissions JavaDoc;
34 import java.util.ArrayList JavaDoc;
35 import java.util.Collections JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.HashSet JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.Locale JavaDoc;
41 import java.util.Map JavaDoc;
42 import java.util.MissingResourceException JavaDoc;
43 import java.util.Properties JavaDoc;
44 import java.util.ResourceBundle JavaDoc;
45 import java.util.Set JavaDoc;
46 import java.util.StringTokenizer JavaDoc;
47 import java.util.jar.Attributes JavaDoc;
48 import java.util.jar.JarFile JavaDoc;
49 import java.util.jar.Manifest JavaDoc;
50 import java.util.logging.Level JavaDoc;
51 import java.util.zip.ZipEntry JavaDoc;
52 import org.netbeans.Module.PackageExport;
53 import org.openide.modules.Dependency;
54 import org.openide.util.Exceptions;
55 import org.openide.util.NbBundle;
56 import org.openide.util.Union2;
57
58 /** Object representing one module, possibly installed.
59  * Responsible for opening of module JAR file; reading
60  * manifest; parsing basic information such as dependencies;
61  * and creating a classloader for use by the installer.
62  * Methods not defined in ModuleInfo must be called from within
63  * the module manager's read mutex as a rule.
64  * @author Jesse Glick
65  */

66 final class StandardModule extends Module {
67     
68     /** JAR file holding the module */
69     private final File JavaDoc jar;
70     /** if reloadable, temporary JAR file actually loaded from */
71     private File JavaDoc physicalJar = null;
72     
73     /** Map from extension JARs to sets of JAR that load them via Class-Path.
74      * Used only for debugging purposes, so that a warning is printed if two
75      * different modules try to load the same extension (which would cause them
76      * to both load their own private copy, which may not be intended).
77      */

78     private static final Map JavaDoc<File JavaDoc,Set JavaDoc<File JavaDoc>> extensionOwners = new HashMap JavaDoc<File JavaDoc,Set JavaDoc<File JavaDoc>>();
79     /** Simple registry of JAR files used as modules.
80      * Used only for debugging purposes, so that we can be sure
81      * that no one is using Class-Path to refer to other modules.
82      */

83     private static final Set JavaDoc<File JavaDoc> moduleJARs = new HashSet JavaDoc<File JavaDoc>();
84
85     /** Set of locale-variants JARs for this module (or null).
86      * Added explicitly to classloader, and can be used by execution engine.
87      */

88     private Set JavaDoc<File JavaDoc> localeVariants = null;
89     /** Set of extension JARs that this module loads via Class-Path (or null).
90      * Can be used e.g. by execution engine. (#9617)
91      */

92     private Set JavaDoc<File JavaDoc> plainExtensions = null;
93     /** Set of localized extension JARs derived from plainExtensions (or null).
94      * Used to add these to the classloader. (#9348)
95      * Can be used e.g. by execution engine.
96      */

97     private Set JavaDoc<File JavaDoc> localeExtensions = null;
98     /** Patches added at the front of the classloader (or null).
99      * Files are assumed to be JARs; directories are themselves.
100      */

101     private Set JavaDoc<File JavaDoc> patches = null;
102     
103     /** localized properties, only non-null if requested from disabled module */
104     private Properties JavaDoc localizedProps;
105     
106     /** Use ModuleManager.create as a factory. */
107     public StandardModule(ModuleManager mgr, Events ev, File JavaDoc jar, Object JavaDoc history, boolean reloadable, boolean autoload, boolean eager) throws IOException JavaDoc {
108         super(mgr, ev, history, reloadable, autoload, eager);
109         this.jar = jar;
110         loadManifest();
111         parseManifest();
112         findExtensionsAndVariants(manifest);
113         // Check if some other module already listed this one in Class-Path.
114
// For the chronologically reverse case, see findExtensionsAndVariants().
115
Set JavaDoc<File JavaDoc> bogoOwners = extensionOwners.get(jar);
116         if (bogoOwners != null) {
117             Util.err.warning("module " + jar + " was incorrectly placed in the Class-Path of other JARs " + bogoOwners + "; please use OpenIDE-Module-Module-Dependencies instead");
118         }
119         moduleJARs.add(jar);
120     }
121     
122     /** Get a localized attribute.
123      * First, if OpenIDE-Module-Localizing-Bundle was given, the specified
124      * bundle file (in all locale JARs as well as base JAR) is searched for
125      * a key of the specified name.
126      * Otherwise, the manifest's main attributes are searched for an attribute
127      * with the specified name, possibly with a locale suffix.
128      * If the attribute name contains a slash, and there is a manifest section
129      * named according to the part before the last slash, then this section's attributes
130      * are searched instead of the main attributes, and for the attribute listed
131      * after the slash. Currently this would only be useful for localized filesystem
132      * names. E.g. you may request the attribute org/foo/MyFileSystem.class/Display-Name.
133      * In the future certain attributes known to be dangerous could be
134      * explicitly suppressed from this list; should only be used for
135      * documented localizable attributes such as OpenIDE-Module-Name etc.
136      */

137     public Object JavaDoc getLocalizedAttribute(String JavaDoc attr) {
138         String JavaDoc locb = getManifest().getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N
139
boolean usingLoader = false;
140         if (locb != null) {
141             if (classloader != null) {
142                 if (locb.endsWith(".properties")) { // NOI18N
143
usingLoader = true;
144                     String JavaDoc basename = locb.substring(0, locb.length() - 11).replace('/', '.');
145                     try {
146                         ResourceBundle JavaDoc bundle = NbBundle.getBundle(basename, Locale.getDefault(), classloader);
147                         try {
148                             return bundle.getString(attr);
149                         } catch (MissingResourceException JavaDoc mre) {
150                             // Fine, ignore.
151
}
152                     } catch (MissingResourceException JavaDoc mre) {
153                         Util.err.log(Level.WARNING, null, mre);
154                     }
155                 } else {
156                     Util.err.warning("cannot efficiently load non-*.properties OpenIDE-Module-Localizing-Bundle: " + locb);
157                 }
158             }
159             if (!usingLoader) {
160                 if (localizedProps == null) {
161                     Util.err.fine("Trying to get localized attr " + attr + " from disabled module " + getCodeNameBase());
162                     try {
163                         // check if the jar file still exists (see issue 82480)
164
if (jar != null && jar.isFile ()) {
165                             JarFile JavaDoc jarFile = new JarFile JavaDoc(jar, false);
166                             try {
167                                 loadLocalizedProps(jarFile, manifest);
168                             } finally {
169                                 jarFile.close();
170                             }
171                         } else {
172                             throw new IllegalStateException JavaDoc();
173                         }
174                     } catch (IOException JavaDoc ioe) {
175                         Util.err.log(Level.WARNING, jar.getAbsolutePath(), ioe);
176                         if (localizedProps == null) {
177                             localizedProps = new Properties JavaDoc();
178                         }
179                     }
180                 }
181                 String JavaDoc val = localizedProps.getProperty(attr);
182                 if (val != null) {
183                     return val;
184                 }
185             }
186         }
187         // Try in the manifest now.
188
int idx = attr.lastIndexOf('/'); // NOI18N
189
if (idx == -1) {
190             // Simple main attribute.
191
return NbBundle.getLocalizedValue(getManifest().getMainAttributes(), new Attributes.Name JavaDoc(attr));
192         } else {
193             // Attribute of a manifest section.
194
String JavaDoc section = attr.substring(0, idx);
195             String JavaDoc realAttr = attr.substring(idx + 1);
196             Attributes JavaDoc attrs = getManifest().getAttributes(section);
197             if (attrs != null) {
198                 return NbBundle.getLocalizedValue(attrs, new Attributes.Name JavaDoc(realAttr));
199             } else {
200                 return null;
201             }
202         }
203     }
204     
205     public boolean owns(Class JavaDoc clazz) {
206         ClassLoader JavaDoc cl = clazz.getClassLoader();
207         if (cl instanceof Util.ModuleProvider) {
208             return ((Util.ModuleProvider) cl).getModule() == this;
209         }
210         return false;
211         
212     }
213     
214     public boolean isFixed() {
215         return false;
216     }
217     
218     /** Get the JAR this module is packaged in.
219      * May be null for modules installed specially, e.g.
220      * automatically from the classpath.
221      * @see #isFixed
222      */

223     public File JavaDoc getJarFile() {
224         return jar;
225     }
226     
227     /** Create a temporary test JAR if necessary.
228      * This is primarily necessary to work around a Java bug,
229      * #4405789, which is marked as fixed so might be obsolete.
230      */

231     private void ensurePhysicalJar() throws IOException JavaDoc {
232         if (reloadable && physicalJar == null) {
233             physicalJar = Util.makeTempJar(jar);
234         }
235     }
236     private void destroyPhysicalJar() {
237         if (physicalJar != null) {
238             if (physicalJar.isFile()) {
239                 if (! physicalJar.delete()) {
240                     Util.err.warning("temporary JAR " + physicalJar + " not currently deletable.");
241                 } else {
242                     Util.err.fine("deleted: " + physicalJar);
243                 }
244             }
245             physicalJar = null;
246         } else {
247             Util.err.fine("no physicalJar to delete for " + this);
248         }
249     }
250     
251     /** Open the JAR, load its manifest, and do related things. */
252     private void loadManifest() throws IOException JavaDoc {
253         Util.err.fine("loading manifest of " + jar);
254         File JavaDoc jarBeingOpened = null; // for annotation purposes
255
try {
256             if (reloadable) {
257                 // Never try to cache reloadable JARs.
258
jarBeingOpened = physicalJar; // might be null
259
ensurePhysicalJar();
260                 jarBeingOpened = physicalJar; // might have changed
261
JarFile JavaDoc jarFile = new JarFile JavaDoc(physicalJar, false);
262                 try {
263                     Manifest JavaDoc m = jarFile.getManifest();
264                     if (m == null) throw new IOException JavaDoc("No manifest found in " + physicalJar); // NOI18N
265
manifest = m;
266                 } finally {
267                     jarFile.close();
268                 }
269             } else {
270                 jarBeingOpened = jar;
271                 manifest = getManager().loadManifest(jar);
272             }
273         } catch (IOException JavaDoc e) {
274             if (jarBeingOpened != null) {
275                 Exceptions.attachMessage(e,
276                                          "While loading manifest from: " +
277                                          jarBeingOpened); // NOI18N
278
}
279             throw e;
280         }
281     }
282     
283     /** Find any extensions loaded by the module, as well as any localized
284      * variants of the module or its extensions.
285      */

286     private void findExtensionsAndVariants(Manifest JavaDoc m) {
287         assert jar != null : "Cannot load extensions from classpath module " + getCodeNameBase();
288         localeVariants = null;
289         List JavaDoc<File JavaDoc> l = Util.findLocaleVariantsOf(jar);
290         if (!l.isEmpty()) {
291             localeVariants = new HashSet JavaDoc<File JavaDoc>(l);
292         }
293         plainExtensions = null;
294         localeExtensions = null;
295         String JavaDoc classPath = m.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
296         if (classPath != null) {
297             StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(classPath);
298             while (tok.hasMoreTokens()) {
299                 String JavaDoc ext = tok.nextToken();
300                 if (new File JavaDoc(ext).isAbsolute() || ext.indexOf("../") != -1) { // NOI18N
301
Util.err.warning("Class-Path value " + ext + " from " + jar + " is illegal according to the Java Extension Mechanism: must be relative and not move up directories");
302                 }
303                 File JavaDoc extfile = new File JavaDoc(jar.getParentFile(), ext.replace('/', File.separatorChar));
304                 if (! extfile.exists()) {
305                     // Ignore unloadable extensions.
306
Util.err.warning("Class-Path value " + ext + " from " + jar + " cannot be found at " + extfile);
307                     continue;
308                 }
309                 //No need to sync on extensionOwners - we are in write mutex
310
Set JavaDoc<File JavaDoc> owners = extensionOwners.get(extfile);
311                     if (owners == null) {
312                         owners = new HashSet JavaDoc<File JavaDoc>(2);
313                         owners.add(jar);
314                         extensionOwners.put(extfile, owners);
315                     } else if (! owners.contains(jar)) {
316                         owners.add(jar);
317                         events.log(Events.EXTENSION_MULTIPLY_LOADED, extfile, owners);
318                     } // else already know about it (OK or warned)
319
// Also check to make sure it is not a module JAR! See constructor for the reverse case.
320
if (moduleJARs.contains(extfile)) {
321                     Util.err.warning("Class-Path value " + ext + " from " + jar + " illegally refers to another module; use OpenIDE-Module-Module-Dependencies instead");
322                 }
323                 if (plainExtensions == null) plainExtensions = new HashSet JavaDoc<File JavaDoc>();
324                 plainExtensions.add(extfile);
325                 l = Util.findLocaleVariantsOf(extfile);
326                 if (!l.isEmpty()) {
327                     if (localeExtensions == null) {
328                         localeExtensions = new HashSet JavaDoc<File JavaDoc>();
329                     }
330                     localeExtensions.addAll(l);
331                 }
332             }
333         }
334         // #9273: load any modules/patches/this-code-name/*.jar files first:
335
File JavaDoc patchdir = new File JavaDoc(new File JavaDoc(jar.getParentFile(), "patches"), // NOI18N
336
getCodeNameBase().replace('.', '-')); // NOI18N
337
scanForPatches(patchdir);
338         // Use of the following system property is not supported, but is used
339
// by e.g. XTest to influence installed modules without changing the build.
340
// Format is -Dnetbeans.patches.org.nb.mods.foo=/path/to.file.jar:/path/to/dir
341
String JavaDoc patchesClassPath = System.getProperty("netbeans.patches." + getCodeNameBase()); // NOI18N
342
if (patchesClassPath != null) {
343             StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(patchesClassPath, File.pathSeparator);
344             while (tokenizer.hasMoreTokens()) {
345                 String JavaDoc element = tokenizer.nextToken();
346                 File JavaDoc fileElement = new File JavaDoc(element);
347                 if (fileElement.exists()) {
348                     if (patches == null) {
349                         patches = new HashSet JavaDoc<File JavaDoc>(15);
350                     }
351                     patches.add(fileElement);
352                 }
353             }
354         }
355         Util.err.fine("localeVariants of " + jar + ": " + localeVariants);
356         Util.err.fine("plainExtensions of " + jar + ": " + plainExtensions);
357         Util.err.fine("localeExtensions of " + jar + ": " + localeExtensions);
358         Util.err.fine("patches of " + jar + ": " + patches);
359         if (patches != null) {
360             for (File JavaDoc patch : patches) {
361                 events.log(Events.PATCH, patch);
362             }
363         }
364     }
365     
366     /** Scans a directory for possible patch JARs. */
367     private void scanForPatches(File JavaDoc patchdir) {
368         if (!patchdir.isDirectory()) {
369             return;
370         }
371         File JavaDoc[] jars = patchdir.listFiles(Util.jarFilter());
372         if (jars != null) {
373             for (File JavaDoc jar : jars) {
374                 if (patches == null) {
375                     patches = new HashSet JavaDoc<File JavaDoc>(5);
376                 }
377                 patches.add(jar);
378             }
379         } else {
380             Util.err.warning("Could not search for patches in " + patchdir);
381         }
382     }
383     
384     /** Check if there is any need to load localized properties.
385      * If so, try to load them. Throw an exception if they cannot
386      * be loaded for some reason. Uses an open JAR file for the
387      * base module at least, though may also open locale variants
388      * as needed.
389      * Note: due to #19698, this cache is not usually used; only if you
390      * specifically go to look at the display properties of a disabled module.
391      * @see <a HREF="http://www.netbeans.org/issues/show_bug.cgi?id=12549">#12549</a>
392      */

393     private void loadLocalizedProps(JarFile JavaDoc jarFile, Manifest JavaDoc m) throws IOException JavaDoc {
394         String JavaDoc locbundle = m.getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N
395
if (locbundle != null) {
396             // Something requested, read it in.
397
// locbundle is a resource path.
398
{
399                 ZipEntry JavaDoc bundleFile = jarFile.getEntry(locbundle);
400                 // May not be present in base JAR: might only be in e.g. default locale variant.
401
if (bundleFile != null) {
402                     localizedProps = new Properties JavaDoc();
403                     InputStream JavaDoc is = jarFile.getInputStream(bundleFile);
404                     try {
405                         localizedProps.load(is);
406                     } finally {
407                         is.close();
408                     }
409                 }
410             }
411             {
412                 // Check also for localized variant JARs and load in anything from them as needed.
413
// Note we need to go in the reverse of the usual search order, so as to
414
// overwrite less specific bundles with more specific.
415
int idx = locbundle.lastIndexOf('.'); // NOI18N
416
String JavaDoc name, ext;
417                 if (idx == -1) {
418                     name = locbundle;
419                     ext = ""; // NOI18N
420
} else {
421                     name = locbundle.substring(0, idx);
422                     ext = locbundle.substring(idx);
423                 }
424                 List JavaDoc<Util.FileWithSuffix> pairs = Util.findLocaleVariantsWithSuffixesOf(jar);
425                 Collections.reverse(pairs);
426                 for (Util.FileWithSuffix pair : pairs) {
427                     File JavaDoc localeJar = pair.file;
428                     String JavaDoc suffix = pair.suffix;
429                     String JavaDoc rsrc = name + suffix + ext;
430                     JarFile JavaDoc localeJarFile = new JarFile JavaDoc(localeJar, false);
431                     try {
432                         ZipEntry JavaDoc bundleFile = localeJarFile.getEntry(rsrc);
433                         // Need not exist in all locale variants.
434
if (bundleFile != null) {
435                             if (localizedProps == null) {
436                                 localizedProps = new Properties JavaDoc();
437                             } // else append and overwrite base-locale values
438
InputStream JavaDoc is = localeJarFile.getInputStream(bundleFile);
439                             try {
440                                 localizedProps.load(is);
441                             } finally {
442                                 is.close();
443                             }
444                         }
445                     } finally {
446                         localeJarFile.close();
447                     }
448                 }
449             }
450             if (localizedProps == null) {
451                 // We should have loaded from at least some bundle in there...
452
throw new IOException JavaDoc("Could not find localizing bundle: " + locbundle); // NOI18N
453
}
454             /* Don't log; too large and annoying:
455             if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) {
456                 Util.err.fine("localizedProps=" + localizedProps);
457             }
458             */

459         }
460     }
461     
462     /** Get all JARs loaded by this module.
463      * Includes the module itself, any locale variants of the module,
464      * any extensions specified with Class-Path, any locale variants
465      * of those extensions.
466      * The list will be in classpath order (patches first).
467      * Currently the temp JAR is provided in the case of test modules, to prevent
468      * sporadic ZIP file exceptions when background threads (like Java parsing) tries
469      * to open libraries found in the library path.
470      * JARs already present in the classpath are <em>not</em> listed.
471      * @return a <code>List&lt;File&gt;</code> of JARs
472      */

473     public List JavaDoc<File JavaDoc> getAllJars() {
474         List JavaDoc<File JavaDoc> l = new ArrayList JavaDoc<File JavaDoc>();
475         if (patches != null) l.addAll(patches);
476         if (physicalJar != null) {
477             l.add(physicalJar);
478         } else if (jar != null) {
479             l.add(jar);
480         }
481         if (plainExtensions != null) l.addAll (plainExtensions);
482         if (localeVariants != null) l.addAll (localeVariants);
483         if (localeExtensions != null) l.addAll (localeExtensions);
484         return l;
485     }
486
487     /** Set whether this module is supposed to be reloadable.
488      * Has no immediate effect, only impacts what happens the
489      * next time it is enabled (after having been disabled if
490      * necessary).
491      * Must be called from within a write mutex.
492      * @param r whether the module should be considered reloadable
493      */

494     public void setReloadable(boolean r) {
495         getManager().assertWritable();
496         if (reloadable != r) {
497             reloadable = r;
498             getManager().fireReloadable(this);
499         }
500     }
501     
502     /** Used as a flag to tell if this module was really successfully released.
503      * Currently does not work, so if it cannot be made to work, delete it.
504      * (Someone seems to be holding a strong reference to the classloader--who?!)
505      */

506     private transient boolean released;
507     /** Count which release() call is really being checked. */
508     private transient int releaseCount = 0;
509
510     /** Reload this module. Access from ModuleManager.
511      * If an exception is thrown, the module is considered
512      * to be in an invalid state.
513      */

514     public void reload() throws IOException JavaDoc {
515         // Probably unnecessary but just in case:
516
destroyPhysicalJar();
517         String JavaDoc codeNameBase1 = getCodeNameBase();
518         localizedProps = null;
519         loadManifest();
520         parseManifest();
521         findExtensionsAndVariants(manifest);
522         String JavaDoc codeNameBase2 = getCodeNameBase();
523         if (! codeNameBase1.equals(codeNameBase2)) {
524             throw new InvalidException("Code name base changed during reload: " + codeNameBase1 + " -> " + codeNameBase2); // NOI18N
525
}
526     }
527     
528     // Access from ModuleManager:
529
/** Turn on the classloader. Passed a list of parent modules to use.
530      * The parents should already have had their classloaders initialized.
531      */

532     protected void classLoaderUp(Set JavaDoc<Module> parents) throws IOException JavaDoc {
533         Util.err.fine("classLoaderUp on " + this + " with parents " + parents);
534         // Find classloaders for dependent modules and parent to them.
535
List JavaDoc<ClassLoader JavaDoc> loaders = new ArrayList JavaDoc<ClassLoader JavaDoc>(parents.size() + 1);
536         // This should really be the base loader created by org.nb.Main for loading openide etc.:
537
loaders.add(Module.class.getClassLoader());
538         Iterator JavaDoc it = parents.iterator();
539         for (Module parent: parents) {
540             PackageExport[] exports = parent.getPublicPackages();
541             if (exports != null && exports.length == 0) {
542                 // Check if there is an impl dep here.
543
boolean implDep = false;
544                 for (Dependency dep : getDependenciesArray()) {
545                     if (dep.getType() == Dependency.TYPE_MODULE &&
546                             dep.getComparison() == Dependency.COMPARE_IMPL &&
547                             dep.getName().equals(parent.getCodeName())) {
548                         implDep = true;
549                         break;
550                     }
551                 }
552                 if (!implDep) {
553                     // Nothing exported from here at all, no sense even adding it.
554
// Shortcut; would not harm anything to add it now, but we would
555
// never use it anyway.
556
// Cf. #27853.
557
continue;
558                 }
559             }
560             ClassLoader JavaDoc l = parent.getClassLoader();
561             if (parent.isFixed() && loaders.contains(l)) {
562                 Util.err.fine("#24996: skipping duplicate classloader from " + parent);
563                 continue;
564             }
565             loaders.add(l);
566         }
567         List JavaDoc<Union2<File JavaDoc,JarFile JavaDoc>> classp = new ArrayList JavaDoc<Union2<File JavaDoc,JarFile JavaDoc>>(3);
568         if (patches != null) {
569             for (File JavaDoc f : patches) {
570                 if (f.isDirectory()) {
571                     classp.add(Union2.<File JavaDoc,JarFile JavaDoc>createFirst(f));
572                 } else {
573                     classp.add(Union2.<File JavaDoc,JarFile JavaDoc>createSecond(new JarFile JavaDoc(f, false)));
574                 }
575             }
576         }
577         if (reloadable) {
578             ensurePhysicalJar();
579             // Using OPEN_DELETE does not work well with test modules under 1.4.
580
// Random code (URL handler?) still expects the JAR to be there and
581
// it is not.
582
classp.add(Union2.<File JavaDoc,JarFile JavaDoc>createSecond(new JarFile JavaDoc(physicalJar, false)));
583         } else {
584             classp.add(Union2.<File JavaDoc,JarFile JavaDoc>createSecond(new JarFile JavaDoc(jar, false)));
585         }
586         // URLClassLoader would not otherwise find these, so:
587
if (localeVariants != null) {
588             for (File JavaDoc var : localeVariants) {
589                 classp.add(Union2.<File JavaDoc,JarFile JavaDoc>createSecond(new JarFile JavaDoc(var, false)));
590             }
591         }
592         if (localeExtensions != null) {
593             for (File JavaDoc ext : localeExtensions) {
594                 classp.add(ext.isDirectory() ?
595                     Union2.<File JavaDoc,JarFile JavaDoc>createFirst(ext) :
596                     Union2.<File JavaDoc,JarFile JavaDoc>createSecond(new JarFile JavaDoc(ext, false)));
597             }
598         }
599         if (plainExtensions != null) {
600             for (File JavaDoc ext : plainExtensions) {
601                 classp.add(ext.isDirectory() ?
602                     Union2.<File JavaDoc,JarFile JavaDoc>createFirst(ext) :
603                     Union2.<File JavaDoc,JarFile JavaDoc>createSecond(new JarFile JavaDoc(ext, false)));
604             }
605         }
606         
607         // #27853:
608
getManager().refineClassLoader(this, loaders);
609         
610         try {
611             classloader = new OneModuleClassLoader(classp, loaders.toArray(new ClassLoader JavaDoc[loaders.size()]));
612         } catch (IllegalArgumentException JavaDoc iae) {
613             // Should not happen, but just in case.
614
throw (IOException JavaDoc) new IOException JavaDoc(iae.toString()).initCause(iae);
615         }
616     }
617     
618     /** Turn off the classloader and release all resources. */
619     protected void classLoaderDown() {
620         if (classloader instanceof ProxyClassLoader) {
621             ((ProxyClassLoader)classloader).destroy();
622         }
623         classloader = null;
624         Util.err.fine("classLoaderDown on " + this + ": releaseCount=" + releaseCount + " released=" + released);
625         released = false;
626     }
627     /** Should be called after turning off the classloader of one or more modules & GC'ing. */
628     protected void cleanup() {
629         if (isEnabled()) throw new IllegalStateException JavaDoc("cleanup on enabled module: " + this); // NOI18N
630
if (classloader != null) throw new IllegalStateException JavaDoc("cleanup on module with classloader: " + this); // NOI18N
631
if (! released) {
632             Util.err.fine("Warning: not all resources associated with module " + jar + " were successfully released.");
633             released = true;
634         } else {
635             Util.err.fine("All resources associated with module " + jar + " were successfully released.");
636         }
637         // XXX should this rather be done when the classloader is collected?
638
destroyPhysicalJar();
639     }
640     
641     /** Notify the module that it is being deleted. */
642     public void destroy() {
643         moduleJARs.remove(jar);
644     }
645     
646     /** String representation for debugging. */
647     public String JavaDoc toString() {
648         String JavaDoc s = "StandardModule:" + getCodeNameBase() + " jarFile: " + jar.getAbsolutePath(); // NOI18N
649
if (!isValid()) s += "[invalid]"; // NOI18N
650
return s;
651     }
652     
653     /** PermissionCollection with an instance of AllPermission. */
654     private static PermissionCollection JavaDoc modulePermissions;
655     /** @return initialized @see #modulePermission */
656     private static synchronized PermissionCollection JavaDoc getAllPermission() {
657         if (modulePermissions == null) {
658             modulePermissions = new Permissions JavaDoc();
659             modulePermissions.add(new AllPermission JavaDoc());
660             modulePermissions.setReadOnly();
661         }
662         return modulePermissions;
663     }
664
665     /** Class loader to load a single module.
666      * Auto-localizing, multi-parented, permission-granting, the works.
667      */

668     private class OneModuleClassLoader extends JarClassLoader implements Util.ModuleProvider {
669         private int rc;
670         /** Create a new loader for a module.
671          * @param classp the List of all module jars of code directories;
672          * includes the module itself, its locale variants,
673          * variants of extensions and Class-Path items from Manifest.
674          * The items are JarFiles for jars and Files for directories
675          * @param parents a set of parent classloaders (from other modules)
676          */

677         public OneModuleClassLoader(List JavaDoc<Union2<File JavaDoc,JarFile JavaDoc>> classp, ClassLoader JavaDoc[] parents) throws IllegalArgumentException JavaDoc {
678             super(classp, parents, false);
679             rc = releaseCount++;
680         }
681         
682         public Module getModule() {
683             return StandardModule.this;
684         }
685         
686         /** Inherited.
687          * @param cs is ignored
688          * @return PermissionCollection with an AllPermission instance
689          */

690         protected PermissionCollection JavaDoc getPermissions(CodeSource JavaDoc cs) {
691             return getAllPermission();
692         }
693         
694         /** look for JNI libraries also in modules/bin/ */
695         protected String JavaDoc findLibrary(String JavaDoc libname) {
696             String JavaDoc mapped = System.mapLibraryName(libname);
697             File JavaDoc lib = new File JavaDoc(new File JavaDoc(jar.getParentFile(), "lib"), mapped); // NOI18N
698
if (lib.isFile()) {
699                 return lib.getAbsolutePath();
700             } else {
701                 return null;
702             }
703         }
704
705         protected boolean isSpecialResource(String JavaDoc pkg) {
706             if (mgr.isSpecialResource(pkg)) {
707                 return true;
708             }
709             return super.isSpecialResource(pkg);
710         }
711         
712         
713         protected boolean shouldDelegateResource(String JavaDoc pkg, ClassLoader JavaDoc parent) {
714             if (!super.shouldDelegateResource(pkg, parent)) {
715                 return false;
716             }
717             Module other;
718             if (parent instanceof Util.ModuleProvider) {
719                 other = ((Util.ModuleProvider)parent).getModule();
720             } else {
721                 other = null;
722             }
723             return getManager().shouldDelegateResource(StandardModule.this, other, pkg);
724         }
725         
726         public String JavaDoc toString() {
727             return super.toString() + "[" + getCodeNameBase() + "]"; // NOI18N
728
}
729
730         protected void finalize() throws Throwable JavaDoc {
731             super.finalize();
732             Util.err.fine("Finalize for " + this + ": rc=" + rc + " releaseCount=" + releaseCount + " released=" + released); // NOI18N
733
if (rc == releaseCount) {
734                 // Hurrah! release() worked.
735
released = true;
736             } else {
737                 Util.err.fine("Now resources for " + getCodeNameBase() + " have been released."); // NOI18N
738
}
739         }
740     }
741
742 }
743
Popular Tags