KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > Util


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans;
21
22 import java.io.*;
23 import java.util.*;
24 import java.util.logging.Level JavaDoc;
25 import java.util.logging.Logger JavaDoc;
26 import org.openide.util.*;
27 import org.openide.modules.*;
28
29 /** Static utility methods for use within this package.
30  * @author Jesse Glick
31  */

32 public abstract class Util {
33
34     // Prevent accidental subclassing.
35
private Util() {}
36
37     /** Log everything happening in the module system. */
38     public static final Logger JavaDoc err = Logger.getLogger("org.netbeans.core.modules"); // NOI18N
39

40     /**
41      * Make a temporary copy of a JAR file.
42      */

43     static File makeTempJar(File moduleFile) throws IOException {
44         String JavaDoc prefix = moduleFile.getName();
45         if (prefix.endsWith(".jar") || prefix.endsWith(".JAR")) { // NOI18N
46
prefix = prefix.substring(0, prefix.length() - 4);
47         }
48         if (prefix.length() < 3) prefix += '.';
49         if (prefix.length() < 3) prefix += '.';
50         if (prefix.length() < 3) prefix += '.';
51         String JavaDoc suffix = "-test.jar"; // NOI18N
52
File physicalModuleFile = File.createTempFile(prefix, suffix);
53         physicalModuleFile.deleteOnExit();
54         InputStream is = new FileInputStream(moduleFile);
55         try {
56             OutputStream os = new FileOutputStream(physicalModuleFile);
57             try {
58                 byte[] buf = new byte[4096];
59                 int i;
60                 while ((i = is.read(buf)) != -1) {
61                     os.write(buf, 0, i);
62                 }
63             } finally {
64                 os.close();
65             }
66         } finally {
67             is.close();
68         }
69         err.fine("Made " + physicalModuleFile);
70         return physicalModuleFile;
71     }
72
73     /**
74      * Find existing locale variants of f, in search order.
75      */

76     static List<File> findLocaleVariantsOf(File f) {
77         List<FileWithSuffix> result = findLocaleVariantsWithSuffixesOf(f);
78         List<File> l = new ArrayList<File>(result.size());
79         for (FileWithSuffix fws : result) {
80             l.add(fws.file);
81         }
82         return l;
83     }
84     static final class FileWithSuffix {
85         public final File file;
86         public final String JavaDoc suffix;
87         FileWithSuffix(File file, String JavaDoc suffix) {
88             this.file = file;
89             this.suffix = suffix;
90         }
91     }
92     /**
93      * Find existing locale variants of f, in search order.
94      */

95     static List<FileWithSuffix> findLocaleVariantsWithSuffixesOf(File f) {
96         if (! f.isFile()) {
97             return Collections.emptyList();
98         }
99         File dir = new File(f.getParentFile(), "locale"); // NOI18N
100
String JavaDoc logicalDir = null;
101         {
102             // #34069: we have to consider that e.g. modules/locale/foo_branding.jar might be
103
// located in a different root of ${netbeans.dirs}, so need to use IFL. Here the
104
// logical path would be "modules/foo.jar" for the base module.
105
String JavaDoc logicalPath = findLogicalPath(f);
106             if (logicalPath != null) {
107                 int slash = logicalPath.lastIndexOf('/');
108                 if (slash != -1) {
109                     logicalDir = logicalPath.substring(0, slash + 1) + "locale/"; // NOI18N
110
} else {
111                     logicalDir = "locale/"; // NOI18N
112
}
113             }
114         }
115         List<FileWithSuffix> l = new ArrayList<FileWithSuffix>(7);
116         String JavaDoc nameExt = f.getName();
117         int idx = nameExt.lastIndexOf('.'); // NOI18N
118
String JavaDoc name, ext;
119         if (idx != -1) {
120             name = nameExt.substring(0, idx);
121             ext = nameExt.substring(idx);
122         } else {
123             name = nameExt;
124             ext = ""; // NOI18N
125
}
126     boolean localeDirExists = dir.exists();
127         String JavaDoc[] suffixes = getLocalizingSuffixesFast();
128         for (int i = 0; i < suffixes.length; i++) {
129             String JavaDoc suffix = suffixes[i];
130             File v;
131         if (localeDirExists) {
132         v = new File(dir, name + suffix + ext);
133         if (v.isFile()) {
134                     l.add(new FileWithSuffix(v, suffix));
135         }
136             } else if (logicalDir != null) {
137                 String JavaDoc path = logicalDir + name + suffix + ext;
138                 v = InstalledFileLocator.getDefault().locate(path, null, false);
139                 if (v != null) {
140                     l.add(new FileWithSuffix(v, suffix));
141                 }
142             }
143         }
144         return l;
145     }
146     
147     /** Similar to {@link NbBundle#getLocalizingSuffixes} but optimized.
148      * @since JST-PENDING: Called from InstalledFileLocatorImpl
149      */

150     public static synchronized String JavaDoc[] getLocalizingSuffixesFast() {
151         if (suffixes == null ||
152                 Locale.getDefault() != lastLocale ||
153                 NbBundle.getBranding() != lastBranding) {
154             List<String JavaDoc> _suffixes = new ArrayList<String JavaDoc>();
155             Iterator<String JavaDoc> it = NbBundle.getLocalizingSuffixes();
156             while (it.hasNext()) {
157                 _suffixes.add(it.next());
158             }
159             suffixes = _suffixes.toArray(new String JavaDoc[_suffixes.size()]);
160             lastLocale = Locale.getDefault();
161             lastBranding = NbBundle.getBranding();
162         }
163         return suffixes;
164     }
165     private static String JavaDoc[] suffixes = null;
166     private static Locale lastLocale = null;
167     private static String JavaDoc lastBranding = null;
168     
169     /**
170      * Find a path such that InstalledFileLocator.getDefault().locate(path, null, false)
171      * yields the given file. Only guaranteed to work in case the logical path is a suffix of
172      * the file's absolute path (after converting path separators); otherwise there is no
173      * general way to invert locate(...) so this heuristic may fail. However for the IFL
174      * implementation used in a plain NB installation (i.e.
175      * org.netbeans.core.modules.InstalledFileLocatorImpl), this condition will in fact hold.
176      * @return the inverse of locate(...), or null if there is no such path
177      * @see "#34069"
178      */

179     private static String JavaDoc findLogicalPath(File f) {
180         InstalledFileLocator l = InstalledFileLocator.getDefault();
181         String JavaDoc path = f.getName();
182         File parent = f.getParentFile();
183         while (parent != null) {
184             File probe = l.locate(path, null, false);
185             //System.err.println("Util.fLP: f=" + f + " parent=" + parent + " probe=" + probe + " f.equals(probe)=" + f.equals(probe));
186
if (f.equals(probe)) {
187                 return path;
188             }
189             path = parent.getName() + '/' + path;
190             parent = parent.getParentFile();
191         }
192         return null;
193     }
194     
195     // XXX ought to be some way to get localized messages for these...
196

197     /** Check whether a simple dependency is met.
198      * Only applicable to Java dependencies.
199      */

200     static boolean checkJavaDependency(Dependency dep) throws IllegalArgumentException JavaDoc {
201         // Note that "any" comparison is not possible for this type.
202
if (dep.getType() == Dependency.TYPE_JAVA) {
203             if (dep.getName().equals(Dependency.JAVA_NAME)) {
204                 if (dep.getComparison() == Dependency.COMPARE_SPEC) {
205                     return new SpecificationVersion(dep.getVersion()).compareTo(Dependency.JAVA_SPEC) <= 0;
206                 } else {
207                     return dep.getVersion().equals(Dependency.JAVA_IMPL);
208                 }
209             } else {
210                 if (dep.getComparison() == Dependency.COMPARE_SPEC) {
211                     return new SpecificationVersion(dep.getVersion()).compareTo(Dependency.VM_SPEC) <= 0;
212                 } else {
213                     return dep.getVersion().equals(Dependency.VM_IMPL);
214                 }
215             }
216         } else {
217             throw new IllegalArgumentException JavaDoc();
218         }
219     }
220     
221     /** Check whether a package dependency is met.
222      * A classloader must be supplied to check in.
223      */

224     static boolean checkPackageDependency(Dependency dep, ClassLoader JavaDoc cl) throws IllegalArgumentException JavaDoc {
225         if (dep.getType() != Dependency.TYPE_PACKAGE) {
226             throw new IllegalArgumentException JavaDoc("Not a package dependency"); // NOI18N
227
}
228         if (! (cl instanceof Util.PackageAccessibleClassLoader) && cl != Util.class.getClassLoader()) {
229             throw new IllegalArgumentException JavaDoc("Not a package-accessible classloader: " + cl); // NOI18N
230
}
231         String JavaDoc name = dep.getName();
232         String JavaDoc version = dep.getVersion();
233         int comparison = dep.getComparison();
234         String JavaDoc packageName, sampleName;
235         int idx = name.indexOf('[');
236         if (idx == -1) {
237             packageName = name;
238             sampleName = null;
239         } else if (idx == 0) {
240             packageName = null;
241             sampleName = name.substring(1, name.length() - 1);
242         } else {
243             packageName = name.substring(0, idx);
244             sampleName = name.substring(idx + 1, name.length() - 1);
245             if (sampleName.indexOf('.') == -1) {
246                 // Unqualified class name; prefix it automatically.
247
sampleName = packageName + '.' + sampleName;
248             }
249         }
250         if (sampleName != null) {
251             try {
252                 cl.loadClass(sampleName);
253             } catch (ClassNotFoundException JavaDoc cnfe) {
254                 if (packageName == null) {
255                     // This was all we were relying on, so it is an error.
256
err.log(Level.WARNING, null, cnfe);
257                     err.fine("Probed class could not be found");
258                     return false;
259                 }
260                 // Else let the regular package check take care of it;
261
// this was only run to enforce that the package defs were loaded.
262
} catch (RuntimeException JavaDoc e) {
263                 // SecurityException, etc. Package exists but is corrupt.
264
err.log(Level.WARNING, null, e);
265                 err.fine("Assuming package " + packageName + " is corrupt");
266                 return false;
267             } catch (LinkageError JavaDoc le) {
268                 // NoClassDefFoundError, etc. Package exists but is corrupt.
269
err.log(Level.WARNING, null, le);
270                 err.fine("Assuming package " + packageName + " is corrupt");
271                 return false;
272             }
273         }
274         if (packageName != null) {
275             Package JavaDoc pkg;
276             if (cl instanceof Util.PackageAccessibleClassLoader) {
277                 pkg = ((Util.PackageAccessibleClassLoader)cl).getPackageAccessibly(packageName);
278             } else {
279                 pkg = Package.getPackage(packageName);
280             }
281             if (pkg == null) {
282                 err.fine("No package with the name " + packageName + " found");
283                 return false;
284             }
285             if (comparison == Dependency.COMPARE_ANY) {
286                 return true;
287             } else if (comparison == Dependency.COMPARE_SPEC) {
288                 if (pkg.getSpecificationVersion() == null) {
289                     err.fine("Package " + packageName + " did not give a specification version");
290                     return false;
291                 } else {
292                     try {
293                         SpecificationVersion versionSpec = new SpecificationVersion(version);
294                         SpecificationVersion pkgSpec = new SpecificationVersion(pkg.getSpecificationVersion().trim());
295                         if (versionSpec.compareTo(pkgSpec) <= 0) {
296                             return true;
297                         } else {
298                             err.fine("Loaded package " + packageName + " was only of version " + pkgSpec + " but " + versionSpec + " was requested");
299                             return false;
300                         }
301                     } catch (NumberFormatException JavaDoc nfe) {
302                         err.log(Level.WARNING, null, nfe);
303                         err.fine("Will not honor a dependency on non-numeric package spec version");
304                         return false;
305                     }
306                 }
307             } else {
308                 // COMPARE_IMPL
309
if (pkg.getImplementationVersion() == null) {
310                     err.fine("Package " + packageName + " had no implementation version");
311                     return false;
312                 } else if (! pkg.getImplementationVersion().trim().equals(version)) {
313                     err.fine("Package " + packageName + " had the wrong impl version: " + pkg.getImplementationVersion());
314                     return false;
315                 } else {
316                     return true;
317                 }
318             }
319         } else {
320             // Satisfied sample class.
321
return true;
322         }
323     }
324
325     /**
326      * Interface to permit a couple of methods in ClassLoader to be made public.
327      * @since 2.1
328      */

329     public interface PackageAccessibleClassLoader {
330         /** @see ClassLoader#getPackage */
331         Package JavaDoc getPackageAccessibly (String JavaDoc name);
332         /** @see ClassLoader#getPackages */
333         Package JavaDoc[] getPackagesAccessibly ();
334     }
335
336     /**
337      * Interface for a classloader to declare that it comes from a module.
338      * @since 2.1
339      */

340     public interface ModuleProvider {
341         Module getModule();
342     }
343     
344     /**
345      * Enumerate (direct) interdependencies among a set of modules.
346      * If used in a topological sort, the result will be a reverse-order
347      * list of modules (suitable for disabling; reverse for enabling).
348      * @param modules some modules
349      * @param modulesByName map from module cnbs to modules (may contain unrelated modules)
350      * @param providersOf map from tokens to sets of modules providing them (may mention unrelated modules)
351      * @return a map from modules to lists of modules they depend on
352      * @see Utilities#topologicalSort
353      * JST-PENDING needed from tests
354      */

355     public static Map<Module,List<Module>> moduleDependencies(Collection<Module> modules, Map<String JavaDoc,Module> modulesByName, Map<String JavaDoc,Set<Module>> _providersOf) {
356         Set<Module> modulesSet = (modules instanceof Set) ? (Set<Module>)modules : new HashSet<Module>(modules);
357         Map<String JavaDoc,List<Module>> providersOf = new HashMap<String JavaDoc,List<Module>>(_providersOf.size() * 2 + 1);
358         for (Map.Entry<String JavaDoc, Set<Module>> entry: _providersOf.entrySet()) {
359             Set<Module> providers = entry.getValue();
360             if (providers != null) {
361                 List<Module> availableProviders = new LinkedList<Module>(providers);
362                 availableProviders.retainAll(modulesSet);
363                 if (!availableProviders.isEmpty()) {
364                     providersOf.put(entry.getKey(), availableProviders);
365                 }
366             }
367         }
368         Map<Module,List<Module>> m = new HashMap<Module,List<Module>>();
369     for (Module m1: modules) {
370             List<Module> l = null;
371             Dependency[] dependencies = m1.getDependenciesArray();
372             for (int i = 0; i < dependencies.length; i++) {
373                 Dependency dep = dependencies[i];
374
375                 if (dep.getType() == Dependency.TYPE_REQUIRES) {
376                     List<Module> providers = providersOf.get(dep.getName());
377
378                     if (providers != null) {
379                         if (l == null) {
380                             l = new LinkedList<Module>();
381                         }
382                         l.addAll(providers);
383                     }
384                 }
385                 else if (dep.getType() == Dependency.TYPE_MODULE) {
386                     String JavaDoc cnb = (String JavaDoc) parseCodeName(dep.getName())[0];
387                     Module m2 = modulesByName.get(cnb);
388
389                     if (m2 != null && modulesSet.contains(m2)) {
390                         if (l == null) {
391                             l = new LinkedList<Module>();
392                         }
393                         l.add(m2);
394                     }
395                 }
396             }
397             if (l != null) {
398                 m.put(m1, l);
399             }
400         }
401         return m;
402     }
403     
404     /**
405      * Get dependencies forward or backwards starting from one module.
406      * @see #moduleDependencies
407      * @see ModuleManager#getModuleInterdependencies
408      */

409     static Set<Module> moduleInterdependencies(Module m, boolean reverse, boolean transitive,
410                                        Set<Module> modules, Map<String JavaDoc,Module> modulesByName, Map<String JavaDoc,Set<Module>> providersOf) {
411         // XXX these algorithms could surely be made faster using standard techniques
412
// for now the speed is not critical however
413
if (reverse) {
414             Set<Module> s = new HashSet<Module>();
415             for (Module m2: modules) {
416                 if (m2 == m) {
417                     continue;
418                 }
419                 if (moduleInterdependencies(m2, false, transitive, modules, modulesByName, providersOf).contains(m)) {
420                     s.add(m2);
421                 }
422             }
423             return s;
424         } else {
425             Set<Module> s = new HashSet<Module>();
426             Dependency[] dependencies = m.getDependenciesArray();
427             for (int i = 0; i < dependencies.length; i++) {
428                 Dependency dep = dependencies[i];
429                 if (dep.getType() == Dependency.TYPE_REQUIRES) {
430                     Set<Module> providers = providersOf.get(dep.getName());
431                     if (providers != null) {
432                         s.addAll(providers);
433                     }
434                 } else if (dep.getType() == Dependency.TYPE_MODULE) {
435                     String JavaDoc cnb = (String JavaDoc)parseCodeName(dep.getName())[0];
436                     Module m2 = modulesByName.get(cnb);
437                     if (m2 != null) {
438                         s.add(m2);
439                     }
440                 }
441             }
442             s.remove(m);
443             if (transitive) {
444                 Set<Module> toAdd;
445                 do {
446                     toAdd = new HashSet<Module>();
447                     for (Module m2: s) {
448                         Set<Module> s2 = moduleInterdependencies(m2, false, false, modules, modulesByName, providersOf);
449                         s2.remove(m);
450                         s2.removeAll(s);
451                         toAdd.addAll(s2);
452                     }
453                     s.addAll(toAdd);
454                 } while (!toAdd.isEmpty());
455             }
456             return s;
457         }
458     }
459     
460     /** Get a comparator for modules by display name (alphabetical).
461      */

462     static Comparator displayNameComparator() {
463         return new DisplayNameComparator();
464     }
465     private static final class DisplayNameComparator implements Comparator {
466         DisplayNameComparator() {}
467         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
468             Module m1 = (Module)o1;
469             Module m2 = (Module)o2;
470             return m1.getDisplayName().compareTo(m2.getDisplayName());
471         }
472     }
473     
474     /** Find the most human-presentable message present in an exception.
475      * At worst, the detail message, but preferably a localized message
476      * if different, or the first localized annotation found.
477      * If returning the detail message is not OK, returns null instead.
478      * @since JST-PENDING: used from NbProblemDisplayer
479      */

480     public static String JavaDoc findLocalizedMessage(Throwable JavaDoc t, boolean detailOK) {
481         String JavaDoc locmsg = t.getLocalizedMessage();
482         if (Utilities.compareObjects(locmsg, t.getMessage())) {
483             locmsg = Exceptions.findLocalizedMessage(t);
484             if (! detailOK) {
485                 return null;
486             }
487         }
488         return locmsg;
489     }
490     
491     /** Get a filter for JAR files. */
492     static FilenameFilter jarFilter() {
493         return new JarFilter();
494     }
495     private static final class JarFilter implements FilenameFilter {
496         JarFilter() {}
497         public boolean accept(File dir, String JavaDoc name) {
498             String JavaDoc n = name.toLowerCase(Locale.US);
499             return n.endsWith(".jar"); // NOI18N
500
}
501     }
502     
503     /** Convert a class file name to a resource name suitable for Beans.instantiate.
504     * @param name resource name of class file
505     * @return class name without the <code>.class</code>/<code>.ser</code> extension, and using dots as package separator
506     * @throws IllegalArgumentException if the name did not have a valid extension, or originally contained dots outside the extension, etc.
507      * @since JST-PENDING: used from NbInstaller
508     */

509     public static String JavaDoc createPackageName(String JavaDoc name) throws IllegalArgumentException JavaDoc {
510         String JavaDoc clExt = ".class"; // NOI18N
511
if (!name.endsWith(clExt)) {
512             // try different extension
513
clExt = ".ser"; // NOI18N
514
}
515         if (name.endsWith(clExt)) {
516             String JavaDoc bareName = name.substring(0, name.length() - clExt.length());
517             if (bareName.length() == 0) { // ".class" // NOI18N
518
throw new IllegalArgumentException JavaDoc("Bad class file name: " + name); // NOI18N
519
}
520             if (bareName.charAt(0) == '/') { // "/foo/bar.class" // NOI18N
521
throw new IllegalArgumentException JavaDoc("Bad class file name: " + name); // NOI18N
522
}
523             if (bareName.charAt(bareName.length() - 1) == '/') { // "foo/bar/.class" // NOI18N
524
throw new IllegalArgumentException JavaDoc("Bad class file name: " + name); // NOI18N
525
}
526             if (bareName.indexOf('.') != -1) { // "foo.bar.class" // NOI18N
527
throw new IllegalArgumentException JavaDoc("Bad class file name: " + name); // NOI18N
528
}
529             return bareName.replace('/', '.'); // NOI18N
530
} else { // "foo/bar" or "foo.bar" // NOI18N
531
throw new IllegalArgumentException JavaDoc("Bad class file name: " + name); // NOI18N
532
}
533     }
534
535     /** A lookup implementation specialized for modules.
536      * Its primary advantage over e.g. AbstractLookup is that
537      * it is possible to add modules to the set at one time and
538      * fire changes in the set of modules later on. ModuleManager
539      * uses this to add modules immediately in create() and destroy(),
540      * but only fire lookup events later and asynchronously, from the
541      * read mutex.
542      */

543     static final class ModuleLookup extends Lookup {
544         ModuleLookup() {}
545         private final Set<Module> modules = new HashSet<Module>(100);
546         private final Set<ModuleResult> results = new WeakSet<ModuleResult>(10);
547         /** Add a module to the set. */
548         public void add(Module m) {
549             synchronized (modules) {
550                 modules.add(m);
551             }
552         }
553         /** Remove a module from the set. */
554         public void remove(Module m) {
555             synchronized (modules) {
556                 modules.remove(m);
557             }
558         }
559         /** Fire changes to all result listeners. */
560         public void changed() {
561             synchronized (results) {
562                 Iterator it = results.iterator();
563                 while (it.hasNext()) {
564                     ((ModuleResult)it.next()).changed();
565                 }
566             }
567         }
568         public <T> T lookup(Class JavaDoc<T> clazz) {
569             if ((clazz == Module.class || clazz == ModuleInfo.class || clazz == Object JavaDoc.class || clazz == null)
570                     && ! modules.isEmpty()) {
571                 synchronized (modules) {
572                     return clazz.cast(modules.iterator().next());
573                 }
574             } else {
575                 return null;
576             }
577         }
578     @SuppressWarnings JavaDoc("unchecked")
579         public <T> Lookup.Result<T> lookup(Lookup.Template<T> t) {
580             Class JavaDoc<T> clazz = t.getType();
581             if (clazz == Module.class || clazz == ModuleInfo.class ||
582                 clazz == Object JavaDoc.class || clazz == null) {
583                 return (Lookup.Result<T>)(Object JavaDoc) new ModuleResult((Lookup.Template<Module>) t);
584             }
585             else {
586                 return Lookup.EMPTY.lookup(t);
587             }
588         }
589         public String JavaDoc toString() {
590             synchronized (modules) {
591                 return "ModuleLookup" + modules; // NOI18N
592
}
593         }
594         private final class ModuleResult extends Lookup.Result<Module> {
595             private final Lookup.Template<? super Module> t;
596             private final Set<LookupListener> listeners = new HashSet<LookupListener>(10);
597             public ModuleResult(Lookup.Template<? super Module> t) {
598                 this.t = t;
599                 synchronized (results) {
600                     results.add(this);
601                 }
602             }
603             public void addLookupListener(LookupListener l) {
604                 synchronized (listeners) {
605                     listeners.add(l);
606                 }
607             }
608             public void removeLookupListener(LookupListener l) {
609                 synchronized (listeners) {
610                     listeners.remove(l);
611                 }
612             }
613             public void changed() {
614                 LookupListener[] _listeners;
615                 synchronized (listeners) {
616                     if (listeners.isEmpty()) {
617                         return;
618                     }
619                     _listeners = listeners.toArray(new LookupListener[listeners.size()]);
620                 }
621                 LookupEvent ev = new LookupEvent(this);
622                 for (int i = 0; i < _listeners.length; i++) {
623                     _listeners[i].resultChanged(ev);
624                 }
625             }
626             public Collection<Module> allInstances() {
627                 synchronized (modules) {
628                     String JavaDoc id = t.getId();
629                     Object JavaDoc inst = t.getInstance();
630                     if (id != null) {
631                         Iterator<Module> it = modules.iterator();
632                         while (it.hasNext()) {
633                             Module m = it.next();
634                             if (id.equals(ModuleItem.PREFIX + m.getCodeNameBase())) {
635                                 if (inst == null || inst == m) {
636                                     return Collections.<Module>singleton(m);
637                                 }
638                             }
639                         }
640                         return Collections.<Module>emptySet();
641                     } else if (inst != null) {
642                         return modules.contains(inst) ? Collections.<Module>singleton(Module.class.cast(inst)) : Collections.<Module>emptySet();
643                     } else {
644                         // Regular lookup based on type.
645
return new HashSet<Module>(modules);
646                     }
647                 }
648             }
649             public Set<Class JavaDoc<? extends Module>> allClasses() {
650                 return Collections.<Class JavaDoc<? extends Module>>singleton(Module.class);
651             }
652             public Collection<? extends Lookup.Item<Module>> allItems() {
653                 Collection<Module> insts = allInstances();
654                 ArrayList<ModuleItem> list = new ArrayList<ModuleItem>(Math.max(1, insts.size()));
655                 for (Module m: insts) {
656                     list.add(new ModuleItem(m));
657                 }
658                 return list;
659             }
660             public String JavaDoc toString() {
661                 return "ModuleResult:" + t; // NOI18N
662
}
663         }
664         private static final class ModuleItem extends Lookup.Item<Module> {
665             public static final String JavaDoc PREFIX = "Module["; // NOI18N
666
private final Module item;
667             public ModuleItem(Module item) {
668                 this.item = item;
669             }
670             public Module getInstance() {
671                 return item;
672             }
673             public Class JavaDoc<? extends Module> getType() {
674                 return Module.class;
675             }
676             public String JavaDoc getId() {
677                 return PREFIX + item.getCodeNameBase();
678             }
679             public String JavaDoc getDisplayName() {
680                 return item.getDisplayName();
681             }
682         }
683     }
684     
685     // OK to not release this memory; module deletion is rare: holds 45kB for 173 modules (June 2005)
686
private static final Map<String JavaDoc,Object JavaDoc[]> codeNameParseCache = new HashMap<String JavaDoc,Object JavaDoc[]>(200); // Map<String,[String,int]>
687
/** Find the code name base and major release version from a code name.
688      * Caches these parses. Thread-safe (i.e. OK from read mutex).
689      * @return an array consisting of the code name base (String) followed by the release version (Integer or null)
690      * followed by another end-range version (Integer or null)
691      * @throws NumberFormatException if the release version is mangled
692      * @since JST-PENDING: used from NbInstaller
693      */

694     public static Object JavaDoc[] parseCodeName(String JavaDoc cn) throws NumberFormatException JavaDoc {
695         synchronized (codeNameParseCache) {
696             Object JavaDoc[] r = codeNameParseCache.get(cn);
697             if (r == null) {
698                 r = new Object JavaDoc[3];
699                 int i = cn.lastIndexOf('/');
700                 if (i == -1) {
701                     r[0] = cn;
702                 } else {
703                     r[0] = cn.substring(0, i).intern();
704                     String JavaDoc end = cn.substring(i + 1);
705                     int j = end.indexOf('-');
706                     if (j == -1) {
707                         r[1] = new Integer JavaDoc(end);
708                     } else {
709                         r[1] = new Integer JavaDoc(end.substring(0, j));
710                         r[2] = new Integer JavaDoc(end.substring(j + 1));
711                     }
712                 }
713                 codeNameParseCache.put(cn.intern(), r);
714             }
715             return r;
716         }
717     }
718
719     /** Get API module dependency, if any, for a module.
720      * @param dependencies module dependencies
721      * @param cnb code name base of API module
722      * @return a fake spec version (0.x.y if x.y w/ no major release, else r.x.y); or null if no dep
723      * @since JST-PENDING: used from NbInstaller
724      */

725     public static SpecificationVersion getModuleDep(Set dependencies, String JavaDoc cnb) {
726         Iterator it = dependencies.iterator();
727         while (it.hasNext()) {
728             Dependency d = (Dependency)it.next();
729             if (d.getType() == Dependency.TYPE_MODULE &&
730                     d.getComparison() == Dependency.COMPARE_SPEC) {
731                 try {
732                     Object JavaDoc[] p = parseCodeName(d.getName());
733                     if (!p[0].equals(cnb)) {
734                         continue;
735                     }
736                     int rel = ((Integer JavaDoc)p[1]).intValue(); // ignore any end range, consider only start
737
if (rel == -1) rel = 0; // XXX will this lead to incorrect semantics?
738
return new SpecificationVersion("" + rel + "." + d.getVersion()); // NOI18N
739
} catch (NumberFormatException JavaDoc nfe) {
740                     Util.err.log(Level.WARNING, null, nfe);
741                     return null;
742                 }
743             }
744         }
745         return null;
746     }
747     
748     /**
749      * Transitively fill out a set of modules with all of its module dependencies.
750      * Dependencies on missing modules are silently ignored, but dependencies
751      * on present but uninstallable (problematic) modules are included.
752      * @param mgr the manager
753      * @param modules a mutable set of modules
754      * @since JST-PENDING: used from NbInstaller
755      */

756     public static void transitiveClosureModuleDependencies(ModuleManager mgr, Set<Module> modules) {
757         Set<Module> nue = null; // Set of newly appended modules
758
while (nue == null || !nue.isEmpty()) {
759             nue = new HashSet<Module>();
760             for (Module m: modules) {
761                 Dependency[] deps = m.getDependenciesArray();
762                 for (int i = 0; i < deps.length; i++) {
763                     if (deps[i].getType() != Dependency.TYPE_MODULE) {
764                         continue;
765                     }
766                     Module other = mgr.get((String JavaDoc)parseCodeName(deps[i].getName())[0]);
767                     if (other != null && !modules.contains(other)) {
768                         nue.add(other);
769                     }
770                 }
771             }
772             modules.addAll(nue);
773         }
774     }
775     
776 }
777
Popular Tags