KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > ruby > modules > project > rake > RakeBasedProjectFactorySingleton


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.modules.project.rake;
21
22 import java.io.File JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.lang.ref.Reference JavaDoc;
25 import java.lang.ref.WeakReference JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.Set JavaDoc;
33 import java.util.WeakHashMap JavaDoc;
34 import org.netbeans.api.project.Project;
35 import org.netbeans.spi.project.ProjectFactory;
36 import org.netbeans.spi.project.ProjectState;
37 import org.netbeans.modules.ruby.spi.project.support.rake.RakeBasedProjectType;
38 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectHelper;
39 import org.openide.ErrorManager;
40 import org.openide.filesystems.FileObject;
41 import org.openide.filesystems.FileUtil;
42 import org.openide.util.Exceptions;
43 import org.openide.util.Lookup;
44 import org.openide.util.LookupEvent;
45 import org.openide.util.LookupListener;
46 import org.openide.util.NbBundle;
47 import org.openide.xml.XMLUtil;
48 import org.w3c.dom.Document JavaDoc;
49 import org.w3c.dom.Element JavaDoc;
50 import org.xml.sax.InputSource JavaDoc;
51 import org.xml.sax.SAXException JavaDoc;
52
53 /**
54  * Singleton {@link ProjectFactory} implementation which handles all Ant-based
55  * projects by delegating some functionality to registered Ant project types.
56  * @author Jesse Glick
57  */

58 public final class RakeBasedProjectFactorySingleton implements ProjectFactory {
59     
60     public static final String JavaDoc PROJECT_XML_PATH = "nbproject/project.xml"; // NOI18N
61

62     public static final String JavaDoc PROJECT_NS = "http://www.netbeans.org/ns/project/1"; // NOI18N
63

64     /** Construct the singleton. */
65     public RakeBasedProjectFactorySingleton() {}
66     
67     private static final Map JavaDoc<Project,Reference JavaDoc<RakeProjectHelper>> project2Helper = new WeakHashMap JavaDoc<Project,Reference JavaDoc<RakeProjectHelper>>();
68     private static final Map JavaDoc<RakeProjectHelper,Reference JavaDoc<Project>> helper2Project = new WeakHashMap JavaDoc<RakeProjectHelper,Reference JavaDoc<Project>>();
69     private static final Map JavaDoc<RakeBasedProjectType,List JavaDoc<Reference JavaDoc<RakeProjectHelper>>> type2Projects = new HashMap JavaDoc<RakeBasedProjectType,List JavaDoc<Reference JavaDoc<RakeProjectHelper>>>(); //for second part of #42738
70
private static final Lookup.Result<RakeBasedProjectType> antBasedProjectTypes;
71     private static Map JavaDoc<String JavaDoc,RakeBasedProjectType> antBasedProjectTypesByType = null;
72     static {
73         antBasedProjectTypes = Lookup.getDefault().lookupResult(RakeBasedProjectType.class);
74         antBasedProjectTypes.addLookupListener(new LookupListener() {
75             public void resultChanged(LookupEvent ev) {
76                 synchronized (RakeBasedProjectFactorySingleton.class) {
77                     Set JavaDoc<RakeBasedProjectType> oldTypes = type2Projects.keySet();
78                     Set JavaDoc<RakeBasedProjectType> removed = new HashSet JavaDoc<RakeBasedProjectType>(oldTypes);
79                     
80                     removed.removeAll(antBasedProjectTypes.allInstances());
81                     
82                     antBasedProjectTypesRemoved(removed);
83                     
84                     antBasedProjectTypesByType = null;
85                 }
86             }
87         });
88     }
89     
90     private static void antBasedProjectTypesRemoved(Set JavaDoc<RakeBasedProjectType> removed) {
91         for (RakeBasedProjectType type : removed) {
92             List JavaDoc<Reference JavaDoc<RakeProjectHelper>> projects = type2Projects.get(type);
93             if (projects != null) {
94                 for (Reference JavaDoc<RakeProjectHelper> r : projects) {
95                     RakeProjectHelper helper = r.get();
96                     if (helper != null) {
97                         helper.notifyDeleted();
98                     }
99                 }
100             }
101             type2Projects.remove(type);
102         }
103     }
104     
105     private static synchronized RakeBasedProjectType findRakeBasedProjectType(String JavaDoc type) {
106         if (antBasedProjectTypesByType == null) {
107             antBasedProjectTypesByType = new HashMap JavaDoc<String JavaDoc,RakeBasedProjectType>();
108             // No need to synchronize similar calls since this is called only inside
109
// ProjectManager.mutex. However dkonecny says that allInstances can
110
// trigger a LookupEvent which would clear antBasedProjectTypesByType,
111
// so need to initialize that later; and who knows then Lookup changes
112
// might be fired.
113
for (RakeBasedProjectType abpt : antBasedProjectTypes.allInstances()) {
114                 antBasedProjectTypesByType.put(abpt.getType(), abpt);
115             }
116         }
117         return antBasedProjectTypesByType.get(type);
118     }
119     
120     public boolean isProject(FileObject dir) {
121         File JavaDoc dirF = FileUtil.toFile(dir);
122         if (dirF == null) {
123             return false;
124         }
125         // Just check whether project.xml exists. Do not attempt to parse it, etc.
126
// Do not use FileObject.getFileObject since that may load other sister files.
127
File JavaDoc projectXmlF = new File JavaDoc(new File JavaDoc(dirF, "nbproject"), "project.xml"); // NOI18N
128
return projectXmlF.isFile();
129     }
130     
131     public Project loadProject(FileObject projectDirectory, ProjectState state) throws IOException JavaDoc {
132         if (FileUtil.toFile(projectDirectory) == null) {
133             return null;
134         }
135         FileObject projectFile = projectDirectory.getFileObject(PROJECT_XML_PATH);
136         //#54488: Added check for virtual
137
if (projectFile == null || !projectFile.isData() || projectFile.isVirtual()) {
138             return null;
139         }
140         File JavaDoc projectDiskFile = FileUtil.toFile(projectFile);
141         //#63834: if projectFile exists and projectDiskFile does not, do nothing:
142
if (projectDiskFile == null) {
143             return null;
144         }
145         Document JavaDoc projectXml;
146         try {
147             projectXml = XMLUtil.parse(new InputSource JavaDoc(projectDiskFile.toURI().toString()), false, true, Util.defaultErrorHandler(), null);
148         } catch (SAXException JavaDoc e) {
149             IOException JavaDoc ioe = (IOException JavaDoc) new IOException JavaDoc(projectDiskFile + ": " + e.toString()).initCause(e);
150             Exceptions.attachLocalizedMessage(ioe, NbBundle.getMessage(RakeBasedProjectFactorySingleton.class,
151                                                                         "RakeBasedProjectFactorySingleton.parseError",
152                                                                         projectDiskFile.getAbsolutePath(), e.getMessage()));
153             throw ioe;
154         }
155         Element JavaDoc projectEl = projectXml.getDocumentElement();
156         if (!"project".equals(projectEl.getLocalName()) || !PROJECT_NS.equals(projectEl.getNamespaceURI())) { // NOI18N
157
return null;
158         }
159         Element JavaDoc typeEl = Util.findElement(projectEl, "type", PROJECT_NS); // NOI18N
160
if (typeEl == null) {
161             return null;
162         }
163         String JavaDoc type = Util.findText(typeEl);
164         if (type == null) {
165             return null;
166         }
167         RakeBasedProjectType provider = findRakeBasedProjectType(type);
168         if (provider == null) {
169             return null;
170         }
171         RakeProjectHelper helper = HELPER_CALLBACK.createHelper(projectDirectory, projectXml, state, provider);
172         Project project = provider.createProject(helper);
173         project2Helper.put(project, new WeakReference JavaDoc<RakeProjectHelper>(helper));
174         helper2Project.put(helper, new WeakReference JavaDoc<Project>(project));
175         List JavaDoc<Reference JavaDoc<RakeProjectHelper>> l = type2Projects.get(provider);
176         
177         if (l == null) {
178             type2Projects.put(provider, l = new ArrayList JavaDoc<Reference JavaDoc<RakeProjectHelper>>());
179         }
180         
181         l.add(new WeakReference JavaDoc<RakeProjectHelper>(helper));
182         
183         return project;
184     }
185     
186     public void saveProject(Project project) throws IOException JavaDoc, ClassCastException JavaDoc {
187         Reference JavaDoc<RakeProjectHelper> helperRef = project2Helper.get(project);
188         if (helperRef == null) {
189             throw new ClassCastException JavaDoc(project.getClass().getName());
190         }
191         RakeProjectHelper helper = helperRef.get();
192         assert helper != null : "RakeProjectHelper collected for " + project;
193         HELPER_CALLBACK.save(helper);
194     }
195     
196     /**
197      * Get the project corresponding to a helper.
198      * For use from {@link RakeProjectHelper}.
199      * @param helper an Ant project helper object
200      * @return the corresponding project
201      */

202     public static Project getProjectFor(RakeProjectHelper helper) {
203         Reference JavaDoc<Project> projectRef = helper2Project.get(helper);
204         assert projectRef != null : "Found a Project reference for " + helper;
205         Project p = projectRef.get();
206         assert p != null : "Found a non-null Project for " + helper;
207         return p;
208     }
209     
210     /**
211      * Get the helper corresponding to a project.
212      * For use from {@link ProjectGenerator}.
213      * @param project an Ant-based project
214      * @return the corresponding Ant project helper object, or null if it is unknown
215      */

216     public static RakeProjectHelper getHelperFor(Project p) {
217         Reference JavaDoc<RakeProjectHelper> helperRef = project2Helper.get(p);
218         return helperRef != null ? helperRef.get() : null;
219     }
220     
221     /**
222      * Callback to create and access RakeProjectHelper objects from outside its package.
223      */

224     public interface RakeProjectHelperCallback {
225         RakeProjectHelper createHelper(FileObject dir, Document JavaDoc projectXml, ProjectState state, RakeBasedProjectType type);
226         void save(RakeProjectHelper helper) throws IOException JavaDoc;
227     }
228     /** Defined in RakeProjectHelper's static initializer. */
229     public static RakeProjectHelperCallback HELPER_CALLBACK;
230     static {
231         Class JavaDoc<?> c = RakeProjectHelper.class;
232         try {
233             Class.forName(c.getName(), true, c.getClassLoader());
234         } catch (ClassNotFoundException JavaDoc e) {
235             assert false : e;
236         }
237         assert HELPER_CALLBACK != null;
238     }
239     
240 }
241
Popular Tags