1 19 20 package org.netbeans.modules.java.j2seproject; 21 22 import java.io.IOException ; 23 import javax.swing.JButton ; 24 import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties; 25 import org.netbeans.modules.websvc.api.jaxws.project.GeneratedFilesHelper; 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.spi.project.AuxiliaryConfiguration; 41 import org.netbeans.spi.project.support.ant.AntProjectHelper; 42 import org.netbeans.spi.project.support.ant.EditableProperties; 43 44 45 51 public class UpdateHelper { 52 53 private static final boolean TRANSPARENT_UPDATE = Boolean.getBoolean("j2seproject.transparentUpdate"); 54 private static final String BUILD_NUMBER = System.getProperty("netbeans.buildnumber"); private static final String MINIMUM_ANT_VERSION_ELEMENT = "minimum-ant-version"; 56 57 private final Project project; 58 private final AntProjectHelper helper; 59 private final AuxiliaryConfiguration cfg; 60 private final GeneratedFilesHelper genFileHelper; 61 private final Notifier notifier; 62 private boolean alreadyAskedInWriteAccess; 63 private Boolean isCurrent; 64 private Element cachedElement; 65 66 74 UpdateHelper (Project project, AntProjectHelper helper, AuxiliaryConfiguration cfg, GeneratedFilesHelper genFileHelper, Notifier notifier) { 75 assert project != null && helper != null && cfg != null && genFileHelper != null && notifier != null; 76 this.project = project; 77 this.helper = helper; 78 this.cfg = cfg; 79 this.genFileHelper = genFileHelper; 80 this.notifier = notifier; 81 } 82 83 88 public EditableProperties getProperties (final String path) { 89 return ProjectManager.mutex().readAccess(new Mutex.Action<EditableProperties>(){ 91 public EditableProperties run() { 92 if (!isCurrent() && AntProjectHelper.PROJECT_PROPERTIES_PATH.equals(path)) { return getUpdatedProjectProperties (); 94 } 95 else { 96 return helper.getProperties(path); 97 } 98 } 99 }); 100 } 101 102 110 public void putProperties (final String path, final EditableProperties props) { 111 ProjectManager.mutex().writeAccess( 112 new Runnable () { 113 public void run() { 114 if (isCurrent() || !AntProjectHelper.PROJECT_PROPERTIES_PATH.equals(path)) { helper.putProperties(path,props); 116 } 117 else if (canUpdate()) { 118 try { 119 saveUpdate (); 120 helper.putProperties(path,props); 121 } catch (IOException ioe) { 122 ErrorManager.getDefault().notify (ioe); 123 } 124 } 125 } 126 }); 127 } 128 129 137 public Element getPrimaryConfigurationData (final boolean shared) { 138 return ProjectManager.mutex().readAccess(new Mutex.Action<Element >(){ 139 public Element run() { 140 if (!shared || isCurrent()) { return helper.getPrimaryConfigurationData(shared); 142 } 143 else { 144 return getUpdatedSharedConfigurationData (); 145 } 146 } 147 }); 148 } 149 150 159 public void putPrimaryConfigurationData (final Element element, final boolean shared) { 160 ProjectManager.mutex().writeAccess(new Runnable () { 161 public void run () { 162 if (!shared || isCurrent()) { 163 helper.putPrimaryConfigurationData(element, shared); 164 } else if (canUpdate()) { 165 try { 166 saveUpdate (); 167 helper.putPrimaryConfigurationData(element, shared); 168 } catch (IOException ioe) { 169 ErrorManager.getDefault().notify(ioe); 170 } 171 } 172 } 173 }); 174 } 175 176 181 public AntProjectHelper getAntProjectHelper () { 182 return this.helper; 183 } 184 185 190 public boolean requestSave () throws IOException { 191 if (isCurrent()) { 192 return true; 193 } 194 if (!canUpdate()) { 195 return false; 196 } 197 saveUpdate (); 198 return true; 199 } 200 201 205 public synchronized boolean isCurrent () { 206 if (this.isCurrent == null) { 207 if ((this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/1",true) != null) || 208 (this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/2",true) != null)) { 209 this.isCurrent = Boolean.FALSE; 210 } else { 211 this.isCurrent = Boolean.TRUE; 212 } 213 } 214 return isCurrent.booleanValue(); 215 } 216 217 private boolean canUpdate () { 218 if (TRANSPARENT_UPDATE) { 219 return true; 220 } 221 if (alreadyAskedInWriteAccess) { 223 return false; 224 } 225 else { 226 boolean canUpdate = this.notifier.canUpdate(); 227 if (!canUpdate) { 228 alreadyAskedInWriteAccess = true; 229 ProjectManager.mutex().postReadRequest(new Runnable () { 230 public void run() { 231 alreadyAskedInWriteAccess = false; 232 } 233 }); 234 } 235 return canUpdate; 236 } 237 } 238 239 private void saveUpdate () throws IOException { 240 this.helper.putPrimaryConfigurationData(getUpdatedSharedConfigurationData(),true); 241 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); 244 synchronized(this) { 245 this.isCurrent = Boolean.TRUE; 246 } 247 } 248 249 private synchronized Element getUpdatedSharedConfigurationData () { 250 if (cachedElement == null) { 251 Element oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/1",true); if (oldRoot != null) { 253 Document doc = oldRoot.getOwnerDocument(); 254 Element newRoot = doc.createElementNS (J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); copyDocument (doc, oldRoot, newRoot); 256 Element sourceRoots = doc.createElementNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"source-roots"); Element root = doc.createElementNS (J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"root"); root.setAttribute ("id","src.dir"); sourceRoots.appendChild(root); 260 newRoot.appendChild (sourceRoots); 261 Element testRoots = doc.createElementNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"test-roots"); root = doc.createElementNS (J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"root"); root.setAttribute ("id","test.src.dir"); testRoots.appendChild (root); 265 newRoot.appendChild (testRoots); 266 cachedElement = updateMinAntVersion (newRoot, doc); 267 } else { 268 oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/2",true); if (oldRoot != null) { 270 Document doc = oldRoot.getOwnerDocument(); 271 Element newRoot = doc.createElementNS (J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); copyDocument (doc, oldRoot, newRoot); 273 cachedElement = updateMinAntVersion (newRoot, doc); 274 } 275 } 276 } 277 return cachedElement; 278 } 279 280 private synchronized EditableProperties getUpdatedProjectProperties () { 281 EditableProperties cachedProperties = this.helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); 282 if (cachedProperties.get (J2SEProjectProperties.JAVADOC_ADDITIONALPARAM)==null) { 284 cachedProperties.put (J2SEProjectProperties.JAVADOC_ADDITIONALPARAM,""); } 286 if (cachedProperties.get ("build.generated.dir")==null) { cachedProperties.put ("build.generated.dir","${build.dir}/generated"); } 289 if (cachedProperties.get ("meta.inf.dir")==null) { cachedProperties.put ("meta.inf.dir","${src.dir}/META-INF"); } 292 return cachedProperties; 293 } 294 295 private static void copyDocument (Document doc, Element from, Element to) { 296 NodeList nl = from.getChildNodes(); 297 int length = nl.getLength(); 298 for (int i=0; i< length; i++) { 299 Node node = nl.item (i); 300 Node newNode = null; 301 switch (node.getNodeType()) { 302 case Node.ELEMENT_NODE: 303 Element oldElement = (Element ) node; 304 newNode = doc.createElementNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,oldElement.getTagName()); 305 NamedNodeMap m = oldElement.getAttributes(); 306 Element newElement = (Element ) newNode; 307 for (int index = 0; index < m.getLength(); index++) { 308 Node attr = m.item(index); 309 newElement.setAttribute(attr.getNodeName(), attr.getNodeValue()); 310 } 311 copyDocument(doc,oldElement,newElement); 312 break; 313 case Node.TEXT_NODE: 314 Text oldText = (Text ) node; 315 newNode = doc.createTextNode(oldText.getData()); 316 break; 317 case Node.COMMENT_NODE: 318 Comment oldComment = (Comment ) node; 319 newNode = doc.createComment(oldComment.getData()); 320 break; 321 } 322 if (newNode != null) { 323 to.appendChild (newNode); 324 } 325 } 326 } 327 328 private static Element updateMinAntVersion (final Element root, final Document doc) { 329 NodeList list = root.getElementsByTagNameNS (J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,MINIMUM_ANT_VERSION_ELEMENT); 330 if (list.getLength() == 1) { 331 Element me = (Element ) list.item(0); 332 list = me.getChildNodes(); 333 if (list.getLength() == 1) { 334 me.replaceChild (doc.createTextNode(J2SEProjectGenerator.MINIMUM_ANT_VERSION), list.item(0)); 335 return root; 336 } 337 } 338 assert false : "Invalid project file"; return root; 340 } 341 342 346 public static Notifier createDefaultNotifier () { 347 return new Notifier() { 348 public boolean canUpdate() { 349 JButton updateOption = new JButton (NbBundle.getMessage(UpdateHelper.class, "CTL_UpdateOption")); 350 updateOption.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(UpdateHelper.class, "AD_UpdateOption")); 351 return DialogDisplayer.getDefault().notify( 352 new NotifyDescriptor (NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdate", BUILD_NUMBER), 353 NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdateTitle"), 354 NotifyDescriptor.DEFAULT_OPTION, 355 NotifyDescriptor.WARNING_MESSAGE, 356 new Object [] { 357 updateOption, 358 NotifyDescriptor.CANCEL_OPTION 359 }, 360 updateOption)) == updateOption; 361 } 362 }; 363 } 364 365 369 public static interface Notifier { 370 374 public boolean canUpdate (); 375 } 376 } 377 | Popular Tags |