1 19 20 package org.netbeans.modules.j2ee.clientproject; 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 (String []) ProjectManager.mutex().readAccess(new Mutex.Action() { 113 public Object 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 (String []) ProjectManager.mutex().readAccess(new Mutex.Action() { 130 public Object 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 (FileObject[]) ProjectManager.mutex().readAccess(new Mutex.Action () { 147 public Object run () { 148 synchronized (this) { 149 if (sourceRoots == null) { 151 String [] srcProps = getRootProperties(); 152 List <FileObject> result = new ArrayList <FileObject>(); 153 for (int i = 0; i<srcProps.length; i++) { 154 String prop = evaluator.getProperty(srcProps[i]); 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 (URL []) ProjectManager.mutex().readAccess(new Mutex.Action () { 180 public Object 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 result.add(url); 196 } catch (MalformedURLException e) { 197 ErrorManager.getDefault().notify(e); 198 } 199 } 200 } 201 sourceRootURLs = Collections.unmodifiableList(result); 202 } 203 } 204 return sourceRootURLs.toArray(new URL [sourceRootURLs.size()]); 205 } 206 }); 207 } 208 209 213 public void addPropertyChangeListener (PropertyChangeListener listener) { 214 this.support.addPropertyChangeListener (listener); 215 } 216 217 221 public void removePropertyChangeListener (PropertyChangeListener listener) { 222 this.support.removePropertyChangeListener (listener); 223 } 224 225 226 231 public void putRoots (final URL [] roots, final String [] labels) { 232 ProjectManager.mutex().writeAccess( 233 new Mutex.Action () { 234 public Object run() { 235 String [] originalProps = getRootProperties(); 236 URL [] originalRoots = getRootURLs(); 237 Map <URL , String > oldRoots2props = new HashMap <URL , String >(); 238 for (int i=0; i<originalProps.length;i++) { 239 oldRoots2props.put (originalRoots[i],originalProps[i]); 240 } 241 Map <URL ,String > newRoots2lab = new HashMap <URL ,String >(); 242 for (int i=0; i<roots.length;i++) { 243 newRoots2lab.put (roots[i],labels[i]); 244 } 245 Element cfgEl = helper.getPrimaryConfigurationData(true); 246 NodeList nl = cfgEl.getElementsByTagNameNS(AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE, elementName); 247 assert nl.getLength() == 1 : "Illegal project.xml"; Element ownerElement = (Element ) nl.item(0); 249 NodeList rootsNodes = ownerElement.getElementsByTagNameNS(AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE, "root"); while (rootsNodes.getLength()>0) { 252 Element root = (Element ) rootsNodes.item(0); 253 ownerElement.removeChild(root); 254 } 255 List newRoots = Arrays.asList(roots); 257 Map <URL , String > propsToRemove = new HashMap <URL , String >(oldRoots2props); 258 propsToRemove.keySet().removeAll(newRoots); 259 EditableProperties props = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); 260 for (Iterator <String > it = propsToRemove.values().iterator(); it.hasNext();) { 261 String propName = it.next(); 262 props.remove(propName); 263 } 264 helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH,props); 265 Document doc = ownerElement.getOwnerDocument(); 267 oldRoots2props.keySet().retainAll(newRoots); 268 for (Iterator it = newRoots.iterator(); it.hasNext();) { 269 URL newRoot = (URL ) it.next (); 270 String rootName = oldRoots2props.get (newRoot); 271 if (rootName == null) { 272 props = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); 274 String [] names = newRoot.getPath().split("/"); rootName = MessageFormat.format(newRootNameTemplate,new Object []{names[names.length-1],""}); int rootIndex = 1; 277 while (props.containsKey(rootName)) { 278 rootIndex++; 279 rootName = MessageFormat.format(newRootNameTemplate,new Object []{names[names.length-1],new Integer (rootIndex)}); 280 } 281 File f = FileUtil.normalizeFile(new File (URI.create(newRoot.toExternalForm()))); 282 File projDir = FileUtil.toFile(helper.getAntProjectHelper().getProjectDirectory()); 283 String path = f.getAbsolutePath(); 284 String prjPath = projDir.getAbsolutePath()+File.separatorChar; 285 if (path.startsWith(prjPath)) { 286 path = path.substring(prjPath.length()); 287 } 288 else { 289 path = refHelper.createForeignFileReference(f, JavaProjectConstants.SOURCES_TYPE_JAVA); 290 props = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); 291 } 292 props.put(rootName,path); 293 helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH,props); 294 } 295 Element newRootNode = doc.createElementNS(AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE, "root"); newRootNode.setAttribute("id",rootName); String label = newRoots2lab.get (newRoot); 298 if (label != null && label.length()>0 && !label.equals (getRootDisplayName(null,rootName))) { newRootNode.setAttribute("name",label); } 301 ownerElement.appendChild (newRootNode); 302 } 303 helper.putPrimaryConfigurationData(cfgEl,true); 304 return null; 305 } 306 } 307 ); 308 } 309 310 316 public String getRootDisplayName (String rootName, String propName) { 317 if (rootName == null || rootName.length() ==0) { 318 if (isTest && "test.src.dir".equals(propName)) { rootName = DEFAULT_TEST_LABEL; 321 } 322 else if (!isTest && "src.dir".equals(propName)) { rootName = DEFAULT_SOURCE_LABEL; 324 } 325 else { 326 String propValue = evaluator.getProperty(propName); 329 File sourceRoot = propValue == null ? null : helper.getAntProjectHelper().resolveFile(propValue); 330 rootName = createInitialDisplayName(sourceRoot); 331 } 332 } 333 return rootName; 334 } 335 336 341 public String createInitialDisplayName (File sourceRoot) { 342 String rootName; 343 if (sourceRoot != null) { 344 String srPath = sourceRoot.getAbsolutePath(); 345 String pdPath = projectDir.getAbsolutePath() + File.separatorChar; 346 if (srPath.startsWith(pdPath)) { 347 rootName = srPath.substring(pdPath.length()); 348 } 349 else { 350 rootName = sourceRoot.getAbsolutePath(); 351 } 352 } 353 else { 354 rootName = isTest ? DEFAULT_TEST_LABEL : DEFAULT_SOURCE_LABEL; 355 } 356 return rootName; 357 } 358 359 364 public boolean isTest () { 365 return this.isTest; 366 } 367 368 private void resetCache (boolean isXMLChange, String propName) { 369 boolean fire = false; 370 synchronized (this) { 371 if (isXMLChange) { 373 this.sourceRootProperties = null; 374 this.sourceRootNames = null; 375 this.sourceRoots = null; 376 this.sourceRootURLs = null; 377 fire = true; 378 } else if (propName == null || (sourceRootProperties != null && sourceRootProperties.contains(propName))) { 379 this.sourceRoots = null; 380 this.sourceRootURLs = null; 381 fire = true; 382 } 383 } 384 if (fire) { 385 if (isXMLChange) { 386 this.support.firePropertyChange (PROP_ROOT_PROPERTIES,null,null); 387 } 388 this.support.firePropertyChange (PROP_ROOTS,null,null); 389 } 390 } 391 392 private void readProjectMetadata () { 393 Element cfgEl = helper.getPrimaryConfigurationData(true); 394 NodeList nl = cfgEl.getElementsByTagNameNS(AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE, elementName); 395 assert nl.getLength() == 0 || nl.getLength() == 1 : "Illegal project.xml"; List <String > rootProps = new ArrayList <String >(); 397 List <String > rootNames = new ArrayList <String >(); 398 if (nl.getLength()==1) { 400 NodeList roots = ((Element )nl.item(0)).getElementsByTagNameNS(AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE, "root"); for (int i=0; i<roots.getLength(); i++) { 402 Element root = (Element ) roots.item(i); 403 String value = root.getAttribute("id"); assert value.length() > 0 : "Illegal project.xml"; 405 rootProps.add(value); 406 value = root.getAttribute("name"); rootNames.add (value); 408 } 409 } 410 this.sourceRootProperties = Collections.unmodifiableList(rootProps); 411 this.sourceRootNames = Collections.unmodifiableList(rootNames); 412 } 413 414 private class ProjectMetadataListener implements PropertyChangeListener ,AntProjectListener { 415 416 public void propertyChange(PropertyChangeEvent evt) { 417 resetCache (false,evt.getPropertyName()); 418 } 419 420 public void configurationXmlChanged(AntProjectEvent ev) { 421 resetCache (true,null); 422 } 423 424 public void propertiesChanged(AntProjectEvent ev) { 425 } 427 } 428 429 } 430 | Popular Tags |