KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > web > project > SourceRoots


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 package org.netbeans.modules.web.project;
20
21 import java.beans.PropertyChangeEvent JavaDoc;
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.beans.PropertyChangeSupport JavaDoc;
24 import java.io.File JavaDoc;
25 import java.net.MalformedURLException JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.net.URI JavaDoc;
28 import java.util.Arrays JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Collections JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.HashMap JavaDoc;
35 import java.text.MessageFormat JavaDoc;
36
37 import org.openide.ErrorManager;
38 import org.openide.filesystems.FileObject;
39 import org.openide.filesystems.FileUtil;
40 import org.openide.util.NbBundle;
41 import org.openide.util.WeakListeners;
42 import org.openide.util.Mutex;
43
44 import org.w3c.dom.Element JavaDoc;
45 import org.w3c.dom.NodeList JavaDoc;
46 import org.w3c.dom.Document JavaDoc;
47
48 import org.netbeans.spi.project.support.ant.AntProjectHelper;
49 import org.netbeans.spi.project.support.ant.AntProjectEvent;
50 import org.netbeans.spi.project.support.ant.AntProjectListener;
51 import org.netbeans.spi.project.support.ant.EditableProperties;
52 import org.netbeans.spi.project.support.ant.PropertyEvaluator;
53 import org.netbeans.spi.project.support.ant.ReferenceHelper;
54 import org.netbeans.api.project.ProjectManager;
55 import org.netbeans.api.java.project.JavaProjectConstants;
56
57 /**
58  * This class represents a project source roots. It is used to obtain roots as Ant properties, FileObject's
59  * or URLs.
60  * @author Tomas Zezula
61  */

62 public final class SourceRoots {
63
64     public static final String JavaDoc PROP_ROOT_PROPERTIES = "rootProperties"; //NOI18N
65
public static final String JavaDoc PROP_ROOTS = "roots"; //NOI18N
66

67     public static final String JavaDoc DEFAULT_SOURCE_LABEL = NbBundle.getMessage(SourceRoots.class, "NAME_src.dir");
68     public static final String JavaDoc DEFAULT_TEST_LABEL = NbBundle.getMessage(SourceRoots.class, "NAME_test.src.dir");
69
70     private final UpdateHelper helper;
71     private final PropertyEvaluator evaluator;
72     private final ReferenceHelper refHelper;
73     private final String JavaDoc elementName;
74     private final String JavaDoc newRootNameTemplate;
75     private List JavaDoc/*<String>*/ sourceRootProperties;
76     private List JavaDoc/*<String>*/ sourceRootNames;
77     private List JavaDoc/*<FileObject>*/ sourceRoots;
78     private List JavaDoc/*<URL>*/ sourceRootURLs;
79     private final PropertyChangeSupport JavaDoc support;
80     private final ProjectMetadataListener listener;
81     private final boolean isTest;
82     private final File JavaDoc projectDir;
83
84     /**
85      * Creates new SourceRoots
86      * @param helper
87      * @param evaluator
88      * @param elementName the name of XML element under which are declared the roots
89      * @param newRootNameTemplate template for new property name of source root
90      */

91     SourceRoots (UpdateHelper helper, PropertyEvaluator evaluator, ReferenceHelper refHelper, String JavaDoc elementName, boolean isTest, String JavaDoc newRootNameTemplate) {
92         assert helper != null && evaluator != null && refHelper != null && elementName != null && newRootNameTemplate != null;
93         this.helper = helper;
94         this.evaluator = evaluator;
95         this.refHelper = refHelper;
96         this.elementName = elementName;
97         this.isTest = isTest;
98         this.newRootNameTemplate = newRootNameTemplate;
99         this.projectDir = FileUtil.toFile(this.helper.getAntProjectHelper().getProjectDirectory());
100         this.support = new PropertyChangeSupport JavaDoc(this);
101         this.listener = new ProjectMetadataListener();
102         this.evaluator.addPropertyChangeListener (WeakListeners.propertyChange(this.listener,this.evaluator));
103         this.helper.getAntProjectHelper().addAntProjectListener ((AntProjectListener)WeakListeners.create(AntProjectListener.class, this.listener,this.helper));
104     }
105
106
107     /**
108      * Returns the display names of soruce roots
109      * The returned array has the same length as an array returned by the getRootProperties.
110      * It may contain empty strings but not null.
111      * @return an array of String
112      */

113     public String JavaDoc[] getRootNames () {
114         return (String JavaDoc[]) ProjectManager.mutex().readAccess(new Mutex.Action() {
115             public Object JavaDoc run() {
116                 synchronized (SourceRoots.this) {
117                     if (sourceRootNames == null) {
118                         readProjectMetadata();
119                     }
120                 }
121                 return sourceRootNames.toArray (new String JavaDoc[sourceRootNames.size()]);
122             }
123         });
124     }
125
126     /**
127      * Returns names of Ant properties in the project.properties file holding the source roots.
128      * @return an array of String
129      */

130     public String JavaDoc[] getRootProperties () {
131         return (String JavaDoc[]) ProjectManager.mutex().readAccess(new Mutex.Action() {
132             public Object JavaDoc run() {
133                 synchronized (SourceRoots.this) {
134                     if (sourceRootProperties == null) {
135                         readProjectMetadata();
136                     }
137                 }
138                 return sourceRootProperties.toArray (new String JavaDoc[sourceRootProperties.size()]);
139             }
140         });
141     }
142
143     /**
144      * Returns the source roots
145      * @return an array of FileObject
146      */

147     public FileObject[] getRoots () {
148         return (FileObject[]) ProjectManager.mutex().readAccess(new Mutex.Action () {
149                 public Object JavaDoc run () {
150                     synchronized (this) {
151                         //Local caching
152
if (sourceRoots == null) {
153                             String JavaDoc[] srcProps = getRootProperties();
154                             List JavaDoc result = new ArrayList JavaDoc();
155                             for (int i = 0; i<srcProps.length; i++) {
156                                 String JavaDoc prop = evaluator.getProperty(srcProps[i]);
157                                 if (prop != null) {
158                                     FileObject f = helper.getAntProjectHelper().resolveFileObject(prop);
159                                     if (f == null) {
160                                         continue;
161                                     }
162                                     if (FileUtil.isArchiveFile(f)) {
163                                         f = FileUtil.getArchiveRoot(f);
164                                     }
165                                     result.add(f);
166                                 }
167                             }
168                             sourceRoots = Collections.unmodifiableList(result);
169                         }
170                     }
171                     return sourceRoots.toArray(new FileObject[sourceRoots.size()]);
172                 }
173         });
174     }
175
176     /**
177      * Returns the source roots as URLs.
178      * @return an array of URL
179      */

180     public URL JavaDoc[] getRootURLs() {
181         return (URL JavaDoc[]) ProjectManager.mutex().readAccess(new Mutex.Action () {
182             public Object JavaDoc run () {
183                 synchronized (this) {
184                     //Local caching
185
if (sourceRootURLs == null) {
186                         String JavaDoc[] srcProps = getRootProperties();
187                         List JavaDoc result = new ArrayList JavaDoc();
188                         for (int i = 0; i<srcProps.length; i++) {
189                             String JavaDoc prop = evaluator.getProperty(srcProps[i]);
190                             if (prop != null) {
191                                 File JavaDoc f = helper.getAntProjectHelper().resolveFile(prop);
192                                 try {
193                                     result.add(WebProjectUtil.getRootURL(f,null));
194                                 } catch (MalformedURLException JavaDoc e) {
195                                     ErrorManager.getDefault().notify(e);
196                                 }
197                             }
198                         }
199                         sourceRootURLs = Collections.unmodifiableList(result);
200                     }
201                 }
202                 return sourceRootURLs.toArray(new URL JavaDoc[sourceRootURLs.size()]);
203             }
204         });
205     }
206
207     /**
208      * Adds PropertyChangeListener
209      * @param listener
210      */

211     public void addPropertyChangeListener (PropertyChangeListener JavaDoc listener) {
212         this.support.addPropertyChangeListener (listener);
213     }
214
215     /**
216      * Removes PropertyChangeListener
217      * @param listener
218      */

219     public void removePropertyChangeListener (PropertyChangeListener JavaDoc listener) {
220         this.support.removePropertyChangeListener (listener);
221     }
222
223
224     /**
225      * Replaces the current roots by the new ones
226      * @param roots the URLs of new roots
227      * @param labels the names of roots
228      */

229     public void putRoots (final URL JavaDoc[] roots, final String JavaDoc[] labels) {
230         ProjectManager.mutex().writeAccess(
231                 new Mutex.Action () {
232                     public Object JavaDoc run() {
233                         String JavaDoc[] originalProps = getRootProperties();
234                         URL JavaDoc[] originalRoots = getRootURLs();
235                         Map JavaDoc oldRoots2props = new HashMap JavaDoc ();
236                         for (int i=0; i<originalProps.length;i++) {
237                             oldRoots2props.put (originalRoots[i],originalProps[i]);
238                         }
239                         Map JavaDoc newRoots2lab = new HashMap JavaDoc();
240                         for (int i=0; i<roots.length;i++) {
241                             newRoots2lab.put (roots[i],labels[i]);
242                         }
243                         Element JavaDoc cfgEl = helper.getPrimaryConfigurationData(true);
244                         NodeList JavaDoc nl = cfgEl.getElementsByTagNameNS(WebProjectType.PROJECT_CONFIGURATION_NAMESPACE, elementName);
245                         assert nl.getLength() == 1 : "Illegal project.xml"; //NOI18N
246
Element JavaDoc ownerElement = (Element JavaDoc) nl.item(0);
247                         //Remove all old roots
248
NodeList JavaDoc rootsNodes = ownerElement.getElementsByTagNameNS(WebProjectType.PROJECT_CONFIGURATION_NAMESPACE, "root"); //NOI18N
249
while (rootsNodes.getLength()>0) {
250                             Element JavaDoc root = (Element JavaDoc) rootsNodes.item(0);
251                             ownerElement.removeChild(root);
252                         }
253                         //Remove all unused root properties
254
List JavaDoc newRoots = Arrays.asList(roots);
255                         Map JavaDoc propsToRemove = new HashMap JavaDoc (oldRoots2props);
256                         propsToRemove.keySet().removeAll(newRoots);
257                         EditableProperties props = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
258                         for (Iterator JavaDoc it = propsToRemove.values().iterator(); it.hasNext();) {
259                             String JavaDoc propName = (String JavaDoc) it.next ();
260                             props.remove(propName);
261                         }
262                         helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH,props);
263                         //Add the new roots
264
Document JavaDoc doc = ownerElement.getOwnerDocument();
265                         oldRoots2props.keySet().retainAll(newRoots);
266                         for (Iterator JavaDoc it = newRoots.iterator(); it.hasNext();) {
267                             URL JavaDoc newRoot = (URL JavaDoc) it.next ();
268                             String JavaDoc rootName = (String JavaDoc) oldRoots2props.get (newRoot);
269                             if (rootName == null) {
270                                 //Root is new generate property for it
271
props = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
272                                 String JavaDoc[] names = newRoot.getPath().split("/"); //NOI18N
273
rootName = MessageFormat.format(newRootNameTemplate, new Object JavaDoc[]{names[names.length-1],""}); //NOI18N
274
int rootIndex = 1;
275                                 while (props.containsKey(rootName)) {
276                                     rootIndex++;
277                                     rootName = MessageFormat.format(newRootNameTemplate,new Object JavaDoc[]{names[names.length-1], Integer.valueOf(rootIndex)});
278                                 }
279                                 File JavaDoc f = FileUtil.normalizeFile(new File JavaDoc(URI.create(newRoot.toExternalForm())));
280                                 File JavaDoc projDir = FileUtil.toFile(helper.getAntProjectHelper().getProjectDirectory());
281                                 String JavaDoc path = f.getAbsolutePath();
282                                 String JavaDoc prjPath = projDir.getAbsolutePath()+File.separatorChar;
283                                 if (path.startsWith(prjPath)) {
284                                     path = path.substring(prjPath.length());
285                                 }
286                                 else {
287                                     path = refHelper.createForeignFileReference(f, JavaProjectConstants.SOURCES_TYPE_JAVA);
288                                     props = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
289                                 }
290                                 props.put(rootName,path);
291                                 helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH,props);
292                             }
293                             Element JavaDoc newRootNode = doc.createElementNS(WebProjectType.PROJECT_CONFIGURATION_NAMESPACE, "root"); //NOI18N
294
newRootNode.setAttribute("id",rootName); //NOI18N
295
String JavaDoc label = (String JavaDoc) newRoots2lab.get (newRoot);
296                             if (label != null && label.length()>0 && !label.equals (getRootDisplayName(null,rootName))) { //NOI18N
297
newRootNode.setAttribute("name",label); //NOI18N
298
}
299                             ownerElement.appendChild (newRootNode);
300                         }
301                         helper.putPrimaryConfigurationData(cfgEl,true);
302                         return null;
303                     }
304                 }
305         );
306     }
307
308     /**
309      * Translates root name into display name of source/test root
310      * @param rootName the name of root got from {@link SourceRoots#getRootNames}
311      * @param propName the name of property the root is stored in
312      * @return the label to be displayed
313      */

314     public String JavaDoc getRootDisplayName (String JavaDoc rootName, String JavaDoc propName) {
315         if (rootName == null || rootName.length() ==0) {
316             //If the prop is src.dir use the default name
317
if (isTest && "test.src.dir".equals(propName)) { //NOI18N
318
rootName = DEFAULT_TEST_LABEL;
319             }
320             else if (!isTest && "src.dir".equals(propName)) { //NOI18N
321
rootName = DEFAULT_SOURCE_LABEL;
322             }
323             else {
324                 //If the name is not given, it should be either a relative path in the project dir
325
//or absolute path when the root is not under the project dir
326
String JavaDoc propValue = evaluator.getProperty(propName);
327                 File JavaDoc sourceRoot = propValue == null ? null : helper.getAntProjectHelper().resolveFile(propValue);
328                 rootName = createInitialDisplayName(sourceRoot);
329             }
330         }
331         return rootName;
332     }
333     
334     public String JavaDoc createInitialDisplayName (File JavaDoc sourceRoot) {
335         String JavaDoc rootName;
336         if (sourceRoot != null) {
337         String JavaDoc srPath = sourceRoot.getAbsolutePath();
338         String JavaDoc pdPath = projectDir.getAbsolutePath() + File.separatorChar;
339         if (srPath.startsWith(pdPath)) {
340             rootName = srPath.substring(pdPath.length());
341         }
342         else {
343             rootName = sourceRoot.getAbsolutePath();
344         }
345         }
346         else {
347             rootName = isTest ? DEFAULT_TEST_LABEL : DEFAULT_SOURCE_LABEL;
348         }
349         return rootName;
350     }
351
352     private void resetCache (boolean isXMLChange, String JavaDoc propName) {
353         boolean fire = false;
354         synchronized (this) {
355             //In case of change reset local cache
356
if (isXMLChange) {
357                 this.sourceRootProperties = null;
358                 this.sourceRootNames = null;
359                 this.sourceRoots = null;
360                 this.sourceRootURLs = null;
361                 fire = true;
362             } else if (propName == null || (sourceRootProperties != null && sourceRootProperties.contains(propName))) {
363                 this.sourceRoots = null;
364                 this.sourceRootURLs = null;
365                 fire = true;
366             }
367         }
368         if (fire) {
369             if (isXMLChange) {
370                 this.support.firePropertyChange (PROP_ROOT_PROPERTIES,null,null);
371             }
372             this.support.firePropertyChange (PROP_ROOTS,null,null);
373         }
374     }
375
376     private void readProjectMetadata () {
377         Element JavaDoc cfgEl = helper.getPrimaryConfigurationData(true);
378         NodeList JavaDoc nl = cfgEl.getElementsByTagNameNS(WebProjectType.PROJECT_CONFIGURATION_NAMESPACE, elementName);
379         assert nl.getLength() == 0 || nl.getLength() == 1 : "Illegal project.xml"; //NOI18N
380
List JavaDoc rootProps = new ArrayList JavaDoc ();
381         List JavaDoc rootNames = new ArrayList JavaDoc ();
382         // It can be 0 in the case when the project is created by WebProjectGenerator and not yet customized
383
if (nl.getLength()==1) {
384             NodeList JavaDoc roots = ((Element JavaDoc)nl.item(0)).getElementsByTagNameNS(WebProjectType.PROJECT_CONFIGURATION_NAMESPACE, "root"); //NOI18N
385
for (int i=0; i<roots.getLength(); i++) {
386                 Element JavaDoc root = (Element JavaDoc) roots.item(i);
387                 String JavaDoc value = root.getAttribute("id"); //NOI18N
388
assert value.length() > 0 : "Illegal project.xml";
389                 rootProps.add(value);
390                 value = root.getAttribute("name"); //NOI18N
391
rootNames.add (value);
392             }
393         }
394         this.sourceRootProperties = Collections.unmodifiableList(rootProps);
395         this.sourceRootNames = Collections.unmodifiableList(rootNames);
396     }
397
398     private class ProjectMetadataListener implements PropertyChangeListener JavaDoc,AntProjectListener {
399
400         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
401             resetCache (false,evt.getPropertyName());
402         }
403
404         public void configurationXmlChanged(AntProjectEvent ev) {
405             resetCache (true,null);
406         }
407
408         public void propertiesChanged(AntProjectEvent ev) {
409             //Handled by propertyChange
410
}
411     }
412
413     public boolean isTest() {
414         return isTest;
415     }
416 }
417
Popular Tags