1 19 20 package org.netbeans.modules.j2ee.earproject; 21 22 import java.io.IOException ; 23 import java.net.URL ; 24 import java.util.ArrayList ; 25 import java.util.List ; 26 import javax.swing.JButton ; 27 import org.netbeans.api.project.libraries.LibraryManager; 28 import org.openide.filesystems.FileObject; 29 import org.openide.filesystems.FileUtil; 30 import org.w3c.dom.Comment ; 31 import org.w3c.dom.Document ; 32 import org.w3c.dom.Element ; 33 import org.w3c.dom.NamedNodeMap ; 34 import org.w3c.dom.Node ; 35 import org.w3c.dom.NodeList ; 36 import org.w3c.dom.Text ; 37 import org.openide.DialogDisplayer; 38 import org.openide.ErrorManager; 39 import org.openide.NotifyDescriptor; 40 import org.openide.util.NbBundle; 41 import org.openide.util.Mutex; 42 import org.netbeans.api.project.Project; 43 import org.netbeans.api.project.ProjectManager; 44 import org.netbeans.spi.project.AuxiliaryConfiguration; 45 import org.netbeans.spi.project.support.ant.AntProjectHelper; 46 import org.netbeans.spi.project.support.ant.EditableProperties; 47 import org.netbeans.spi.project.support.ant.GeneratedFilesHelper; 48 49 50 56 public class UpdateHelper { 57 58 private static final boolean TRANSPARENT_UPDATE = Boolean.getBoolean("webproject.transparentUpdate"); private static final String BUILD_NUMBER = System.getProperty("netbeans.buildnumber"); 61 private final Project project; 62 private final AntProjectHelper helper; 63 private final AuxiliaryConfiguration cfg; 64 private final GeneratedFilesHelper genFileHelper; 65 private final Notifier notifier; 66 private boolean alreadyAskedInWriteAccess; 67 private Boolean isCurrent; 68 private Element cachedElement; 69 private static final String TAG_FILE = "file"; private static final String TAG_LIBRARY = "library"; private static final String ATTR_FILES = "files"; private static final String ATTR_DIRS = "dirs"; 74 82 UpdateHelper (Project project, AntProjectHelper helper, AuxiliaryConfiguration cfg, GeneratedFilesHelper genFileHelper, Notifier notifier) { 83 if(!( project != null && helper != null && cfg != null && genFileHelper != null && notifier != null)) throw new IllegalArgumentException ("Constructor argument(s) is(are) null"); 84 this.project = project; 85 this.helper = helper; 86 this.cfg = cfg; 87 this.genFileHelper = genFileHelper; 88 this.notifier = notifier; 89 } 90 91 96 public EditableProperties getProperties (String path) { 97 return this.helper.getProperties(path); 99 } 100 101 109 public void putProperties (final String path, final EditableProperties props) { 110 ProjectManager.mutex().writeAccess( 111 new Runnable () { 112 public void run() { 113 if (isCurrent() || !AntProjectHelper.PROJECT_PROPERTIES_PATH.equals(path)) { helper.putProperties(path,props); 115 } 116 else if (canUpdate()) { 117 try { 118 saveUpdate (props); 119 helper.putProperties(path,props); 120 } catch (IOException ioe) { 121 ErrorManager.getDefault().notify (ioe); 122 } 123 } 124 } 125 }); 126 } 127 128 136 public Element getPrimaryConfigurationData (final boolean shared) { 137 return (Element ) ProjectManager.mutex().readAccess(new Mutex.Action (){ 138 public Object run() { 139 if (!shared || isCurrent()) { return helper.getPrimaryConfigurationData(shared); 141 } 142 else { 143 return getUpdatedSharedConfigurationData (); 144 } 145 } 146 }); 147 } 148 149 158 public void putPrimaryConfigurationData (final Element element, final boolean shared) { 159 ProjectManager.mutex().writeAccess(new Runnable () { 160 public void run () { 161 if (!shared || isCurrent()) { 162 helper.putPrimaryConfigurationData(element, shared); 163 } else if (canUpdate()) { 164 try { 165 saveUpdate (null); 166 helper.putPrimaryConfigurationData(element, shared); 167 } catch (IOException ioe) { 168 ErrorManager.getDefault().notify(ioe); 169 } 170 } 171 } 172 }); 173 } 174 175 180 public AntProjectHelper getAntProjectHelper () { 181 return this.helper; 182 } 183 184 189 public boolean requestSave () throws IOException { 190 if (isCurrent()) { 191 return true; 192 } 193 if (!canUpdate()) { 194 return false; 195 } 196 saveUpdate (null); 197 return true; 198 } 199 200 204 public synchronized boolean isCurrent () { 205 if (this.isCurrent == null) { 206 this.isCurrent = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-earproject/1",true) == null ? Boolean.TRUE : Boolean.FALSE; 208 } 209 return isCurrent.booleanValue(); 210 } 211 212 private boolean canUpdate () { 213 if (TRANSPARENT_UPDATE) { 214 return true; 215 } 216 if (alreadyAskedInWriteAccess) { 218 return false; 219 } 220 else { 221 boolean canUpdate = this.notifier.canUpdate(); 222 if (!canUpdate) { 223 alreadyAskedInWriteAccess = true; 224 ProjectManager.mutex().postReadRequest(new Runnable () { 225 public void run() { 226 alreadyAskedInWriteAccess = false; 227 } 228 }); 229 } 230 return canUpdate; 231 } 232 } 233 234 private void saveUpdate (EditableProperties props) throws IOException { 235 this.helper.putPrimaryConfigurationData(getUpdatedSharedConfigurationData(),true); 236 this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-earproject/1",true); ProjectManager.getDefault().saveProject (this.project); 238 synchronized(this) { 239 this.isCurrent = Boolean.TRUE; 240 } 241 } 242 243 private synchronized Element getUpdatedSharedConfigurationData() { 244 if (cachedElement == null) { 245 final String ns = EarProjectType.PROJECT_CONFIGURATION_NAMESPACE; Element oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-earproject/1" ,true); if(oldRoot != null) { 248 Document doc = oldRoot.getOwnerDocument(); 249 Element newRoot = doc.createElementNS(EarProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); copyDocument(doc, oldRoot, newRoot); 251 252 258 NodeList libList = newRoot.getElementsByTagNameNS(ns, TAG_LIBRARY); 259 for (int i = 0; i < libList.getLength(); i++) { 260 if (libList.item(i).getNodeType() == Node.ELEMENT_NODE) { 261 Element library = (Element ) libList.item(i); 262 Node webFile = library.getElementsByTagNameNS(ns, TAG_FILE).item(0); 263 String webFileText = findText(webFile); 265 webFileText = webFileText.substring(2, webFileText.length() - 1); 266 if (webFileText.startsWith("libs.")) { 267 String libName = webFileText.substring(5, webFileText.indexOf(".classpath")); @SuppressWarnings ("unchecked") 269 List <URL > roots = LibraryManager.getDefault().getLibrary(libName).getContent("classpath"); List <FileObject> files = new ArrayList <FileObject>(); 271 List <FileObject> dirs = new ArrayList <FileObject>(); 272 for (URL rootUrl : roots) { 273 FileObject root = org.openide.filesystems.URLMapper.findFileObject(rootUrl); 274 if ("jar".equals(rootUrl.getProtocol())) { root = FileUtil.getArchiveFile(root); 276 } 277 if (root != null) { 278 if (root.isData()) { 279 files.add(root); 280 } else { 281 dirs.add(root); 282 } 283 } 284 } 285 if (files.size() > 0) { 286 library.setAttribute(ATTR_FILES, "" + files.size()); 287 } 288 if (dirs.size() > 0) { 289 library.setAttribute(ATTR_DIRS, "" + dirs.size()); 290 } 291 } 292 } 293 } 294 cachedElement = newRoot; 295 } 296 } 297 return cachedElement; 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(EarProjectType.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,(Element )newNode); 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 337 public static Notifier createDefaultNotifier () { 338 return new Notifier() { 339 public boolean canUpdate() { 340 JButton updateOption = new JButton (NbBundle.getMessage(UpdateHelper.class, "CTL_UpdateOption")); 341 return DialogDisplayer.getDefault().notify( 342 new NotifyDescriptor (NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdate", BUILD_NUMBER), 343 NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdateTitle"), 344 NotifyDescriptor.DEFAULT_OPTION, 345 NotifyDescriptor.WARNING_MESSAGE, 346 new Object [] { 347 updateOption, 348 NotifyDescriptor.CANCEL_OPTION 349 }, 350 updateOption)) == updateOption; 351 } 352 }; 353 } 354 355 361 private static String findText(Node parent) { 362 NodeList l = parent.getChildNodes(); 363 for (int i = 0; i < l.getLength(); i++) { 364 if (l.item(i).getNodeType() == Node.TEXT_NODE) { 365 Text text = (Text )l.item(i); 366 return text.getNodeValue(); 367 } 368 } 369 return null; 370 } 371 372 376 public static interface Notifier { 377 381 public boolean canUpdate (); 382 } 383 384 private ProjectUpdateListener projectUpdateListener; 385 386 public void setProjectUpdateListener(ProjectUpdateListener l) { 387 this.projectUpdateListener = l; 388 } 389 390 392 public static interface ProjectUpdateListener { 393 public void projectUpdated(); 394 } 395 396 } 397 | Popular Tags |