KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > apisupport > project > 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.modules.apisupport.project;
21
22 import org.netbeans.modules.apisupport.project.spi.NbModuleProvider;
23 import java.beans.PropertyChangeEvent JavaDoc;
24 import java.beans.PropertyChangeListener JavaDoc;
25 import java.io.File JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.io.OutputStream JavaDoc;
29 import java.net.MalformedURLException JavaDoc;
30 import java.net.URL JavaDoc;
31 import java.text.Collator JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Collection JavaDoc;
34 import java.util.Collections JavaDoc;
35 import java.util.Comparator JavaDoc;
36 import java.util.Enumeration JavaDoc;
37 import java.util.HashMap JavaDoc;
38 import java.util.HashSet JavaDoc;
39 import java.util.Iterator JavaDoc;
40 import java.util.LinkedHashSet JavaDoc;
41 import java.util.List JavaDoc;
42 import java.util.Locale JavaDoc;
43 import java.util.Map JavaDoc;
44 import java.util.Set JavaDoc;
45 import java.util.SortedSet JavaDoc;
46 import java.util.StringTokenizer JavaDoc;
47 import java.util.TreeSet JavaDoc;
48 import java.util.jar.JarFile JavaDoc;
49 import java.util.jar.Manifest JavaDoc;
50 import java.util.zip.ZipEntry JavaDoc;
51 import javax.swing.event.ChangeEvent JavaDoc;
52 import javax.swing.event.ChangeListener JavaDoc;
53 import org.netbeans.api.java.project.JavaProjectConstants;
54 import org.netbeans.api.project.Project;
55 import org.netbeans.api.project.ProjectInformation;
56 import org.netbeans.api.project.ProjectManager;
57 import org.netbeans.api.project.ProjectUtils;
58 import org.netbeans.api.project.SourceGroup;
59 import org.netbeans.api.project.Sources;
60 import org.netbeans.api.project.Sources;
61 import org.netbeans.api.queries.VisibilityQuery;
62 import org.netbeans.modules.apisupport.project.ui.customizer.ModuleDependency;
63 import org.netbeans.modules.apisupport.project.universe.LocalizedBundleInfo;
64 import org.netbeans.modules.apisupport.project.universe.ModuleEntry;
65 import org.netbeans.modules.apisupport.project.universe.NbPlatform;
66 import org.netbeans.spi.project.support.ant.EditableProperties;
67 import org.netbeans.spi.project.support.ant.PropertyEvaluator;
68 import org.netbeans.spi.project.support.ant.PropertyProvider;
69 import org.netbeans.spi.project.support.ant.PropertyUtils;
70 import org.openide.ErrorManager;
71 import org.openide.filesystems.FileLock;
72 import org.openide.filesystems.FileObject;
73 import org.openide.filesystems.FileUtil;
74 import org.openide.filesystems.URLMapper;
75 import org.openide.modules.SpecificationVersion;
76 import org.openide.util.NbBundle;
77 import org.openide.util.Utilities;
78 import org.openide.util.WeakListeners;
79 import org.w3c.dom.Element JavaDoc;
80 import org.w3c.dom.NamedNodeMap JavaDoc;
81 import org.w3c.dom.Node JavaDoc;
82 import org.w3c.dom.NodeList JavaDoc;
83 import org.w3c.dom.Text JavaDoc;
84
85 /**
86  * Utility methods for the module.
87  *
88  * @author Jesse Glick, Martin Krauskopf
89  */

90 public final class Util {
91     
92     private Util() {}
93     
94     public static final ErrorManager err = ErrorManager.getDefault().getInstance("org.netbeans.modules.apisupport.project"); // NOI18N
95

96     private static final String JavaDoc SFS_VALID_PATH_RE = "(\\p{Alnum}|\\/|_)+"; // NOI18N
97

98     // COPIED FROM org.netbeans.modules.project.ant:
99
// (except for namespace == null support in findElement)
100
// (and support for comments in findSubElements)
101

102     /**
103      * Search for an XML element in the direct children of a parent.
104      * DOM provides a similar method but it does a recursive search
105      * which we do not want. It also gives a node list and we want
106      * only one result.
107      * @param parent a parent element
108      * @param name the intended local name
109      * @param namespace the intended namespace (or null)
110      * @return the one child element with that name, or null if none or more than one
111      */

112     public static Element JavaDoc findElement(Element JavaDoc parent, String JavaDoc name, String JavaDoc namespace) {
113         Element JavaDoc result = null;
114         NodeList JavaDoc l = parent.getChildNodes();
115         for (int i = 0; i < l.getLength(); i++) {
116             if (l.item(i).getNodeType() == Node.ELEMENT_NODE) {
117                 Element JavaDoc el = (Element JavaDoc)l.item(i);
118                 if ((namespace == null && name.equals(el.getTagName())) ||
119                         (namespace != null && name.equals(el.getLocalName()) &&
120                         namespace.equals(el.getNamespaceURI()))) {
121                     if (result == null) {
122                         result = el;
123                     } else {
124                         return null;
125                     }
126                 }
127             }
128         }
129         return result;
130     }
131     
132     /**
133      * Extract nested text from an element.
134      * Currently does not handle coalescing text nodes, CDATA sections, etc.
135      * @param parent a parent element
136      * @return the nested text, or null if none was found
137      */

138     public static String JavaDoc findText(Element JavaDoc parent) {
139         NodeList JavaDoc l = parent.getChildNodes();
140         for (int i = 0; i < l.getLength(); i++) {
141             if (l.item(i).getNodeType() == Node.TEXT_NODE) {
142                 Text JavaDoc text = (Text JavaDoc)l.item(i);
143                 return text.getNodeValue();
144             }
145         }
146         return null;
147     }
148     
149     /**
150      * Find all direct child elements of an element.
151      * More useful than {@link Element#getElementsByTagNameNS} because it does
152      * not recurse into recursive child elements.
153      * Children which are all-whitespace text nodes or comments are ignored; others cause
154      * an exception to be thrown.
155      * @param parent a parent element in a DOM tree
156      * @return a list of direct child elements (may be empty)
157      * @throws IllegalArgumentException if there are non-element children besides whitespace
158      */

159     public static List JavaDoc<Element JavaDoc> findSubElements(Element JavaDoc parent) throws IllegalArgumentException JavaDoc {
160         NodeList JavaDoc l = parent.getChildNodes();
161         List JavaDoc<Element JavaDoc> elements = new ArrayList JavaDoc<Element JavaDoc>(l.getLength());
162         for (int i = 0; i < l.getLength(); i++) {
163             Node JavaDoc n = l.item(i);
164             if (n.getNodeType() == Node.ELEMENT_NODE) {
165                 elements.add((Element JavaDoc)n);
166             } else if (n.getNodeType() == Node.TEXT_NODE) {
167                 String JavaDoc text = ((Text JavaDoc)n).getNodeValue();
168                 if (text.trim().length() > 0) {
169                     throw new IllegalArgumentException JavaDoc("non-ws text encountered in " + parent + ": " + text); // NOI18N
170
}
171             } else if (n.getNodeType() == Node.COMMENT_NODE) {
172                 // OK, ignore
173
} else {
174                 throw new IllegalArgumentException JavaDoc("unexpected non-element child of " + parent + ": " + n); // NOI18N
175
}
176         }
177         return elements;
178     }
179
180     /**
181      * Convert an XML fragment from one namespace to another.
182      */

183     public static Element JavaDoc translateXML(Element JavaDoc from, String JavaDoc namespace) {
184         Element JavaDoc to = from.getOwnerDocument().createElementNS(namespace, from.getLocalName());
185         NodeList JavaDoc nl = from.getChildNodes();
186         int length = nl.getLength();
187         for (int i = 0; i < length; i++) {
188             Node JavaDoc node = nl.item(i);
189             Node JavaDoc newNode;
190             if (node.getNodeType() == Node.ELEMENT_NODE) {
191                 newNode = translateXML((Element JavaDoc) node, namespace);
192             } else {
193                 newNode = node.cloneNode(true);
194             }
195             to.appendChild(newNode);
196         }
197         NamedNodeMap JavaDoc m = from.getAttributes();
198         for (int i = 0; i < m.getLength(); i++) {
199             Node JavaDoc attr = m.item(i);
200             to.setAttribute(attr.getNodeName(), attr.getNodeValue());
201         }
202         return to;
203     }
204
205     // CANDIDATES FOR FileUtil (#59311):
206

207     /**
208      * Creates a URL for a directory on disk.
209      * Works correctly even if the directory does not currently exist.
210      */

211     public static URL JavaDoc urlForDir(File JavaDoc dir) {
212         try {
213             URL JavaDoc u = FileUtil.normalizeFile(dir).toURI().toURL();
214             String JavaDoc s = u.toExternalForm();
215             if (s.endsWith("/")) { // NOI18N
216
return u;
217             } else {
218                 return new URL JavaDoc(s + "/"); // NOI18N
219
}
220         } catch (MalformedURLException JavaDoc e) {
221             throw new AssertionError JavaDoc(e);
222         }
223     }
224     
225     /**
226      * Creates a URL for the root of a JAR on disk.
227      */

228     public static URL JavaDoc urlForJar(File JavaDoc jar) {
229         try {
230             return FileUtil.getArchiveRoot(FileUtil.normalizeFile(jar).toURI().toURL());
231         } catch (MalformedURLException JavaDoc e) {
232             throw new AssertionError JavaDoc(e);
233         }
234     }
235     
236     /**
237      * Creates a URL for a directory on disk or the root of a JAR.
238      * Works correctly whether or not the directory or JAR currently exists.
239      * Detects whether the file is supposed to be a directory or a JAR.
240      */

241     public static URL JavaDoc urlForDirOrJar(File JavaDoc location) {
242         try {
243             URL JavaDoc u = FileUtil.normalizeFile(location).toURI().toURL();
244             if (FileUtil.isArchiveFile(u)) {
245                 u = FileUtil.getArchiveRoot(u);
246             } else {
247                 String JavaDoc us = u.toExternalForm();
248                 if (!us.endsWith("/")) { // NOI18N
249
u = new URL JavaDoc(us + "/"); // NOI18N
250
}
251             }
252             return u;
253         } catch (MalformedURLException JavaDoc e) {
254             throw new AssertionError JavaDoc(e);
255         }
256     }
257     
258     /**
259      * Tries to find {@link Project} in the given directory. If succeeds
260      * delegates to {@link ProjectInformation#getDisplayName}. Returns {@link
261      * FileUtil#getFileDisplayName} otherwise.
262      */

263     public static String JavaDoc getDisplayName(FileObject projectDir) {
264         if (projectDir.isFolder()) {
265             try {
266                 Project p = ProjectManager.getDefault().findProject(projectDir);
267                 if (p != null) {
268                     return ProjectUtils.getInformation(p).getDisplayName();
269                 }
270             } catch (IOException JavaDoc e) {
271                 // ignore
272
}
273         }
274         return FileUtil.getFileDisplayName(projectDir);
275     }
276     
277     /**
278      * Normalizes the given value to a regular dotted code name base.
279      * @param value to be normalized
280      */

281     public static String JavaDoc normalizeCNB(String JavaDoc value) {
282         StringTokenizer JavaDoc tk = new StringTokenizer JavaDoc(value.toLowerCase(Locale.ENGLISH), ".", true); // NOI18N
283
StringBuffer JavaDoc normalizedCNB = new StringBuffer JavaDoc();
284         boolean delimExpected = false;
285         while (tk.hasMoreTokens()) {
286             String JavaDoc namePart = tk.nextToken();
287             if (!delimExpected) {
288                 if (namePart.equals(".")) { //NOI18N
289
continue;
290                 }
291                 for (int i = 0; i < namePart.length(); i++) {
292                     char c = namePart.charAt(i);
293                     if (i == 0) {
294                         if (!Character.isJavaIdentifierStart(c)) {
295                             continue;
296                         }
297                     } else {
298                         if (!Character.isJavaIdentifierPart(c)) {
299                             continue;
300                         }
301                     }
302                     normalizedCNB.append(c);
303                 }
304             } else {
305                 if (namePart.equals(".")) { //NOI18N
306
normalizedCNB.append(namePart);
307                 }
308             }
309             delimExpected = !delimExpected;
310         }
311         // also be sure there is no '.' left at the end of the cnb
312
return normalizedCNB.toString().replaceAll("\\.$", ""); // NOI18N
313
}
314
315     /**
316      * Check whether a given name can serve as a legal <ol>
317      * <li>Java class name
318      * <li>Java package name
319      * <li>NB module code name base
320      * </ol>
321      */

322     public static boolean isValidJavaFQN(String JavaDoc name) {
323         if (name.length() == 0) {
324             return false;
325         }
326         StringTokenizer JavaDoc tk = new StringTokenizer JavaDoc(name,".",true); //NOI18N
327
boolean delimExpected = false;
328         while (tk.hasMoreTokens()) {
329             String JavaDoc namePart = tk.nextToken();
330             if (delimExpected ^ namePart.equals(".")) { // NOI18N
331
return false;
332             }
333             if (!delimExpected && !Utilities.isJavaIdentifier(namePart)) {
334                 return false;
335             }
336             delimExpected = !delimExpected;
337         }
338         return delimExpected;
339     }
340     
341     /**
342      * Search for an appropriate localized bundle (i.e.
343      * OpenIDE-Module-Localizing-Bundle) entry in the given
344      * <code>manifest</code> taking into account branding and localization
345      * (using {@link NbBundle#getLocalizingSuffixes}) and returns an
346      * appropriate <em>valid</em> {@link LocalizedBundleInfo} instance. By
347      * <em>valid</em> it's meant that a found localized bundle contains at
348      * least a display name. If <em>valid</em> bundle is not found
349      * <code>null</code> is returned.
350      *
351      * @param sourceDir source directory to be used for as a <em>searching
352      * path</em> for the bundle
353      * @param manifest manifest the bundle's path should be extracted from
354      * @return localized bundle info for the given project or <code>null</code>
355      */

356     public static LocalizedBundleInfo findLocalizedBundleInfo(FileObject sourceDir, Manifest JavaDoc manifest) {
357         String JavaDoc locBundleResource =
358                 ManifestManager.getInstance(manifest, false).getLocalizingBundle();
359         try {
360             if (locBundleResource != null) {
361                 List JavaDoc<FileObject> bundleFOs = new ArrayList JavaDoc<FileObject>();
362                 for (Iterator JavaDoc it = getPossibleResources(locBundleResource); it.hasNext(); ) {
363                     String JavaDoc resource = (String JavaDoc) it.next();
364                     FileObject bundleFO = sourceDir.getFileObject(resource);
365                     if (bundleFO != null) {
366                         bundleFOs.add(bundleFO);
367                     }
368                 }
369                 if (!bundleFOs.isEmpty()) {
370                     Collections.reverse(bundleFOs);
371                     return LocalizedBundleInfo.load(bundleFOs.toArray(new FileObject[bundleFOs.size()]));
372                 }
373             }
374         } catch (IOException JavaDoc e) {
375             Util.err.notify(ErrorManager.INFORMATIONAL, e);
376         }
377         return null;
378     }
379     
380     /**
381      * Actually deletages to {@link #findLocalizedBundleInfo(FileObject, Manifest)}.
382      */

383     public static LocalizedBundleInfo findLocalizedBundleInfo(File JavaDoc projectDir) {
384         FileObject projectDirFO = FileUtil.toFileObject(projectDir);
385         if (projectDirFO == null) {
386             return null;
387         }
388         NbModuleProject p;
389         try {
390             p = (NbModuleProject) ProjectManager.getDefault().findProject(projectDirFO);
391         } catch (IOException JavaDoc e) {
392             return null;
393         }
394         if (p == null) {
395             return null;
396         }
397         String JavaDoc src = p.evaluator().getProperty("src.dir"); // NOI18N
398
assert src != null : "Cannot evaluate src.dir property for " + p;
399         File JavaDoc srcF = FileUtil.normalizeFile(new File JavaDoc(projectDir, src));
400         FileObject sourceDir = FileUtil.toFileObject(srcF);
401         FileObject manifestFO = FileUtil.toFileObject(new File JavaDoc(projectDir, "manifest.mf")); // NOI18N
402

403         LocalizedBundleInfo locInfo = null;
404         Manifest JavaDoc mf = getManifest(manifestFO);
405         if (sourceDir != null && mf != null) {
406             locInfo = findLocalizedBundleInfo(sourceDir, mf);
407         }
408         return locInfo;
409     }
410     
411     /**
412      * The same as {@link #findLocalizedBundleInfo(FileObject, Manifest)} but
413      * searching in the given JAR representing a NetBeans module.
414      */

415     public static LocalizedBundleInfo findLocalizedBundleInfoFromJAR(File JavaDoc binaryProject) {
416         try {
417             JarFile JavaDoc main = new JarFile JavaDoc(binaryProject);
418             try {
419                 Manifest JavaDoc mf = main.getManifest();
420                 String JavaDoc locBundleResource =
421                         ManifestManager.getInstance(mf, false).getLocalizingBundle();
422                 if (locBundleResource != null) {
423                     List JavaDoc<InputStream JavaDoc> bundleISs = new ArrayList JavaDoc<InputStream JavaDoc>();
424                     Collection JavaDoc<JarFile JavaDoc> extraJarFiles = new ArrayList JavaDoc<JarFile JavaDoc>();
425                     try {
426                         // Look for locale variant JARs too.
427
// XXX the following could be simplified with #29580:
428
String JavaDoc name = binaryProject.getName();
429                         int dot = name.lastIndexOf('.');
430                         if (dot == -1) {
431                             dot = name.length();
432                         }
433                         String JavaDoc base = name.substring(0, dot);
434                         String JavaDoc suffix = name.substring(dot);
435                         Iterator JavaDoc<String JavaDoc> it = NbBundle.getLocalizingSuffixes();
436                         while (it.hasNext()) {
437                             String JavaDoc infix = it.next();
438                             File JavaDoc variant = new File JavaDoc(binaryProject.getParentFile(), "locale" + File.separatorChar + base + infix + suffix); // NOI18N
439
if (variant.isFile()) {
440                                 JarFile JavaDoc jf = new JarFile JavaDoc(variant);
441                                 extraJarFiles.add(jf);
442                                 addBundlesFromJar(jf, bundleISs, locBundleResource);
443                             }
444                         }
445                         // Add main last, since we are about to reverse it:
446
addBundlesFromJar(main, bundleISs, locBundleResource);
447                         if (!bundleISs.isEmpty()) {
448                             Collections.reverse(bundleISs);
449                             return LocalizedBundleInfo.load(bundleISs.toArray(new InputStream JavaDoc[bundleISs.size()]));
450                         }
451                     } finally {
452                         for (InputStream JavaDoc bundleIS : bundleISs) {
453                             bundleIS.close();
454                         }
455                         for (JarFile JavaDoc jarFile : extraJarFiles) {
456                             jarFile.close();
457                         }
458                     }
459                 }
460             } finally {
461                 main.close();
462             }
463         } catch (IOException JavaDoc e) {
464             Util.err.notify(ErrorManager.INFORMATIONAL, e);
465         }
466         return null;
467     }
468     
469     private static void addBundlesFromJar(JarFile JavaDoc jf, List JavaDoc<InputStream JavaDoc> bundleISs, String JavaDoc locBundleResource) throws IOException JavaDoc {
470         for (Iterator JavaDoc it = getPossibleResources(locBundleResource); it.hasNext(); ) {
471             String JavaDoc resource = (String JavaDoc) it.next();
472             ZipEntry JavaDoc entry = jf.getEntry(resource);
473             if (entry != null) {
474                 InputStream JavaDoc bundleIS = jf.getInputStream(entry);
475                 bundleISs.add(bundleIS);
476             }
477         }
478     }
479     
480     /**
481      * Convenience method for loading {@link EditableProperties} from a {@link
482      * FileObject}. New items will alphabetizied by key.
483      *
484      * @param propsFO file representing properties file
485      * @exception FileNotFoundException if the file represented by the given
486      * FileObject does not exists, is a folder rather than a regular
487      * file or is invalid. i.e. as it is thrown by {@link
488      * FileObject#getInputStream()}.
489      */

490     public static EditableProperties loadProperties(FileObject propsFO) throws IOException JavaDoc {
491         InputStream JavaDoc propsIS = propsFO.getInputStream();
492         EditableProperties props = new EditableProperties(true);
493         try {
494             props.load(propsIS);
495         } finally {
496             propsIS.close();
497         }
498         return props;
499     }
500     
501     /**
502      * Convenience method for storing {@link EditableProperties} into a {@link
503      * FileObject}.
504      *
505      * @param propsFO file representing where properties will be stored
506      * @param props properties to be stored
507      * @exception IOException if properties cannot be written to the file
508      */

509     public static void storeProperties(FileObject propsFO, EditableProperties props) throws IOException JavaDoc {
510         FileLock lock = propsFO.lock();
511         try {
512             OutputStream JavaDoc os = propsFO.getOutputStream(lock);
513             try {
514                 props.store(os);
515             } finally {
516                 os.close();
517             }
518         } finally {
519             lock.releaseLock();
520         }
521     }
522     
523     /**
524      * Convenience method for loading {@link EditableManifest} from a {@link
525      * FileObject}.
526      *
527      * @param manifestFO file representing manifest
528      * @exception FileNotFoundException if the file represented by the given
529      * FileObject does not exists, is a folder rather than a regular
530      * file or is invalid. i.e. as it is thrown by {@link
531      * FileObject#getInputStream()}.
532      */

533     public static EditableManifest loadManifest(FileObject manifestFO) throws IOException JavaDoc {
534         InputStream JavaDoc mfIS = manifestFO.getInputStream();
535         try {
536             return new EditableManifest(mfIS);
537         } finally {
538             mfIS.close();
539         }
540     }
541     
542     /**
543      * Convenience method for storing {@link EditableManifest} into a {@link
544      * FileObject}.
545      *
546      * @param manifestFO file representing where manifest will be stored
547      * @param em manifest to be stored
548      * @exception IOException if manifest cannot be written to the file
549      */

550     public static void storeManifest(FileObject manifestFO, EditableManifest em) throws IOException JavaDoc {
551         FileLock lock = manifestFO.lock();
552         try {
553             OutputStream JavaDoc os = manifestFO.getOutputStream(lock);
554             try {
555                 em.write(os);
556             } finally {
557                 os.close();
558             }
559         } finally {
560             lock.releaseLock();
561         }
562     }
563     
564     /**
565      * Find Javadoc URL for NetBeans.org modules. May return <code>null</code>.
566      */

567     public static URL JavaDoc findJavadocForNetBeansOrgModules(final ModuleDependency dep) {
568         ModuleEntry entry = dep.getModuleEntry();
569         File JavaDoc destDir = entry.getDestDir();
570         File JavaDoc nbOrg = null;
571         if (destDir.getParent() != null) {
572             nbOrg = destDir.getParentFile().getParentFile();
573         }
574         if (nbOrg == null) {
575             throw new IllegalArgumentException JavaDoc("ModuleDependency " + dep + // NOI18N
576
" doesn't represent nb.org module"); // NOI18N
577
}
578         File JavaDoc builtJavadoc = new File JavaDoc(nbOrg, "nbbuild/build/javadoc"); // NOI18N
579
URL JavaDoc[] javadocURLs = null;
580         if (builtJavadoc.exists()) {
581             File JavaDoc[] javadocs = builtJavadoc.listFiles();
582             javadocURLs = new URL JavaDoc[javadocs.length];
583             for (int i = 0; i < javadocs.length; i++) {
584                 javadocURLs[i] = Util.urlForDirOrJar(javadocs[i]);
585             }
586         }
587         return javadocURLs == null ? null : findJavadocURL(
588                 dep.getModuleEntry().getCodeNameBase().replace('.', '-'), javadocURLs);
589     }
590     
591     /**
592      * Find Javadoc URL for the given module dependency using Javadoc roots of
593      * the given platform. May return <code>null</code>.
594      */

595     public static URL JavaDoc findJavadoc(final ModuleDependency dep, final NbPlatform platform) {
596         String JavaDoc cnbdashes = dep.getModuleEntry().getCodeNameBase().replace('.', '-');
597         URL JavaDoc[] roots = platform.getJavadocRoots();
598         return roots == null ? null : findJavadocURL(cnbdashes, roots);
599     }
600     
601     public static boolean isValidSFSPath(final String JavaDoc path) {
602         return path.matches(SFS_VALID_PATH_RE);
603     }
604     
605     /**
606      * Delegates to {@link #addDependency(NbModuleProject, String)}.
607      */

608     public static boolean addDependency(final NbModuleProject target,
609             final NbModuleProject dependency) throws IOException JavaDoc {
610         return addDependency(target, dependency.getCodeNameBase());
611     }
612     
613     /**
614      * Delegates to {@link Util#addDependency(NbModuleProject, String, String,
615      * SpecificationVersion, boolean)}.
616      */

617     public static boolean addDependency(final NbModuleProject target,
618             final String JavaDoc codeNameBase) throws IOException JavaDoc {
619         return Util.addDependency(target, codeNameBase, null, null, true);
620     }
621     
622     /**
623      * Makes <code>target</code> project to be dependend on the given
624      * <code>dependency</code> project. I.e. adds new &lt;module-dependency&gt;
625      * element into target's <em>project.xml</em>. If such a dependency already
626      * exists the method does nothing. If the given code name base cannot be
627      * found in the module's universe the method logs informational message and
628      * does nothing otherwise.
629      * <p>
630      * Note that the method does <strong>not</strong> save the
631      * <code>target</code> project. You need to do so explicitly (see {@link
632      * ProjectManager#saveProject}).
633      *
634      * @param codeNameBase codename base.
635      * @param releaseVersion release version, if <code>null</code> will be taken from the
636      * entry found in platform.
637      * @param version {@link SpecificationVersion specification version}, if
638      * <code>null</code>, will be taken from the entry found in the
639      * module's target platform.
640      * @param useInCompiler whether this this module needs a
641      * <code>dependency</code> module at a compile time.
642      * @return true if a dependency was successfully added; false otherwise
643      * (e.g. when such dependency already exists)
644      */

645     public static boolean addDependency(final NbModuleProject target,
646             final String JavaDoc codeNameBase, final String JavaDoc releaseVersion,
647             final SpecificationVersion version, final boolean useInCompiler) throws IOException JavaDoc {
648         ModuleEntry me = target.getModuleList().getEntry(codeNameBase);
649         if (me == null) { // ignore semi-silently (#72611)
650
Util.err.log(ErrorManager.INFORMATIONAL, "Trying to add " + codeNameBase + // NOI18N
651
" which cannot be found in the module's universe."); // NOI18N
652
return false;
653         }
654         
655         ProjectXMLManager pxm = new ProjectXMLManager(target);
656         
657         // firstly check if the dependency is already not there
658
Set JavaDoc currentDeps = pxm.getDirectDependencies();
659         for (Iterator JavaDoc it = currentDeps.iterator(); it.hasNext(); ) {
660             ModuleDependency md = (ModuleDependency) it.next();
661             if (codeNameBase.equals(md.getModuleEntry().getCodeNameBase())) {
662                 Util.err.log(ErrorManager.INFORMATIONAL, codeNameBase + " already added"); // NOI18N
663
return false;
664             }
665         }
666         
667         ModuleDependency md = new ModuleDependency(me,
668                 (releaseVersion == null) ? me.getReleaseVersion() : releaseVersion,
669                 version == null ? me.getSpecificationVersion() : version.toString(),
670                 useInCompiler, false);
671         pxm.addDependency(md);
672         return true;
673     }
674     
675     private static URL JavaDoc findJavadocURL(final String JavaDoc cnbdashes, final URL JavaDoc[] roots) {
676         URL JavaDoc indexURL = null;
677         for (int i = 0; i < roots.length; i++) {
678             URL JavaDoc root = roots[i];
679             try {
680                 indexURL = Util.normalizeURL(new URL JavaDoc(root, cnbdashes + "/index.html")); // NOI18N
681
if (indexURL == null && (root.toExternalForm().indexOf(cnbdashes) != -1)) {
682                     indexURL = Util.normalizeURL(new URL JavaDoc(root, "index.html")); // NOI18N
683
}
684             } catch (MalformedURLException JavaDoc ex) {
685                 // ignore - let the indexURL == null
686
}
687             if (indexURL != null) {
688                 break;
689             }
690         }
691         return indexURL;
692     }
693     
694     private static URL JavaDoc normalizeURL(URL JavaDoc url) {
695         // not sure - in some private tests it seems that input
696
// jar:file:/home/..../NetBeansAPIs.zip!/..../index.html result in:
697
// http://localhost:8082/..../index.html
698
// URL resolvedURL = null;
699
// FileObject fo = URLMapper.findFileObject(url);
700
// if (fo != null) {
701
// resolvedURL = URLMapper.findURL(fo, URLMapper.EXTERNAL);
702
// }
703
return URLMapper.findFileObject(url) == null ? null : url;
704     }
705     
706     private static Iterator JavaDoc getPossibleResources(String JavaDoc locBundleResource) {
707         String JavaDoc locBundleResourceBase, locBundleResourceExt;
708         int idx = locBundleResource.lastIndexOf('.');
709         if (idx != -1 && idx > locBundleResource.lastIndexOf('/')) {
710             locBundleResourceBase = locBundleResource.substring(0, idx);
711             locBundleResourceExt = locBundleResource.substring(idx);
712         } else {
713             locBundleResourceBase = locBundleResource;
714             locBundleResourceExt = "";
715         }
716         Collection JavaDoc<String JavaDoc> resources = new LinkedHashSet JavaDoc<String JavaDoc>();
717         for (Iterator JavaDoc<String JavaDoc> it = NbBundle.getLocalizingSuffixes(); it.hasNext(); ) {
718             String JavaDoc suffix = it.next();
719             String JavaDoc resource = locBundleResourceBase + suffix + locBundleResourceExt;
720             resources.add(resource);
721             resources.add(resource);
722         }
723         return resources.iterator();
724     }
725     
726     public static Manifest JavaDoc getManifest(FileObject manifestFO) {
727         if (manifestFO != null) {
728             try {
729                 InputStream JavaDoc is = manifestFO.getInputStream();
730                 try {
731                     return new Manifest JavaDoc(is);
732                 } finally {
733                     is.close();
734                 }
735             } catch (IOException JavaDoc e) {
736                 Util.err.notify(ErrorManager.INFORMATIONAL, e);
737             }
738         }
739         return null;
740     }
741     
742     /**
743      * Property provider which computes one or more properties based on some properties coming
744      * from an intermediate evaluator, and is capable of firing changes correctly.
745      */

746     public static abstract class ComputedPropertyProvider implements PropertyProvider, PropertyChangeListener JavaDoc {
747         private final PropertyEvaluator eval;
748         private final List JavaDoc<ChangeListener JavaDoc> listeners = new ArrayList JavaDoc<ChangeListener JavaDoc>();
749         protected ComputedPropertyProvider(PropertyEvaluator eval) {
750             this.eval = eval;
751             eval.addPropertyChangeListener(WeakListeners.propertyChange(this, eval));
752         }
753         /** get properties based on the incoming properties */
754         protected abstract Map JavaDoc<String JavaDoc,String JavaDoc> getProperties(Map JavaDoc<String JavaDoc,String JavaDoc> inputPropertyValues);
755         /** specify interesting input properties */
756         protected abstract Set JavaDoc<String JavaDoc> inputProperties();
757         public final Map JavaDoc<String JavaDoc,String JavaDoc> getProperties() {
758             Map JavaDoc<String JavaDoc,String JavaDoc> vals = new HashMap JavaDoc<String JavaDoc, String JavaDoc>();
759             for (String JavaDoc k : inputProperties()) {
760                 vals.put(k, eval.getProperty(k));
761             }
762             return getProperties(vals);
763         }
764         public final void addChangeListener(ChangeListener JavaDoc l) {
765             synchronized (listeners) {
766                 listeners.add(l);
767             }
768         }
769         public final void removeChangeListener(ChangeListener JavaDoc l) {
770             synchronized (listeners) {
771                 listeners.remove(l);
772             }
773         }
774         public final void propertyChange(PropertyChangeEvent JavaDoc evt) {
775             String JavaDoc p = evt.getPropertyName();
776             if (p != null && !inputProperties().contains(p)) {
777                 return;
778             }
779             ChangeEvent JavaDoc ev = new ChangeEvent JavaDoc(this);
780             Iterator JavaDoc<ChangeListener JavaDoc> it;
781             synchronized (listeners) {
782                 if (listeners.isEmpty()) {
783                     return;
784                 }
785                 it = new HashSet JavaDoc<ChangeListener JavaDoc>(listeners).iterator();
786             }
787             while (it.hasNext()) {
788                 it.next().stateChanged(ev);
789             }
790         }
791     }
792     
793     public static final class UserPropertiesFileProvider implements PropertyProvider, PropertyChangeListener JavaDoc, ChangeListener JavaDoc {
794         private final PropertyEvaluator eval;
795         private final File JavaDoc basedir;
796         private final List JavaDoc<ChangeListener JavaDoc> listeners = new ArrayList JavaDoc<ChangeListener JavaDoc>();
797         private PropertyProvider delegate;
798         public UserPropertiesFileProvider(PropertyEvaluator eval, File JavaDoc basedir) {
799             this.eval = eval;
800             this.basedir = basedir;
801             eval.addPropertyChangeListener(WeakListeners.propertyChange(this, eval));
802             computeDelegate();
803         }
804         private void computeDelegate() {
805             if (delegate != null) {
806                 delegate.removeChangeListener(this);
807             }
808             String JavaDoc buildS = eval.getProperty("user.properties.file"); // NOI18N
809
if (buildS != null) {
810                 delegate = PropertyUtils.propertiesFilePropertyProvider(PropertyUtils.resolveFile(basedir, buildS));
811                 delegate.addChangeListener(this);
812             } else {
813                 /* XXX what should we do?
814                 delegate = null;
815                  */

816                 delegate = PropertyUtils.globalPropertyProvider();
817                 delegate.addChangeListener(this);
818             }
819         }
820         public Map JavaDoc<String JavaDoc,String JavaDoc> getProperties() {
821             if (delegate != null) {
822                 return delegate.getProperties();
823             } else {
824                 return Collections.emptyMap();
825             }
826         }
827         public void addChangeListener(ChangeListener JavaDoc l) {
828             synchronized (listeners) {
829                 listeners.add(l);
830             }
831         }
832         public void removeChangeListener(ChangeListener JavaDoc l) {
833             synchronized (listeners) {
834                 listeners.remove(l);
835             }
836         }
837         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
838             String JavaDoc p = evt.getPropertyName();
839             if (p == null || p.equals("user.properties.file")) { // NOI18N
840
computeDelegate();
841                 fireChange();
842             }
843         }
844         public void stateChanged(ChangeEvent JavaDoc e) {
845             fireChange();
846         }
847         private void fireChange() {
848             ChangeEvent JavaDoc ev = new ChangeEvent JavaDoc(this);
849             Iterator JavaDoc<ChangeListener JavaDoc> it;
850             synchronized (listeners) {
851                 if (listeners.isEmpty()) {
852                     return;
853                 }
854                 it = new HashSet JavaDoc<ChangeListener JavaDoc>(listeners).iterator();
855             }
856             while (it.hasNext()) {
857                 it.next().stateChanged(ev);
858             }
859         }
860     }
861     
862     /**
863      * Order projects by display name.
864      */

865     public static Comparator JavaDoc<Project> projectDisplayNameComparator() {
866         return new Comparator JavaDoc<Project>() {
867             private final Collator JavaDoc LOC_COLLATOR = Collator.getInstance();
868             public int compare(Project o1, Project o2) {
869                 ProjectInformation i1 = ProjectUtils.getInformation(o1);
870                 ProjectInformation i2 = ProjectUtils.getInformation(o2);
871                 int result = LOC_COLLATOR.compare(i1.getDisplayName(), i2.getDisplayName());
872                 if (result != 0) {
873                     return result;
874                 } else {
875                     result = i1.getName().compareTo(i2.getName());
876                     if (result != 0) {
877                         return result;
878                     } else {
879                         return System.identityHashCode(o1) - System.identityHashCode(o2);
880                     }
881                 }
882             }
883         };
884     }
885     
886     /**
887      * Returns {@link NbModuleProvider.NbModuleType} from a project's lookup.
888      */

889     public static NbModuleProvider.NbModuleType getModuleType(final Project project) {
890         NbModuleProvider provider = project.getLookup().lookup(NbModuleProvider.class);
891         assert provider != null : "has NbModuleProvider in the lookup";
892         return provider.getModuleType();
893     }
894     
895     /**
896      * Finds all available packages in a given project directory. Found entries
897      * are in the form of a regular java package (x.y.z).
898      *
899      * @param prjDir directory containing project to be scanned
900      * @return a set of found packages
901      */

902     public static SortedSet JavaDoc<String JavaDoc> scanProjectForPackageNames(final File JavaDoc prjDir) {
903         NbModuleProject project = null;
904         // find all available public packages in classpath extensions
905
FileObject source = FileUtil.toFileObject(prjDir);
906         if (source != null) { // ??
907
try {
908                 project = (NbModuleProject) ProjectManager.getDefault().findProject(source);
909             } catch (IOException JavaDoc e) {
910                 Util.err.notify(ErrorManager.INFORMATIONAL, e);
911             }
912         }
913         
914         if (project == null) {
915             return new TreeSet JavaDoc<String JavaDoc>(Collections.<String JavaDoc>emptySet());
916         }
917         
918         SortedSet JavaDoc<String JavaDoc> availablePublicPackages = new TreeSet JavaDoc<String JavaDoc>();
919         // find all available public packages in a source root
920
Set JavaDoc<FileObject> pkgs = new HashSet JavaDoc<FileObject>();
921         FileObject srcDirFO = project.getSourceDirectory();
922         Util.scanForPackages(pkgs, srcDirFO, "java"); // NOI18N
923
for (FileObject pkg : pkgs) {
924             if (srcDirFO.equals(pkg)) { // default package #71532
925
continue;
926             }
927             String JavaDoc pkgS = PropertyUtils.relativizeFile(FileUtil.toFile(srcDirFO), FileUtil.toFile(pkg));
928             availablePublicPackages.add(pkgS.replace('/', '.'));
929         }
930         
931         String JavaDoc[] libsPaths = new ProjectXMLManager(project).getBinaryOrigins();
932         for (int i = 0; i < libsPaths.length; i++) {
933             scanJarForPackageNames(availablePublicPackages, project.getHelper().resolveFile(libsPaths[i]));
934         }
935         
936         // #72669: remove invalid packages.
937
Iterator JavaDoc it = availablePublicPackages.iterator();
938         while (it.hasNext()) {
939             String JavaDoc pkg = (String JavaDoc) it.next();
940             if (!Util.isValidJavaFQN(pkg)) {
941                 it.remove();
942             }
943         }
944         return availablePublicPackages;
945     }
946     
947     /**
948      * Scans a given jar file for all packages which contains at least one
949      * .class file. Found entries are in the form of a regular java package
950      * (x.y.z).
951      *
952      * @param jarFile jar file to be scanned
953      * @param packages a set into which found packages will be added
954      */

955     public static void scanJarForPackageNames(final Set JavaDoc<String JavaDoc> packages, final File JavaDoc jarFile) {
956         FileObject jarFileFO = FileUtil.toFileObject(jarFile);
957         if (jarFileFO == null) {
958             // Broken classpath entry, perhaps.
959
return;
960         }
961         FileObject root = FileUtil.getArchiveRoot(jarFileFO);
962         if (root == null) {
963             // Not really a JAR?
964
return;
965         }
966         Set JavaDoc<FileObject> pkgs = new HashSet JavaDoc<FileObject>();
967         Util.scanForPackages(pkgs, root, "class"); // NOI18N
968
for (FileObject pkg : pkgs) {
969             if (root.equals(pkg)) { // default package #71532
970
continue;
971             }
972             String JavaDoc pkgS = pkg.getPath();
973             packages.add(pkgS.replace('/', '.'));
974         }
975     }
976     
977     /**
978      * Scan recursively through all folders in the given <code>dir</code> and
979      * add every directory/package, which contains at least one file with the
980      * given extension (probably class or java), into the given
981      * <code>validPkgs</code> set. Added entries are in the form of regular java
982      * package (x.y.z)
983      */

984     private static void scanForPackages(final Set JavaDoc<FileObject> validPkgs, final FileObject dir, final String JavaDoc ext) {
985         if (dir == null) {
986             return;
987         }
988         for (Enumeration JavaDoc en1 = dir.getFolders(false); en1.hasMoreElements(); ) {
989             FileObject subDir = (FileObject) en1.nextElement();
990             if (VisibilityQuery.getDefault().isVisible(subDir)) {
991                 scanForPackages(validPkgs, subDir, ext);
992             }
993         }
994         for (Enumeration JavaDoc en2 = dir.getData(false); en2.hasMoreElements(); ) {
995             FileObject kid = (FileObject) en2.nextElement();
996             if (kid.hasExt(ext) && Utilities.isJavaIdentifier(kid.getName())) {
997                 // at least one class inside directory -> valid package
998
validPkgs.add(dir);
999                 break;
1000            }
1001        }
1002    }
1003    
1004    /**
1005     * when ever there is need for non-java files creation or lookup,
1006     * use this method to get the right location for all projects.
1007     * Eg. maven places resources not next to the java files.
1008     */

1009    public static FileObject getResourceDirectory(Project prj) {
1010        Sources srcs = ProjectUtils.getSources(prj);
1011        SourceGroup[] grps = srcs.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_RESOURCES);
1012        if (grps != null && grps.length > 0) {
1013            return grps[0].getRootFolder();
1014        }
1015        // fallback to sources..
1016
NbModuleProvider prov = prj.getLookup().lookup(NbModuleProvider.class);
1017        assert prov != null;
1018        return prov.getSourceDirectory();
1019    }
1020    
1021}
1022
Popular Tags