KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > ruby > rubyproject > RubyProject


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.ruby.rubyproject;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.beans.PropertyChangeSupport JavaDoc;
25 import java.io.File JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.util.Collections JavaDoc;
28 import javax.swing.Icon JavaDoc;
29 import javax.swing.ImageIcon JavaDoc;
30 import org.netbeans.api.java.classpath.ClassPath;
31 import org.netbeans.api.java.classpath.GlobalPathRegistry;
32 import org.netbeans.api.project.Project;
33 import org.netbeans.api.project.ProjectInformation;
34 import org.netbeans.api.project.ProjectManager;
35 import org.netbeans.modules.ruby.rubyproject.SourceRoots;
36 import org.netbeans.modules.ruby.rubyproject.classpath.ClassPathProviderImpl;
37 import org.netbeans.modules.ruby.rubyproject.ui.RubyLogicalViewProvider;
38 import org.netbeans.modules.ruby.rubyproject.ui.customizer.CustomizerProviderImpl;
39 import org.netbeans.modules.ruby.rubyproject.ui.customizer.RubyProjectProperties;
40 import org.netbeans.spi.project.AuxiliaryConfiguration;
41 import org.netbeans.spi.project.SubprojectProvider;
42 import org.netbeans.spi.project.support.LookupProviderSupport;
43 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectEvent;
44 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectHelper;
45 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectListener;
46 import org.netbeans.modules.ruby.spi.project.support.rake.FilterPropertyProvider;
47 import org.netbeans.modules.ruby.spi.project.support.rake.GeneratedFilesHelper;
48 import org.netbeans.modules.ruby.spi.project.support.rake.ProjectXmlSavedHook;
49 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyEvaluator;
50 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyProvider;
51 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyUtils;
52 import org.netbeans.modules.ruby.spi.project.support.rake.ReferenceHelper;
53 import org.netbeans.spi.project.ui.PrivilegedTemplates;
54 import org.netbeans.spi.project.ui.ProjectOpenedHook;
55 import org.netbeans.spi.project.ui.RecommendedTemplates;
56 import org.netbeans.spi.project.ui.support.UILookupMergerSupport;
57 import org.openide.ErrorManager;
58 import org.openide.filesystems.FileObject;
59 import org.openide.filesystems.FileUtil;
60 import org.openide.util.Lookup;
61 import org.openide.util.Mutex;
62 import org.openide.util.Utilities;
63 import org.openide.util.lookup.Lookups;
64 import org.w3c.dom.Element JavaDoc;
65 import org.w3c.dom.Text JavaDoc;
66 import org.w3c.dom.Node JavaDoc;
67 import org.w3c.dom.NodeList JavaDoc;
68
69 /**
70  * Represents one plain Ruby project.
71  * @author Jesse Glick, et al.
72  */

73 public final class RubyProject implements Project, RakeProjectListener {
74     /**
75      * Ruby package root sources type.
76      * @see org.netbeans.api.project.Sources
77      */

78     public static final String JavaDoc SOURCES_TYPE_RUBY = "ruby"; // NOI18N
79

80     private static final Icon JavaDoc Ruby_PROJECT_ICON = new ImageIcon JavaDoc(Utilities.loadImage("org/netbeans/modules/ruby/rubyproject/ui/resources/jruby.png")); // NOI18N
81

82     private final AuxiliaryConfiguration aux;
83     private final RakeProjectHelper helper;
84     private final PropertyEvaluator eval;
85     private final ReferenceHelper refHelper;
86     private final GeneratedFilesHelper genFilesHelper;
87     private final Lookup lookup;
88     private final UpdateHelper updateHelper;
89 // private MainClassUpdater mainClassUpdater;
90
private SourceRoots sourceRoots;
91     private SourceRoots testRoots;
92     
93     RubyProject(RakeProjectHelper helper) throws IOException JavaDoc {
94         this.helper = helper;
95         eval = createEvaluator();
96         aux = helper.createAuxiliaryConfiguration();
97         refHelper = new ReferenceHelper(helper, aux, eval);
98         genFilesHelper = new GeneratedFilesHelper(helper);
99         this.updateHelper = new UpdateHelper (this, this.helper, this.aux, this.genFilesHelper,
100             UpdateHelper.createDefaultNotifier());
101
102         lookup = createLookup(aux);
103         helper.addRakeProjectListener(this);
104     }
105
106     /**
107      * Returns the project directory
108      * @return the directory the project is located in
109      */

110     public FileObject getProjectDirectory() {
111         return helper.getProjectDirectory();
112     }
113
114     public String JavaDoc toString() {
115         return "RubyProject[" + FileUtil.getFileDisplayName(getProjectDirectory()) + "]"; // NOI18N
116
}
117     
118     private PropertyEvaluator createEvaluator() {
119         // It is currently safe to not use the UpdateHelper for PropertyEvaluator; UH.getProperties() delegates to APH
120
// Adapted from APH.getStandardPropertyEvaluator (delegates to ProjectProperties):
121
PropertyEvaluator baseEval1 = PropertyUtils.sequentialPropertyEvaluator(
122                 helper.getStockPropertyPreprovider(),
123                 helper.getPropertyProvider(RubyConfigurationProvider.CONFIG_PROPS_PATH));
124         PropertyEvaluator baseEval2 = PropertyUtils.sequentialPropertyEvaluator(
125                 helper.getStockPropertyPreprovider(),
126                 helper.getPropertyProvider(RakeProjectHelper.PRIVATE_PROPERTIES_PATH));
127         return PropertyUtils.sequentialPropertyEvaluator(
128                 helper.getStockPropertyPreprovider(),
129                 helper.getPropertyProvider(RubyConfigurationProvider.CONFIG_PROPS_PATH),
130                 new ConfigPropertyProvider(baseEval1, "nbproject/private/configs", helper), // NOI18N
131
helper.getPropertyProvider(RakeProjectHelper.PRIVATE_PROPERTIES_PATH),
132                 PropertyUtils.userPropertiesProvider(baseEval2,
133                     "user.properties.file", FileUtil.toFile(getProjectDirectory())), // NOI18N
134
new ConfigPropertyProvider(baseEval1, "nbproject/configs", helper), // NOI18N
135
helper.getPropertyProvider(RakeProjectHelper.PROJECT_PROPERTIES_PATH));
136     }
137     private static final class ConfigPropertyProvider extends FilterPropertyProvider implements PropertyChangeListener JavaDoc {
138         private final PropertyEvaluator baseEval;
139         private final String JavaDoc prefix;
140         private final RakeProjectHelper helper;
141         public ConfigPropertyProvider(PropertyEvaluator baseEval, String JavaDoc prefix, RakeProjectHelper helper) {
142             super(computeDelegate(baseEval, prefix, helper));
143             this.baseEval = baseEval;
144             this.prefix = prefix;
145             this.helper = helper;
146             baseEval.addPropertyChangeListener(this);
147         }
148         public void propertyChange(PropertyChangeEvent JavaDoc ev) {
149             if (RubyConfigurationProvider.PROP_CONFIG.equals(ev.getPropertyName())) {
150                 setDelegate(computeDelegate(baseEval, prefix, helper));
151             }
152         }
153         private static PropertyProvider computeDelegate(PropertyEvaluator baseEval, String JavaDoc prefix, RakeProjectHelper helper) {
154             String JavaDoc config = baseEval.getProperty(RubyConfigurationProvider.PROP_CONFIG);
155             if (config != null) {
156                 return helper.getPropertyProvider(prefix + "/" + config + ".properties"); // NOI18N
157
} else {
158                 return PropertyUtils.fixedPropertyProvider(Collections.<String JavaDoc,String JavaDoc>emptyMap());
159             }
160         }
161     }
162     
163     public PropertyEvaluator evaluator() {
164         return eval;
165     }
166
167     ReferenceHelper getReferenceHelper () {
168         return this.refHelper;
169     }
170
171     public UpdateHelper getUpdateHelper() {
172         return this.updateHelper;
173     }
174     
175     public Lookup getLookup() {
176         return lookup;
177     }
178     
179     public RakeProjectHelper getRakeProjectHelper() {
180         return helper;
181     }
182
183     private Lookup createLookup(AuxiliaryConfiguration aux) {
184         SubprojectProvider spp = refHelper.createSubprojectProvider();
185         Lookup base = Lookups.fixed(new Object JavaDoc[] {
186             new Info(),
187             aux,
188             helper.createCacheDirectoryProvider(),
189             spp,
190             new RubyActionProvider( this, this.updateHelper ),
191             new RubyLogicalViewProvider(this, this.updateHelper, evaluator(), spp, refHelper),
192             new ClassPathProviderImpl(this.helper, evaluator(), getSourceRoots(),getTestSourceRoots()), //Does not use APH to get/put properties/cfgdata
193
// new RubyCustomizerProvider(this, this.updateHelper, evaluator(), refHelper),
194
new CustomizerProviderImpl(this, this.updateHelper, evaluator(), refHelper, this.genFilesHelper),
195             new ProjectXmlSavedHookImpl(),
196             new ProjectOpenedHookImpl(),
197             new RubySources (this.helper, evaluator(), getSourceRoots(), getTestSourceRoots()),
198             new RubySharabilityQuery (this.helper, evaluator(), getSourceRoots(), getTestSourceRoots()), //Does not use APH to get/put properties/cfgdata
199
new RubyFileBuiltQuery (this.helper, evaluator(),getSourceRoots(),getTestSourceRoots()), //Does not use APH to get/put properties/cfgdata
200
new RecommendedTemplatesImpl (this.updateHelper),
201             this, // never cast an externally obtained Project to RubyProject - use lookup instead
202
new RubyProjectOperations(this),
203             new RubyConfigurationProvider(this),
204             UILookupMergerSupport.createPrivilegedTemplatesMerger(),
205             UILookupMergerSupport.createRecommendedTemplatesMerger(),
206             LookupProviderSupport.createSourcesMerger()
207         });
208         return LookupProviderSupport.createCompositeLookup(base, "Projects/org-netbeans-modules-ruby-rubyproject/Lookup"); //NOI18N
209
}
210
211     public void configurationXmlChanged(RakeProjectEvent ev) {
212         if (ev.getPath().equals(RakeProjectHelper.PROJECT_XML_PATH)) {
213             // Could be various kinds of changes, but name & displayName might have changed.
214
Info info = (Info)getLookup().lookup(ProjectInformation.class);
215             info.firePropertyChange(ProjectInformation.PROP_NAME);
216             info.firePropertyChange(ProjectInformation.PROP_DISPLAY_NAME);
217         }
218     }
219
220     public void propertiesChanged(RakeProjectEvent ev) {
221         // currently ignored (probably better to listen to evaluator() if you need to)
222
}
223     
224     // Package private methods -------------------------------------------------------------
225

226     /**
227      * Returns the source roots of this project
228      * @return project's source roots
229      */

230     public synchronized SourceRoots getSourceRoots() {
231         if (this.sourceRoots == null) { //Local caching, no project metadata access
232
this.sourceRoots = new SourceRoots(this.updateHelper, evaluator(), getReferenceHelper(), "source-roots", false, "src.{0}{1}.dir"); //NOI18N
233
}
234         return this.sourceRoots;
235     }
236     
237     public synchronized SourceRoots getTestSourceRoots() {
238         if (this.testRoots == null) { //Local caching, no project metadata access
239
this.testRoots = new SourceRoots(this.updateHelper, evaluator(), getReferenceHelper(), "test-roots", true, "test.{0}{1}.dir"); //NOI18N
240
}
241         return this.testRoots;
242     }
243     
244     File JavaDoc getTestClassesDirectory() {
245         String JavaDoc testClassesDir = evaluator().getProperty(RubyProjectProperties.BUILD_TEST_CLASSES_DIR);
246         if (testClassesDir == null) {
247             return null;
248         }
249         return helper.resolveFile(testClassesDir);
250     }
251     
252     // Currently unused (but see #47230):
253
/** Store configured project name. */
254     public void setName(final String JavaDoc name) {
255         ProjectManager.mutex().writeAccess(new Mutex.Action<Void JavaDoc>() {
256             public Void JavaDoc run() {
257                 Element JavaDoc data = helper.getPrimaryConfigurationData(true);
258                 // XXX replace by XMLUtil when that has findElement, findText, etc.
259
NodeList JavaDoc nl = data.getElementsByTagNameNS(RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE, "name");
260                 Element JavaDoc nameEl;
261                 if (nl.getLength() == 1) {
262                     nameEl = (Element JavaDoc) nl.item(0);
263                     NodeList JavaDoc deadKids = nameEl.getChildNodes();
264                     while (deadKids.getLength() > 0) {
265                         nameEl.removeChild(deadKids.item(0));
266                     }
267                 } else {
268                     nameEl = data.getOwnerDocument().createElementNS(RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE, "name");
269                     data.insertBefore(nameEl, /* OK if null */data.getChildNodes().item(0));
270                 }
271                 nameEl.appendChild(data.getOwnerDocument().createTextNode(name));
272                 helper.putPrimaryConfigurationData(data, true);
273                 return null;
274             }
275         });
276     }
277
278
279
280
281     // Private innerclasses ----------------------------------------------------------------
282

283     private final class Info implements ProjectInformation {
284         
285         private final PropertyChangeSupport JavaDoc pcs = new PropertyChangeSupport JavaDoc(this);
286         
287         Info() {}
288         
289         void firePropertyChange(String JavaDoc prop) {
290             pcs.firePropertyChange(prop, null, null);
291         }
292         
293         public String JavaDoc getName() {
294             return PropertyUtils.getUsablePropertyName(getDisplayName());
295         }
296         
297         public String JavaDoc getDisplayName() {
298             return ProjectManager.mutex().readAccess(new Mutex.Action<String JavaDoc>() {
299                 public String JavaDoc run() {
300                     Element JavaDoc data = updateHelper.getPrimaryConfigurationData(true);
301                     // XXX replace by XMLUtil when that has findElement, findText, etc.
302
NodeList JavaDoc nl = data.getElementsByTagNameNS(RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE, "name"); // NOI18N
303
if (nl.getLength() == 1) {
304                         nl = nl.item(0).getChildNodes();
305                         if (nl.getLength() == 1 && nl.item(0).getNodeType() == Node.TEXT_NODE) {
306                             return ((Text JavaDoc) nl.item(0)).getNodeValue();
307                         }
308                     }
309                     return "???"; // NOI18N
310
}
311             });
312         }
313         
314         public Icon JavaDoc getIcon() {
315             return Ruby_PROJECT_ICON;
316         }
317         
318         public Project getProject() {
319             return RubyProject.this;
320         }
321         
322         public void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
323             pcs.addPropertyChangeListener(listener);
324         }
325         
326         public void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
327             pcs.removePropertyChangeListener(listener);
328         }
329         
330     }
331     
332     private final class ProjectXmlSavedHookImpl extends ProjectXmlSavedHook {
333         
334         ProjectXmlSavedHookImpl() {}
335         
336         protected void projectXmlSaved() throws IOException JavaDoc {
337             //May be called by {@link AuxiliaryConfiguration#putConfigurationFragment}
338
//which didn't affect the j2seproject
339
/*
340             if (updateHelper.isCurrent()) {
341                 //Refresh build-impl.xml only for j2seproject/2
342                 genFilesHelper.refreshBuildScript(
343                     GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
344                     RubyProject.class.getResource("resources/build-impl.xsl"),
345                     false);
346                 genFilesHelper.refreshBuildScript(
347                     GeneratedFilesHelper.BUILD_XML_PATH,
348                     RubyProject.class.getResource("resources/build.xsl"),
349                     false);
350             }
351 */

352         }
353         
354     }
355     
356     private final class ProjectOpenedHookImpl extends ProjectOpenedHook {
357         
358         ProjectOpenedHookImpl() {}
359         
360         protected void projectOpened() {
361             // Check up on build scripts.
362
/*
363             try {
364                 if (updateHelper.isCurrent()) {
365                     //Refresh build-impl.xml only for j2seproject/2
366                     genFilesHelper.refreshBuildScript(
367                         GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
368                         RubyProject.class.getResource("resources/build-impl.xsl"),
369                         true);
370                     genFilesHelper.refreshBuildScript(
371                         GeneratedFilesHelper.BUILD_XML_PATH,
372                         RubyProject.class.getResource("resources/build.xsl"),
373                         true);
374                 }
375             } catch (IOException e) {
376                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
377             }
378 */

379             // register project's classpaths to GlobalPathRegistry
380
ClassPathProviderImpl cpProvider = (ClassPathProviderImpl)lookup.lookup(ClassPathProviderImpl.class);
381             GlobalPathRegistry.getDefault().register(ClassPath.BOOT, cpProvider.getProjectClassPaths(ClassPath.BOOT));
382             GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, cpProvider.getProjectClassPaths(ClassPath.SOURCE));
383             //GlobalPathRegistry.getDefault().register(ClassPath.COMPILE, cpProvider.getProjectClassPaths(ClassPath.COMPILE));
384

385             
386             //register updater of main.class
387
//the updater is active only on the opened projects
388

389 /*
390             // Make it easier to run headless builds on the same machine at least.
391             ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
392                 public Void run() {
393                     EditableProperties ep = updateHelper.getProperties(RakeProjectHelper.PRIVATE_PROPERTIES_PATH);
394                     File buildProperties = new File(System.getProperty("netbeans.user"), "build.properties"); // NOI18N
395                     ep.setProperty("user.properties.file", buildProperties.getAbsolutePath()); //NOI18N
396                     updateHelper.putProperties(RakeProjectHelper.PRIVATE_PROPERTIES_PATH, ep);
397                     try {
398                         ProjectManager.getDefault().saveProject(RubyProject.this);
399                     } catch (IOException e) {
400                         ErrorManager.getDefault().notify(e);
401                     }
402                     return null;
403                 }
404             });
405             RubyLogicalViewProvider physicalViewProvider = (RubyLogicalViewProvider)
406                 RubyProject.this.getLookup().lookup (RubyLogicalViewProvider.class);
407             if (physicalViewProvider != null && physicalViewProvider.hasBrokenLinks()) {
408                 BrokenReferencesSupport.showAlert();
409             }
410 */

411         }
412         
413         protected void projectClosed() {
414             // Probably unnecessary, but just in case:
415
try {
416                 ProjectManager.getDefault().saveProject(RubyProject.this);
417             } catch (IOException JavaDoc e) {
418                 ErrorManager.getDefault().notify(e);
419             }
420             
421             // unregister project's classpaths to GlobalPathRegistry
422
ClassPathProviderImpl cpProvider = (ClassPathProviderImpl)lookup.lookup(ClassPathProviderImpl.class);
423             GlobalPathRegistry.getDefault().unregister(ClassPath.BOOT, cpProvider.getProjectClassPaths(ClassPath.BOOT));
424             GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, cpProvider.getProjectClassPaths(ClassPath.SOURCE));
425             //GlobalPathRegistry.getDefault().unregister(ClassPath.COMPILE, cpProvider.getProjectClassPaths(ClassPath.COMPILE));
426

427 //XXX: to compile workaround
428
// if (mainClassUpdater != null) {
429
// mainClassUpdater.unregister ();
430
// mainClassUpdater = null;
431
// }
432

433         }
434         
435     }
436         
437     private static final class RecommendedTemplatesImpl implements RecommendedTemplates, PrivilegedTemplates {
438         RecommendedTemplatesImpl (UpdateHelper helper) {
439             this.helper = helper;
440         }
441         
442         private UpdateHelper helper;
443         
444         // List of primarily supported templates
445

446         private static final String JavaDoc[] APPLICATION_TYPES = new String JavaDoc[] {
447             "ruby", // NOI18N
448
"XML", // NOI18N
449
"simple-files" // NOI18N
450
};
451         
452         private static final String JavaDoc[] PRIVILEGED_NAMES = new String JavaDoc[] {
453             "Templates/Ruby/main.rb", // NOI18N
454
"Templates/Ruby/test.rb", // NOI18N
455
"Templates/Ruby/class.rb", // NOI18N
456
"Templates/Ruby/module.rb", // NOI18N
457
"Templates/Ruby/rakefile.rb", // NOI18N
458
"Templates/Ruby/suite.rb", // NOI18N
459
};
460         
461         public String JavaDoc[] getRecommendedTypes() {
462             return APPLICATION_TYPES;
463         }
464         
465         public String JavaDoc[] getPrivilegedTemplates() {
466             return PRIVILEGED_NAMES;
467         }
468         
469     }
470 }
471
Popular Tags