1 19 20 package org.netbeans.modules.j2ee.clientproject; 21 22 import java.io.IOException ; 23 import javax.swing.JButton ; 24 import org.netbeans.modules.j2ee.clientproject.api.AppClientProjectGenerator; 25 import org.netbeans.modules.j2ee.clientproject.ui.customizer.AppClientProjectProperties; 26 import org.w3c.dom.Comment ; 27 import org.w3c.dom.Document ; 28 import org.w3c.dom.Element ; 29 import org.w3c.dom.NamedNodeMap ; 30 import org.w3c.dom.Node ; 31 import org.w3c.dom.NodeList ; 32 import org.w3c.dom.Text ; 33 import org.openide.DialogDisplayer; 34 import org.openide.ErrorManager; 35 import org.openide.NotifyDescriptor; 36 import org.openide.util.NbBundle; 37 import org.openide.util.Mutex; 38 import org.netbeans.api.project.Project; 39 import org.netbeans.api.project.ProjectManager; 40 import org.netbeans.modules.websvc.api.jaxws.project.GeneratedFilesHelper; 41 import org.netbeans.spi.project.AuxiliaryConfiguration; 42 import org.netbeans.spi.project.support.ant.AntProjectHelper; 43 import org.netbeans.spi.project.support.ant.EditableProperties; 44 45 46 52 public class UpdateHelper { 53 54 private static final boolean TRANSPARENT_UPDATE = Boolean.getBoolean("carproject.transparentUpdate"); 55 private static final String BUILD_NUMBER = System.getProperty("netbeans.buildnumber"); private static final String MINIMUM_ANT_VERSION_ELEMENT = "minimum-ant-version"; 58 private final Project project; 59 private final AntProjectHelper helper; 60 private final AuxiliaryConfiguration cfg; 61 private final GeneratedFilesHelper genFileHelper; 62 private final Notifier notifier; 63 private boolean alreadyAskedInWriteAccess; 64 private Boolean isCurrent; 65 private Element cachedElement; 66 67 75 UpdateHelper (Project project, AntProjectHelper helper, AuxiliaryConfiguration cfg, GeneratedFilesHelper genFileHelper, Notifier notifier) { 76 assert project != null && helper != null && cfg != null && genFileHelper != null && notifier != null; 77 this.project = project; 78 this.helper = helper; 79 this.cfg = cfg; 80 this.genFileHelper = genFileHelper; 81 this.notifier = notifier; 82 } 83 84 89 public EditableProperties getProperties (final String path) { 90 return (EditableProperties) ProjectManager.mutex().readAccess(new Mutex.Action (){ 92 public Object run() { 93 if (!isCurrent() && AntProjectHelper.PROJECT_PROPERTIES_PATH.equals(path)) { return getUpdatedProjectProperties (); 95 } 96 else { 97 return helper.getProperties(path); 98 } 99 } 100 }); 101 } 102 103 111 public void putProperties (final String path, final EditableProperties props) { 112 ProjectManager.mutex().writeAccess( 113 new Runnable () { 114 public void run() { 115 if (isCurrent() || !AntProjectHelper.PROJECT_PROPERTIES_PATH.equals(path)) { helper.putProperties(path,props); 117 } 118 else if (canUpdate()) { 119 try { 120 saveUpdate (); 121 helper.putProperties(path,props); 122 } catch (IOException ioe) { 123 ErrorManager.getDefault().notify (ioe); 124 } 125 } 126 } 127 }); 128 } 129 130 138 public Element getPrimaryConfigurationData (final boolean shared) { 139 return (Element ) ProjectManager.mutex().readAccess(new Mutex.Action (){ 140 public Object run() { 141 if (!shared || isCurrent()) { return helper.getPrimaryConfigurationData(shared); 143 } 144 else { 145 return getUpdatedSharedConfigurationData (); 146 } 147 } 148 }); 149 } 150 151 160 public void putPrimaryConfigurationData (final Element element, final boolean shared) { 161 ProjectManager.mutex().writeAccess(new Runnable () { 162 public void run () { 163 if (!shared || isCurrent()) { 164 helper.putPrimaryConfigurationData(element, shared); 165 } else if (canUpdate()) { 166 try { 167 saveUpdate (); 168 helper.putPrimaryConfigurationData(element, shared); 169 } catch (IOException ioe) { 170 ErrorManager.getDefault().notify(ioe); 171 } 172 } 173 } 174 }); 175 } 176 177 182 public AntProjectHelper getAntProjectHelper () { 183 return this.helper; 184 } 185 186 191 public boolean requestSave () throws IOException { 192 if (isCurrent()) { 193 return true; 194 } 195 if (!canUpdate()) { 196 return false; 197 } 198 saveUpdate (); 199 return true; 200 } 201 202 206 public synchronized boolean isCurrent () { 207 218 return true; 220 } 221 222 private boolean canUpdate () { 223 if (TRANSPARENT_UPDATE) { 224 return true; 225 } 226 if (alreadyAskedInWriteAccess) { 228 return false; 229 } 230 else { 231 boolean canUpdate = this.notifier.canUpdate(); 232 if (!canUpdate) { 233 alreadyAskedInWriteAccess = true; 234 ProjectManager.mutex().postReadRequest(new Runnable () { 235 public void run() { 236 alreadyAskedInWriteAccess = false; 237 } 238 }); 239 } 240 return canUpdate; 241 } 242 } 243 244 private void saveUpdate () throws IOException { 245 this.helper.putPrimaryConfigurationData(getUpdatedSharedConfigurationData(),true); 246 this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/1",true); this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/2",true); ProjectManager.getDefault().saveProject (this.project); 249 synchronized(this) { 250 this.isCurrent = Boolean.TRUE; 251 } 252 } 253 254 private synchronized Element getUpdatedSharedConfigurationData () { 255 if (cachedElement == null) { 256 Element oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/1",true); if (oldRoot != null) { 258 Document doc = oldRoot.getOwnerDocument(); 259 Element newRoot = doc.createElementNS (AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); copyDocument (doc, oldRoot, newRoot); 261 Element sourceRoots = doc.createElementNS(AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE,"source-roots"); Element root = doc.createElementNS (AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE,"root"); root.setAttribute ("id","src.dir"); sourceRoots.appendChild(root); 265 newRoot.appendChild (sourceRoots); 266 Element testRoots = doc.createElementNS(AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE,"test-roots"); root = doc.createElementNS (AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE,"root"); root.setAttribute ("id","test.src.dir"); testRoots.appendChild (root); 270 newRoot.appendChild (testRoots); 271 cachedElement = updateMinAntVersion (newRoot, doc); 272 } else { 273 oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/2",true); if (oldRoot != null) { 275 Document doc = oldRoot.getOwnerDocument(); 276 Element newRoot = doc.createElementNS (AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); copyDocument (doc, oldRoot, newRoot); 278 cachedElement = updateMinAntVersion (newRoot, doc); 279 } 280 } 281 } 282 return cachedElement; 283 } 284 285 private synchronized EditableProperties getUpdatedProjectProperties () { 286 EditableProperties cachedProperties = this.helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); 287 if (cachedProperties.get (AppClientProjectProperties.JAVADOC_ADDITIONALPARAM)==null) { 289 cachedProperties.put (AppClientProjectProperties.JAVADOC_ADDITIONALPARAM,""); } 291 if (cachedProperties.get ("build.generated.dir")==null) { cachedProperties.put ("build.generated.dir","${build.dir}/generated"); } 294 if (cachedProperties.get (AppClientProjectProperties.META_INF)==null) { cachedProperties.put (AppClientProjectProperties.META_INF,"${src.dir}/conf"); } 297 return cachedProperties; 298 } 299 300 private static void copyDocument (Document doc, Element from, Element to) { 301 NodeList nl = from.getChildNodes(); 302 int length = nl.getLength(); 303 for (int i=0; i< length; i++) { 304 Node node = nl.item (i); 305 Node newNode = null; 306 switch (node.getNodeType()) { 307 case Node.ELEMENT_NODE: 308 Element oldElement = (Element ) node; 309 newNode = doc.createElementNS(AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE,oldElement.getTagName()); 310 NamedNodeMap m = oldElement.getAttributes(); 311 Element newElement = (Element ) newNode; 312 for (int index = 0; index < m.getLength(); index++) { 313 Node attr = m.item(index); 314 newElement.setAttribute(attr.getNodeName(), attr.getNodeValue()); 315 } 316 copyDocument(doc,oldElement,newElement); 317 break; 318 case Node.TEXT_NODE: 319 Text oldText = (Text ) node; 320 newNode = doc.createTextNode(oldText.getData()); 321 break; 322 case Node.COMMENT_NODE: 323 Comment oldComment = (Comment ) node; 324 newNode = doc.createComment(oldComment.getData()); 325 break; 326 } 327 if (newNode != null) { 328 to.appendChild (newNode); 329 } 330 } 331 } 332 333 private static Element updateMinAntVersion (final Element root, final Document doc) { 334 NodeList list = root.getElementsByTagNameNS (AppClientProjectType.PROJECT_CONFIGURATION_NAMESPACE,MINIMUM_ANT_VERSION_ELEMENT); 335 if (list.getLength() == 1) { 336 Element me = (Element ) list.item(0); 337 list = me.getChildNodes(); 338 if (list.getLength() == 1) { 339 me.replaceChild (doc.createTextNode(AppClientProjectGenerator.MINIMUM_ANT_VERSION), list.item(0)); 340 return root; 341 } 342 } 343 assert false : "Invalid project file"; return root; 345 } 346 347 351 public static Notifier createDefaultNotifier () { 352 return new Notifier() { 353 public boolean canUpdate() { 354 JButton updateOption = new JButton (NbBundle.getMessage(UpdateHelper.class, "CTL_UpdateOption")); 355 updateOption.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(UpdateHelper.class, "AD_UpdateOption")); 356 return DialogDisplayer.getDefault().notify( 357 new NotifyDescriptor (NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdate", BUILD_NUMBER), 358 NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdateTitle"), 359 NotifyDescriptor.DEFAULT_OPTION, 360 NotifyDescriptor.WARNING_MESSAGE, 361 new Object [] { 362 updateOption, 363 NotifyDescriptor.CANCEL_OPTION 364 }, 365 updateOption)) == updateOption; 366 } 367 }; 368 } 369 370 374 public static interface Notifier { 375 379 public boolean canUpdate (); 380 } 381 } 382 | Popular Tags |