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