1 19 20 package org.netbeans.modules.java.j2seproject; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.beans.PropertyChangeSupport ; 25 import java.io.File ; 26 import java.net.MalformedURLException ; 27 import java.net.URL ; 28 import java.net.URI ; 29 import java.util.Arrays ; 30 import java.util.ArrayList ; 31 import java.util.Collections ; 32 import java.util.Iterator ; 33 import java.util.List ; 34 import java.util.Map ; 35 import java.util.HashMap ; 36 import java.text.MessageFormat ; 37 import org.openide.ErrorManager; 38 import org.openide.filesystems.FileObject; 39 import org.openide.filesystems.FileUtil; 40 import org.openide.util.WeakListeners; 41 import org.openide.util.Mutex; 42 import org.openide.util.NbBundle; 43 import org.w3c.dom.Element ; 44 import org.w3c.dom.NodeList ; 45 import org.w3c.dom.Document ; 46 import org.netbeans.spi.project.support.ant.AntProjectHelper; 47 import org.netbeans.spi.project.support.ant.AntProjectEvent; 48 import org.netbeans.spi.project.support.ant.AntProjectListener; 49 import org.netbeans.spi.project.support.ant.EditableProperties; 50 import org.netbeans.spi.project.support.ant.PropertyEvaluator; 51 import org.netbeans.spi.project.support.ant.ReferenceHelper; 52 import org.netbeans.api.project.ProjectManager; 53 import org.netbeans.api.java.project.JavaProjectConstants; 54 55 60 public final class SourceRoots { 61 62 public static final String PROP_ROOT_PROPERTIES = "rootProperties"; public static final String PROP_ROOTS = "roots"; 65 public static final String DEFAULT_SOURCE_LABEL = NbBundle.getMessage(SourceRoots.class, "NAME_src.dir"); 66 public static final String DEFAULT_TEST_LABEL = NbBundle.getMessage(SourceRoots.class, "NAME_test.src.dir"); 67 68 private final UpdateHelper helper; 69 private final PropertyEvaluator evaluator; 70 private final ReferenceHelper refHelper; 71 private final String elementName; 72 private final String newRootNameTemplate; 73 private List <String > sourceRootProperties; 74 private List <String > sourceRootNames; 75 private List <FileObject> sourceRoots; 76 private List <URL > sourceRootURLs; 77 private final PropertyChangeSupport support; 78 private final ProjectMetadataListener listener; 79 private final boolean isTest; 80 private final File projectDir; 81 82 89 SourceRoots (UpdateHelper helper, PropertyEvaluator evaluator, ReferenceHelper refHelper, String elementName, boolean isTest, String newRootNameTemplate) { 90 assert helper != null && evaluator != null && refHelper != null && elementName != null && newRootNameTemplate != null; 91 this.helper = helper; 92 this.evaluator = evaluator; 93 this.refHelper = refHelper; 94 this.elementName = elementName; 95 this.isTest = isTest; 96 this.newRootNameTemplate = newRootNameTemplate; 97 this.projectDir = FileUtil.toFile(this.helper.getAntProjectHelper().getProjectDirectory()); 98 this.support = new PropertyChangeSupport (this); 99 this.listener = new ProjectMetadataListener(); 100 this.evaluator.addPropertyChangeListener (WeakListeners.propertyChange(this.listener,this.evaluator)); 101 this.helper.getAntProjectHelper().addAntProjectListener ((AntProjectListener)WeakListeners.create(AntProjectListener.class, this.listener,this.helper)); 102 } 103 104 105 111 public String [] getRootNames () { 112 return ProjectManager.mutex().readAccess(new Mutex.Action<String []>() { 113 public String [] run() { 114 synchronized (SourceRoots.this) { 115 if (sourceRootNames == null) { 116 readProjectMetadata(); 117 } 118 } 119 return sourceRootNames.toArray (new String [sourceRootNames.size()]); 120 } 121 }); 122 } 123 124 128 public String [] getRootProperties () { 129 return ProjectManager.mutex().readAccess(new Mutex.Action<String []>() { 130 public String [] run() { 131 synchronized (SourceRoots.this) { 132 if (sourceRootProperties == null) { 133 readProjectMetadata(); 134 } 135 } 136 return sourceRootProperties.toArray (new String [sourceRootProperties.size()]); 137 } 138 }); 139 } 140 141 145 public FileObject[] getRoots () { 146 return ProjectManager.mutex().readAccess(new Mutex.Action<FileObject[]>() { 147 public FileObject[] run () { 148 synchronized (this) { 149 if (sourceRoots == null) { 151 String [] srcProps = getRootProperties(); 152 List <FileObject> result = new ArrayList <FileObject>(); 153 for (String p : srcProps) { 154 String prop = evaluator.getProperty(p); 155 if (prop != null) { 156 FileObject f = helper.getAntProjectHelper().resolveFileObject(prop); 157 if (f == null) { 158 continue; 159 } 160 if (FileUtil.isArchiveFile(f)) { 161 f = FileUtil.getArchiveRoot(f); 162 } 163 result.add(f); 164 } 165 } 166 sourceRoots = Collections.unmodifiableList(result); 167 } 168 } 169 return sourceRoots.toArray(new FileObject[sourceRoots.size()]); 170 } 171 }); 172 } 173 174 178 public URL [] getRootURLs() { 179 return ProjectManager.mutex().readAccess(new Mutex.Action<URL []>() { 180 public URL [] run () { 181 synchronized (this) { 182 if (sourceRootURLs == null) { 184 String [] srcProps = getRootProperties(); 185 List <URL > result = new ArrayList <URL >(); 186 for (int i = 0; i<srcProps.length; i++) { 187 String prop = evaluator.getProperty(srcProps[i]); 188 if (prop != null) { 189 File f = helper.getAntProjectHelper().resolveFile(prop); 190 try { 191 URL url = f.toURI().toURL(); 192 if (!f.exists()) { 193 url = new URL (url.toExternalForm() + "/"); } 195 assert url.toExternalForm().endsWith("/") : "#90639 violation for " + url + "; " + f + " exists? " + f.exists() + " dir? " + f.isDirectory() + " file? " + f.isFile(); 196 result.add(url); 197 } catch (MalformedURLException e) { 198 ErrorManager.getDefault().notify(e); 199 } 200 } 201 } 202 sourceRootURLs = Collections.unmodifiableList(result); 203 } 204 } 205 return sourceRootURLs.toArray(new URL [sourceRootURLs.size()]); 206 } 207 }); 208 } 209 210 214 public void addPropertyChangeListener (PropertyChangeListener listener) { 215 this.support.addPropertyChangeListener (listener); 216 } 217 218 222 public void removePropertyChangeListener (PropertyChangeListener listener) { 223 this.support.removePropertyChangeListener (listener); 224 } 225 226 227 232 public void putRoots (final URL [] roots, final String [] labels) { 233 ProjectManager.mutex().writeAccess( 234 new Mutex.Action<Void >() { 235 public Void run() { 236 String [] originalProps = getRootProperties(); 237 URL [] originalRoots = getRootURLs(); 238 Map <URL ,String > oldRoots2props = new HashMap <URL ,String >(); 239 for (int i=0; i<originalProps.length;i++) { 240 oldRoots2props.put (originalRoots[i],originalProps[i]); 241 } 242 Map <URL ,String > newRoots2lab = new HashMap <URL ,String >(); 243 for (int i=0; i<roots.length;i++) { 244 newRoots2lab.put (roots[i],labels[i]); 245 } 246 Element cfgEl = helper.getPrimaryConfigurationData(true); 247 NodeList nl = cfgEl.getElementsByTagNameNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE, elementName); 248 assert nl.getLength() == 1 : "Illegal project.xml"; Element ownerElement = (Element ) nl.item(0); 250 NodeList rootsNodes = ownerElement.getElementsByTagNameNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE, "root"); while (rootsNodes.getLength()>0) { 253 Element root = (Element ) rootsNodes.item(0); 254 ownerElement.removeChild(root); 255 } 256 List <URL > newRoots = Arrays.asList(roots); 258 Map <URL ,String > propsToRemove = new HashMap <URL ,String >(oldRoots2props); 259 propsToRemove.keySet().removeAll(newRoots); 260 EditableProperties props = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); 261 props.keySet().removeAll(propsToRemove.values()); 262 helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH,props); 263 Document doc = ownerElement.getOwnerDocument(); 265 oldRoots2props.keySet().retainAll(newRoots); 266 for (URL newRoot : newRoots) { 267 String rootName = oldRoots2props.get(newRoot); 268 if (rootName == null) { 269 props = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); 271 String [] names = newRoot.getPath().split("/"); rootName = MessageFormat.format(newRootNameTemplate, new Object [] {names[names.length - 1], ""}); int rootIndex = 1; 274 while (props.containsKey(rootName)) { 275 rootIndex++; 276 rootName = MessageFormat.format(newRootNameTemplate, new Object [] {names[names.length - 1], rootIndex}); 277 } 278 File f = FileUtil.normalizeFile(new File (URI.create(newRoot.toExternalForm()))); 279 File projDir = FileUtil.toFile(helper.getAntProjectHelper().getProjectDirectory()); 280 String path = f.getAbsolutePath(); 281 String prjPath = projDir.getAbsolutePath()+File.separatorChar; 282 if (path.startsWith(prjPath)) { 283 path = path.substring(prjPath.length()); 284 } 285 else { 286 path = refHelper.createForeignFileReference(f, JavaProjectConstants.SOURCES_TYPE_JAVA); 287 props = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); 288 } 289 props.put(rootName,path); 290 helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH,props); 291 } 292 Element newRootNode = doc.createElementNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE, "root"); newRootNode.setAttribute("id",rootName); String label = (String ) newRoots2lab.get (newRoot); 295 if (label != null && label.length()>0 && !label.equals (getRootDisplayName(null,rootName))) { newRootNode.setAttribute("name",label); } 298 ownerElement.appendChild (newRootNode); 299 } 300 helper.putPrimaryConfigurationData(cfgEl,true); 301 return null; 302 } 303 } 304 ); 305 } 306 307 313 public String getRootDisplayName (String rootName, String propName) { 314 if (rootName == null || rootName.length() ==0) { 315 if (isTest && "test.src.dir".equals(propName)) { rootName = DEFAULT_TEST_LABEL; 318 } 319 else if (!isTest && "src.dir".equals(propName)) { rootName = DEFAULT_SOURCE_LABEL; 321 } 322 else { 323 String propValue = evaluator.getProperty(propName); 326 File sourceRoot = propValue == null ? null : helper.getAntProjectHelper().resolveFile(propValue); 327 rootName = createInitialDisplayName(sourceRoot); 328 } 329 } 330 return rootName; 331 } 332 333 338 public String createInitialDisplayName (File sourceRoot) { 339 String rootName; 340 if (sourceRoot != null) { 341 String srPath = sourceRoot.getAbsolutePath(); 342 String pdPath = projectDir.getAbsolutePath() + File.separatorChar; 343 if (srPath.startsWith(pdPath)) { 344 rootName = srPath.substring(pdPath.length()); 345 } 346 else { 347 rootName = sourceRoot.getAbsolutePath(); 348 } 349 } 350 else { 351 rootName = isTest ? DEFAULT_TEST_LABEL : DEFAULT_SOURCE_LABEL; 352 } 353 return rootName; 354 } 355 356 361 public boolean isTest () { 362 return this.isTest; 363 } 364 365 private void resetCache (boolean isXMLChange, String propName) { 366 boolean fire = false; 367 synchronized (this) { 368 if (isXMLChange) { 370 this.sourceRootProperties = null; 371 this.sourceRootNames = null; 372 this.sourceRoots = null; 373 this.sourceRootURLs = null; 374 fire = true; 375 } else if (propName == null || (sourceRootProperties != null && sourceRootProperties.contains(propName))) { 376 this.sourceRoots = null; 377 this.sourceRootURLs = null; 378 fire = true; 379 } 380 } 381 if (fire) { 382 if (isXMLChange) { 383 this.support.firePropertyChange (PROP_ROOT_PROPERTIES,null,null); 384 } 385 this.support.firePropertyChange (PROP_ROOTS,null,null); 386 } 387 } 388 389 private void readProjectMetadata () { 390 Element cfgEl = helper.getPrimaryConfigurationData(true); 391 NodeList nl = cfgEl.getElementsByTagNameNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE, elementName); 392 assert nl.getLength() == 0 || nl.getLength() == 1 : "Illegal project.xml"; List <String > rootProps = new ArrayList <String >(); 394 List <String > rootNames = new ArrayList <String >(); 395 if (nl.getLength()==1) { 397 NodeList roots = ((Element )nl.item(0)).getElementsByTagNameNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE, "root"); for (int i=0; i<roots.getLength(); i++) { 399 Element root = (Element ) roots.item(i); 400 String value = root.getAttribute("id"); assert value.length() > 0 : "Illegal project.xml"; 402 rootProps.add(value); 403 value = root.getAttribute("name"); rootNames.add (value); 405 } 406 } 407 this.sourceRootProperties = Collections.unmodifiableList(rootProps); 408 this.sourceRootNames = Collections.unmodifiableList(rootNames); 409 } 410 411 private class ProjectMetadataListener implements PropertyChangeListener ,AntProjectListener { 412 413 public void propertyChange(PropertyChangeEvent evt) { 414 resetCache (false,evt.getPropertyName()); 415 } 416 417 public void configurationXmlChanged(AntProjectEvent ev) { 418 resetCache (true,null); 419 } 420 421 public void propertiesChanged(AntProjectEvent ev) { 422 } 424 } 425 426 } 427 | Popular Tags |