KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > core > LoaderPoolNode


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;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.beans.IntrospectionException JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.ObjectInputStream JavaDoc;
27 import java.io.ObjectOutputStream JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Arrays JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.Collections JavaDoc;
32 import java.util.Enumeration JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.HashSet JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.LinkedList JavaDoc;
37 import java.util.List JavaDoc;
38 import java.util.Map JavaDoc;
39 import java.util.Set JavaDoc;
40 import java.util.logging.Level JavaDoc;
41 import java.util.logging.Logger JavaDoc;
42 import javax.swing.Action JavaDoc;
43 import javax.swing.event.ChangeEvent JavaDoc;
44 import javax.swing.event.ChangeListener JavaDoc;
45 import org.netbeans.core.startup.ManifestSection;
46 import org.openide.actions.MoveDownAction;
47 import org.openide.actions.MoveUpAction;
48 import org.openide.actions.PropertiesAction;
49 import org.openide.actions.ReorderAction;
50 import org.openide.actions.ToolsAction;
51 import org.openide.filesystems.FileLock;
52 import org.openide.filesystems.FileObject;
53 import org.openide.filesystems.FileSystem;
54 import org.openide.filesystems.MIMEResolver;
55 import org.openide.filesystems.Repository;
56 import org.openide.loaders.DataLoader;
57 import org.openide.loaders.DataLoaderPool;
58 import org.openide.loaders.InstanceSupport;
59 import org.openide.modules.ModuleInfo;
60 import org.openide.modules.SpecificationVersion;
61 import org.openide.nodes.AbstractNode;
62 import org.openide.nodes.BeanNode;
63 import org.openide.nodes.Children;
64 import org.openide.nodes.Node;
65 import org.openide.util.HelpCtx;
66 import org.openide.util.Lookup;
67 import org.openide.util.LookupEvent;
68 import org.openide.util.LookupListener;
69 import org.openide.util.NbBundle;
70 import org.openide.util.RequestProcessor;
71 import org.openide.util.TopologicalSortException;
72 import org.openide.util.Utilities;
73 import org.openide.util.actions.SystemAction;
74 import org.openide.util.io.NbMarshalledObject;
75 import org.openide.util.io.NbObjectInputStream;
76 import org.openide.util.io.NbObjectOutputStream;
77
78 /** Node which represents loader pool and its content - all loaders
79 * in the system. LoaderPoolNode also supports subnode reordering.<P>
80 * LoaderPoolNode is singleton and that's why it can be obtained
81 * only via call to static factory method getLoaderPoolNode().<P>
82 * The same situation applies for NbLoaderPool inner class.
83 * @author Dafe Simonek et al.
84 */

85 public final class LoaderPoolNode extends AbstractNode {
86     /** The only instance of the LoaderPoolNode class in the system.
87     * This value is returned from the getLoaderPoolNode() static method */

88     private static LoaderPoolNode loaderPoolNode;
89     private static final Logger JavaDoc err =
90         Logger.getLogger("org.netbeans.core.LoaderPoolNode"); // NOI18N
91

92     private static LoaderChildren myChildren;
93
94     /** Array of DataLoader objects */
95     private static List JavaDoc<DataLoader> loaders = new ArrayList JavaDoc<DataLoader> ();
96     /** Those which have been modified since being read from the pool */
97     private static Set JavaDoc<DataLoader> modifiedLoaders = new HashSet JavaDoc<DataLoader>();
98     /** Loaders by class name */
99     private static Map JavaDoc<String JavaDoc,DataLoader> names2Loaders = new HashMap JavaDoc<String JavaDoc,DataLoader>(200);
100     /** Loaders by representation class name */
101     private static Map JavaDoc<String JavaDoc,DataLoader> repNames2Loaders = new HashMap JavaDoc<String JavaDoc,DataLoader>(200);
102
103     /** Map from loader class names to arrays of class names for Install-Before's */
104     private static Map JavaDoc<String JavaDoc,String JavaDoc[]> installBefores = new HashMap JavaDoc<String JavaDoc,String JavaDoc[]> ();
105     /** Map from loader class names to arrays of class names for Install-After's */
106     private static Map JavaDoc<String JavaDoc,String JavaDoc[]> installAfters = new HashMap JavaDoc<String JavaDoc,String JavaDoc[]> ();
107
108     /** copy of the loaders to prevent copying */
109     private static DataLoader[] loadersArray;
110
111     /** true if changes in loaders should be notified */
112     private static boolean installationFinished = false;
113     
114     /** if true, we are adding/removing a bunch of loaders; resort later */
115     private static boolean updatingBatch = false;
116     /** see above; true if at least one change */
117     private static boolean updatingBatchUsed = false;
118
119     /** Just workaround, need to pass instance of
120     * the LoaderPoolNodeChildren as two params to superclass
121     */

122     private LoaderPoolNode () {
123         super (new LoaderChildren ());
124         
125         myChildren = (LoaderChildren)getChildren ();
126         
127         setName("LoaderPoolNode"); // NOI18N
128
setDisplayName(NbBundle.getMessage(LoaderPoolNode.class, "CTL_LoaderPool"));
129
130         getCookieSet ().add (new Index ());
131         getCookieSet ().add (new InstanceSupport.Instance (getNbLoaderPool ()));
132     }
133
134     public HelpCtx getHelpCtx () {
135         return new HelpCtx (LoaderPoolNode.class);
136     }
137
138     /** Getter for set of actions that should be present in the
139     * popup menu of this node.
140     *
141     * @return array of system actions that should be in popup menu
142     */

143     public Action JavaDoc[] getActions(boolean context) {
144         return new Action JavaDoc[] {
145                    SystemAction.get(ReorderAction.class),
146                    null,
147                    SystemAction.get(ToolsAction.class),
148                    SystemAction.get(PropertiesAction.class),
149                };
150
151     }
152     
153     public static synchronized void beginUpdates() {
154         updatingBatch = true;
155         updatingBatchUsed = false;
156     }
157     public static synchronized void endUpdates() {
158         if (!updatingBatch) throw new IllegalStateException JavaDoc();
159         updatingBatch = false;
160         if (updatingBatchUsed) {
161             updatingBatchUsed = false;
162             resort();
163         }
164     }
165     
166     /** Allows tests to wait while processing of events is finished.
167      */

168     public static void waitFinished() {
169         getNbLoaderPool().fireTask.waitFinished();
170     }
171
172     /** Adds new loader when previous and following are specified.
173     * An attempt will be made to (re-)order the loader pool according to specified
174     * dependencies.
175     * <p>If a loader of the same class already existed in the pool, that will be <b>removed</b>
176     * and replaced with the new one.
177     * @param s adds loader section
178     */

179     public static void add (ManifestSection.LoaderSection s) throws Exception JavaDoc {
180         // the instantiation of the loader is done outside of synchronized block,
181
// because foreign code is called and can cause deadlocks
182
DataLoader l = (DataLoader)s.getInstance ();
183         doAdd (l, s);
184     }
185
186     /** Really adds the loader.
187      */

188     static synchronized void doAdd (DataLoader l, ManifestSection.LoaderSection s) throws Exception JavaDoc {
189         if (err.isLoggable(Level.FINE) && s != null) {
190             List JavaDoc before = s.getInstallBefore() == null ? null : Arrays.asList(s.getInstallBefore());
191             List JavaDoc after = s.getInstallAfter() == null ? null : Arrays.asList(s.getInstallAfter());
192             err.fine("add: " + l + " repclass: " + l.getRepresentationClass().getName() + " before: " + before + " after: " + after);
193         }
194         Iterator JavaDoc it = loaders.iterator ();
195         Class JavaDoc c = l.getClass();
196         while (it.hasNext ()) {
197             if (it.next ().getClass () == c) {
198                 it.remove ();
199                 break;
200             }
201         }
202         loaders.add (l);
203         l.removePropertyChangeListener (getNbLoaderPool ());
204         l.addPropertyChangeListener (getNbLoaderPool ());
205         
206         String JavaDoc cname = c.getName();
207         names2Loaders.put(cname, l);
208         repNames2Loaders.put(l.getRepresentationClassName(), l);
209         if (s != null) {
210             String JavaDoc[] ib = s.getInstallBefore();
211             if (ib != null) installBefores.put(cname, ib);
212             String JavaDoc[] ia = s.getInstallAfter();
213             if (ia != null) installAfters.put(cname, ia);
214         }
215         if (updatingBatch) {
216             updatingBatchUsed = true;
217         } else {
218             resort ();
219         }
220     }
221
222
223     /** Resort the loader pool according to stated dependencies.
224     * Attempts to keep a stable order whenever possible, i.e. more-recently-installed
225     * loaders will tend to stay near the end unless they need to be moved forward.
226     * Note that dependencies on nonexistent (or unloadable) representation classes are simply
227     * ignored and have no effect on ordering.
228     * If there is a cycle (contradictory set of dependencies) in the loader pool,
229     * its order is not changed.
230     * In any case, a change event is fired afterwards.
231     */

232     private static synchronized void resort () {
233         // A partial ordering over loaders based on their Install-* tags:
234
Map JavaDoc<DataLoader,List JavaDoc<DataLoader>> deps = new HashMap JavaDoc<DataLoader,List JavaDoc<DataLoader>>();
235         add2Deps(deps, installBefores, true);
236         add2Deps(deps, installAfters, false);
237         if (err.isLoggable(Level.FINE)) {
238             err.fine("Before sort: " + loaders);
239         }
240         
241         try {
242             loaders = Utilities.topologicalSort(loaders, deps);
243             if (err.isLoggable(Level.FINE)) {
244                 err.fine("After sort: " + loaders);
245             }
246         } catch (TopologicalSortException ex) {
247             err.log(Level.WARNING, null, ex);
248             err.warning("Contradictory loader ordering: " + deps); // NOI18N
249
}
250         update ();
251     }
252     /**
253      * Add to loader ordering dependencies.
254      * Only pays attention to dependencies among loaders that actually exist.
255      * @param deps a map from loaders to lists of loaders they must come before
256      * @param orderings either {@link #installBefore} or {@link #installAfter}
257      * @param before true if orderings refers to before, false if to after
258      * @see Utilities#topologicalSort
259      */

260     private static void add2Deps(Map JavaDoc<DataLoader,List JavaDoc<DataLoader>> deps, Map JavaDoc orderings, boolean before) {
261         Iterator JavaDoc it = orderings.entrySet().iterator();
262         while (it.hasNext()) {
263             Map.Entry JavaDoc e = (Map.Entry JavaDoc) it.next();
264             String JavaDoc loaderClassName = (String JavaDoc) e.getKey();
265             DataLoader l = names2Loaders.get(loaderClassName);
266
267             if (l == null) {
268                 throw new IllegalStateException JavaDoc("No such loader: " + loaderClassName); // NOI18N
269
}
270             String JavaDoc[] repClassNames = (String JavaDoc[]) e.getValue();
271
272             if (repClassNames == null) {
273                 throw new IllegalStateException JavaDoc("Null Install-" + (before ? "Before" : "After") + " for " + loaderClassName); // NOI18N
274
}
275             for (int i = 0; i < repClassNames.length; i++) {
276                 String JavaDoc repClassName = repClassNames[i];
277                 DataLoader l2 = repNames2Loaders.get(repClassName);
278
279                 if (l2 != null) {
280                     if (before) {
281                         addDep(deps, l, l2);
282                     }
283                     else {
284                         addDep(deps, l2, l);
285                     }
286                 }
287                 else {
288                     l2 = names2Loaders.get(repClassName);
289                     if (l2 != null) {
290                         warn(loaderClassName, repClassName,
291                              l2.getRepresentationClassName());
292                     }
293                 }
294             }
295         }
296     }
297     /**
298      * Add one loader ordering dependency.
299      * @param deps see {@link #add2Deps}
300      * @param a the earlier loader
301      * @param b the later loader
302      */

303     private static void addDep(Map JavaDoc<DataLoader,List JavaDoc<DataLoader>> deps, DataLoader a, DataLoader b) {
304         List JavaDoc<DataLoader> l = deps.get(a);
305         if (l == null) {
306             deps.put(a, l = new LinkedList JavaDoc<DataLoader>());
307         }
308         if (!l.contains(b)) {
309             l.add(b);
310         }
311     }
312     /**
313      * Warn about misuse of Install-{After,Before} to refer to loader class names rather
314      * than representation class names.
315      */

316     private static void warn(String JavaDoc yourLoader, String JavaDoc otherLoader, String JavaDoc otherRepn) {
317         err.warning("Warning: a possible error in the manifest containing " + yourLoader + " was found."); // NOI18N
318
err.warning("The loader specified an Install-{After,Before} on " + otherLoader + ", but this is a DataLoader class."); // NOI18N
319
err.warning("Probably you wanted " + otherRepn + " which is the loader's representation class."); // NOI18N
320
}
321
322     /** Notification to finish installation of nodes during startup.
323     */

324     static void installationFinished () {
325         installationFinished = true;
326         
327         if (myChildren != null) {
328             myChildren.update ();
329         }
330     }
331     
332     /** Checks whether a loader is modified. E.g. whether the loader
333      * considers it to be modified and necessary to be saved.
334      */

335     static synchronized boolean isModified (DataLoader l) {
336         return modifiedLoaders.contains (l);
337     }
338
339     /** Stores all the objects into stream.
340     * @param oos object output stream to write to
341     */

342     private static synchronized void writePool (ObjectOutputStream JavaDoc oos)
343     throws IOException JavaDoc {
344         if (err.isLoggable(Level.FINE)) err.fine("writePool");
345         // No longer bother storing these (#29671):
346
oos.writeObject (new HashMap JavaDoc()/*installBefores*/);
347         oos.writeObject (new HashMap JavaDoc()/*installAfters*/);
348         
349         // Note which module each loader came from.
350
Collection JavaDoc modules = Lookup.getDefault().lookupAll(ModuleInfo.class); // Collection<ModuleInfo>
351

352         Iterator JavaDoc it = loaders.iterator ();
353
354         while (it.hasNext ()) {
355             DataLoader l = (DataLoader)it.next ();
356             
357             if (!isModified (l)) {
358                 // #27190 - no real need to write this in detail.
359
String JavaDoc c = l.getClass().getName();
360                 if (err.isLoggable(Level.FINE)) err.fine("writing unmodified " + c);
361                 // '=' not a permissible part of a cnb, so this distinguishes it
362
oos.writeObject("=" + c); // NOI18N
363
continue;
364             }
365
366             NbMarshalledObject obj;
367             try {
368                 obj = new NbMarshalledObject (l);
369             } catch (IOException JavaDoc ex) {
370                 err.log(Level.WARNING, null, ex);
371                 obj = null;
372             }
373
374             if (obj != null) {
375                 if (err.isLoggable(Level.FINE)) err.fine("writing modified " + l.getClass().getName());
376                 // Find its module, if any.
377
Class JavaDoc c = l.getClass();
378                 Iterator JavaDoc mit = modules.iterator();
379                 boolean found = false;
380                 while (mit.hasNext()) {
381                     ModuleInfo m = (ModuleInfo)mit.next();
382                     if (m.isEnabled() && m.owns(c)) {
383                         if (err.isLoggable(Level.FINE)) err.fine("belongs to module: " + m.getCodeNameBase());
384                         oos.writeObject(m.getCodeNameBase());
385                         int r = m.getCodeNameRelease();
386                         oos.writeInt(r); // might be -1, note
387
SpecificationVersion v = m.getSpecificationVersion();
388                         if (v != null) {
389                             oos.writeObject(v.toString());
390                         } else {
391                             oos.writeObject(null);
392                         }
393                         found = true;
394                         break;
395                     }
396                 }
397                 if (!found) {
398                     if (err.isLoggable(Level.FINE)) err.fine("does not belong to any module");
399                     // just write the NbMarshalledObject<DataLoader> itself;
400
// we need to support that for compatibility of old loader
401
// pools anyway
402
}
403                 oos.writeObject (obj);
404             }
405         }
406         if (err.isLoggable(Level.FINE)) err.fine("writing null");
407         oos.writeObject (null);
408
409         // Write out system loaders now:
410
Enumeration JavaDoc e = getNbLoaderPool ().allLoaders ();
411         while (e.hasMoreElements ()) {
412             DataLoader l = (DataLoader) e.nextElement ();
413             if (loaders.contains (l)) continue;
414             if (!isModified (l)) {
415                 // #27190 again. No need to write anything
416
String JavaDoc c = l.getClass().getName();
417                 if (err.isLoggable(Level.FINE)) err.fine("skipping unmodified " + c);
418                 continue;
419             }
420             NbMarshalledObject obj;
421             try {
422                 obj = new NbMarshalledObject (l);
423             } catch (IOException JavaDoc ex) {
424                 err.log(Level.WARNING, null, ex);
425                 obj = null;
426             }
427             if (obj != null) {
428                 if (err.isLoggable(Level.FINE)) err.fine("writing " + l.getClass().getName());
429                 // No associated module, no need to write such info.
430
oos.writeObject (obj);
431             }
432         }
433         if (err.isLoggable(Level.FINE)) err.fine("writing null");
434         oos.writeObject (null);
435
436         if (err.isLoggable(Level.FINE)) err.fine("done writing");
437     }
438
439     /** Reads loader from the input stream.
440     * @param ois object input stream to read from
441     */

442     private static synchronized void readPool (ObjectInputStream JavaDoc ois)
443     throws IOException JavaDoc, ClassNotFoundException JavaDoc {
444         /*installBefores = (Map)*/ois.readObject ();
445         /*installAfters = (Map)*/ois.readObject ();
446
447         HashSet JavaDoc<Class JavaDoc> classes = new HashSet JavaDoc<Class JavaDoc> ();
448         LinkedList JavaDoc<DataLoader> l = new LinkedList JavaDoc<DataLoader> ();
449         
450         Iterator JavaDoc<? extends ModuleInfo> mit = Lookup.getDefault().lookupAll(ModuleInfo.class).iterator();
451         Map JavaDoc<String JavaDoc,ModuleInfo> modules = new HashMap JavaDoc<String JavaDoc,ModuleInfo>();
452         while (mit.hasNext()) {
453             ModuleInfo m = mit.next();
454             modules.put(m.getCodeNameBase(), m);
455         }
456
457         for (;;) {
458             Object JavaDoc o1 = ois.readObject();
459
460             if (o1 == null) {
461                 if (err.isLoggable(Level.FINE))
462                     err.fine("reading null");
463                 break;
464             }
465             NbMarshalledObject obj;
466
467             if (o1 instanceof String JavaDoc) {
468                 String JavaDoc name = (String JavaDoc)o1;
469                 if (name.length() > 0 && name.charAt(0) == '=') { // NOI18N
470
// #27190: unmodified loader, just here for the ordering.
471
String JavaDoc cname = name.substring(1);
472                     DataLoader dl = names2Loaders.get(cname);
473
474                     if (dl != null) {
475                         if (err.isLoggable(Level.FINE))
476                             err.fine("reading unmodified " + cname);
477                         l.add(dl);
478                         classes.add(dl.getClass());
479                     }
480                     else {
481                         // No such known loaded - presumably disabled module.
482
if (err.isLoggable(Level.FINE))
483                             err.fine("skipping unmodified nonexistent " + cname);
484                     }
485                     continue;
486                 }
487                 // Module information.
488
int rel = ois.readInt();
489                 String JavaDoc spec = (String JavaDoc) ois.readObject();
490
491                 obj = (NbMarshalledObject) ois.readObject();
492                 ModuleInfo m = modules.get(name);
493
494                 if (m == null) {
495                     if (err.isLoggable(Level.FINE))
496                         err.fine("No known module " + name + ", skipping loader");
497                     continue;
498                 }
499                 if (!m.isEnabled()) {
500                     if (err.isLoggable(Level.FINE))
501                         err.fine("Module " + name +
502                                  " is disabled, skipping loader");
503                     continue;
504                 }
505                 if (m.getCodeNameRelease() < rel) {
506                     if (err.isLoggable(Level.FINE))
507                         err.fine("Module " + name + " is too old (major vers.), skipping loader");
508                     continue;
509                 }
510                 if (spec != null) {
511                     SpecificationVersion v = m.getSpecificationVersion();
512
513                     if (v == null ||
514                         v.compareTo(new SpecificationVersion(spec)) < 0) {
515                         if (err.isLoggable(Level.FINE))
516                             err.fine("Module " + name + " is too old (spec. vers.), skipping loader");
517                         continue;
518                     }
519                 }
520                 if (err.isLoggable(Level.FINE))
521                     err.fine("Module " + name +
522                              " is OK, will try to restore loader");
523             }
524             else {
525                 // Loader with no known module, or backward compatibility.
526
obj = (NbMarshalledObject) o1;
527             }
528             Exception JavaDoc t = null;
529
530             try {
531                 DataLoader loader = (DataLoader) obj.get();
532
533                 if (loader == null) {
534                     // loader that wishes to be skipped (right now WSLoader from
535
// issue 38658)
536
continue;
537                 }
538                 Class JavaDoc clazz = loader.getClass();
539
540                 if (err.isLoggable(Level.FINE))
541                     err.fine("reading modified " + clazz.getName());
542                 l.add(loader);
543                 classes.add(clazz);
544             }
545             catch (IOException JavaDoc ex) {
546                 t = ex;
547             }
548             catch (ClassNotFoundException JavaDoc ex) {
549                 t = ex;
550             }
551         }
552
553         // Read system loaders. But not into any particular order.
554
for (;;) {
555             NbMarshalledObject obj = (NbMarshalledObject) ois.readObject ();
556             if (obj == null) {
557                 if (err.isLoggable(Level.FINE)) err.fine("reading null");
558                 break;
559             }
560             Exception JavaDoc t = null;
561             try {
562                 // Just reads its shared state, nothing more.
563
DataLoader loader = (DataLoader) obj.get ();
564                 if (err.isLoggable(Level.FINE)) err.fine("reading " + loader.getClass().getName());
565             } catch (IOException JavaDoc ex) {
566                 t = ex;
567             } catch (ClassNotFoundException JavaDoc ex) {
568                 t = ex;
569             }
570         }
571
572         if (err.isLoggable(Level.FINE)) err.fine("done reading");
573
574         // Explanation: modules are permitted to restoreDefault () before
575
// the loader pool is de-externalized. This means that all loader manifest
576
// sections will add a default-instance entry to the pool at startup
577
// time. Later, when the pool is restored, this may reorder existing ones,
578
// as well as change properties. But if any loader is missing (typically
579
// due to failed deserialization), it will nonetheless be added to the end
580
// now (and the pool resorted just in case).
581

582         Iterator JavaDoc it = loaders.iterator ();
583         while (it.hasNext ()) {
584             DataLoader loader = (DataLoader)it.next ();
585             if (!classes.contains (loader.getClass ())) {
586                 l.add (loader);
587             }
588         }
589         if (l.size() > new HashSet JavaDoc<DataLoader>(l).size()) throw new IllegalStateException JavaDoc("Duplicates in " + l); // NOI18N
590

591         loaders = l;
592         // Always "resort": if the existing order was in fact compatible with the
593
// current install-befores/afters, then this is no op (besides firing an
594
// update event). Cf. #29671.
595
resort ();
596         
597     }
598     
599     // I/O with loaders.ser; moved from NbProjectOperation:
600
public static void store() throws IOException JavaDoc {
601         FileObject ser = getLoaderPoolStorage(true);
602         FileLock lock = ser.lock();
603         try {
604             ObjectOutputStream JavaDoc oos = new NbObjectOutputStream(ser.getOutputStream(lock));
605             try {
606                 NbObjectOutputStream.writeSafely(oos, getNbLoaderPool());
607             } finally {
608                 oos.close();
609             }
610         } finally {
611             lock.releaseLock();
612         }
613     }
614     public static void load() throws IOException JavaDoc {
615         FileObject ser = getLoaderPoolStorage(false);
616         if (ser != null) {
617             ObjectInputStream JavaDoc ois = new NbObjectInputStream(ser.getInputStream());
618             try {
619                 NbObjectInputStream.readSafely(ois);
620             } finally {
621                 ois.close();
622             }
623         }
624     }
625     private static final String JavaDoc LOADER_POOL_NAME = "loaders.ser"; // NOI18N
626
public static FileObject getLoaderPoolStorage(boolean create) throws IOException JavaDoc {
627         FileSystem sfs = Repository.getDefault().getDefaultFileSystem();
628         FileObject fo = sfs.findResource(LOADER_POOL_NAME);
629         if (fo == null && create) {
630             fo = sfs.getRoot().createData(LOADER_POOL_NAME);
631         }
632         return fo;
633     }
634
635
636     /** Notification that the state of pool has changed
637     */

638     private static synchronized void update () {
639         if (err.isLoggable(Level.FINE)) err.fine("update");
640         // clear the cache of loaders
641
loadersArray = null;
642
643         NbLoaderPool lp = getNbLoaderPool();
644         if (lp != null && installationFinished) {
645             lp.superFireChangeEvent();
646         }
647         
648         if (lp != null) {
649             Enumeration JavaDoc e = lp.allLoaders();
650             while (e.hasMoreElements()) {
651                 DataLoader l = (DataLoader)e.nextElement();
652                 // so the pool is there only once
653
l.removePropertyChangeListener(lp);
654                 l.addPropertyChangeListener(lp);
655             }
656         }
657     }
658
659
660     /** Removes the loader. It is only removed from the list but
661     * if an DataObject instance created exists it will be still
662     * valid.
663     * <P>
664     * So the only difference is that when a DataObject is searched
665     * for a FileObject this loader will not be taken into account.
666     * <P>The loader pool may be resorted.
667     * @param dl data loader to remove
668     * @return true if the loader was registered and false if not
669     */

670     public static synchronized boolean remove (DataLoader dl) {
671         if (loaders.remove (dl)) {
672             if (err.isLoggable(Level.FINE)) err.fine("remove: " + dl);
673             String JavaDoc cname = dl.getClass().getName();
674             names2Loaders.remove(cname);
675             repNames2Loaders.remove(dl.getRepresentationClassName());
676             installBefores.remove(cname);
677             installAfters.remove(cname);
678             dl.removePropertyChangeListener (getNbLoaderPool ());
679         
680             if (updatingBatch) {
681                 updatingBatchUsed = true;
682             } else {
683                 resort ();
684             }
685             modifiedLoaders.remove(dl);
686             return true;
687         }
688         return false;
689     }
690
691     /** Returns the only instance of the loader pool node in our system.
692     * There's no other way to get an instance of this class,
693     * loader pool node is singleton.
694     * @return loader pool node instance
695     */

696     public static synchronized LoaderPoolNode getLoaderPoolNode () {
697         if (loaderPoolNode == null)
698             loaderPoolNode = new LoaderPoolNode();
699         return loaderPoolNode;
700     }
701
702     /** Returns the only instance of the loader pool in our system.
703     * There's no other way to get an instance of this class,
704     * loader pool is singleton too.
705     * @return loader pool instance
706     */

707     public static synchronized NbLoaderPool getNbLoaderPool () {
708         if (nbLoaderPool == null) {
709             nbLoaderPool = (NbLoaderPool)DataLoaderPool.getDefault ();
710         }
711         return nbLoaderPool;
712     }
713     private static NbLoaderPool nbLoaderPool = null;
714
715
716     /***** Inner classes **************/
717
718     /** Node representing one loader in Loader Pool */
719     private static class LoaderPoolItemNode extends BeanNode<DataLoader> {
720
721         /** true if a system loader */
722         boolean isSystem;
723
724         /**
725         * Constructs LoaderPoolItemNode for specified DataLoader.
726         *
727         * @param theBean bean for which we can construct BeanNode
728         * @param parent The parent of this node.
729         */

730         public LoaderPoolItemNode(DataLoader loader) throws IntrospectionException JavaDoc {
731             super(loader);
732             setSynchronizeName (false);
733             String JavaDoc displayName = getDisplayName();
734             setName(loader.getClass().getName());
735             isSystem = ! loaders.contains (loader);
736             if (isSystem) {
737                 setDisplayName(NbBundle.getMessage(LoaderPoolNode.class, "LBL_system_data_loader", displayName));
738             } else {
739                 setDisplayName(displayName);
740             }
741         }
742
743         /** Getter for set of actions that should be present in the
744         * popup menu of this node.
745         *
746         * @return array of system actions that should be in popup menu
747         */

748         public Action JavaDoc[] getActions(boolean context) {
749             if (isSystem)
750                 return new Action JavaDoc[] {
751                            SystemAction.get(ToolsAction.class),
752                            SystemAction.get(PropertiesAction.class),
753                        };
754             else
755                 return new Action JavaDoc[] {
756                            SystemAction.get(MoveUpAction.class),
757                            SystemAction.get(MoveDownAction.class),
758                            null,
759                            SystemAction.get(ToolsAction.class),
760                            SystemAction.get(PropertiesAction.class),
761                        };
762         }
763
764         /** @return true
765         */

766         public Action JavaDoc getPreferredAction() {
767             return SystemAction.get (PropertiesAction.class);
768         }
769
770         /** Cannot be deleted.
771          * Any deleted loaders would reappear after refresh anyway.
772         */

773         public boolean canDestroy () {
774             return false;
775         }
776
777         /** Cannot be copied
778         */

779         public boolean canCopy () {
780             return false;
781         }
782
783         /** Cannot be cut
784         */

785         public boolean canCut () {
786             return false;
787         }
788
789         public boolean canRename () {
790             return false;
791         }
792         
793         public HelpCtx getHelpCtx () {
794             HelpCtx help = super.getHelpCtx();
795             if (help == null || help.getHelpID() == null || help.getHelpID().equals(BeanNode.class.getName())) {
796                 help = new HelpCtx (LoaderPoolItemNode.class);
797             }
798             return help;
799         }
800     } // end of LoaderPoolItemNode
801

802     /** Implementation of children for LoaderPool node in explorer.
803     * Extends Index.MapChildren implementation to map nodes to loaders and to support
804     * children reordering.
805     */

806     private static final class LoaderChildren extends Children.Keys<DataLoader>
807     implements ChangeListener JavaDoc {
808         public LoaderChildren () {
809             update ();
810             getNbLoaderPool().addChangeListener(this);
811         }
812
813         /** Update the the nodes */
814         public void update () {
815             setKeys(Collections.list(getNbLoaderPool().allLoaders()));
816         }
817
818         /** Creates new node for the loader.
819         */

820         protected Node[] createNodes(DataLoader loader) {
821             try {
822                 return new Node[] {new LoaderPoolItemNode(loader)};
823             } catch (IntrospectionException JavaDoc e) {
824                 err.log(Level.WARNING, null, e);
825                 return new Node[] { };
826             }
827         }
828
829         public void stateChanged(ChangeEvent JavaDoc e) {
830             update();
831         }
832
833     } // end of LoaderPoolChildren
834

835     /** Concrete implementation of and abstract DataLoaderPool
836     * (former CoronaLoaderPool).
837     * Being a singleton, this class is private and the only system instance
838     * can be obtained via LoaderPoolNode.getNbLoaderPool() call.
839     * Delegates its work to the outer class LoaderPoolNode.
840     */

841     public static final class NbLoaderPool extends DataLoaderPool
842     implements PropertyChangeListener JavaDoc, Runnable JavaDoc, LookupListener {
843         private static final long serialVersionUID =-8488524097175567566L;
844
845         private transient RequestProcessor.Task fireTask;
846
847         private transient Lookup.Result mimeResolvers;
848         private static RequestProcessor rp = new RequestProcessor("Refresh Loader Pool"); // NOI18N
849

850         public NbLoaderPool() {
851             fireTask = rp.create(this, true);
852             mimeResolvers = Lookup.getDefault().lookupResult(MIMEResolver.class);
853             mimeResolvers.addLookupListener(this);
854         }
855
856         /** Enumerates all loaders. Loaders are taken from children
857         * structure of LoaderPoolNode. */

858         protected Enumeration JavaDoc<DataLoader> loaders () {
859
860             //
861
// prevents from extensive copying
862
//
863

864             DataLoader[] arr = loadersArray;
865             if (arr == null) {
866                 synchronized (LoaderPoolNode.class) {
867                     arr = loadersArray = loaders.toArray (new DataLoader[loaders.size()]);
868                 }
869             }
870             return org.openide.util.Enumerations.array (arr);
871         }
872
873         /** Listener to property changes.
874         */

875         public void propertyChange (PropertyChangeEvent JavaDoc ev) {
876             DataLoader l = (DataLoader)ev.getSource();
877             String JavaDoc prop = ev.getPropertyName ();
878             if (DataLoader.PROP_ACTIONS.equals (prop) && ev.getNewValue () == null) {
879                 // skip this change as this means the loader is using new storage mechanism
880
return;
881             }
882             modifiedLoaders.add(l);
883             if (err.isLoggable(Level.FINE)) err.fine("Got change in " + l.getClass().getName() + "." + prop);
884             if (DataLoader.PROP_ACTIONS.equals (prop) || DataLoader.PROP_DISPLAY_NAME.equals (prop))
885                 return; // these are not important to the pool, i.e. to file recognition
886
if (installationFinished) {
887                 superFireChangeEvent ();
888             }
889         }
890
891         /** Fires change event to all listeners
892         * (Delegates all work to its superclass)
893         * Accessor for inner classes only.
894         * @param che change event
895         */

896         void superFireChangeEvent () {
897             err.fine("Change in loader pool scheduled"); // NOI18N
898
fireTask.schedule (1000);
899         }
900
901         /** Called from the request task */
902         public void run () {
903             err.fine("going to fire change in loaders"); // NOI18N
904
super.fireChangeEvent(new ChangeEvent JavaDoc (this));
905             err.fine("change event fired"); // NOI18N
906
}
907
908
909         /** Write the object.
910         */

911         private void writeObject (ObjectOutputStream JavaDoc oos) throws IOException JavaDoc {
912             LoaderPoolNode.writePool (oos);
913         }
914
915         /** Reads the object.
916         */

917         private void readObject (ObjectInputStream JavaDoc ois)
918         throws IOException JavaDoc, ClassNotFoundException JavaDoc {
919             LoaderPoolNode.readPool (ois);
920         }
921
922         /** Replaces the pool with default instance.
923         */

924         private Object JavaDoc readResolve () {
925             return getNbLoaderPool ();
926         }
927
928         public void resultChanged(LookupEvent ev) {
929             if (org.netbeans.core.startup.Main.isInitialized()) {
930                 superFireChangeEvent();
931             }
932         }
933     } // end of NbLoaderPool
934

935     /** Index support for reordering of file system pool.
936     */

937     private final class Index extends org.openide.nodes.Index.Support {
938         
939         Index() {}
940         
941         /** Get the nodes; should be overridden if needed.
942         * @return the nodes
943         * @throws NotImplementedException always
944         */

945         public Node[] getNodes () {
946             Enumeration JavaDoc e = getChildren ().nodes ();
947             List JavaDoc<Node> l = new ArrayList JavaDoc<Node> ();
948             while (e.hasMoreElements ()) {
949                 LoaderPoolItemNode node = (LoaderPoolItemNode) e.nextElement ();
950                 if (! node.isSystem) l.add (node);
951             }
952             return l.toArray (new Node[l.size ()]);
953         }
954
955         /** Get the node count. Subclasses must provide this.
956         * @return the count
957         */

958         public int getNodesCount () {
959             return getNodes ().length;
960         }
961
962         /** Reorder by permutation. Subclasses must provide this.
963         * @param perm the permutation
964         */

965         public void reorder (int[] perm) {
966             synchronized (LoaderPoolNode.class) {
967                 DataLoader[] arr = loaders.toArray (new DataLoader[loaders.size()]);
968
969                 if (arr.length == perm.length) {
970                     DataLoader[] target = new DataLoader[arr.length];
971                     for (int i = 0; i < arr.length; i++) {
972                         if (target[perm[i]] != null) {
973                             throw new IllegalArgumentException JavaDoc ();
974                         }
975                         target[perm[i]] = arr[i];
976                     }
977
978                     loaders = new ArrayList JavaDoc<DataLoader> (Arrays.asList (target));
979                     update ();
980                 } else {
981                     throw new IllegalArgumentException JavaDoc ();
982                 }
983             }
984         }
985
986     } // End of Index
987

988 }
989
Popular Tags