KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > apisupport > project > layers > LayerUtils


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.layers;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.beans.PropertyChangeSupport JavaDoc;
25 import java.beans.PropertyVetoException JavaDoc;
26 import java.io.File JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.OutputStream JavaDoc;
29 import java.net.URL JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.Arrays JavaDoc;
32 import java.util.Collections JavaDoc;
33 import java.util.Enumeration JavaDoc;
34 import java.util.HashSet JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.LinkedList JavaDoc;
37 import java.util.List JavaDoc;
38 import java.util.Locale JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.Set JavaDoc;
41 import java.util.WeakHashMap JavaDoc;
42 import java.util.jar.Manifest JavaDoc;
43 import java.util.regex.Matcher JavaDoc;
44 import java.util.regex.Pattern JavaDoc;
45 import org.netbeans.api.java.classpath.ClassPath;
46 import org.netbeans.api.project.Project;
47 import org.netbeans.api.project.ProjectManager;
48 import org.netbeans.modules.apisupport.project.EditableManifest;
49 import org.netbeans.modules.apisupport.project.ManifestManager;
50 import org.netbeans.modules.apisupport.project.NbModuleProject;
51 import org.netbeans.modules.apisupport.project.NbModuleProjectGenerator;
52 import org.netbeans.modules.apisupport.project.Util;
53 import org.netbeans.modules.apisupport.project.Util;
54 import org.netbeans.modules.apisupport.project.spi.NbModuleProvider;
55 import org.netbeans.modules.apisupport.project.suite.SuiteProject;
56 import org.netbeans.modules.apisupport.project.ui.customizer.SuiteProperties;
57 import org.netbeans.modules.apisupport.project.ui.customizer.SuiteUtils;
58 import org.netbeans.modules.apisupport.project.universe.ModuleEntry;
59 import org.netbeans.modules.apisupport.project.universe.ModuleList;
60 import org.netbeans.modules.apisupport.project.universe.NbPlatform;
61 import org.netbeans.modules.xml.tax.cookies.TreeEditorCookie;
62 import org.netbeans.modules.xml.tax.parser.XMLParsingSupport;
63 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
64 import org.netbeans.spi.project.support.ant.PropertyEvaluator;
65 import org.netbeans.tax.TreeDocumentRoot;
66 import org.netbeans.tax.TreeException;
67 import org.netbeans.tax.TreeObject;
68 import org.netbeans.tax.io.TreeStreamResult;
69 import org.openide.ErrorManager;
70 import org.openide.filesystems.FileAttributeEvent;
71 import org.openide.filesystems.FileChangeListener;
72 import org.openide.filesystems.FileEvent;
73 import org.openide.filesystems.FileLock;
74 import org.openide.filesystems.FileObject;
75 import org.openide.filesystems.FileRenameEvent;
76 import org.openide.filesystems.FileStateInvalidException;
77 import org.openide.filesystems.FileSystem;
78 import org.openide.filesystems.FileUtil;
79 import org.openide.filesystems.MultiFileSystem;
80 import org.openide.filesystems.XMLFileSystem;
81 import org.openide.util.Task;
82 import org.xml.sax.InputSource JavaDoc;
83 import org.xml.sax.SAXException JavaDoc;
84
85 /**
86  * Misc support for dealing with layers.
87  * @author Jesse Glick
88  */

89 public class LayerUtils {
90     
91     private LayerUtils() {}
92     
93     /**
94      * Translates nbres: into nbrescurr: for internal use.
95      * Returns an array of one or more URLs.
96      * May just be original URL, but will try to produce URLs corresponding to real files.
97      * If there is a suffix, may produce several, most specific first.
98      */

99     static URL JavaDoc[] currentify(URL JavaDoc u, String JavaDoc suffix, ClassPath cp) {
100         if (cp == null) {
101             return new URL JavaDoc[] {u};
102         }
103         try {
104             if (u.getProtocol().equals("nbres")) { // NOI18N
105
String JavaDoc path = u.getFile();
106                 if (path.startsWith("/")) path = path.substring(1); // NOI18N
107
FileObject fo = cp.findResource(path);
108                 if (fo != null) {
109                     return new URL JavaDoc[] {fo.getURL()};
110                 }
111             } else if (u.getProtocol().equals("nbresloc")) { // NOI18N
112
List JavaDoc<URL JavaDoc> urls = new ArrayList JavaDoc();
113                 String JavaDoc path = u.getFile();
114                 if (path.startsWith("/")) path = path.substring(1); // NOI18N
115
int idx = path.lastIndexOf('/');
116                 String JavaDoc folder;
117                 String JavaDoc nameext;
118                 if (idx == -1) {
119                     folder = ""; // NOI18N
120
nameext = path;
121                 } else {
122                     folder = path.substring(0, idx + 1);
123                     nameext = path.substring(idx + 1);
124                 }
125                 idx = nameext.lastIndexOf('.');
126                 String JavaDoc name;
127                 String JavaDoc ext;
128                 if (idx == -1) {
129                     name = nameext;
130                     ext = ""; // NOI18N
131
} else {
132                     name = nameext.substring(0, idx);
133                     ext = nameext.substring(idx);
134                 }
135                 List JavaDoc suffixes = new ArrayList JavaDoc(computeSubVariants(suffix));
136                 suffixes.add(suffix);
137                 Collections.reverse(suffixes);
138                 Iterator JavaDoc it = suffixes.iterator();
139                 while (it.hasNext()) {
140                     String JavaDoc trysuffix = (String JavaDoc) it.next();
141                     String JavaDoc trypath = folder + name + trysuffix + ext;
142                     FileObject fo = cp.findResource(trypath);
143                     if (fo != null) {
144                         urls.add(fo.getURL());
145                     }
146                 }
147                 if (!urls.isEmpty()) {
148                     return (URL JavaDoc[]) urls.toArray(new URL JavaDoc[urls.size()]);
149                 }
150             }
151         } catch (FileStateInvalidException fsie) {
152             Util.err.notify(ErrorManager.WARNING, fsie);
153         }
154         return new URL JavaDoc[] {u};
155     }
156     
157     // E.g. for name 'foo_f4j_ce_ja', should produce list:
158
// 'foo', 'foo_ja', 'foo_f4j', 'foo_f4j_ja', 'foo_f4j_ce'
159
// Will actually produce:
160
// 'foo', 'foo_ja', 'foo_ce', 'foo_ce_ja', 'foo_f4j', 'foo_f4j_ja', 'foo_f4j_ce'
161
// since impossible to distinguish locale from branding reliably.
162
private static List JavaDoc<String JavaDoc> computeSubVariants(String JavaDoc name) {
163         int idx = name.indexOf('_');
164         if (idx == -1) {
165             return Collections.EMPTY_LIST;
166         } else {
167             String JavaDoc base = name.substring(0, idx);
168             String JavaDoc suffix = name.substring(idx);
169             List JavaDoc l = computeSubVariants(base, suffix);
170             return l.subList(0, l.size() - 1);
171         }
172     }
173     private static List JavaDoc<String JavaDoc> computeSubVariants(String JavaDoc base, String JavaDoc suffix) {
174         int idx = suffix.indexOf('_', 1);
175         if (idx == -1) {
176             List JavaDoc l = new LinkedList JavaDoc();
177             l.add(base);
178             l.add(base + suffix);
179             return l;
180         } else {
181             String JavaDoc remainder = suffix.substring(idx);
182             List JavaDoc l1 = computeSubVariants(base, remainder);
183             List JavaDoc l2 = computeSubVariants(base + suffix.substring(0, idx), remainder);
184             List JavaDoc l = new LinkedList JavaDoc(l1);
185             l.addAll(l2);
186             return l;
187         }
188     }
189     
190     // XXX needs to hold a strong ref only when modified, probably?
191
private static final Map JavaDoc<Project,LayerHandle> layerHandleCache = new WeakHashMap JavaDoc();
192     
193     /**
194      * Gets a handle for one project's XML layer.
195      */

196     public static LayerHandle layerForProject(Project project) {
197         LayerHandle handle = (LayerHandle) layerHandleCache.get(project);
198         if (handle == null) {
199             handle = new LayerHandle(project);
200             layerHandleCache.put(project, handle);
201         }
202         return handle;
203     }
204
205     private static final Set JavaDoc<String JavaDoc> XML_LIKE_TYPES = new HashSet JavaDoc();
206     static {
207         XML_LIKE_TYPES.add(".settings"); // NOI18N
208
XML_LIKE_TYPES.add(".wstcref"); // NOI18N
209
XML_LIKE_TYPES.add(".wsmode"); // NOI18N
210
XML_LIKE_TYPES.add(".wsgrp"); // NOI18N
211
XML_LIKE_TYPES.add(".wsmgr"); // NOI18N
212
}
213     /**
214      * Find the name of the external file that will be generated for a given
215      * layer path if it is created with contents.
216      * @param parent parent folder, or null
217      * @param layerPath full path in layer
218      * @return a simple file name
219      */

220     public static String JavaDoc findGeneratedName(FileObject parent, String JavaDoc layerPath) {
221         Matcher JavaDoc m = Pattern.compile("(.+/)?([^/.]+)(\\.[^/]+)?").matcher(layerPath); // NOI18N
222
if (!m.matches()) {
223             throw new IllegalArgumentException JavaDoc(layerPath);
224         }
225         String JavaDoc base = m.group(2);
226         String JavaDoc ext = m.group(3);
227         if (ext == null) {
228             ext = "";
229         } else if (ext.equals(".java")) { // NOI18N
230
ext = "_java"; // NOI18N
231
} else if (XML_LIKE_TYPES.contains(ext)) {
232             String JavaDoc upper = ext.substring(1,2).toUpperCase(Locale.ENGLISH);
233             base = base + upper + ext.substring(2);
234             ext = ".xml"; // NOI18N
235
}
236         String JavaDoc name = base + ext;
237         if (parent == null || parent.getFileObject(name) == null) {
238             return name;
239         } else {
240             for (int i = 1; true; i++) {
241                 name = base + '_' + i + ext;
242                 if (parent.getFileObject(name) == null) {
243                     return name;
244                 }
245             }
246         }
247     }
248     
249     /**
250      * Representation of in-memory TAX tree which can be saved upon request.
251      */

252     interface SavableTreeEditorCookie extends TreeEditorCookie {
253         
254         /** property change fired when dirty flag changes */
255         String JavaDoc PROP_DIRTY = "dirty"; // NOI18N
256

257         /** true if there are in-memory mods */
258         boolean isDirty();
259         
260         /** try to save any in-memory mods to disk */
261         void save() throws IOException JavaDoc;
262         
263     }
264     
265     private static final class CookieImpl implements SavableTreeEditorCookie, FileChangeListener {
266         private TreeDocumentRoot root;
267         private boolean dirty;
268         private Exception JavaDoc problem;
269         private final FileObject f;
270         private final PropertyChangeSupport JavaDoc pcs = new PropertyChangeSupport JavaDoc(this);
271         private boolean saving;
272         public CookieImpl(FileObject f) {
273             //System.err.println("new CookieImpl for " + f);
274
this.f = f;
275             f.addFileChangeListener(FileUtil.weakFileChangeListener(this, f));
276         }
277         public TreeDocumentRoot getDocumentRoot() {
278             return root;
279         }
280         public int getStatus() {
281             if (problem != null) {
282                 return TreeEditorCookie.STATUS_ERROR;
283             } else if (root != null) {
284                 return TreeEditorCookie.STATUS_OK;
285             } else {
286                 return TreeEditorCookie.STATUS_NOT;
287             }
288         }
289         public TreeDocumentRoot openDocumentRoot() throws IOException JavaDoc, TreeException {
290             if (root == null) {
291                 try {
292                     //System.err.println("openDocumentRoot: really opening");
293
boolean oldDirty = dirty;
294                     int oldStatus = getStatus();
295                     root = new XMLParsingSupport().parse(new InputSource JavaDoc(f.getURL().toExternalForm()));
296                     problem = null;
297                     dirty = false;
298                     pcs.firePropertyChange(PROP_DIRTY, oldDirty, false);
299                     pcs.firePropertyChange(PROP_STATUS, oldStatus, TreeEditorCookie.STATUS_OK);
300                     //pcs.firePropertyChange(PROP_DOCUMENT_ROOT, null, root);
301
} catch (IOException JavaDoc e) {
302                     problem = e;
303                     throw e;
304                 } catch (TreeException e) {
305                     problem = e;
306                     throw e;
307                 }
308                 ((TreeObject) root).addPropertyChangeListener(new PropertyChangeListener JavaDoc() {
309                     public void propertyChange(PropertyChangeEvent JavaDoc evt) {
310                         //System.err.println("tree modified");
311
modified();
312                     }
313                 });
314             }
315             return root;
316         }
317         public Task prepareDocumentRoot() {
318             throw new UnsupportedOperationException JavaDoc();
319         }
320         public void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
321             pcs.addPropertyChangeListener(listener);
322         }
323         public void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
324             pcs.removePropertyChangeListener(listener);
325         }
326         private void modified() {
327             //System.err.println("modified(): dirty=" + dirty + " in " + Thread.currentThread().getName() + " for " + this);
328
if (!dirty) {
329                 dirty = true;
330                 pcs.firePropertyChange(PROP_DIRTY, false, true);
331             }
332         }
333         public boolean isDirty() {
334             return dirty;
335         }
336         public synchronized void save() throws IOException JavaDoc {
337             //System.err.println("save(): dirty=" + dirty + " in " + Thread.currentThread().getName() + " for " + this);
338
if (root == null || !dirty) {
339                 return;
340             }
341             assert !saving;
342             saving = true;
343             //System.err.println("saving");
344
try {
345                 FileLock lock = f.lock();
346                 try {
347                     OutputStream JavaDoc os = f.getOutputStream(lock);
348                     try {
349                         new TreeStreamResult(os).getWriter(root).writeDocument();
350                     } catch (TreeException e) {
351                         throw (IOException JavaDoc) new IOException JavaDoc(e.toString()).initCause(e);
352                     } finally {
353                         os.close();
354                     }
355                 } finally {
356                     lock.releaseLock();
357                 }
358             } finally {
359                 saving = false;
360                 //System.err.println("!saving in " + Thread.currentThread().getName() + " for " + this);
361
}
362             dirty = false;
363             pcs.firePropertyChange(PROP_DIRTY, true, false);
364         }
365         public void fileChanged(FileEvent fe) {
366             changed();
367         }
368         public void fileDeleted(FileEvent fe) {
369             changed();
370         }
371         public void fileRenamed(FileRenameEvent fe) {
372             changed();
373         }
374         public void fileAttributeChanged(FileAttributeEvent fe) {
375             // ignore
376
}
377         public void fileFolderCreated(FileEvent fe) {
378             assert false;
379         }
380         public void fileDataCreated(FileEvent fe) {
381             assert false;
382         }
383         private void changed() {
384             //System.err.println("changed on disk; saving=" + saving + " in " + Thread.currentThread().getName() + " for " + this);
385
synchronized (this) {
386                 if (saving) {
387                     return;
388                 }
389                 problem = null;
390                 dirty = false;
391                 root = null;
392             }
393             pcs.firePropertyChange(PROP_DOCUMENT_ROOT, null, null);
394         }
395     }
396     
397     static SavableTreeEditorCookie cookieForFile(FileObject f) {
398         return new CookieImpl(f);
399     }
400     
401     /**
402      * Manages one project's XML layer.
403      */

404     public static final class LayerHandle {
405         
406         private final Project project;
407         private FileSystem fs;
408         private SavableTreeEditorCookie cookie;
409         private boolean autosave;
410         
411         LayerHandle(Project project) {
412             //System.err.println("new LayerHandle for " + project);
413
this.project = project;
414         }
415         
416         /**
417          * Get the layer as a structured filesystem.
418          * You can make whatever Filesystems API calls you like to it.
419          * Just call {@link #save} when you are done so the modified XML document is saved
420          * (or the user can save it explicitly if you don't).
421          * @param create if true, and there is no layer yet, create it now; if false, just return null
422          */

423         public synchronized FileSystem layer(boolean create) {
424             if (fs == null) {
425                 FileObject xml = getLayerFile();
426                 if (xml == null) {
427                     if (!create) {
428                         return null;
429                     }
430                     try {
431                         NbModuleProvider module = project.getLookup().lookup(NbModuleProvider.class);
432                         // Check to see if the manifest entry is already specified.
433
String JavaDoc layerSrcPath = ManifestManager.getInstance(Util.getManifest(module.getManifestFile()), false).getLayer();
434                         if (layerSrcPath == null) {
435                             layerSrcPath = newLayerPath();
436                             FileObject manifest = module.getManifestFile();
437                             EditableManifest m = Util.loadManifest(manifest);
438                             m.setAttribute(ManifestManager.OPENIDE_MODULE_LAYER, layerSrcPath, null);
439                             Util.storeManifest(manifest, m);
440                         }
441                         xml = NbModuleProjectGenerator.createLayer(project.getProjectDirectory(), module.getResourceDirectoryPath(false) + '/' + newLayerPath());
442                     } catch (IOException JavaDoc e) {
443                         Util.err.notify(ErrorManager.INFORMATIONAL, e);
444                         return fs = FileUtil.createMemoryFileSystem();
445                     }
446                 }
447                 try {
448                     fs = new WritableXMLFileSystem(xml.getURL(), cookie = cookieForFile(xml), /*XXX*/null);
449                 } catch (FileStateInvalidException e) {
450                     throw new AssertionError JavaDoc(e);
451                 }
452                 cookie.addPropertyChangeListener(new PropertyChangeListener JavaDoc() {
453                     public void propertyChange(PropertyChangeEvent JavaDoc evt) {
454                         //System.err.println("changed in mem");
455
if (autosave && SavableTreeEditorCookie.PROP_DIRTY.equals(evt.getPropertyName())) {
456                             //System.err.println(" will save...");
457
try {
458                                 save();
459                             } catch (IOException JavaDoc e) {
460                                 Util.err.notify(ErrorManager.INFORMATIONAL, e);
461                             }
462                         }
463                     }
464                 });
465             }
466             return fs;
467         }
468         
469         /**
470          * Save the layer, if it was in fact modified.
471          * Note that nonempty layer entries you created will already be on disk.
472          */

473         public void save() throws IOException JavaDoc {
474             if (cookie == null) {
475                 throw new IOException JavaDoc("Cannot save a nonexistent layer"); // NOI18N
476
}
477             cookie.save();
478         }
479         
480         /**
481          * Find the XML layer file for this project, if it exists.
482          * @return the layer, or null
483          */

484         public FileObject getLayerFile() {
485             NbModuleProvider module = project.getLookup().lookup(NbModuleProvider.class);
486             Manifest JavaDoc mf = Util.getManifest(module.getManifestFile());
487             if (mf == null) {
488                 return null;
489             }
490             String JavaDoc path = ManifestManager.getInstance(mf, false).getLayer();
491             if (path == null) {
492                 return null;
493             }
494             return Util.getResourceDirectory(project).getFileObject(path);
495         }
496         
497         /**
498          * Set whether to automatically save changes to disk.
499          * @param true to save changes immediately, false to save only upon request
500          */

501         public void setAutosave(boolean autosave) {
502             this.autosave = autosave;
503             if (autosave && cookie != null) {
504                 try {
505                     cookie.save();
506                 } catch (IOException JavaDoc e) {
507                     Util.err.notify(ErrorManager.INFORMATIONAL, e);
508                 }
509             }
510         }
511         
512         /**
513          * Check whether this handle is currently in autosave mode.
514          */

515         public boolean isAutosave() {
516             return autosave;
517         }
518         
519         /**
520          * Resource path in which to make a new XML layer.
521          */

522         private String JavaDoc newLayerPath() {
523             NbModuleProvider module = project.getLookup().lookup(NbModuleProvider.class);
524             return module.getCodeNameBase().replace('.', '/') + "/layer.xml"; // NOI18N
525
}
526         
527     }
528     
529     /**
530      * Get a filesystem that will look like what this project would "see".
531      * <p>There are four possibilities:</p>
532      * <ol>
533      * <li><p>For a standalone module project, the filesystem will include all the XML
534      * layers from all modules in the selected platform, plus this module's XML layer
535      * as the writable layer (use {@link LayerHandle#save} to save changes as needed).</p></li>
536      * <li><p>For a module suite project, the filesystem will include all the XML layers
537      * from all modules in the selected platform which are not excluded in the current
538      * suite configuration, plus the XML layers for modules in the suite (currently all
539      * read-only, i.e. the filesystem is read-only).</p></li>
540      * <li><p>For a suite component module project, the filesystem will include all XML
541      * layers from non-excluded platform modules, plus the XML layers for modules in the
542      * suite, with this module's layer being writable.</p></li>
543      * <li><p>For a netbeans.org module, the filesystem will include all XML layers
544      * from all netbeans.org modules that are not in the <code>extra</code> cluster,
545      * plus the layer from this module (if it is in the <code>extra</code> cluster,
546      * with this module's layer always writable.</p></li>
547      * </ol>
548      * <p>Does not currently attempt to cache the result,
549      * though that could be attempted later as needed.</p>
550      * <p>Will try to produce pleasant-looking display names and/or icons for files.</p>
551      * <p>Note that parsing XML layers is not terribly fast so it would be wise to show
552      * a "please wait" label or some other simple progress indication while this
553      * is being called, if blocking the UI.</p>
554      * @param project a project of one of the three types enumerated above
555      * @return the effective system filesystem seen by that project
556      * @throws IOException if there were problems loading layers, etc.
557      * @see "#62257"
558      */

559     public static FileSystem getEffectiveSystemFilesystem(Project p) throws IOException JavaDoc {
560         
561             NbModuleProvider.NbModuleType type = Util.getModuleType(p);
562             FileSystem projectLayer = layerForProject(p).layer(false);
563             if (type == NbModuleProvider.STANDALONE) {
564                 Set JavaDoc<File JavaDoc> jars =
565                         getPlatformJarsForStandaloneProject(p);
566                 FileSystem[] platformLayers = getPlatformLayers(jars);
567                 ClassPath cp = createLayerClasspath(Collections.singleton(p), jars);
568                 return mergeFilesystems(projectLayer, platformLayers, cp);
569             } else if (type == NbModuleProvider.SUITE_COMPONENT) {
570                 SuiteProject suite = SuiteUtils.findSuite(p);
571                 if (suite == null) {
572                     throw new IOException JavaDoc("Could not load suite for " + p); // NOI18N
573
}
574                 List JavaDoc<FileSystem> readOnlyLayers = new ArrayList JavaDoc();
575                 Set JavaDoc<? extends Project> modules = SuiteUtils.getSubProjects(suite);
576                 Iterator JavaDoc it = modules.iterator();
577                 while (it.hasNext()) {
578                     NbModuleProject sister = (NbModuleProject) it.next();
579                     if (sister == p) {
580                         continue;
581                     }
582                     LayerHandle handle = layerForProject(sister);
583                     FileSystem roLayer = handle.layer(false);
584                     if (roLayer != null) {
585                         readOnlyLayers.add(roLayer);
586                     }
587                 }
588                 Set JavaDoc<File JavaDoc> jars = getPlatformJarsForSuiteComponentProject(p, suite);
589                 readOnlyLayers.addAll(Arrays.asList(getPlatformLayers(jars)));
590                 ClassPath cp = createLayerClasspath(modules, jars);
591                 return mergeFilesystems(projectLayer, (FileSystem[]) readOnlyLayers.toArray(new FileSystem[readOnlyLayers.size()]), cp);
592             } else if (type == NbModuleProvider.NETBEANS_ORG) {
593                 //it's safe to cast to NbModuleProject here.
594
NbModuleProject nbprj = p.getLookup().lookup(NbModuleProject.class);
595                 Set JavaDoc<? extends Project> projects = getProjectsForNetBeansOrgProject(nbprj);
596                 List JavaDoc<URL JavaDoc> otherLayerURLs = new ArrayList JavaDoc();
597                 Iterator JavaDoc it = projects.iterator();
598                 while (it.hasNext()) {
599                     NbModuleProject p2 = (NbModuleProject) it.next();
600                     ManifestManager mm = ManifestManager.getInstance(p2.getManifest(), false);
601                     String JavaDoc layer = mm.getLayer();
602                     if (layer == null) {
603                         continue;
604                     }
605                     FileObject src = p2.getSourceDirectory();
606                     if (src == null) {
607                         continue;
608                     }
609                     FileObject layerXml = src.getFileObject(layer);
610                     if (layerXml == null) {
611                         continue;
612                     }
613                     otherLayerURLs.add(layerXml.getURL());
614                 }
615                 XMLFileSystem xfs = new XMLFileSystem();
616                 try {
617                     xfs.setXmlUrls((URL JavaDoc[]) otherLayerURLs.toArray(new URL JavaDoc[otherLayerURLs.size()]));
618                 } catch (PropertyVetoException JavaDoc ex) {
619                     assert false : ex;
620                 }
621                 ClassPath cp = createLayerClasspath(projects, Collections.EMPTY_SET);
622                 return mergeFilesystems(projectLayer, new FileSystem[] {xfs}, cp);
623             } else {
624                 throw new AssertionError JavaDoc(type);
625             }
626     }
627     
628     /**
629      * Get the platform JARs associated with a standalone module project.
630      */

631     public static Set JavaDoc<File JavaDoc> getPlatformJarsForStandaloneProject(Project project) {
632         NbModuleProvider mod = project.getLookup().lookup(NbModuleProvider.class);
633         //TODO create a utility method to do this if needed in more places
634
NbPlatform platform = null;
635         File JavaDoc platformDir = mod.getActivePlatformLocation();
636         if (platformDir != null) {
637             platform = NbPlatform.getPlatformByDestDir(platformDir);
638         }
639         if (platform == null || !platform.isValid()) {
640             platform = NbPlatform.getDefaultPlatform();
641         }
642         return getPlatformJars(platform, null, null, null);
643     }
644     
645     public static Set JavaDoc<File JavaDoc> getPlatformJarsForSuiteComponentProject(Project project, SuiteProject suite) {
646         NbPlatform platform = suite.getPlatform(true);
647         PropertyEvaluator eval = suite.getEvaluator();
648         String JavaDoc[] includedClusters = SuiteProperties.getArrayProperty(eval, SuiteProperties.ENABLED_CLUSTERS_PROPERTY);
649         String JavaDoc[] excludedClusters = SuiteProperties.getArrayProperty(eval, SuiteProperties.DISABLED_CLUSTERS_PROPERTY);
650         String JavaDoc[] excludedModules = SuiteProperties.getArrayProperty(eval, SuiteProperties.DISABLED_MODULES_PROPERTY);
651         return getPlatformJars(platform, includedClusters, excludedClusters, excludedModules);
652     }
653     
654     public static Set JavaDoc<NbModuleProject> getProjectsForNetBeansOrgProject(NbModuleProject project) throws IOException JavaDoc {
655         ModuleList list = project.getModuleList();
656         Set JavaDoc<NbModuleProject> projects = new HashSet JavaDoc();
657         projects.add(project);
658         Iterator JavaDoc it = list.getAllEntriesSoft().iterator();
659         while (it.hasNext()) {
660             ModuleEntry other = (ModuleEntry) it.next();
661             if (other.getClusterDirectory().getName().equals("extra")) { // NOI18N
662
continue;
663             }
664             File JavaDoc root = other.getSourceLocation();
665             assert root != null : other;
666             NbModuleProject p2 = (NbModuleProject) ProjectManager.getDefault().findProject(FileUtil.toFileObject(root));
667             if (p2 == null) {
668                 continue;
669             }
670             projects.add(p2);
671         }
672         return projects;
673     }
674     
675     /**
676      * Finds all the module JARs in the platform.
677      * Can optionally pass non-null lists of cluster names and module CNBs to exclude, as per suite properties.
678      */

679     private static Set JavaDoc<File JavaDoc> getPlatformJars(NbPlatform platform, String JavaDoc[] includedClusters, String JavaDoc[] excludedClusters, String JavaDoc[] excludedModules) {
680         if (platform == null) {
681             return Collections.EMPTY_SET;
682         }
683         Set JavaDoc<String JavaDoc> includedClustersS = (includedClusters != null) ? new HashSet JavaDoc(Arrays.asList(includedClusters)) : Collections.EMPTY_SET;
684         Set JavaDoc<String JavaDoc> excludedClustersS = (excludedClusters != null) ? new HashSet JavaDoc(Arrays.asList(excludedClusters)) : Collections.EMPTY_SET;
685         Set JavaDoc<String JavaDoc> excludedModulesS = (excludedModules != null) ? new HashSet JavaDoc(Arrays.asList(excludedModules)) : Collections.EMPTY_SET;
686         ModuleEntry[] entries = platform.getModules();
687         Set JavaDoc<File JavaDoc> jars = new HashSet JavaDoc(entries.length);
688         for (int i = 0; i < entries.length; i++) {
689             if (!includedClustersS.isEmpty() && !includedClustersS.contains(entries[i].getClusterDirectory().getName())) {
690                 continue;
691             }
692             if (includedClustersS.isEmpty() && excludedClustersS.contains(entries[i].getClusterDirectory().getName())) {
693                 continue;
694             }
695             if (excludedModulesS.contains(entries[i].getCodeNameBase())) {
696                 continue;
697             }
698             jars.add(entries[i].getJarLocation());
699         }
700         return jars;
701     }
702
703     /**
704      * Constructs a list of filesystems representing the XML layers of the supplied platform module JARs.
705      */

706     private static FileSystem[] getPlatformLayers(Set JavaDoc<File JavaDoc> platformJars) throws IOException JavaDoc {
707         List JavaDoc<FileSystem> layers = new ArrayList JavaDoc();
708         Iterator JavaDoc it = platformJars.iterator();
709         JAR: while (it.hasNext()) {
710             File JavaDoc jar = (File JavaDoc) it.next();
711             ManifestManager mm = ManifestManager.getInstanceFromJAR(jar);
712             String JavaDoc[] toks = mm.getRequiredTokens();
713             for (int i = 0; i < toks.length; i++) {
714                 if (toks[i].startsWith("org.openide.modules.os.")) { // NOI18N
715
// Best to exclude platform-specific modules, e.g. ide/applemenu, as they can cause confusion.
716
continue JAR;
717                 }
718             }
719             String JavaDoc layer = mm.getLayer();
720             if (layer != null) {
721                 URL JavaDoc u = new URL JavaDoc("jar:" + jar.toURI() + "!/" + layer);
722                 try {
723                     // XXX nbres: and such URL protocols may not work in platform layers
724
// (cf. org.openide.filesystems.ExternalUtil.findClass)
725
FileSystem xfs = new XMLFileSystem(u);
726                     boolean hasMasks = false;
727                     Enumeration JavaDoc e = xfs.getRoot().getChildren(true);
728                     while (e.hasMoreElements()) {
729                         FileObject f = (FileObject) e.nextElement();
730                         if (f.getNameExt().endsWith("_hidden")) { // NOI18N
731
// #63295: put it at the beginning. Not as good as following module deps but probably close enough.
732
hasMasks = true;
733                             break;
734                         }
735                     }
736                     if (hasMasks) {
737                         layers.add(0, xfs);
738                     } else {
739                         layers.add(xfs);
740                     }
741                 } catch (SAXException JavaDoc e) {
742                     throw (IOException JavaDoc) new IOException JavaDoc(e.toString()).initCause(e);
743                 }
744             }
745         }
746         return (FileSystem[]) layers.toArray(new FileSystem[layers.size()]);
747     }
748     
749     /**
750      * Creates a classpath representing the source roots and platform binary JARs for a project/suite.
751      */

752     static ClassPath createLayerClasspath(Set JavaDoc<? extends Project> moduleProjects, Set JavaDoc<File JavaDoc> platformJars) throws IOException JavaDoc {
753         List JavaDoc<URL JavaDoc> roots = new ArrayList JavaDoc();
754         for (Project p : moduleProjects) {
755             NbModuleProvider mod = p.getLookup().lookup(NbModuleProvider.class);
756             FileObject src = mod.getSourceDirectory();
757             if (src != null) {
758                 roots.add(src.getURL());
759             }
760         }
761         for (File JavaDoc jar : platformJars) {
762             roots.add(FileUtil.getArchiveRoot(jar.toURI().toURL()));
763             File JavaDoc locale = new File JavaDoc(jar.getParentFile(), "locale"); // NOI18N
764
if (locale.isDirectory()) {
765                 String JavaDoc n = jar.getName();
766                 int x = n.lastIndexOf('.');
767                 if (x == -1) {
768                     x = n.length();
769                 }
770                 String JavaDoc base = n.substring(0, x);
771                 String JavaDoc ext = n.substring(x);
772                 String JavaDoc[] variants = locale.list();
773                 if (variants != null) {
774                     for (int i = 0; i < variants.length; i++) {
775                         if (variants[i].startsWith(base) && variants[i].endsWith(ext) && variants[i].charAt(x) == '_') {
776                             roots.add(FileUtil.getArchiveRoot(new File JavaDoc(locale, variants[i]).toURI().toURL()));
777                         }
778                     }
779                 }
780             }
781         }
782         // XXX in principle, could add CP extensions from modules... but probably not necessary
783
return ClassPathSupport.createClassPath((URL JavaDoc[]) roots.toArray(new URL JavaDoc[roots.size()]));
784     }
785
786     /**
787      * Create a merged filesystem from one writable layer (may be null) and some read-only layers.
788      * You should also pass a classpath that can be used to look up resource bundles and icons.
789      */

790     private static FileSystem mergeFilesystems(FileSystem writableLayer, FileSystem[] readOnlyLayers, final ClassPath cp) {
791         if (writableLayer == null) {
792             writableLayer = new XMLFileSystem();
793         }
794         final FileSystem[] layers = new FileSystem[readOnlyLayers.length + 1];
795         layers[0] = writableLayer;
796         System.arraycopy(readOnlyLayers, 0, layers, 1, readOnlyLayers.length);
797         class BadgingMergedFileSystem extends MultiFileSystem {
798             private final BadgingSupport status;
799             public BadgingMergedFileSystem() {
800                 super(layers);
801                 status = new BadgingSupport(this);
802                 status.setClasspath(cp);
803                 status.setSuffix("_" + Locale.getDefault());
804                 // XXX listening?
805
}
806             public FileSystem.Status getStatus() {
807                 return status;
808             }
809         }
810         return new BadgingMergedFileSystem();
811     }
812     
813 }
814
Popular Tags