1 19 20 package org.netbeans.modules.ruby.modules.project.rake; 21 22 import java.io.File ; 23 import java.io.IOException ; 24 import java.lang.ref.Reference ; 25 import java.lang.ref.WeakReference ; 26 import java.util.ArrayList ; 27 import java.util.HashMap ; 28 import java.util.HashSet ; 29 import java.util.Iterator ; 30 import java.util.List ; 31 import java.util.Map ; 32 import java.util.Set ; 33 import java.util.WeakHashMap ; 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 ; 49 import org.w3c.dom.Element ; 50 import org.xml.sax.InputSource ; 51 import org.xml.sax.SAXException ; 52 53 58 public final class RakeBasedProjectFactorySingleton implements ProjectFactory { 59 60 public static final String PROJECT_XML_PATH = "nbproject/project.xml"; 62 public static final String PROJECT_NS = "http://www.netbeans.org/ns/project/1"; 64 65 public RakeBasedProjectFactorySingleton() {} 66 67 private static final Map <Project,Reference <RakeProjectHelper>> project2Helper = new WeakHashMap <Project,Reference <RakeProjectHelper>>(); 68 private static final Map <RakeProjectHelper,Reference <Project>> helper2Project = new WeakHashMap <RakeProjectHelper,Reference <Project>>(); 69 private static final Map <RakeBasedProjectType,List <Reference <RakeProjectHelper>>> type2Projects = new HashMap <RakeBasedProjectType,List <Reference <RakeProjectHelper>>>(); private static final Lookup.Result<RakeBasedProjectType> antBasedProjectTypes; 71 private static Map <String ,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 <RakeBasedProjectType> oldTypes = type2Projects.keySet(); 78 Set <RakeBasedProjectType> removed = new HashSet <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 <RakeBasedProjectType> removed) { 91 for (RakeBasedProjectType type : removed) { 92 List <Reference <RakeProjectHelper>> projects = type2Projects.get(type); 93 if (projects != null) { 94 for (Reference <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 type) { 106 if (antBasedProjectTypesByType == null) { 107 antBasedProjectTypesByType = new HashMap <String ,RakeBasedProjectType>(); 108 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 dirF = FileUtil.toFile(dir); 122 if (dirF == null) { 123 return false; 124 } 125 File projectXmlF = new File (new File (dirF, "nbproject"), "project.xml"); return projectXmlF.isFile(); 129 } 130 131 public Project loadProject(FileObject projectDirectory, ProjectState state) throws IOException { 132 if (FileUtil.toFile(projectDirectory) == null) { 133 return null; 134 } 135 FileObject projectFile = projectDirectory.getFileObject(PROJECT_XML_PATH); 136 if (projectFile == null || !projectFile.isData() || projectFile.isVirtual()) { 138 return null; 139 } 140 File projectDiskFile = FileUtil.toFile(projectFile); 141 if (projectDiskFile == null) { 143 return null; 144 } 145 Document projectXml; 146 try { 147 projectXml = XMLUtil.parse(new InputSource (projectDiskFile.toURI().toString()), false, true, Util.defaultErrorHandler(), null); 148 } catch (SAXException e) { 149 IOException ioe = (IOException ) new IOException (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 projectEl = projectXml.getDocumentElement(); 156 if (!"project".equals(projectEl.getLocalName()) || !PROJECT_NS.equals(projectEl.getNamespaceURI())) { return null; 158 } 159 Element typeEl = Util.findElement(projectEl, "type", PROJECT_NS); if (typeEl == null) { 161 return null; 162 } 163 String 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 <RakeProjectHelper>(helper)); 174 helper2Project.put(helper, new WeakReference <Project>(project)); 175 List <Reference <RakeProjectHelper>> l = type2Projects.get(provider); 176 177 if (l == null) { 178 type2Projects.put(provider, l = new ArrayList <Reference <RakeProjectHelper>>()); 179 } 180 181 l.add(new WeakReference <RakeProjectHelper>(helper)); 182 183 return project; 184 } 185 186 public void saveProject(Project project) throws IOException , ClassCastException { 187 Reference <RakeProjectHelper> helperRef = project2Helper.get(project); 188 if (helperRef == null) { 189 throw new ClassCastException (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 202 public static Project getProjectFor(RakeProjectHelper helper) { 203 Reference <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 216 public static RakeProjectHelper getHelperFor(Project p) { 217 Reference <RakeProjectHelper> helperRef = project2Helper.get(p); 218 return helperRef != null ? helperRef.get() : null; 219 } 220 221 224 public interface RakeProjectHelperCallback { 225 RakeProjectHelper createHelper(FileObject dir, Document projectXml, ProjectState state, RakeBasedProjectType type); 226 void save(RakeProjectHelper helper) throws IOException ; 227 } 228 229 public static RakeProjectHelperCallback HELPER_CALLBACK; 230 static { 231 Class <?> c = RakeProjectHelper.class; 232 try { 233 Class.forName(c.getName(), true, c.getClassLoader()); 234 } catch (ClassNotFoundException e) { 235 assert false : e; 236 } 237 assert HELPER_CALLBACK != null; 238 } 239 240 } 241 | Popular Tags |