KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > autoupdate > catalog > ModuleBean


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.modules.autoupdate.catalog;
21
22 import java.awt.Component JavaDoc;
23 import java.util.logging.Logger JavaDoc;
24 import org.netbeans.core.NbTopManager;
25 import org.netbeans.core.startup.*;
26 import org.netbeans.*;
27 import java.util.*;
28 import javax.swing.SwingUtilities JavaDoc;
29 import org.openide.modules.SpecificationVersion;
30 import java.io.File JavaDoc;
31 import java.beans.*;
32 import org.openide.*;
33 import java.io.IOException JavaDoc;
34 import java.util.logging.Level JavaDoc;
35 import org.openide.util.*;
36
37 /** Bean representing a module.
38  * Mirrors its properties but provides safe access from the event thread.
39  * Also permits delayed write access, again safe to initiate from the event thread.
40  * These changes are batched and auto-validating.
41  * @author Jesse Glick
42  */

43 public final class ModuleBean implements Runnable JavaDoc, PropertyChangeListener {
44     
45     private static final Logger JavaDoc err = Logger.getLogger("org.netbeans.modules.autoupdate.catalog.ModuleBean"); // NOI18N
46

47     private final Module module;
48     
49     private String JavaDoc codeName;
50     private String JavaDoc codeNameBase;
51     private String JavaDoc specVers;
52     private String JavaDoc implVers;
53     private String JavaDoc buildVers;
54     private String JavaDoc[] provides;
55     private File JavaDoc jar;
56     private boolean enabled;
57     private boolean reloadable;
58     private boolean autoload;
59     private boolean eager;
60     private boolean problematic;
61     private String JavaDoc[] problemDescriptions;
62     private String JavaDoc displayName;
63     private String JavaDoc shortDescription;
64     private String JavaDoc longDescription;
65     private String JavaDoc category;
66     private String JavaDoc classpath;
67     
68     /** Must be created within mutex. */
69     private ModuleBean(Module m) {
70         module = m;
71         loadProps();
72         module.addPropertyChangeListener(WeakListeners.propertyChange(this, module));
73     }
74     
75     /** If necessary, get the underlying module. */
76     public Module getModule() {
77         return module;
78     }
79     
80     private void loadProps() {
81         if (SwingUtilities.isEventDispatchThread()) throw new IllegalStateException JavaDoc();
82         err.log(Level.FINE, "loadProps: module=" + module);
83         if (! module.isValid()) {
84             err.log(Level.FINE, "invalid, forget it...");
85             return;
86         }
87         // Set fields. Called inside read mutex.
88
codeName = module.getCodeName();
89         codeNameBase = module.getCodeNameBase();
90         SpecificationVersion sv = module.getSpecificationVersion();
91         specVers = (sv == null ? null : sv.toString());
92         implVers = module.getImplementationVersion ();
93         buildVers = module.getBuildVersion ();
94         provides = module.getProvides();
95         jar = module.getJarFile();
96         enabled = module.isEnabled();
97         reloadable = module.isReloadable();
98         autoload = module.isAutoload();
99         eager = module.isEager();
100         Set problems = module.getProblems();
101         problematic = !problems.isEmpty();
102         if (problematic) {
103             problemDescriptions = new String JavaDoc[problems.size()];
104             Iterator it = problems.iterator();
105             int i = 0;
106             while (it.hasNext()) {
107                 problemDescriptions[i++] = NbProblemDisplayer.messageForProblem(module, it.next());
108             }
109         } else {
110             problemDescriptions = null;
111         }
112         err.log (Level.FINE, "IZ #82480: Module.getJarFile() " + module.getJarFile () + // NOI18N
113
(module.getJarFile () != null ? " exists " + Boolean.toString (module.getJarFile ().exists ()) : "")); // NOI18N
114
displayName = module.getDisplayName();
115         shortDescription = (String JavaDoc)module.getLocalizedAttribute("OpenIDE-Module-Short-Description"); // NOI18N
116
longDescription = (String JavaDoc)module.getLocalizedAttribute("OpenIDE-Module-Long-Description"); // NOI18N
117
category = (String JavaDoc)module.getLocalizedAttribute("OpenIDE-Module-Display-Category"); // NOI18N
118
classpath = NbTopManager.getUninitialized().getModuleSystem().getEffectiveClasspath(module);
119     }
120     
121     /** Get the code name. */
122     public String JavaDoc getCodeName() {
123         return codeName;
124     }
125     
126     /** Get the code name base. */
127     public String JavaDoc getCodeNameBase() {
128         return codeNameBase;
129     }
130     
131     /** Get the specification version, or null. */
132     public String JavaDoc getSpecificationVersion() {
133         return specVers;
134     }
135     
136     /** Get the implementation version, or null. */
137     public String JavaDoc getImplementationVersion() {
138         return implVers;
139     }
140     
141     /** Get the build version, or null. */
142     public String JavaDoc getBuildVersion() {
143         return buildVers;
144     }
145     
146     /** Get a list of provided tokens (never null, maybe empty). */
147     public String JavaDoc[] getProvides() {
148         return provides;
149     }
150     
151     /** Get the module JAR file, or null. */
152     public File JavaDoc getJar() {
153         return jar;
154     }
155     
156     /** Get the module JAR cluster, or null if unknown or inapplicable. */
157     public File JavaDoc getCluster() {
158         if (jar != null) {
159             File JavaDoc p = jar.getParentFile();
160             if (p != null && p.getName().matches("eager|autoload")) { // NOI18N
161
p = p.getParentFile();
162             }
163             if (p != null && p.getName().matches("modules|lib|core")) { // NOI18N
164
return p.getParentFile();
165             }
166         }
167         return null;
168     }
169     
170     /** Test whether the module is enabled. */
171     public boolean isEnabled() {
172         return enabled;
173     }
174     
175     /** Enable/disable the module. */
176     public void setEnabled(boolean e) {
177         if (enabled == e) return;
178         if (jar == null || autoload || eager || problematic) throw new IllegalStateException JavaDoc();
179         err.log(Level.FINE, "setEnabled: module=" + module + " enabled=" + e);
180         enabled = e; // optimistic change
181
supp.firePropertyChange("enabled", null, null); // NOI18N
182
Update u = new Update(e ? "enable" : "disable", module); // NOI18N
183
AllModulesBean.getDefault().update(u);
184     }
185     
186     /** Test whether the module is a library module. */
187     public boolean isAutoload() {
188         return autoload;
189     }
190     
191     /** Test whether the module is a bridge module. */
192     public boolean isEager() {
193         return eager;
194     }
195     
196     /** Test whether the module is reloadable. */
197     public boolean isReloadable() {
198         return reloadable;
199     }
200     
201     /** Set whether the module is reloadable. */
202     public void setReloadable(boolean r) {
203         // XXX sanity-check
204
if (reloadable == r) return;
205         err.log(Level.FINE,
206                 "setReloadable: module=" + module + " reloadable=" + r);
207         reloadable = r; // optimistic change
208
supp.firePropertyChange("reloadable", null, null); // NOI18N
209
Update u = new Update(r ? "makeReloadable" : "makeUnreloadable", module); // NOI18N
210
AllModulesBean.getDefault().update(u);
211     }
212     
213     /** Delete the module. */
214     public void delete() {
215         if (jar == null) throw new IllegalStateException JavaDoc();
216         err.log(Level.FINE, "delete: module=" + module);
217         Update u = new Update("delete", module); // NOI18N
218
AllModulesBean.getDefault().update(u);
219     }
220     
221     /** Test whether the module has problems with installation. */
222     public boolean isProblematic() {
223         return problematic;
224     }
225     
226     /**
227      * Get a list of descriptions of each problem in the module (if it has any).
228      * Each item will be a localized phrase.
229      * @return a nonempty array of explanations if {@link #isProblematic}, null otherwise
230      * @see NbProblemDisplayer#messageForProblem
231      * @see "#16636"
232      */

233     public String JavaDoc[] getProblemDescriptions() {
234         return problemDescriptions;
235     }
236     
237     /** Get the display name. */
238     public String JavaDoc getDisplayName() {
239         return displayName;
240     }
241     
242     /** Get the short description, or null. */
243     public String JavaDoc getShortDescription() {
244         return shortDescription;
245     }
246     
247     /** Get the long description, or null. */
248     public String JavaDoc getLongDescription() {
249         return longDescription;
250     }
251     
252     /** Get the display category, or null. */
253     public String JavaDoc getCategory() {
254         return category;
255     }
256     
257     /** Get the effective classpath for this module.
258      * May be the empty string for a disabled module.
259      * @see ModuleSystem#getEffectiveClasspath
260      * @see "#22466"
261      */

262     public String JavaDoc getEffectiveClasspath() {
263         return classpath;
264     }
265     
266     private final PropertyChangeSupport supp = new PropertyChangeSupport(this);
267     
268     /** Listen to changes in bean properties. */
269     public void addPropertyChangeListener(PropertyChangeListener l) {
270         supp.removePropertyChangeListener(l);
271         supp.addPropertyChangeListener(l);
272     }
273     
274     /** Stop listening to changes in bean properties. */
275     public void removePropertyChangeListener(PropertyChangeListener l) {
276         supp.removePropertyChangeListener(l);
277     }
278     
279     public void propertyChange(PropertyChangeEvent evt) {
280         if (SwingUtilities.isEventDispatchThread()) throw new IllegalStateException JavaDoc();
281         // Something on the module changed. Inside read mutex.
282
err.log(Level.FINE, "got changes: module=" + module + " evt=" + evt);
283         if (/* #13834 */ evt != null && Module.PROP_CLASS_LOADER.equals(evt.getPropertyName())) {
284             err.log(Level.FINE, "ignoring PROP_CLASS_LOADER");
285             // Speed optimization.
286
return;
287         }
288         loadProps();
289         SwingUtilities.invokeLater(this);
290     }
291     
292     public void run() {
293         if (! SwingUtilities.isEventDispatchThread()) throw new IllegalStateException JavaDoc();
294         // Inside event thread after a change.
295
err.log(Level.FINE, "firing changes: module=" + module);
296         supp.firePropertyChange(null, null, null);
297         ModuleSelectionPanel.getGUI (false).setWaitingState (false, false);
298     }
299     
300     // ModuleNode uses these as keys, so make sure even if recreated after change
301
// in list of modules that the node selection is retained. Cf. #23757 however:
302

303     public boolean equals(Object JavaDoc o) {
304         return (o instanceof ModuleBean) &&
305             codeNameBase.equals(((ModuleBean)o).codeNameBase);
306     }
307     
308     public int hashCode() {
309         return 35632846 ^ codeNameBase.hashCode();
310     }
311     
312     public String JavaDoc toString() {
313         return "ModuleBean[" + codeNameBase + "]"; // NOI8N
314
}
315     
316     public static final class AllModulesBean implements Runnable JavaDoc, PropertyChangeListener, Comparator {
317         
318         private static AllModulesBean deflt = null;
319         /** Get the bean representing all modules. */
320         public static synchronized AllModulesBean getDefault() {
321             if (deflt == null) deflt = new AllModulesBean();
322             return deflt;
323         }
324         private AllModulesBean() {}
325         
326         private final ModuleManager mgr = NbTopManager.getUninitialized().getModuleSystem().getManager();
327         private final Events ev = NbTopManager.getUninitialized().getModuleSystem().getEvents();
328         
329         private final PropertyChangeSupport supp = new PropertyChangeSupport(this);
330         
331         /** Listen to changes in the list of modules or whether there are pending updates. */
332         public void addPropertyChangeListener(PropertyChangeListener l) {
333             supp.removePropertyChangeListener(l);
334             supp.addPropertyChangeListener(l);
335         }
336         
337         /** Stop listening to changes in the list of modules and whether there are pending updates. */
338         public void removePropertyChangeListener(PropertyChangeListener l) {
339             supp.removePropertyChangeListener(l);
340         }
341         
342         private ModuleBean[] modules = null;
343         
344         private Task recalcTask = null;
345         
346         /** Get the list of all modules. */
347         public synchronized ModuleBean[] getModules() {
348             err.log(Level.FINE,
349                     "getModules: modules count=" +
350                     (modules == null ? "null"
351                                      : String.valueOf(modules.length)));
352             if (modules == null) {
353                 recalcTask = RequestProcessor.getDefault().post(new Reader());
354                 modules = new ModuleBean[0];
355                 return modules;
356             } else {
357                 return modules/*.clone()*/;
358             }
359         }
360         
361         /** Get a task representing the need to get all modules.
362          * When it is finished (if it is not already), they will be ready.
363          * It is <em>not</em> guaranteed that changes will have been fired to
364          * listeners by the time this task finishes.
365          */

366         public synchronized Task waitForModules() {
367             getModules();
368             if (recalcTask != null) {
369                 return recalcTask;
370             } else {
371                 return Task.EMPTY;
372             }
373         }
374         
375         /** Create a new module from JAR file, perhaps reloadable. */
376         public void create(File JavaDoc jar, boolean reloadable) {
377             err.log(Level.FINE, "create: jar=" + jar);
378             Update u = new Update(reloadable ? "createReloadable" : "create", jar); // NOI18N
379
update(u);
380         }
381         
382         private class Reader implements Runnable JavaDoc {
383             private boolean theother = false;
384             Reader() {}
385             /** Called first in request processor, then pushed to read mutex,
386              * to read list of modules.
387              */

388             public void run() {
389                 if (SwingUtilities.isEventDispatchThread()) throw new IllegalStateException JavaDoc();
390                 if (! theother) {
391                     err.log(Level.FINE, "will load modules in read mutex...");
392                     Reader r = new Reader();
393                     r.theother = true;
394                     mgr.mutex().readAccess(r);
395                     return;
396                 }
397                 err.log(Level.FINE, "first time, finding module list");
398                 // First time. We are in read mutex and need to find out what is here.
399
Set modulesSet = mgr.getModules();
400                 ModuleBean[] _modules = new ModuleBean[modulesSet.size()];
401                 Iterator it = modulesSet.iterator();
402                 int i = 0;
403                 while (it.hasNext()) {
404                     Module m = (Module)it.next();
405                     _modules[i++] = new ModuleBean(m);
406                 }
407                 synchronized (AllModulesBean.this) {
408                     modules = _modules;
409                     recalcTask = null;
410                 }
411                 // Listen for further changes.
412
mgr.addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange(AllModulesBean.this, mgr));
413                 // Relative to the initial list of zero modules, something 'has changed'.
414
SwingUtilities.invokeLater(AllModulesBean.this);
415             }
416         }
417         
418         public void run() {
419             if (! SwingUtilities.isEventDispatchThread()) throw new IllegalStateException JavaDoc();
420             err.log(Level.FINE, "in event thread, will fire changes");
421             // Something changed and now we are in the event thread.
422
// (Either list of modules or pending changes or both.)
423
supp.firePropertyChange(null, null, null);
424         }
425         
426         public void propertyChange(PropertyChangeEvent evt) {
427             if (SwingUtilities.isEventDispatchThread()) throw new IllegalStateException JavaDoc();
428             err.log(Level.FINE, "got changes: evt=" + evt);
429             ModuleSelectionPanel.getGUI (false).setWaitingState (true, true);
430             if (ModuleManager.PROP_MODULES.equals(evt.getPropertyName())) {
431                 // Later on. Something changed. Again in read mutex.
432
Map modules2Beans = new HashMap(modules.length * 4 / 3 + 1);
433                 for (int i = 0; i < modules.length; i++) {
434                     modules2Beans.put(modules[i].getModule(), modules[i]);
435                 }
436                 Set modulesSet = mgr.getModules();
437                 ModuleBean[] themodules = new ModuleBean[modulesSet.size()];
438                 Iterator it = modulesSet.iterator();
439                 int i = 0;
440                 while (it.hasNext()) {
441                     Module m = (Module)it.next();
442                     ModuleBean existing = (ModuleBean)modules2Beans.get(m);
443                     if (existing == null) existing = new ModuleBean(m);
444                     themodules[i++] = existing;
445                 }
446                 synchronized (this) {
447                     modules = themodules;
448                 }
449                 // Fire changes later.
450
SwingUtilities.invokeLater(this);
451             }
452         }
453         
454         private final List<Update> updates = new LinkedList<Update>();
455         
456         private boolean paused = false;
457         
458         private Runnable JavaDoc updater = new Updater();
459         
460         private RequestProcessor.Task updaterTask = new RequestProcessor ("module-bean-updater").create (updater);
461         
462         /** Pause any pending updates for later. */
463         public void pause() {
464             err.log(Level.FINE, "pause");
465             paused = true;
466         }
467         
468         /** Resume any previously paused updates. */
469         public void resume() {
470             err.log(Level.FINE, "resume");
471             paused = false;
472             updaterTask.schedule (0);
473         }
474         
475         /** Cancel any previously posted updates (whether paused or not). */
476         public void cancel() {
477             err.log(Level.FINE, "cancel");
478             synchronized (updates) {
479                 updates.clear();
480             }
481             paused = false;
482             supp.firePropertyChange("pending", null, null); // NOI18N
483
}
484         
485         /** Test whether there are any pending updates (whether paused or not). */
486         public boolean isPending() {
487             synchronized (updates) {
488                 return ! updates.isEmpty();
489             }
490         }
491         
492         /** Called from event thread.
493          * Access only from within this class or from ModuleBean.
494          */

495         void update(Update u) {
496             synchronized (updates) {
497                 // If nonempty, we are already waiting for it...
498
boolean runme = updates.isEmpty();
499                 updates.add(u);
500                 err.log(Level.FINE, "pending updates: " + updates);
501                 if (runme) {
502                     updaterTask.schedule (0);
503                 }
504             }
505             supp.firePropertyChange("pending", null, null); // NOI18N
506
}
507         
508         private class Updater implements Runnable JavaDoc {
509             Updater() {}
510             /** Called from request processor to actually perform updates.
511              * Or from the write mutex if isWriteAccess().
512              */

513             public void run() {
514                 if (SwingUtilities.isEventDispatchThread()) throw new IllegalStateException JavaDoc();
515                 if (! mgr.mutex ().isWriteAccess ()) {
516                     err.log(Level.FINE, "saving all documents...");
517                     org.openide.LifecycleManager.getDefault ().saveAll ();
518                     err.log(Level.FINE, "will run updates in write mutex...");
519                     mgr.mutex().writeAccess(this);
520                     return;
521                 }
522                 try {
523                     if (paused) {
524                         err.log(Level.FINE, "run updates, but paused");
525                         return;
526                     }
527                     ModuleSelectionPanel.getGUI (false).setWaitingState (true, true);
528                     Set toEnable = new HashSet(); // Set<Module>
529
Set toDisable = new HashSet(); // Set<Module>
530
Set toMakeReloadable = new HashSet(); // Set<Module>
531
Set toMakeUnreloadable = new HashSet(); // Set<Module>
532
Set toDelete = new HashSet(); // Set<Module>
533
Set toCreate = new HashSet(); // Set<File>
534
Set toCreateReloable = new HashSet(); // Set<File>
535
Iterator it;
536                     synchronized (updates) {
537                         if (updates.isEmpty()) {
538                             err.log(Level.FINE, "run updates, but empty");
539                             return;
540                         }
541                         err.log(Level.FINE, "run updates: " + updates);
542                         it = new LinkedList(updates).iterator();
543                         updates.clear();
544                     }
545                     while (it.hasNext()) {
546                         Update u = (Update)it.next();
547                         if (u.command.equals("enable")) { // NOI18N
548
if (toDelete.contains(u.arg)) throw new IllegalStateException JavaDoc();
549                             toDisable.remove(u.arg);
550                             toEnable.add(u.arg);
551                         } else if (u.command.equals("disable")) { // NOI18N
552
if (toDelete.contains(u.arg)) throw new IllegalStateException JavaDoc();
553                             toEnable.remove(u.arg);
554                             toDisable.add(u.arg);
555                         } else if (u.command.equals("makeReloadable")) { // NOI18N
556
if (toDelete.contains(u.arg)) throw new IllegalStateException JavaDoc();
557                             toMakeUnreloadable.remove(u.arg);
558                             toMakeReloadable.add(u.arg);
559                         } else if (u.command.equals("makeUnreloadable")) { // NOI18N
560
if (toDelete.contains(u.arg)) throw new IllegalStateException JavaDoc();
561                             toMakeReloadable.remove(u.arg);
562                             toMakeUnreloadable.add(u.arg);
563                         } else if (u.command.equals("delete")) { // NOI18N
564
toEnable.remove(u.arg);
565                             toDisable.remove(u.arg); // will always be disabled anyway
566
toMakeReloadable.remove(u.arg);
567                             toMakeUnreloadable.remove(u.arg);
568                             toDelete.add(u.arg);
569                         } else if (u.command.equals("create")) { // NOI18N
570
toCreateReloable.remove(u.arg);
571                             toCreate.add(u.arg);
572                         } else if (u.command.equals("createReloadable")) { // NOI18N
573
toCreate.remove(u.arg);
574                             toCreateReloable.add(u.arg);
575                         } else {
576                             throw new IllegalStateException JavaDoc();
577                         }
578                     }
579                     doDelete(toDelete);
580                     doDisable(toDisable, true);
581                     it = toMakeReloadable.iterator();
582                     while (it.hasNext()) {
583                         Module m = (Module)it.next();
584                         m.setReloadable(true);
585                     }
586                     it = toMakeUnreloadable.iterator();
587                     while (it.hasNext()) {
588                         Module m = (Module)it.next();
589                         m.setReloadable(false);
590                     }
591                     doEnable(toEnable);
592                     doCreate(toCreate, false);
593                     doCreate(toCreateReloable, true);
594                 } catch (RuntimeException JavaDoc re) {
595                     Exceptions.printStackTrace(re);
596                     // Never know. Revert everything to real state just in case.
597
// #17873: if not inited, no need...
598
ModuleBean[] _modules = modules;
599                     if (_modules != null) {
600                         for (int i = 0; i < _modules.length; i++) {
601                             _modules[i].propertyChange(null);
602                         }
603                     }
604                 } finally {
605                     ModuleSelectionPanel.getGUI (false).setWaitingState (false, true);
606                 }
607                 // Fire a change in pending property.
608
SwingUtilities.invokeLater(AllModulesBean.this);
609             }
610             
611         }
612         
613         // Actual command to do certain kinds of updates, called within
614
// write mutex and should take care of their own UI. Note that it
615
// is OK to block on the event thread here indirectly, by means of
616
// calling TopManager.notify and waiting for the result.
617

618         private void doDelete(Set modules) {
619             if (modules.isEmpty()) return;
620             err.log(Level.FINE, "doDelete: " + modules);
621             // Have to be turned off first:
622
doDisable(modules, false);
623             Iterator it = modules.iterator();
624             while (it.hasNext()) {
625                 Module m = (Module)it.next();
626                 if (m.isFixed()) {
627                     // Hmm, ignore.
628
continue;
629                 }
630                 mgr.delete(m);
631             }
632         }
633         
634         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
635             Module m1 = (Module)o1;
636             Module m2 = (Module)o2;
637             int i = m1.getDisplayName().compareTo(m2.getDisplayName());
638             if (i != 0) {
639                 return i;
640             } else {
641                 return m1.getCodeNameBase().compareTo(m2.getCodeNameBase());
642             }
643         }
644
645         private void doDisable(Set modules, boolean cancelable) {
646             if (modules.isEmpty()) return;
647             err.log(Level.FINE, "doDisable: " + modules);
648             SortedSet realModules = new TreeSet(this); // SortedSet<Module>
649
realModules.addAll(modules);
650             Iterator it = realModules.iterator();
651             while (it.hasNext()) {
652                 Module m = (Module)it.next();
653                 if (!m.isEnabled() || m.isAutoload() || m.isEager() || m.isFixed()) {
654                     // In here by mistake, ignore.
655
it.remove();
656                 }
657             }
658             List toDisable = mgr.simulateDisable(realModules);
659             // Check if there are any non-autoloads/eagers added.
660
it = toDisable.iterator();
661             SortedSet others = new TreeSet(this); // SortedSet<Module>
662
while (it.hasNext()) {
663                 Module m = (Module)it.next();
664                 if (!m.isAutoload() && !m.isEager() && !realModules.contains(m)) {
665                     others.add(m);
666                 }
667             }
668             if (! others.isEmpty()) {
669                 Component JavaDoc c = new ModuleEnableDisablePanel(false, realModules, others);
670                 // component's accessibility will be used for Dialog accessibility
671
c.getAccessibleContext().setAccessibleName(NbBundle.getMessage(ModuleBean.class, "ACSN_TITLE_disabling"));
672                 c.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(ModuleBean.class, "ACSD_TITLE_disabling"));
673                 NotifyDescriptor d = new NotifyDescriptor.Confirmation(c,
674                     NbBundle.getMessage(ModuleBean.class, "MB_TITLE_disabling"),
675                     cancelable ? NotifyDescriptor.YES_NO_OPTION : NotifyDescriptor.DEFAULT_OPTION);
676                 if (org.openide.DialogDisplayer.getDefault().notify(d) != NotifyDescriptor.YES_OPTION) {
677                     // User refused.
678
// Fire changes again since modules are now wrong & need recalc.
679
ModuleBean[] _modules = this.modules;
680                     if (_modules != null) {
681                         for (int i = 0; i < _modules.length; i++) {
682                             if (realModules.contains(_modules[i].module)) {
683                                 _modules[i].propertyChange(null);
684                             }
685                         }
686                     }
687                     return;
688                 }
689                 realModules.addAll(others);
690             }
691             // Ready to go.
692
mgr.disable(realModules);
693         }
694         
695         private void doEnable(Set modules) {
696             if (modules.isEmpty()) return;
697             err.log(Level.FINE, "doEnable: " + modules);
698             SortedSet realModules = new TreeSet(this); // SortedSet<Module>
699
realModules.addAll(modules);
700             Iterator it = realModules.iterator();
701             while (it.hasNext()) {
702                 Module m = (Module)it.next();
703                 if (m.isEnabled() || m.isAutoload() || m.isEager() || m.isFixed() || ! m.getProblems().isEmpty()) {
704                     // In here by mistake, ignore.
705
it.remove();
706                 }
707             }
708             List toEnable = mgr.simulateEnable(realModules);
709             // Check if there are any non-autoloads/eagers added.
710
it = toEnable.iterator();
711             SortedSet others = new TreeSet(this); // SortedSet<Module>
712
while (it.hasNext()) {
713                 Module m = (Module)it.next();
714                 if (!m.isAutoload() && !m.isEager() && !realModules.contains(m)) {
715                     others.add(m);
716                 }
717             }
718             if (! others.isEmpty()) {
719                 Component JavaDoc c = new ModuleEnableDisablePanel(true, realModules, others);
720                 // component's accessibility will be used for Dialog accessibility
721
c.getAccessibleContext().setAccessibleName(NbBundle.getMessage(ModuleBean.class, "ACSN_TITLE_disabling"));
722                 c.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(ModuleBean.class, "ACSD_TITLE_disabling"));
723                 NotifyDescriptor d = new NotifyDescriptor.Confirmation(c,
724                     NbBundle.getMessage(ModuleBean.class, "MB_TITLE_enabling"),
725                     NotifyDescriptor.YES_NO_OPTION);
726                 if (org.openide.DialogDisplayer.getDefault().notify(d) != NotifyDescriptor.YES_OPTION) {
727                     // User refused.
728
// Fire changes again since modules are now wrong & need recalc.
729
ModuleBean[] _modules = this.modules;
730                     if (_modules != null) {
731                         for (int i = 0; i < _modules.length; i++) {
732                             if (realModules.contains(_modules[i].module)) {
733                                 _modules[i].propertyChange(null);
734                             }
735                         }
736                     }
737                     return;
738                 }
739                 realModules.addAll(others);
740             }
741             // Ready to go. First reload any test modules.
742
it = toEnable.iterator();
743             while (it.hasNext()) {
744                 Module m = (Module)it.next();
745                 if (m.isReloadable()) {
746                     try {
747                         mgr.reload(m);
748                     } catch (IOException JavaDoc ioe) {
749                         Exceptions.printStackTrace(ioe);
750                         // Refresh all.
751
ModuleBean[] _modules = this.modules;
752                         if (_modules != null) {
753                             for (int i = 0; i < _modules.length; i++) {
754                                 if (realModules.contains(_modules[i].module)) {
755                                     _modules[i].propertyChange(null);
756                                 }
757                             }
758                         }
759                         return;
760                     }
761                 }
762             }
763             try {
764                 mgr.enable(realModules);
765             } catch (InvalidException ie) {
766                 err.log(Level.WARNING, null, ie);
767                 Module bad = ie.getModule();
768                 if (bad == null) throw new IllegalStateException JavaDoc();
769                 ev.log(Events.FAILED_INSTALL_NEW_UNEXPECTED, new Object JavaDoc[] { bad, ie });
770                 // Refresh it.
771
ModuleBean[] _modules = this.modules;
772                 if (_modules != null) {
773                     for (int i = 0; i < _modules.length; i++) {
774                         if (_modules[i].module == bad) {
775                             _modules[i].propertyChange(null);
776                         }
777                     }
778                 }
779                 // Try to enable a subset this time.
780
realModules.remove(ie.getModule());
781                 doEnable(realModules);
782             }
783         }
784         
785         private void doCreate(Set files, boolean reloadable) {
786             if (files.isEmpty()) return;
787             err.log(Level.FINE,
788                     "doCreate: " + files + " reloadable=" + reloadable);
789             Iterator it = files.iterator();
790             while (it.hasNext()) {
791                 File JavaDoc jar = (File JavaDoc)it.next();
792                 Module nue;
793                 try {
794                     nue = mgr.create(jar, new ModuleHistory(jar.getAbsolutePath()), reloadable, false, false);
795                 } catch (IOException JavaDoc ioe) {
796                     DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Exception(ioe));
797                     continue;
798                 } catch (DuplicateException dupe) {
799                     // Replace the old one.
800
Module old = dupe.getOldModule();
801                     if (old.isFixed()) {
802                         // Cannot replace it.
803
continue;
804                     }
805                     if (old.isEnabled()) {
806                         // Need to turn it off first.
807
if (old.isAutoload() || old.isEager()) {
808                             // Hmm, too complicated to deal with now. Skip it.
809
continue;
810                         }
811                         doDisable(Collections.singleton(old), true);
812                         if (old.isEnabled()) {
813                             // Did not work for some reason, skip it.
814
continue;
815                         }
816                     }
817                     mgr.delete(old);
818                     try {
819                         nue = mgr.create(jar, new ModuleHistory(jar.getAbsolutePath()), reloadable, false, false);
820                     } catch (IOException JavaDoc ioe) {
821                         DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Exception(ioe));
822                         continue;
823                     } catch (DuplicateException dupe2) {
824                         // Huh??
825
Exceptions.printStackTrace(dupe2);
826                         continue;
827                     }
828                 }
829                 // Now turn it on.
830
if (nue.getProblems().isEmpty()) {
831                     doEnable(Collections.singleton(nue));
832                     // If it did not work, just leave it there disabled, user
833
// can delete if desired.
834
} else {
835                     // Cannot install, make sure user knows about it!
836
ev.log(Events.FAILED_INSTALL_NEW, new Object JavaDoc[] { Collections.singleton(nue) });
837                 }
838             }
839         }
840         
841         // Inter-module dependencies; see #22504.
842
// Cumbersome to do with the property + change model used for simple
843
// properties of modules, because these properties may be expensive
844
// to compute and might never be needed. It is also harder to know for
845
// sure when they might have changed.
846

847         /**
848          * Modules directly needed by this module.
849          */

850         public static final int RELATION_DIRECTLY_NEEDS = 0;
851         /**
852          * All modules needed by this module.
853          */

854         public static final int RELATION_TRANSITIVELY_NEEDS = 1;
855         /**
856          * Modules which directly need this module.
857          */

858         public static final int RELATION_DIRECTLY_NEEDED_BY = 2;
859         /**
860          * All modules which need this module.
861          */

862         public static final int RELATION_TRANSITIVELY_NEEDED_BY = 3;
863         
864         /** A callback used to supply the result of a relationship computation
865          * asynchronously.
866          */

867         public interface RelationCallback {
868             /** Called when a computation is done.
869              * @param modules a set of module beans
870              */

871             void result(Set<ModuleBean> modules);
872         }
873         
874         private static final RequestProcessor RELATION_COMPUTER_RP = new RequestProcessor("RelationComputer"); // NOI18N
875
/**
876          * Compute the relations of other modules to this one.
877          * <p>Provide-require dependencies are treated just like direct dependencies,
878          * where there is in fact a provider for a requirement. Note that this could
879          * lead to slightly misleading results in some cases: for example, consider
880          * if A (enabled) requires X, and B (enabled) and C (enabled) both provide X.
881          * A's reported dependency list will include both B and C, despite the fact
882          * that it is possible to disable either one by itself without disabling A.
883          * <p>This computation is done asynchronously. Call this method
884          * from the event thread; the callback will be called later
885          * from the event thread.
886          * @param mb the module to start with
887          * @param type one of the RELATION_* constants
888          * @param callback will be called when the computation is done
889          */

890         public void getRelations(ModuleBean mb, int type, RelationCallback callback) {
891             if (type != RELATION_DIRECTLY_NEEDS && type != RELATION_TRANSITIVELY_NEEDS &&
892                     type != RELATION_DIRECTLY_NEEDED_BY && type != RELATION_TRANSITIVELY_NEEDED_BY) {
893                 throw new IllegalArgumentException JavaDoc("bad type: " + type); // NOI18N
894
}
895             RELATION_COMPUTER_RP.post(new RelationComputer(mb.module, type, callback));
896         }
897         
898         private class RelationComputer implements Runnable JavaDoc {
899             private int stage;
900             private final Module m;
901             private final int type;
902             private final RelationCallback callback;
903             private Set result; // Set<Module>
904
public RelationComputer(Module m, int type, RelationCallback callback) {
905                 this.stage = 0;
906                 this.m = m;
907                 this.type = type;
908                 this.callback = callback;
909             }
910             public void run() {
911                 switch (stage) {
912                     case 0:
913                         stage = 1;
914                         mgr.mutex().readAccess(this);
915                         break;
916                     case 1:
917                         compute();
918                         stage = 2;
919                         SwingUtilities.invokeLater(this);
920                         break;
921                     default:
922                         // Convert Module -> ModuleBean and return it.
923
Set mbresult = new HashSet(result.size() * 2 + 1); // Set<ModuleBean>
924
ModuleBean[] _modules = getModules();
925                         for (int i = 0; i < _modules.length; i++) {
926                             if (result.contains(_modules[i].module)) {
927                                 mbresult.add(_modules[i]);
928                             }
929                         }
930                         callback.result(mbresult);
931                         break;
932                 }
933             }
934             /** Called from within module system read mutex.
935              * Should do the calculations and store them.
936              */

937             private void compute() {
938                 switch (type) {
939                 case RELATION_DIRECTLY_NEEDS:
940                     result = mgr.getModuleInterdependencies(m, false, false);
941                     break;
942                 case RELATION_DIRECTLY_NEEDED_BY:
943                     result = mgr.getModuleInterdependencies(m, true, false);
944                     break;
945                 case RELATION_TRANSITIVELY_NEEDS:
946                     result = mgr.getModuleInterdependencies(m, false, true);
947                     break;
948                 case RELATION_TRANSITIVELY_NEEDED_BY:
949                     result = mgr.getModuleInterdependencies(m, true, true);
950                     break;
951                 default:
952                     assert false : type;
953                 }
954             }
955         }
956         
957     }
958
959     /** One update to run. */
960     private static final class Update {
961         public final String JavaDoc command;
962         public final Object JavaDoc arg;
963         public Update(String JavaDoc command, Object JavaDoc arg) {
964             this.command = command;
965             this.arg = arg;
966         }
967         public boolean equals(Object JavaDoc o) {
968             if (! (o instanceof Update)) return false;
969             Update u = (Update)o;
970             return command.equals(u.command) && arg.equals(u.arg);
971         }
972         public int hashCode() {
973             return command.hashCode() ^ arg.hashCode();
974         }
975         public String JavaDoc toString() {
976             return "Update[" + command + "," + arg + "]"; // NOI18N
977
}
978     }
979     
980 }
981
Popular Tags