KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > core > startup > ModuleSystem


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.core.startup;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.io.File JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.net.MalformedURLException JavaDoc;
28 import java.net.URL JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.Collections JavaDoc;
32 import java.util.Enumeration JavaDoc;
33 import java.util.HashSet JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.List JavaDoc;
36 import java.util.Set JavaDoc;
37 import java.util.jar.Attributes JavaDoc;
38 import java.util.jar.Manifest JavaDoc;
39 import java.util.logging.Level JavaDoc;
40 import org.netbeans.DuplicateException;
41 import org.netbeans.Events;
42 import org.netbeans.Module;
43 import org.netbeans.ModuleManager;
44 import org.netbeans.Util;
45 import org.openide.filesystems.FileObject;
46 import org.openide.filesystems.FileSystem;
47 import org.openide.util.Exceptions;
48
49 /** Controller of the IDE's whole module system.
50  * Contains higher-level convenience methods to
51  * access the basic functionality and procedural
52  * stages of the module system.
53  * The NbTopManager should hold a reference to one instance.
54  * Methods are thread-safe.
55  * @author Jesse Glick
56  */

57 public final class ModuleSystem {
58     private final ModuleManager mgr;
59     private final NbInstaller installer;
60     private final ModuleList list;
61     private final Events ev;
62     
63     /** Initialize module system.
64      * The system file system is needed as that holds the Modules/ folder.
65      * Note if the systemFileSystem is read-only, no module list will be created,
66      * so it is forbidden to call readList, scanForNewAndRestore, or installNew.
67      */

68     public ModuleSystem(FileSystem systemFileSystem) throws IOException JavaDoc {
69         if (Boolean.getBoolean("org.netbeans.core.startup.ModuleSystem.CULPRIT")) Thread.dumpStack(); // NOI18N
70
ev = Boolean.getBoolean("netbeans.modules.quiet") ? (Events)new QuietEvents() : new NbEvents();
71         installer = new NbInstaller(ev);
72         mgr = new ModuleManager(installer, ev);
73         PropertyChangeListener JavaDoc l = new PropertyChangeListener JavaDoc() {
74             public void propertyChange(PropertyChangeEvent JavaDoc ev) {
75                 if (ModuleManager.PROP_CLASS_LOADER.equals(ev.getPropertyName())) {
76                     org.netbeans.core.startup.MainLookup.systemClassLoaderChanged(mgr.getClassLoader());
77                 }
78             }
79         };
80         mgr.addPropertyChangeListener(l);
81         
82         // now initialize to core/* classloader, later we reassign to all modules
83
org.netbeans.core.startup.MainLookup.systemClassLoaderChanged(installer.getClass ().getClassLoader ());
84         // #28465: initialize module lookup early
85
org.netbeans.core.startup.MainLookup.moduleLookupReady(mgr.getModuleLookup());
86         if (systemFileSystem.isReadOnly()) {
87             list = null;
88         } else {
89             FileObject root = systemFileSystem.getRoot();
90             FileObject modulesFolder = root.getFileObject("Modules"); // NOI18N
91
if (modulesFolder == null) {
92                 modulesFolder = root.createFolder("Modules"); // NOI18N
93
}
94             list = new ModuleList(mgr, modulesFolder, ev);
95             installer.registerList(list);
96             installer.registerManager(mgr);
97         }
98         ev.log(Events.CREATED_MODULE_SYSTEM);
99     }
100     
101     /** Get the raw module manager.
102      * Useful for pieces of the UI needing to directly affect the set of installed modules.
103      * For example, the Modules node in the Options window may use this.
104      */

105     public ModuleManager getManager() {
106         return mgr;
107     }
108     
109     /** Get the event-logging handler.
110      */

111     public Events getEvents() {
112         return ev;
113     }
114     
115     /** Produce a list of JAR files including all installed modules,
116      * their extensions, and enabled locale variants of both.
117      * Will be returned in a classpath-like order.
118      * Intended for use by the execution engine (though sort of deprecated).
119      * @return list of module-related JARs/ZIPs
120      */

121     public List JavaDoc<File JavaDoc> getModuleJars () {
122         mgr.mutexPrivileged().enterReadAccess();
123         try {
124             List JavaDoc<File JavaDoc> l = new ArrayList JavaDoc<File JavaDoc>();
125             for (Module m: mgr.getEnabledModules()) {
126                 l.addAll(m.getAllJars());
127             }
128             return l;
129         } finally {
130             mgr.mutexPrivileged().exitReadAccess();
131         }
132     }
133
134     /** We just make the modules now, restore them later
135      * to optimize the layer merge.
136      */

137     private Set JavaDoc<Module> bootModules = null;
138     
139     /** Load modules found in the classpath.
140      * Note that they might not satisfy all their dependencies, in which
141      * case oh well...
142      */

143     public void loadBootModules() {
144         // Keep a list of manifest URL prefixes which we know we do not need to
145
// parse. Some of these manifests might be signed, and if so, we do not
146
// want to touch them, as it slows down startup quite a bit.
147
Collection JavaDoc<String JavaDoc> ignoredPrefixes = new ArrayList JavaDoc<String JavaDoc>(3); // List<String>
148
try {
149             // skip the JDK/JRE libraries
150
String JavaDoc jdk = System.getProperty("java.home");
151             if (jdk.endsWith(File.separator + "jre")) { // NOI18N
152
jdk = jdk.substring(0, jdk.length() - 4);
153             }
154             File JavaDoc f = new File JavaDoc(jdk);
155             if (new File JavaDoc(new File JavaDoc(f, "lib"), "tools.jar").isFile()) { // NOI18N
156
// #74287: do not ignore in case we are using an embedded JRE!
157
ignoredPrefixes.add("jar:" + f.toURI().toURL()); // NOI18N
158
}
159             // skip $nbhome/lib/ext/*.jar; all fixes modules should be in
160
// $nbhome/lib/ (or perhaps elsewhere, with -cp:a)
161
String JavaDoc nbhomeS = System.getProperty("netbeans.home");
162             if (nbhomeS != null) {
163                 File JavaDoc nbhome = new File JavaDoc(nbhomeS);
164                 f = new File JavaDoc(new File JavaDoc(nbhome, "lib"), "ext"); // NOI18N
165
ignoredPrefixes.add("jar:" + f.toURI().toURL()); // NOI18N
166
}
167         } catch (MalformedURLException JavaDoc e) {
168             Util.err.log(Level.WARNING, null, e);
169         }
170         Util.err.log(Level.FINE, "ignoredPrefixes={0}", ignoredPrefixes);
171         
172         mgr.mutexPrivileged().enterWriteAccess();
173         ev.log(Events.START_LOAD_BOOT_MODULES);
174         try {
175             bootModules = new HashSet JavaDoc<Module>(10);
176             ClassLoader JavaDoc loader = ModuleSystem.class.getClassLoader();
177             Enumeration JavaDoc<URL JavaDoc> e = loader.getResources("META-INF/MANIFEST.MF"); // NOI18N
178
ev.log(Events.PERF_TICK, "got all manifests"); // NOI18N
179

180             // There will be duplicates: cf. #32576.
181
Set JavaDoc<URL JavaDoc> checkedManifests = new HashSet JavaDoc<URL JavaDoc>();
182             MANIFESTS:
183             while (e.hasMoreElements()) {
184                 URL JavaDoc manifestUrl = e.nextElement();
185                 if (!checkedManifests.add(manifestUrl)) {
186                     // Already seen, ignore.
187
continue;
188                 }
189                 String JavaDoc manifestUrlS = manifestUrl.toExternalForm();
190                 for (String JavaDoc pref: ignoredPrefixes) {
191                     if (manifestUrlS.startsWith(pref)) {
192                         Util.err.log(Level.FINE, "ignoring JDK/JRE manifest: {0}", manifestUrlS);
193                         continue MANIFESTS;
194                     }
195                 }
196                 Util.err.log(Level.FINE, "Checking boot manifest: {0}", manifestUrlS);
197                 
198                 InputStream JavaDoc is;
199                 try {
200                     is = manifestUrl.openStream();
201                 } catch (IOException JavaDoc ioe) {
202                     // Debugging for e.g. #32493 - which JAR was guilty?
203
Exceptions.attachMessage(ioe, "URL: " + manifestUrl); // NOI18N
204
throw ioe;
205                 }
206                 try {
207                     Manifest JavaDoc mani = new Manifest JavaDoc(is);
208                     Attributes JavaDoc attr = mani.getMainAttributes();
209                     if (attr.getValue("OpenIDE-Module") == null) { // NOI18N
210
// Not a module.
211
continue;
212                     }
213                     bootModules.add(mgr.createFixed(mani, manifestUrl, loader));
214                 } finally {
215                     is.close();
216                 }
217             }
218             if (list == null) {
219                 // Plain calling us, we have to install now.
220
// Do it the simple way.
221
mgr.enable(bootModules);
222             }
223             ev.log(Events.PERF_TICK, "added all classpath modules"); // NOI18N
224

225         } catch (IOException JavaDoc ioe) {
226             // Note: includes also InvalidException's for malformed this and that.
227
// Probably if a bootstrap module is corrupt we are in pretty bad shape
228
// anyway, so don't bother trying to be fancy and install just some of
229
// them etc.
230
Util.err.log(Level.WARNING, null, ioe);
231         } catch (DuplicateException de) {
232             Util.err.log(Level.WARNING, null, de);
233         } finally {
234             // Not 100% accurate in this case:
235
ev.log(Events.FINISH_LOAD_BOOT_MODULES);
236             mgr.mutexPrivileged().exitWriteAccess();
237         }
238     }
239     
240     /** Read disk settings and determine what the known modules are.
241      */

242     public void readList() {
243         ev.log(Events.PERF_START, "ModuleSystem.readList"); // NOI18N
244
mgr.mutexPrivileged().enterWriteAccess();
245         try {
246             list.readInitial();
247         } finally {
248             mgr.mutexPrivileged().exitWriteAccess();
249         }
250     ev.log(Events.PERF_END, "ModuleSystem.readList"); // NOI18N
251
}
252     
253     /** Install read modules.
254      */

255     public void restore() {
256     ev.log(Events.PERF_START, "ModuleSystem.restore"); // NOI18N
257
mgr.mutexPrivileged().enterWriteAccess();
258         try {
259             Set JavaDoc<Module> toTrigger = new HashSet JavaDoc<Module>(bootModules/*Collections.EMPTY_SET*/);
260             list.trigger(toTrigger);
261         } finally {
262             mgr.mutexPrivileged().exitWriteAccess();
263         }
264     ev.log(Events.PERF_END, "ModuleSystem.restore"); // NOI18N
265
}
266     
267     /** Shut down the system: ask modules to shut down.
268      * Some of them may refuse.
269      */

270     public boolean shutDown(Runnable JavaDoc midHook) {
271         mgr.mutexPrivileged().enterWriteAccess();
272         try {
273             return mgr.shutDown(midHook);
274         } finally {
275             mgr.mutexPrivileged().exitWriteAccess();
276         }
277     }
278     
279     /** Load a module in test (reloadable) mode.
280      * If there is an existing module with a different JAR, get
281      * rid of it and load this one instead.
282      * If it is already installed, disable it and reenable it
283      * to reload its contents.
284      * If other modules depend on it, disable them first and
285      * then (try to) enable them again later.
286      */

287     final void deployTestModule(File JavaDoc jar) throws IOException JavaDoc {
288         if (! jar.isAbsolute()) throw new IOException JavaDoc("Absolute paths only please"); // NOI18N
289
mgr.mutexPrivileged().enterWriteAccess();
290         ev.log(Events.START_DEPLOY_TEST_MODULE, jar);
291         // For now, just print to stderr directly; could also go thru Events.
292
// No need for I18N, module developers are expected to know English
293
// well enough.
294
System.err.println("Deploying test module " + jar + "..."); // NOI18N
295
try {
296             // The test module:
297
Module tm = null;
298             // Anything that needs to be turned back on later:
299
Set JavaDoc<Module> toReenable = new HashSet JavaDoc<Module>();
300             // First see if this refers to an existing module.
301
// (If so, make sure it is reloadable.)
302
Iterator JavaDoc it = mgr.getModules().iterator();
303             while (it.hasNext()) {
304                 Module m = (Module)it.next();
305                 if (m.getJarFile() != null) {
306                     if (jar.equals(m.getJarFile())) {
307                         // Hah, found it.
308
if (! m.isReloadable()) {
309                             m.setReloadable(true);
310                         }
311                         turnOffModule(m, toReenable);
312                         mgr.reload(m);
313                         tm = m;
314                         break;
315                     }
316                 }
317             }
318             if (tm == null) {
319                 // This JAR not encountered before. Try to load it. If it is
320
// a duplicate of an existing module in a different location,
321
// kill the existing one and replace it with this one.
322
try {
323                     tm = mgr.create(jar, new ModuleHistory(jar.getAbsolutePath()), true, false, false);
324                 } catch (DuplicateException dupe) {
325                     Module old = dupe.getOldModule();
326                     System.err.println("Replacing old module in " + old); // NOI18N
327
turnOffModule(old, toReenable);
328                     mgr.delete(old);
329                     try {
330                         tm = mgr.create(jar, new ModuleHistory(jar.getAbsolutePath()), true, false, false);
331                     } catch (DuplicateException dupe2) {
332                         // Should not happen.
333
throw (IOException JavaDoc) new IOException JavaDoc(dupe2.toString()).initCause(dupe2);
334                     }
335                 }
336             }
337             // Try to turn on the test module. It might throw InvalidExc < IOExc.
338
System.err.println("Enabling " + tm + "..."); // NOI18N
339
if (!mgr.simulateEnable(Collections.singleton(tm)).contains(tm)) {
340                 throw new IOException JavaDoc("Cannot enable " + tm + "; problems: " + tm.getProblems());
341             }
342             mgr.enable(tm);
343             // OK, so far so good; also try to turn on any other modules if
344
// we can that were on before. Just try to turn them all on.
345
// Don't get fancy; if some of them could not be turned on, the
346
// developer will be told and can clean up the situation as needed.
347
// Also any of them marked as reloadable, reload them now.
348
if (! toReenable.isEmpty()) {
349                 System.err.println("Also re-enabling:"); // NOI18N
350
it = toReenable.iterator();
351                 while (it.hasNext()) {
352                     Module m = (Module)it.next();
353                     System.err.println("\t" + m.getDisplayName()); // NOI18N
354
if (m.isReloadable()) {
355                         m.reload();
356                     }
357                 }
358                 try {
359                     mgr.enable(toReenable);
360                 } catch (IllegalArgumentException JavaDoc iae) {
361                     // Strange new dependencies, etc.
362
throw new IOException JavaDoc(iae.toString());
363                 }
364             }
365             System.err.println("Done."); // NOI18N
366
} finally {
367             ev.log(Events.FINISH_DEPLOY_TEST_MODULE, jar);
368             mgr.mutexPrivileged().exitWriteAccess();
369         }
370     }
371     /** Make sure some module is disabled.
372      * If there were any other non-autoload modules enabled
373      * which depended on it, make note of them.
374      */

375     private void turnOffModule(Module m, Set JavaDoc<Module> toReenable) {
376         if (! m.isEnabled()) {
377             // Already done.
378
return;
379         }
380         for (Module m2: mgr.simulateDisable(Collections.<Module>singleton(m))) {
381             if (!m2.isAutoload() && !m2.isEager()) {
382                 toReenable.add(m2);
383             }
384         }
385         try {
386             System.err.println("Disabling " + m + "..."); // NOI18N
387
// Don't mention the others, they will be mentioned later anyway.
388
mgr.disable(toReenable);
389         } finally {
390             toReenable.remove(m);
391         }
392     }
393     
394     /** Get the effective "classpath" used by a module.
395      * <p>This is a somewhat stretched notion, but should give something that looks
396      * as much like a classpath as possible, i.e. a list of directories or JARs
397      * separated by the standard separator, which roughly represents what resources
398      * are visible to the module's classloader. May use special syntax to represent
399      * situations in which only certain packages are available from a particular
400      * "classpath" entry.
401      * <p>Disabled modules have no classpath (empty string).
402      * <p>Call within a mutex.
403      * @param m the module to build a classpath for
404      * @return an approximation of that module's classpath
405      * @see "#22466"
406      * @since org.netbeans.core/1 > 1.5
407      */

408     public String JavaDoc getEffectiveClasspath(Module m) {
409         return installer.getEffectiveClasspath(m);
410     }
411     
412     /** Dummy event handler that does not print anything.
413      * Useful for test scripts where you do not really want to see
414      * everything going by.
415      */

416     private static final class QuietEvents extends Events {
417         QuietEvents() {}
418         protected void logged(String JavaDoc message, Object JavaDoc[] args) {}
419     }
420
421 }
422
Popular Tags