KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > apisupport > project > universe > NbPlatform


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.apisupport.project.universe;
21
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.beans.PropertyChangeSupport JavaDoc;
24 import java.io.File JavaDoc;
25 import java.io.FileNotFoundException JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.net.MalformedURLException JavaDoc;
29 import java.net.URI JavaDoc;
30 import java.net.URL JavaDoc;
31 import java.text.MessageFormat JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Arrays JavaDoc;
34 import java.util.Collection JavaDoc;
35 import java.util.HashSet JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.List JavaDoc;
38 import java.util.Locale JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.Properties JavaDoc;
41 import java.util.Set JavaDoc;
42 import java.util.SortedSet JavaDoc;
43 import java.util.TreeSet JavaDoc;
44 import java.util.jar.JarFile JavaDoc;
45 import java.util.zip.ZipEntry JavaDoc;
46 import org.netbeans.api.project.ProjectManager;
47 import org.netbeans.modules.apisupport.project.ManifestManager;
48 import org.netbeans.modules.apisupport.project.Util;
49 import org.netbeans.spi.project.support.ant.EditableProperties;
50 import org.netbeans.spi.project.support.ant.PropertyProvider;
51 import org.netbeans.spi.project.support.ant.PropertyUtils;
52 import org.openide.ErrorManager;
53 import org.openide.filesystems.FileUtil;
54 import org.openide.modules.InstalledFileLocator;
55 import org.openide.modules.SpecificationVersion;
56 import org.openide.util.Mutex;
57 import org.openide.util.MutexException;
58 import org.openide.util.NbBundle;
59
60 /**
61  * Represents one NetBeans platform, i.e. installation of the NB platform or IDE
62  * or some derivative product.
63  * Has a code id and can have associated sources and Javadoc, just like e.g. Java platforms.
64  *
65  * @author Jesse Glick
66  */

67 public final class NbPlatform {
68     
69     private static final String JavaDoc PLATFORM_PREFIX = "nbplatform."; // NOI18N
70
private static final String JavaDoc PLATFORM_DEST_DIR_SUFFIX = ".netbeans.dest.dir"; // NOI18N
71
private static final String JavaDoc PLATFORM_LABEL_SUFFIX = ".label"; // NOI18N
72
private static final String JavaDoc PLATFORM_SOURCES_SUFFIX = ".sources"; // NOI18N
73
private static final String JavaDoc PLATFORM_JAVADOC_SUFFIX = ".javadoc"; // NOI18N
74
private static final String JavaDoc PLATFORM_HARNESS_DIR_SUFFIX = ".harness.dir"; // NOI18N
75
public static final String JavaDoc PLATFORM_ID_DEFAULT = "default"; // NOI18N
76

77     public static final String JavaDoc PROP_SOURCE_ROOTS = "sourceRoots"; // NOI18N
78

79     private static Set JavaDoc<NbPlatform> platforms;
80     
81     private final PropertyChangeSupport JavaDoc pcs = new PropertyChangeSupport JavaDoc(this);
82     
83     // should proceed in chronological order so we can do compatibility tests with >=
84
/** Unknown version - platform might be invalid, or just predate any 5.0 release version. */
85     public static final int HARNESS_VERSION_UNKNOWN = 0;
86     /** Harness version found in 5.0. */
87     public static final int HARNESS_VERSION_50 = 1;
88     /** Harness version found in 5.0 update 1 and 5.5. */
89     public static final int HARNESS_VERSION_50u1 = 2;
90     /** Harness version found in 5.5 update 1. */
91     public static final int HARNESS_VERSION_55u1 = 3;
92     /** Harness version found in 6.0. */
93     public static final int HARNESS_VERSION_60 = 4;
94     
95     /**
96      * Reset cached info so unit tests can start from scratch.
97      */

98     public static void reset() {
99         platforms = null;
100     }
101     
102     /**
103      * Get a set of all registered platforms.
104      */

105     public static synchronized Set JavaDoc<NbPlatform> getPlatforms() {
106         return new HashSet JavaDoc(getPlatformsInternal());
107     }
108
109     private static Set JavaDoc<NbPlatform> getPlatformsInternal() {
110         if (platforms == null) {
111             platforms = new HashSet JavaDoc();
112             Map JavaDoc<String JavaDoc,String JavaDoc> p = PropertyUtils.sequentialPropertyEvaluator(null, new PropertyProvider[] {PropertyUtils.globalPropertyProvider()}).getProperties();
113             boolean foundDefault = false;
114             Iterator JavaDoc entries = p.entrySet().iterator();
115             while (entries.hasNext()) {
116                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) entries.next();
117                 String JavaDoc key = (String JavaDoc) entry.getKey();
118                 if (key.startsWith(PLATFORM_PREFIX) && key.endsWith(PLATFORM_DEST_DIR_SUFFIX)) {
119                     String JavaDoc id = key.substring(PLATFORM_PREFIX.length(), key.length() - PLATFORM_DEST_DIR_SUFFIX.length());
120                     String JavaDoc label = (String JavaDoc) p.get(PLATFORM_PREFIX + id + PLATFORM_LABEL_SUFFIX);
121                     String JavaDoc destdir = (String JavaDoc) entry.getValue();
122                     String JavaDoc harnessdir = (String JavaDoc) p.get(PLATFORM_PREFIX + id + PLATFORM_HARNESS_DIR_SUFFIX);
123                     String JavaDoc sources = (String JavaDoc) p.get(PLATFORM_PREFIX + id + PLATFORM_SOURCES_SUFFIX);
124                     String JavaDoc javadoc = (String JavaDoc) p.get(PLATFORM_PREFIX + id + PLATFORM_JAVADOC_SUFFIX);
125                     File JavaDoc destdirF = FileUtil.normalizeFile(new File JavaDoc(destdir));
126                     File JavaDoc harness;
127                     if (harnessdir != null) {
128                         harness = FileUtil.normalizeFile(new File JavaDoc(harnessdir));
129                     } else {
130                         harness = findHarness(destdirF);
131                     }
132                     platforms.add(new NbPlatform(id, label, destdirF, harness, findURLs(sources), findURLs(javadoc)));
133                     foundDefault |= id.equals(PLATFORM_ID_DEFAULT);
134                 }
135             }
136             if (!foundDefault) {
137                 File JavaDoc loc = defaultPlatformLocation();
138                 if (loc != null) {
139                     platforms.add(new NbPlatform(PLATFORM_ID_DEFAULT, null, loc, findHarness(loc), new URL JavaDoc[0], new URL JavaDoc[0]));
140                 }
141             }
142             if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) {
143                 Util.err.log("NbPlatform initial list: " + platforms);
144             }
145         }
146         return platforms;
147     }
148     
149     /**
150      * Get the default platform.
151      * @return the default platform, if there is one (usually should be)
152      */

153     public static NbPlatform getDefaultPlatform() {
154         return NbPlatform.getPlatformByID(PLATFORM_ID_DEFAULT);
155     }
156     
157     /**
158      * Get the location of the default platform, or null.
159      */

160     public static File JavaDoc defaultPlatformLocation() {
161         // XXX cache the result?
162
// Semi-arbitrary platform* component.
163
File JavaDoc bootJar = InstalledFileLocator.getDefault().locate("core/core.jar", "org.netbeans.core.startup", false); // NOI18N
164
if (bootJar == null) {
165             if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) {
166                 Util.err.log("no core/core.jar");
167             }
168             return null;
169         }
170         // Semi-arbitrary harness component.
171
File JavaDoc harnessJar = InstalledFileLocator.getDefault().locate("modules/org-netbeans-modules-apisupport-harness.jar", "org.netbeans.modules.apisupport.harness", false); // NOI18N
172
if (harnessJar == null) {
173             ErrorManager.getDefault().log(ErrorManager.WARNING, "Cannot resolve default platform. " + // NOI18N
174
"Probably either \"org.netbeans.modules.apisupport.harness\" module is missing or is corrupted."); // NOI18N
175
return null;
176         }
177         File JavaDoc loc = harnessJar.getParentFile().getParentFile().getParentFile();
178         try {
179             if (!loc.getCanonicalFile().equals(bootJar.getParentFile().getParentFile().getParentFile().getCanonicalFile())) {
180                 // Unusual installation structure, punt.
181
if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) {
182                     Util.err.log("core.jar & harness.jar locations do not match: " + bootJar + " vs. " + harnessJar);
183                 }
184                 return null;
185             }
186         } catch (IOException JavaDoc x) {
187             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, x);
188         }
189         // Looks good.
190
return FileUtil.normalizeFile(loc);
191     }
192     
193     /**
194      * Get any sources which should by default be associated with the default platform.
195      */

196     private static URL JavaDoc[] defaultPlatformSources(File JavaDoc loc) {
197         if (loc.getName().equals("netbeans") && loc.getParentFile().getName().equals("nbbuild")) { // NOI18N
198
try {
199                 return new URL JavaDoc[] {loc.getParentFile().getParentFile().toURI().toURL()};
200             } catch (MalformedURLException JavaDoc e) {
201                 assert false : e;
202             }
203         }
204         return new URL JavaDoc[0];
205     }
206     
207     /**
208      * Get any Javadoc which should by default be associated with the default platform.
209      */

210     private static URL JavaDoc[] defaultPlatformJavadoc() {
211         File JavaDoc apidocsZip = InstalledFileLocator.getDefault().locate("docs/NetBeansAPIs.zip", "org.netbeans.modules.apisupport.apidocs", true); // NOI18N
212
if (apidocsZip != null) {
213             return new URL JavaDoc[] {Util.urlForJar(apidocsZip)};
214         } else {
215             return new URL JavaDoc[0];
216         }
217     }
218     
219     /**
220      * Find a platform by its ID.
221      * @param id an ID (as in {@link #getID})
222      * @return the platform with that ID, or null
223      */

224     public static synchronized NbPlatform getPlatformByID(String JavaDoc id) {
225         Iterator JavaDoc it = getPlatformsInternal().iterator();
226         while (it.hasNext()) {
227             NbPlatform p = (NbPlatform) it.next();
228             if (p.getID().equals(id)) {
229                 return p;
230             }
231         }
232         return null;
233     }
234     
235     /**
236      * Find a platform by its installation directory.
237      * If there is a registered platform for that directory, returns it.
238      * Otherwise will create an anonymous platform ({@link #getID} will be null).
239      * An anonymous platform might have sources associated with it;
240      * currently this will be true in case the dest dir is nbbuild/netbeans/ inside a netbeans.org checkout.
241      * @param the installation directory (as in {@link #getDestDir})
242      * @return the platform with that destination directory
243      */

244     public static synchronized NbPlatform getPlatformByDestDir(File JavaDoc destDir) {
245         Iterator JavaDoc it = getPlatformsInternal().iterator();
246         while (it.hasNext()) {
247             NbPlatform p = (NbPlatform) it.next();
248             if (p.getDestDir().equals(destDir)) {
249                 return p;
250             }
251         }
252         URL JavaDoc[] sources = new URL JavaDoc[0];
253         if (destDir.getName().equals("netbeans")) { // NOI18N
254
File JavaDoc parent = destDir.getParentFile();
255             if (parent != null && parent.getName().equals("nbbuild")) { // NOI18N
256
File JavaDoc superparent = parent.getParentFile();
257                 if (superparent != null && ModuleList.isNetBeansOrg(superparent)) {
258                     sources = new URL JavaDoc[] {Util.urlForDir(superparent)};
259                 }
260             }
261         }
262         // XXX might also check OpenProjectList for NbModuleProject's and/or SuiteProject's with a matching
263
// dest dir and look up property 'sources' to use; TBD whether Javadoc could also be handled in a
264
// similar way
265
return new NbPlatform(null, null, destDir, findHarness(destDir), sources, new URL JavaDoc[0]);
266     }
267     
268     /**
269      * Find the location of the harness inside a platform.
270      * Guaranteed to be a child directory (but might not exist yet).
271      */

272     private static File JavaDoc findHarness(File JavaDoc destDir) {
273         File JavaDoc[] kids = destDir.listFiles();
274         if (kids != null) {
275             for (int i = 0; i < kids.length; i++) {
276                 if (isHarness(kids[i])) {
277                     return kids[i];
278                 }
279             }
280         }
281         return new File JavaDoc(destDir, "harness"); // NOI18N
282
}
283     
284     /**
285      * Check whether a given directory is really a valid harness.
286      */

287     public static boolean isHarness(File JavaDoc dir) {
288         return new File JavaDoc(dir, "modules" + File.separatorChar + "org-netbeans-modules-apisupport-harness.jar").isFile(); // NOI18N
289
}
290     
291     /**
292      * Returns whether the platform within the given directory is already
293      * registered.
294      */

295     public static synchronized boolean contains(File JavaDoc destDir) {
296         boolean contains = false;
297         Iterator JavaDoc it = getPlatformsInternal().iterator();
298         while (it.hasNext()) {
299             NbPlatform p = (NbPlatform) it.next();
300             if (p.getDestDir().equals(destDir)) {
301                 contains = true;
302                 break;
303             }
304         }
305         return contains;
306     }
307     
308     /**
309      * Register a new platform.
310      * @param id unique ID string for the platform
311      * @param destdir destination directory (i.e. top-level directory beneath which there are clusters)
312      * @param label display label
313      * @return the created platform
314      * @throws IOException in case of problems (e.g. destination directory does not exist)
315      */

316     public static NbPlatform addPlatform(final String JavaDoc id, final File JavaDoc destdir, final String JavaDoc label) throws IOException JavaDoc {
317         return addPlatform(id, destdir, findHarness(destdir), label);
318     }
319     
320     /**
321      * Register a new platform.
322      * @param id unique ID string for the platform
323      * @param destdir destination directory (i.e. top-level directory beneath which there are clusters)
324      * @param harness harness directory
325      * @param label display label
326      * @return the created platform
327      * @throws IOException in case of problems (e.g. destination directory does not exist)
328      */

329     public static NbPlatform addPlatform(final String JavaDoc id, final File JavaDoc destdir, final File JavaDoc harness, final String JavaDoc label) throws IOException JavaDoc {
330         try {
331             ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction() {
332                 public Object JavaDoc run() throws IOException JavaDoc {
333                     EditableProperties props = PropertyUtils.getGlobalProperties();
334                     String JavaDoc plafDestDir = PLATFORM_PREFIX + id + PLATFORM_DEST_DIR_SUFFIX;
335                     props.setProperty(plafDestDir, destdir.getAbsolutePath());
336                     if (!destdir.isDirectory()) {
337                         throw new FileNotFoundException JavaDoc(destdir.getAbsolutePath());
338                     }
339                     storeHarnessLocation(id, destdir, harness, props);
340                     props.setProperty(PLATFORM_PREFIX + id + PLATFORM_LABEL_SUFFIX, label);
341                     PropertyUtils.putGlobalProperties(props);
342                     return null;
343                 }
344             });
345         } catch (MutexException e) {
346             throw (IOException JavaDoc) e.getException();
347         }
348         NbPlatform plaf = new NbPlatform(id, label, FileUtil.normalizeFile(destdir), harness,
349                 findURLs(null), findURLs(null));
350         synchronized (NbPlatform.class) {
351             getPlatformsInternal().add(plaf);
352         }
353         if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) {
354             Util.err.log("NbPlatform added: " + plaf);
355         }
356         return plaf;
357     }
358     
359     private static void storeHarnessLocation(String JavaDoc id, File JavaDoc destdir, File JavaDoc harness, EditableProperties props) {
360         String JavaDoc harnessDirKey = PLATFORM_PREFIX + id + PLATFORM_HARNESS_DIR_SUFFIX;
361         if (harness.equals(findHarness(destdir))) {
362             // Common case.
363
String JavaDoc plafDestDir = PLATFORM_PREFIX + id + PLATFORM_DEST_DIR_SUFFIX;
364             props.setProperty(harnessDirKey, "${" + plafDestDir + "}/" + harness.getName()); // NOI18N
365
} else if (harness.equals(getDefaultPlatform().getHarnessLocation())) {
366             // Also common.
367
props.setProperty(harnessDirKey, "${" + PLATFORM_PREFIX + PLATFORM_ID_DEFAULT + PLATFORM_HARNESS_DIR_SUFFIX + "}"); // NOI18N
368
} else {
369             // Some random location.
370
props.setProperty(harnessDirKey, harness.getAbsolutePath());
371         }
372     }
373     
374     public static void removePlatform(final NbPlatform plaf) throws IOException JavaDoc {
375         try {
376             ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction() {
377                 public Object JavaDoc run() throws IOException JavaDoc {
378                     EditableProperties props = PropertyUtils.getGlobalProperties();
379                     props.remove(PLATFORM_PREFIX + plaf.getID() + PLATFORM_DEST_DIR_SUFFIX);
380                     props.remove(PLATFORM_PREFIX + plaf.getID() + PLATFORM_HARNESS_DIR_SUFFIX);
381                     props.remove(PLATFORM_PREFIX + plaf.getID() + PLATFORM_LABEL_SUFFIX);
382                     props.remove(PLATFORM_PREFIX + plaf.getID() + PLATFORM_SOURCES_SUFFIX);
383                     props.remove(PLATFORM_PREFIX + plaf.getID() + PLATFORM_JAVADOC_SUFFIX);
384                     PropertyUtils.putGlobalProperties(props);
385                     return null;
386                 }
387             });
388         } catch (MutexException e) {
389             throw (IOException JavaDoc) e.getException();
390         }
391         synchronized (NbPlatform.class) {
392             getPlatformsInternal().remove(plaf);
393         }
394         if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) {
395             Util.err.log("NbPlatform removed: " + plaf);
396         }
397     }
398     
399     private final String JavaDoc id;
400     private String JavaDoc label;
401     private File JavaDoc nbdestdir;
402     private File JavaDoc harness;
403     private URL JavaDoc[] sourceRoots;
404     private URL JavaDoc[] javadocRoots;
405     private List JavaDoc<ModuleList> listsForSources;
406     private int harnessVersion = -1;
407     
408     private NbPlatform(String JavaDoc id, String JavaDoc label, File JavaDoc nbdestdir, File JavaDoc harness, URL JavaDoc[] sources, URL JavaDoc[] javadoc) {
409         this.id = id;
410         this.label = label;
411         this.nbdestdir = nbdestdir;
412         this.harness = harness;
413         this.sourceRoots = sources;
414         this.javadocRoots = javadoc;
415     }
416     
417     static URL JavaDoc[] findURLs(final String JavaDoc path) {
418         if (path == null) {
419             return new URL JavaDoc[0];
420         }
421         String JavaDoc[] pieces = PropertyUtils.tokenizePath(path);
422         URL JavaDoc[] urls = new URL JavaDoc[pieces.length];
423         for (int i = 0; i < pieces.length; i++) {
424             // XXX perhaps also support http: URLs somehow?
425
urls[i] = Util.urlForDirOrJar(FileUtil.normalizeFile(new File JavaDoc(pieces[i])));
426         }
427         return urls;
428     }
429     
430     /**
431      * Get a unique ID for this platform.
432      * Used e.g. in <code>nbplatform.active</code> in <code>platform.properties</code>.
433      * @return a unique ID, or <code>null</code> for <em>anonymous</em>
434      * platforms (see {@link #getPlatformByDestDir}).
435      */

436     public String JavaDoc getID() {
437         return id;
438     }
439     
440     /**
441      * Check if this is the default platform.
442      * @return true for the one default platform
443      */

444     public boolean isDefault() {
445         return PLATFORM_ID_DEFAULT.equals(id);
446     }
447     
448     /**
449      * Get a display label suitable for the user.
450      * If not set, {@link #computeDisplayName} is used.
451      * The {@link #isDefault default platform} is specially marked.
452      * @return a display label
453      */

454     public String JavaDoc getLabel() {
455         if (label == null) {
456             try {
457                 label = isValid() ? computeDisplayName(nbdestdir) :
458                     NbBundle.getMessage(NbPlatform.class, "MSG_InvalidPlatform", // NOI18N
459
getDestDir().getAbsolutePath());
460             } catch (IOException JavaDoc e) {
461                 Util.err.notify(ErrorManager.INFORMATIONAL, e);
462                 label = nbdestdir.getAbsolutePath();
463             }
464         }
465         if (isDefault()) {
466             return NbBundle.getMessage(NbPlatform.class, "LBL_default_platform", label);
467         } else {
468             return label;
469         }
470     }
471     
472     /**
473      * Get the installation directory.
474      * @return the installation directory
475      */

476     public File JavaDoc getDestDir() {
477         return nbdestdir;
478     }
479     
480     public void setDestDir(File JavaDoc destdir) {
481         this.nbdestdir = destdir;
482         // XXX write build.properties too
483
}
484     
485     /**
486      * Get associated source roots for this platform.
487      * Each root could be a netbeans.org CVS checkout or a module suite project directory.
488      * @return a list of source root URLs (may be empty but not null)
489      */

490     public URL JavaDoc[] getSourceRoots() {
491         if (sourceRoots.length == 0 && isDefault()) {
492             return defaultPlatformSources(getDestDir());
493         } else {
494             return sourceRoots;
495         }
496     }
497     
498     private void maybeUpdateDefaultPlatformSources() {
499         if (sourceRoots.length == 0 && isDefault()) {
500             sourceRoots = defaultPlatformSources(getDestDir());
501             pcs.firePropertyChange(PROP_SOURCE_ROOTS, null, null);
502         }
503     }
504     
505     /**
506      * Add given source root to the current source root list and save the
507      * result into the global properties in the <em>userdir</em> (see {@link
508      * PropertyUtils#putGlobalProperties})
509      */

510     public void addSourceRoot(URL JavaDoc root) throws IOException JavaDoc {
511         maybeUpdateDefaultPlatformSources();
512         URL JavaDoc[] newSourceRoots = new URL JavaDoc[sourceRoots.length + 1];
513         System.arraycopy(sourceRoots, 0, newSourceRoots, 0, sourceRoots.length);
514         newSourceRoots[sourceRoots.length] = root;
515         setSourceRoots(newSourceRoots);
516     }
517     
518     /**
519      * Remove given source roots from the current source root list and save the
520      * result into the global properties in the <em>userdir</em> (see {@link
521      * PropertyUtils#putGlobalProperties})
522      */

523     public void removeSourceRoots(URL JavaDoc[] urlsToRemove) throws IOException JavaDoc {
524         maybeUpdateDefaultPlatformSources();
525         Collection JavaDoc newSources = new ArrayList JavaDoc(Arrays.asList(sourceRoots));
526         newSources.removeAll(Arrays.asList(urlsToRemove));
527         URL JavaDoc[] sources = new URL JavaDoc[newSources.size()];
528         setSourceRoots((URL JavaDoc[]) newSources.toArray(sources));
529     }
530     
531     public void moveSourceRootUp(int indexToUp) throws IOException JavaDoc {
532         maybeUpdateDefaultPlatformSources();
533         if (indexToUp <= 0) {
534             return; // nothing needs to be done
535
}
536         URL JavaDoc[] newSourceRoots = new URL JavaDoc[sourceRoots.length];
537         System.arraycopy(sourceRoots, 0, newSourceRoots, 0, sourceRoots.length);
538         newSourceRoots[indexToUp - 1] = sourceRoots[indexToUp];
539         newSourceRoots[indexToUp] = sourceRoots[indexToUp - 1];
540         setSourceRoots(newSourceRoots);
541     }
542     
543     public void moveSourceRootDown(int indexToDown) throws IOException JavaDoc {
544         maybeUpdateDefaultPlatformSources();
545         if (indexToDown >= (sourceRoots.length - 1)) {
546             return; // nothing needs to be done
547
}
548         URL JavaDoc[] newSourceRoots = new URL JavaDoc[sourceRoots.length];
549         System.arraycopy(sourceRoots, 0, newSourceRoots, 0, sourceRoots.length);
550         newSourceRoots[indexToDown + 1] = sourceRoots[indexToDown];
551         newSourceRoots[indexToDown] = sourceRoots[indexToDown + 1];
552         setSourceRoots(newSourceRoots);
553     }
554     
555     public void setSourceRoots(URL JavaDoc[] roots) throws IOException JavaDoc {
556         putGlobalProperty(
557                 PLATFORM_PREFIX + getID() + PLATFORM_SOURCES_SUFFIX,
558                 urlsToAntPath(roots));
559         sourceRoots = roots;
560         pcs.firePropertyChange(PROP_SOURCE_ROOTS, null, null);
561         listsForSources = null;
562     }
563     
564     /**
565      * Get associated Javadoc roots for this platform.
566      * Each root may contain some Javadoc sets in the usual format as subdirectories,
567      * where the subdirectory is named acc. to the code name base of the module it
568      * is documenting (using '-' in place of '.').
569      * @return a list of Javadoc root URLs (may be empty but not null)
570      */

571     public URL JavaDoc[] getJavadocRoots() {
572         if (javadocRoots.length == 0 && isDefault()) {
573             return defaultPlatformJavadoc();
574         } else {
575             return javadocRoots;
576         }
577     }
578     
579     private void maybeUpdateDefaultPlatformJavadoc() {
580         if (javadocRoots.length == 0 && isDefault()) {
581             javadocRoots = defaultPlatformJavadoc();
582         }
583     }
584     
585     /**
586      * Add given javadoc root to the current javadoc root list and save the
587      * result into the global properties in the <em>userdir</em> (see {@link
588      * PropertyUtils#putGlobalProperties})
589      */

590     public void addJavadocRoot(URL JavaDoc root) throws IOException JavaDoc {
591         maybeUpdateDefaultPlatformJavadoc();
592         URL JavaDoc[] newJavadocRoots = new URL JavaDoc[javadocRoots.length + 1];
593         System.arraycopy(javadocRoots, 0, newJavadocRoots, 0, javadocRoots.length);
594         newJavadocRoots[javadocRoots.length] = root;
595         setJavadocRoots(newJavadocRoots);
596     }
597     
598     /**
599      * Remove given javadoc roots from the current javadoc root list and save
600      * the result into the global properties in the <em>userdir</em> (see
601      * {@link PropertyUtils#putGlobalProperties})
602      */

603     public void removeJavadocRoots(URL JavaDoc[] urlsToRemove) throws IOException JavaDoc {
604         maybeUpdateDefaultPlatformJavadoc();
605         Collection JavaDoc newJavadocs = new ArrayList JavaDoc(Arrays.asList(javadocRoots));
606         newJavadocs.removeAll(Arrays.asList(urlsToRemove));
607         URL JavaDoc[] javadocs = new URL JavaDoc[newJavadocs.size()];
608         setJavadocRoots((URL JavaDoc[]) newJavadocs.toArray(javadocs));
609     }
610     
611     public void moveJavadocRootUp(int indexToUp) throws IOException JavaDoc {
612         maybeUpdateDefaultPlatformJavadoc();
613         if (indexToUp <= 0) {
614             return; // nothing needs to be done
615
}
616         URL JavaDoc[] newJavadocRoots = new URL JavaDoc[javadocRoots.length];
617         System.arraycopy(javadocRoots, 0, newJavadocRoots, 0, javadocRoots.length);
618         newJavadocRoots[indexToUp - 1] = javadocRoots[indexToUp];
619         newJavadocRoots[indexToUp] = javadocRoots[indexToUp - 1];
620         setJavadocRoots(newJavadocRoots);
621     }
622     
623     public void moveJavadocRootDown(int indexToDown) throws IOException JavaDoc {
624         maybeUpdateDefaultPlatformJavadoc();
625         if (indexToDown >= (javadocRoots.length - 1)) {
626             return; // nothing needs to be done
627
}
628         URL JavaDoc[] newJavadocRoots = new URL JavaDoc[javadocRoots.length];
629         System.arraycopy(javadocRoots, 0, newJavadocRoots, 0, javadocRoots.length);
630         newJavadocRoots[indexToDown + 1] = javadocRoots[indexToDown];
631         newJavadocRoots[indexToDown] = javadocRoots[indexToDown + 1];
632         setJavadocRoots(newJavadocRoots);
633     }
634     
635     public void setJavadocRoots(URL JavaDoc[] roots) throws IOException JavaDoc {
636         putGlobalProperty(
637                 PLATFORM_PREFIX + getID() + PLATFORM_JAVADOC_SUFFIX,
638                 urlsToAntPath(roots));
639         javadocRoots = roots;
640     }
641     
642     /**
643      * Test whether this platform is valid or not. See
644      * {@link #isPlatformDirectory}
645      */

646     public boolean isValid() {
647         return NbPlatform.isPlatformDirectory(getDestDir());
648     }
649     
650     static String JavaDoc urlsToAntPath(final URL JavaDoc[] urls) {
651         StringBuffer JavaDoc path = new StringBuffer JavaDoc();
652         for (int i = 0; i < urls.length; i++) {
653             if (urls[i].getProtocol().equals("jar")) { // NOI18N
654
path.append(urlToAntPath(FileUtil.getArchiveFile(urls[i])));
655             } else {
656                 path.append(urlToAntPath(urls[i]));
657             }
658             if (i != urls.length - 1) {
659                 path.append(':'); // NOI18N
660
}
661         }
662         return path.toString();
663     }
664     
665     private static String JavaDoc urlToAntPath(final URL JavaDoc url) {
666         return new File JavaDoc(URI.create(url.toExternalForm())).getAbsolutePath();
667     }
668     
669     private void putGlobalProperty(final String JavaDoc key, final String JavaDoc value) throws IOException JavaDoc {
670         try {
671             ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction() {
672                 public Object JavaDoc run() throws IOException JavaDoc {
673                     EditableProperties props = PropertyUtils.getGlobalProperties();
674                     if ("".equals(value)) { // NOI18N
675
props.remove(key);
676                     } else {
677                         props.setProperty(key, value);
678                     }
679                     PropertyUtils.putGlobalProperties(props);
680                     return null;
681                 }
682             });
683         } catch (MutexException e) {
684             throw (IOException JavaDoc) e.getException();
685         }
686     }
687     
688     /**
689      * Find sources for a module JAR file contained in this destination directory.
690      * @param jar a JAR file in the destination directory
691      * @return the directory of sources for this module (a project directory), or null
692      */

693     public File JavaDoc getSourceLocationOfModule(File JavaDoc jar) {
694         if (listsForSources == null) {
695             listsForSources = new ArrayList JavaDoc();
696             URL JavaDoc[] sourceRoots = getSourceRoots();
697             for (int i = 0; i < sourceRoots.length; i++) {
698                 URL JavaDoc u = sourceRoots[i];
699                 if (!u.getProtocol().equals("file")) { // NOI18N
700
continue;
701                 }
702                 File JavaDoc dir = new File JavaDoc(URI.create(u.toExternalForm()));
703                 if (dir.isDirectory()) {
704                     try {
705                         if (ModuleList.isNetBeansOrg(dir)) {
706                             listsForSources.add(ModuleList.findOrCreateModuleListFromNetBeansOrgSources(dir));
707                         } else {
708                             listsForSources.add(ModuleList.findOrCreateModuleListFromSuiteWithoutBinaries(dir));
709                         }
710                     } catch (IOException JavaDoc e) {
711                         Util.err.notify(ErrorManager.INFORMATIONAL, e);
712                     }
713                 }
714             }
715         }
716         Iterator JavaDoc it = listsForSources.iterator();
717         while (it.hasNext()) {
718             ModuleList l = (ModuleList) it.next();
719             Set JavaDoc<ModuleEntry> entries = l.getAllEntriesSoft();
720             Iterator JavaDoc it2 = entries.iterator();
721             while (it2.hasNext()) {
722                 ModuleEntry entry = (ModuleEntry) it2.next();
723                 // XXX should be more strict (e.g. compare also clusters)
724
if (!entry.getJarLocation().getName().equals(jar.getName())) {
725                     continue;
726                 }
727                 File JavaDoc src = entry.getSourceLocation();
728                 if (src != null && src.isDirectory()) {
729                     return src;
730                 }
731             }
732             entries = l.getAllEntries();
733             it2 = entries.iterator();
734             while (it2.hasNext()) {
735                 ModuleEntry entry = (ModuleEntry) it2.next();
736                 if (!entry.getJarLocation().getName().equals(jar.getName())) {
737                     continue;
738                 }
739                 File JavaDoc src = entry.getSourceLocation();
740                 if (src != null && src.isDirectory()) {
741                     return src;
742                 }
743             }
744         }
745         return null;
746     }
747     
748     /**
749      * Returns (naturally sorted) array of all module entries pertaining to
750      * <code>this</code> NetBeans platform. This is just a convenient delegate
751      * to the {@link ModuleList#findOrCreateModuleListFromBinaries}.
752      */

753     public ModuleEntry[] getModules() {
754         try {
755             SortedSet JavaDoc<ModuleEntry> set = new TreeSet JavaDoc(
756                     ModuleList.findOrCreateModuleListFromBinaries(getDestDir()).getAllEntriesSoft());
757             ModuleEntry[] entries = new ModuleEntry[set.size()];
758             set.toArray(entries);
759             return entries;
760         } catch (IOException JavaDoc e) {
761             Util.err.notify(e);
762             return new ModuleEntry[0];
763         }
764     }
765     
766     private static File JavaDoc findCoreJar(File JavaDoc destdir) {
767         File JavaDoc[] subdirs = destdir.listFiles();
768         if (subdirs != null) {
769             for (int i = 0; i < subdirs.length; i++) {
770                 if (!subdirs[i].isDirectory()) {
771                     continue;
772                 }
773                 if (!subdirs[i].getName().startsWith("platform")) { // NOI18N
774
continue;
775                 }
776                 File JavaDoc coreJar = new File JavaDoc(subdirs[i], "core" + File.separatorChar + "core.jar"); // NOI18N
777
if (coreJar.isFile()) {
778                     return coreJar;
779                 }
780             }
781         }
782         return null;
783     }
784     
785     /**
786      * Check whether a given directory on disk is a valid destdir as per {@link #getDestDir}.
787      * @param destdir a candidate directory
788      * @return true if it can be used as a platform
789      */

790     public static boolean isPlatformDirectory(File JavaDoc destdir) {
791         return findCoreJar(destdir) != null;
792     }
793     
794     public static boolean isSupportedPlatform(File JavaDoc destdir) {
795         boolean valid = false;
796         File JavaDoc coreJar = findCoreJar(destdir);
797         if (coreJar != null) {
798             String JavaDoc platformDir = coreJar.getParentFile().getParentFile().getName();
799             assert platformDir.startsWith("platform"); // NOI18N
800
int version = Integer.parseInt(platformDir.substring(8)); // 8 == "platform".length
801
valid = version >= 6;
802         }
803         return valid;
804     }
805     
806     /**
807      * Find a display name for a NetBeans platform on disk.
808      * @param destdir a dir passing {@link #isPlatformDirectory}
809      * @return a display name
810      * @throws IllegalArgumentException if {@link #isPlatformDirectory} was false
811      * @throws IOException if its labelling info could not be read
812      */

813     public static String JavaDoc computeDisplayName(File JavaDoc destdir) throws IOException JavaDoc {
814         File JavaDoc coreJar = findCoreJar(destdir);
815         if (coreJar == null) {
816             throw new IllegalArgumentException JavaDoc(destdir.getAbsolutePath());
817         }
818         String JavaDoc currVer, implVers;
819         JarFile JavaDoc jf = new JarFile JavaDoc(coreJar);
820         try {
821             currVer = findCurrVer(jf, "");
822             if (currVer == null) {
823                 throw new IOException JavaDoc(coreJar.getAbsolutePath());
824             }
825             implVers = jf.getManifest().getMainAttributes().getValue("OpenIDE-Module-Implementation-Version"); // NOI18N
826
if (implVers == null) {
827                 throw new IOException JavaDoc(coreJar.getAbsolutePath());
828             }
829         } finally {
830             jf.close();
831         }
832         // Also check in localizing bundles for 'currentVersion', since it may be branded.
833
// We do not know what the runtime branding will be, so look for anything.
834
File JavaDoc[] clusters = destdir.listFiles();
835         BRANDED_CURR_VER: if (clusters != null) {
836             for (int i = 0; i < clusters.length; i++) {
837                 File JavaDoc coreLocaleDir = new File JavaDoc(clusters[i], "core" + File.separatorChar + "locale"); // NOI18N
838
if (!coreLocaleDir.isDirectory()) {
839                     continue;
840                 }
841                 String JavaDoc[] kids = coreLocaleDir.list();
842                 if (kids != null) {
843                     for (int j = 0; j < kids.length; j++) {
844                         String JavaDoc name = kids[j];
845                         String JavaDoc prefix = "core"; // NOI18N
846
String JavaDoc suffix = ".jar"; // NOI18N
847
if (!name.startsWith(prefix) || !name.endsWith(suffix)) {
848                             continue;
849                         }
850                         String JavaDoc infix = name.substring(prefix.length(), name.length() - suffix.length());
851                         int uscore = infix.lastIndexOf('_');
852                         if (uscore == -1) {
853                             // Malformed.
854
continue;
855                         }
856                         String JavaDoc lastPiece = infix.substring(uscore + 1);
857                         if (Arrays.asList(Locale.getISOCountries()).contains(lastPiece) ||
858                                 (!lastPiece.equals("nb") && Arrays.asList(Locale.getISOLanguages()).contains(lastPiece))) { // NOI18N
859
// Probably a localization, not a branding... so skip it. (We want to show English only.)
860
// But hardcode support for branding 'nb' since this is also Norwegian Bokmal, apparently!
861
// XXX should this try to use Locale.getDefault() localization if possible?
862
continue;
863                         }
864                         jf = new JarFile JavaDoc(new File JavaDoc(coreLocaleDir, name));
865                         try {
866                             String JavaDoc brandedCurrVer = findCurrVer(jf, infix);
867                             if (brandedCurrVer != null) {
868                                 currVer = brandedCurrVer;
869                                 break BRANDED_CURR_VER;
870                             }
871                         } finally {
872                             jf.close();
873                         }
874                     }
875                 }
876             }
877         }
878         return MessageFormat.format(currVer, new Object JavaDoc[] {implVers});
879     }
880     private static String JavaDoc findCurrVer(JarFile JavaDoc jar, String JavaDoc infix) throws IOException JavaDoc {
881         // first try to find the Bundle for 5.0+ (after openide split)
882
ZipEntry JavaDoc bundle = jar.getEntry("org/netbeans/core/startup/Bundle" + infix + ".properties"); // NOI18N
883
if (bundle == null) {
884             // might be <5.0 (before openide split)
885
bundle = jar.getEntry("org/netbeans/core/Bundle" + infix + ".properties"); // NOI18N
886
}
887         if (bundle == null) {
888             return null;
889         }
890         Properties JavaDoc props = new Properties JavaDoc();
891         InputStream JavaDoc is = jar.getInputStream(bundle);
892         try {
893             props.load(is);
894         } finally {
895             is.close();
896         }
897         return props.getProperty("currentVersion"); // NOI18N
898
}
899     
900     /**
901      * Returns whether the given label (see {@link #getLabel}) is valid.
902      * <em>Valid</em> label must be non-null and must not be used by any
903      * already defined platform.
904      */

905     public static boolean isLabelValid(String JavaDoc supposedLabel) {
906         if (supposedLabel == null) {
907             return false;
908         }
909         for (Iterator JavaDoc it = NbPlatform.getPlatforms().iterator(); it.hasNext(); ) {
910             String JavaDoc label = ((NbPlatform) it.next()).getLabel();
911             if (supposedLabel.equals(label)) {
912                 return false;
913             }
914         }
915         return true;
916     }
917     
918     public String JavaDoc toString() {
919         return "NbPlatform[" + getID() + ":" + getDestDir() + ";sources=" + Arrays.asList(getSourceRoots()) + ";javadoc=" + Arrays.asList(getJavadocRoots()) + "]"; // NOI18N;
920
}
921     
922     /**
923      * Get the version of this platform's harness.
924      */

925     public int getHarnessVersion() {
926         if (harnessVersion != -1) {
927             return harnessVersion;
928         }
929         if (!isValid()) {
930             return harnessVersion = HARNESS_VERSION_UNKNOWN;
931         }
932         File JavaDoc harnessJar = new File JavaDoc(harness, "modules" + File.separatorChar + "org-netbeans-modules-apisupport-harness.jar"); // NOI18N
933
if (harnessJar.isFile()) {
934             try {
935                 JarFile JavaDoc jf = new JarFile JavaDoc(harnessJar);
936                 try {
937                     String JavaDoc spec = jf.getManifest().getMainAttributes().getValue(ManifestManager.OPENIDE_MODULE_SPECIFICATION_VERSION);
938                     if (spec != null) {
939                         SpecificationVersion v = new SpecificationVersion(spec);
940                         if (v.compareTo(new SpecificationVersion("1.10")) >= 0) { // NOI18N
941
return harnessVersion = HARNESS_VERSION_60;
942                         } else if (v.compareTo(new SpecificationVersion("1.9")) >= 0) { // NOI18N
943
return harnessVersion = HARNESS_VERSION_55u1;
944                         } else if (v.compareTo(new SpecificationVersion("1.7")) >= 0) { // NOI18N
945
return harnessVersion = HARNESS_VERSION_50u1;
946                         } else if (v.compareTo(new SpecificationVersion("1.6")) >= 0) { // NOI18N
947
return harnessVersion = HARNESS_VERSION_50;
948                         } // earlier than beta2? who knows...
949
}
950                 } finally {
951                     jf.close();
952                 }
953             } catch (IOException JavaDoc e) {
954                 Util.err.notify(ErrorManager.INFORMATIONAL, e);
955             } catch (NumberFormatException JavaDoc e) {
956                 Util.err.notify(ErrorManager.INFORMATIONAL, e);
957             }
958         }
959         return harnessVersion = HARNESS_VERSION_UNKNOWN;
960     }
961     
962     /**
963      * Get the current location of this platform's harness
964      */

965     public File JavaDoc getHarnessLocation() {
966         return harness;
967     }
968     
969     /**
970      * Get the location of the harness bundled with this platform.
971      */

972     public File JavaDoc getBundledHarnessLocation() {
973         return findHarness(nbdestdir);
974     }
975     
976     /**
977      * Set a new location for this platform's harness.
978      */

979     public void setHarnessLocation(final File JavaDoc harness) throws IOException JavaDoc {
980         if (harness.equals(this.harness)) {
981             return;
982         }
983         try {
984             ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction() {
985                 public Object JavaDoc run() throws IOException JavaDoc {
986                     EditableProperties props = PropertyUtils.getGlobalProperties();
987                     storeHarnessLocation(id, nbdestdir, harness, props);
988                     PropertyUtils.putGlobalProperties(props);
989                     return null;
990                 }
991             });
992         } catch (MutexException e) {
993             throw (IOException JavaDoc) e.getException();
994         }
995         this.harness = harness;
996         harnessVersion = -1;
997     }
998     
999     /**
1000     * Gets a quick display name for the <em>version</em> of a harness.
1001     * @param {@link #HARNESS_VERSION_50} etc.
1002     * @return a short display name
1003     */

1004    public static String JavaDoc getHarnessVersionDisplayName(int version) {
1005        switch (version) {
1006            case HARNESS_VERSION_50:
1007                return NbBundle.getMessage(NbPlatform.class, "LBL_harness_version_5.0");
1008            case HARNESS_VERSION_50u1:
1009                return NbBundle.getMessage(NbPlatform.class, "LBL_harness_version_5.0u1");
1010            case HARNESS_VERSION_55u1:
1011                return NbBundle.getMessage(NbPlatform.class, "LBL_harness_version_5.5u1");
1012            case HARNESS_VERSION_60:
1013                return NbBundle.getMessage(NbPlatform.class, "LBL_harness_version_6.0");
1014            default:
1015                assert version == HARNESS_VERSION_UNKNOWN;
1016                return NbBundle.getMessage(NbPlatform.class, "LBL_harness_version_unknown");
1017        }
1018    }
1019    
1020    public void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
1021        pcs.addPropertyChangeListener(listener);
1022    }
1023    
1024    public void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
1025        pcs.removePropertyChangeListener(listener);
1026    }
1027    
1028}
1029
Popular Tags