KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > ruby > railsprojects > RailsProject


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.railsprojects;
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.railsprojects.SourceRoots;
36 import org.netbeans.modules.ruby.railsprojects.classpath.ClassPathProviderImpl;
37 import org.netbeans.modules.ruby.railsprojects.server.WebrickServer;
38 import org.netbeans.modules.ruby.railsprojects.ui.RailsLogicalViewProvider;
39 import org.netbeans.modules.ruby.railsprojects.ui.customizer.CustomizerProviderImpl;
40 import org.netbeans.modules.ruby.railsprojects.ui.customizer.RailsProjectProperties;
41 import org.netbeans.spi.project.AuxiliaryConfiguration;
42 import org.netbeans.spi.project.SubprojectProvider;
43 import org.netbeans.spi.project.support.LookupProviderSupport;
44 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectEvent;
45 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectHelper;
46 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectListener;
47 import org.netbeans.modules.ruby.spi.project.support.rake.FilterPropertyProvider;
48 import org.netbeans.modules.ruby.spi.project.support.rake.GeneratedFilesHelper;
49 import org.netbeans.modules.ruby.spi.project.support.rake.ProjectXmlSavedHook;
50 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyEvaluator;
51 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyProvider;
52 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyUtils;
53 import org.netbeans.modules.ruby.spi.project.support.rake.ReferenceHelper;
54 import org.netbeans.spi.project.ui.PrivilegedTemplates;
55 import org.netbeans.spi.project.ui.ProjectOpenedHook;
56 import org.netbeans.spi.project.ui.RecommendedTemplates;
57 import org.netbeans.spi.project.ui.support.UILookupMergerSupport;
58 import org.openide.ErrorManager;
59 import org.openide.filesystems.FileObject;
60 import org.openide.filesystems.FileUtil;
61 import org.openide.util.Lookup;
62 import org.openide.util.Mutex;
63 import org.openide.util.Utilities;
64 import org.openide.util.lookup.Lookups;
65 import org.w3c.dom.Element JavaDoc;
66 import org.w3c.dom.Text JavaDoc;
67 import org.w3c.dom.Node JavaDoc;
68 import org.w3c.dom.NodeList JavaDoc;
69
70 /**
71  * Represents one plain Ruby project.
72  * @author Jesse Glick, et al.
73  */

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

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

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

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

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

228     /**
229      * Returns the source roots of this project
230      * @return project's source roots
231      */

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

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

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

373             // register project's classpaths to GlobalPathRegistry
374
ClassPathProviderImpl cpProvider = (ClassPathProviderImpl)lookup.lookup(ClassPathProviderImpl.class);
375             GlobalPathRegistry.getDefault().register(ClassPath.BOOT, cpProvider.getProjectClassPaths(ClassPath.BOOT));
376             GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, cpProvider.getProjectClassPaths(ClassPath.SOURCE));
377             //GlobalPathRegistry.getDefault().register(ClassPath.COMPILE, cpProvider.getProjectClassPaths(ClassPath.COMPILE));
378

379             //register updater of main.class
380
//the updater is active only on the opened projects
381

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

404         }
405         
406         protected void projectClosed() {
407             // Probably unnecessary, but just in case:
408
try {
409                 ProjectManager.getDefault().saveProject(RailsProject.this);
410             } catch (IOException JavaDoc e) {
411                 ErrorManager.getDefault().notify(e);
412             }
413             
414             // unregister project's classpaths to GlobalPathRegistry
415
ClassPathProviderImpl cpProvider = (ClassPathProviderImpl)lookup.lookup(ClassPathProviderImpl.class);
416             GlobalPathRegistry.getDefault().unregister(ClassPath.BOOT, cpProvider.getProjectClassPaths(ClassPath.BOOT));
417             GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, cpProvider.getProjectClassPaths(ClassPath.SOURCE));
418             //GlobalPathRegistry.getDefault().unregister(ClassPath.COMPILE, cpProvider.getProjectClassPaths(ClassPath.COMPILE));
419

420             //XXX: to compile workaround
421
// if (mainClassUpdater != null) {
422
// mainClassUpdater.unregister ();
423
// mainClassUpdater = null;
424
// }
425

426         }
427         
428     }
429         
430     private static final class RecommendedTemplatesImpl implements RecommendedTemplates, PrivilegedTemplates {
431         RecommendedTemplatesImpl (UpdateHelper helper) {
432             this.helper = helper;
433         }
434         
435         private UpdateHelper helper;
436         
437         // List of primarily supported templates
438

439         private static final String JavaDoc[] APPLICATION_TYPES = new String JavaDoc[] {
440             "ruby", // NOI18N
441
"XML", // NOI18N
442
"simple-files" // NOI18N
443
};
444         
445         private static final String JavaDoc[] PRIVILEGED_NAMES = new String JavaDoc[] {
446             "Templates/Ruby/RhtmlTemplate.rhtml", // NOI18N
447
"Templates/Ruby/main.rb", // NOI18N
448
"Templates/Ruby/test.rb", // NOI18N
449
"Templates/Ruby/class.rb", // NOI18N
450
"Templates/Ruby/module.rb", // NOI18N
451
"Templates/Ruby/rakefile.rb", // NOI18N
452
};
453         
454         public String JavaDoc[] getRecommendedTypes() {
455             return APPLICATION_TYPES;
456         }
457         
458         public String JavaDoc[] getPrivilegedTemplates() {
459             return PRIVILEGED_NAMES;
460         }
461         
462     }
463 }
464
Popular Tags