KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > j2ee > earproject > UpdateHelper


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.j2ee.earproject;
21
22 import java.io.IOException JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.List JavaDoc;
26 import javax.swing.JButton JavaDoc;
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 JavaDoc;
31 import org.w3c.dom.Document JavaDoc;
32 import org.w3c.dom.Element JavaDoc;
33 import org.w3c.dom.NamedNodeMap JavaDoc;
34 import org.w3c.dom.Node JavaDoc;
35 import org.w3c.dom.NodeList JavaDoc;
36 import org.w3c.dom.Text JavaDoc;
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 /**
51  * Proxy for the AntProjectHelper which defers the update of the project metadata
52  * to explicit user action. Currently it is hard coded for update from
53  * "http://www.netbeans.org/ns/web-project/1" to "http://www.netbeans.org/ns/web-project/2".
54  * In future it should define plugable SPI.
55  */

56 public class UpdateHelper {
57
58     private static final boolean TRANSPARENT_UPDATE = Boolean.getBoolean("webproject.transparentUpdate"); //NOI18N
59
private static final String JavaDoc BUILD_NUMBER = System.getProperty("netbeans.buildnumber"); // NOI18N
60

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 JavaDoc isCurrent;
68     private Element JavaDoc cachedElement;
69     private static final String JavaDoc TAG_FILE = "file"; //NOI18N
70
private static final String JavaDoc TAG_LIBRARY = "library"; //NOI18N
71
private static final String JavaDoc ATTR_FILES = "files"; //NOI18N
72
private static final String JavaDoc ATTR_DIRS = "dirs"; //NOI18N
73

74     /**
75      * Creates new UpdateHelper
76      * @param project
77      * @param helper AntProjectHelper
78      * @param cfg AuxiliaryConfiguration
79      * @param genFileHelper GeneratedFilesHelper
80      * @param notifier used to ask user about project update
81      */

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 JavaDoc("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     /**
92      * Returns the AntProjectHelper.getProperties(), {@link AntProjectHelper#getProperties(String)}
93      * @param path a relative URI in the project directory.
94      * @return a set of properties
95      */

96     public EditableProperties getProperties (String JavaDoc path) {
97         //Properties are the same in both webproject/1 and webproject/2
98
return this.helper.getProperties(path);
99     }
100
101     /**
102      * In the case that the project is of current version or the properties are not {@link AntProjectHelper#PROJECT_PROPERTIES_PATH}
103      * it calls AntProjectHelper.putProperties(), {@link AntProjectHelper#putProperties(String, EditableProperties)}
104      * otherwise it asks user to updata project. If the user agrees with the project update, it does the update and calls
105      * AntProjectHelper.putProperties().
106      * @param path a relative URI in the project directory.
107      * @param props a set of properties
108      */

109     public void putProperties (final String JavaDoc path, final EditableProperties props) {
110         ProjectManager.mutex().writeAccess(
111             new Runnable JavaDoc () {
112                 public void run() {
113                     if (isCurrent() || !AntProjectHelper.PROJECT_PROPERTIES_PATH.equals(path)) { //Only project props should cause update
114
helper.putProperties(path,props);
115                     }
116                     else if (canUpdate()) {
117                         try {
118                             saveUpdate (props);
119                             helper.putProperties(path,props);
120                         } catch (IOException JavaDoc ioe) {
121                             ErrorManager.getDefault().notify (ioe);
122                         }
123                     }
124                 }
125             });
126     }
127
128     /**
129      * In the case that the project is of current version or shared is false it delegates to
130      * AntProjectHelper.getPrimaryConfigurationData(), {@link AntProjectHelper#getPrimaryConfigurationData(boolean)}.
131      * Otherwise it creates an in memory update of shared configuration data and returns it.
132      * @param shared if true, refers to <code>project.xml</code>, else refers to
133      * <code>private.xml</code>
134      * @return the configuration data that is available
135      */

136     public Element JavaDoc getPrimaryConfigurationData (final boolean shared) {
137         return (Element JavaDoc) ProjectManager.mutex().readAccess(new Mutex.Action (){
138             public Object JavaDoc run() {
139                 if (!shared || isCurrent()) { //Only shared props should cause update
140
return helper.getPrimaryConfigurationData(shared);
141                 }
142                 else {
143                     return getUpdatedSharedConfigurationData ();
144                 }
145             }
146         });
147     }
148
149     /**
150      * In the case that the project is of current version or shared is false it calls AntProjectHelper.putPrimaryConfigurationData(),
151      * {@link AntProjectHelper#putPrimaryConfigurationData(Element, boolean)}.
152      * Otherwise it asks user to update the project. If the user agrees with the project update, it does the update and calls
153      * AntProjectHelper.PrimaryConfigurationData().
154      * @param element the configuration data
155      * @param shared if true, refers to <code>project.xml</code>, else refers to
156      * <code>private.xml</code>
157      */

158     public void putPrimaryConfigurationData (final Element JavaDoc element, final boolean shared) {
159         ProjectManager.mutex().writeAccess(new Runnable JavaDoc () {
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 JavaDoc ioe) {
168                         ErrorManager.getDefault().notify(ioe);
169                     }
170                 }
171             }
172         });
173     }
174
175     /**
176      * Returns an AntProjectHelper. The helper may not be used for accessing/storing project metadata.
177      * For project metadata manipulation the UpdateHelper must be used.
178      * @return AntProjectHelper
179      */

180     public AntProjectHelper getAntProjectHelper () {
181         return this.helper;
182     }
183
184     /**
185      * Request an saving of update. If the project is not of current version the user will be asked to update the project.
186      * If the user agrees with an update the project is updated.
187      * @return true if the metadata are of current version or updated
188      */

189     public boolean requestSave () throws IOException JavaDoc{
190         if (isCurrent()) {
191             return true;
192         }
193         if (!canUpdate()) {
194             return false;
195         }
196         saveUpdate (null);
197         return true;
198     }
199     
200     /**
201      * Returns true if the project is of current version.
202      * @return true if the project is of current version, otherwise false.
203      */

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 //NOI18N
207
? Boolean.TRUE : Boolean.FALSE;
208         }
209         return isCurrent.booleanValue();
210     }
211
212     private boolean canUpdate () {
213         if (TRANSPARENT_UPDATE) {
214             return true;
215         }
216         //Ask just once under a single write access
217
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 JavaDoc() {
225                     public void run() {
226                         alreadyAskedInWriteAccess = false;
227                     }
228                 });
229             }
230             return canUpdate;
231         }
232     }
233
234     private void saveUpdate (EditableProperties props) throws IOException JavaDoc {
235         this.helper.putPrimaryConfigurationData(getUpdatedSharedConfigurationData(),true);
236         this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-earproject/1",true); //NOI18N
237
ProjectManager.getDefault().saveProject (this.project);
238         synchronized(this) {
239             this.isCurrent = Boolean.TRUE;
240         }
241     }
242
243     private synchronized Element JavaDoc getUpdatedSharedConfigurationData() {
244         if (cachedElement == null) {
245             final String JavaDoc ns = EarProjectType.PROJECT_CONFIGURATION_NAMESPACE; //NOI18N
246
Element JavaDoc oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-earproject/1" ,true); //NOI18N
247
if(oldRoot != null) {
248                 Document JavaDoc doc = oldRoot.getOwnerDocument();
249                 Element JavaDoc newRoot = doc.createElementNS(EarProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); //NOI18N
250
copyDocument(doc, oldRoot, newRoot);
251                 
252                 //update <web-module-/additional/-libraries/> to <j2ee-module-/additional/-libraries/>
253
// NodeList contList = newRoot.getElementsByTagNameNS(ns, "web-module-libraries");
254
// contList.item(0).setNodeValue(ArchiveProjectProperties.TAG_WEB_MODULE_LIBRARIES);
255
// contList = newRoot.getElementsByTagNameNS(ns, "web-module-additional-libraries");
256
// contList.item(0).setNodeValue(ArchiveProjectProperties.TAG_WEB_MODULE__ADDITIONAL_LIBRARIES);
257

258                 NodeList JavaDoc 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 JavaDoc library = (Element JavaDoc) libList.item(i);
262                         Node JavaDoc webFile = library.getElementsByTagNameNS(ns, TAG_FILE).item(0);
263                         //remove ${ and } from the beginning and end
264
String JavaDoc webFileText = findText(webFile);
265                         webFileText = webFileText.substring(2, webFileText.length() - 1);
266                         if (webFileText.startsWith("libs.")) {
267                             String JavaDoc libName = webFileText.substring(5, webFileText.indexOf(".classpath")); //NOI18N
268
@SuppressWarnings JavaDoc("unchecked")
269                             List JavaDoc<URL JavaDoc> roots = LibraryManager.getDefault().getLibrary(libName).getContent("classpath"); //NOI18N
270
List JavaDoc<FileObject> files = new ArrayList JavaDoc<FileObject>();
271                             List JavaDoc<FileObject> dirs = new ArrayList JavaDoc<FileObject>();
272                             for (URL JavaDoc rootUrl : roots) {
273                                 FileObject root = org.openide.filesystems.URLMapper.findFileObject(rootUrl);
274                                 if ("jar".equals(rootUrl.getProtocol())) { //NOI18N
275
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 JavaDoc doc, Element JavaDoc from, Element JavaDoc to) {
301         NodeList JavaDoc nl = from.getChildNodes();
302         int length = nl.getLength();
303         for (int i=0; i< length; i++) {
304             Node JavaDoc node = nl.item (i);
305             Node JavaDoc newNode = null;
306             switch (node.getNodeType()) {
307                 case Node.ELEMENT_NODE:
308                     Element JavaDoc oldElement = (Element JavaDoc) node;
309                     newNode = doc.createElementNS(EarProjectType.PROJECT_CONFIGURATION_NAMESPACE,oldElement.getTagName());
310                     NamedNodeMap JavaDoc m = oldElement.getAttributes();
311                     Element JavaDoc newElement = (Element JavaDoc) newNode;
312                     for (int index = 0; index < m.getLength(); index++) {
313                         Node JavaDoc attr = m.item(index);
314                         newElement.setAttribute(attr.getNodeName(), attr.getNodeValue());
315                     }
316                     copyDocument(doc,oldElement,(Element JavaDoc)newNode);
317                     break;
318                 case Node.TEXT_NODE:
319                     Text JavaDoc oldText = (Text JavaDoc) node;
320                     newNode = doc.createTextNode(oldText.getData());
321                     break;
322                 case Node.COMMENT_NODE:
323                     Comment JavaDoc oldComment = (Comment JavaDoc) node;
324                     newNode = doc.createComment(oldComment.getData());
325                     break;
326             }
327             if (newNode != null) {
328                 to.appendChild (newNode);
329             }
330         }
331     }
332
333     /**
334      * Creates an default Notifier. The default notifier displays a dialog warning user about project update.
335      * @return notifier
336      */

337     public static Notifier createDefaultNotifier () {
338         return new Notifier() {
339             public boolean canUpdate() {
340                 JButton JavaDoc updateOption = new JButton JavaDoc (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 JavaDoc[] {
347                             updateOption,
348                             NotifyDescriptor.CANCEL_OPTION
349                         },
350                         updateOption)) == updateOption;
351             }
352         };
353     }
354
355     /**
356      * Extract nested text from a node.
357      * Currently does not handle coalescing text nodes, CDATA sections, etc.
358      * @param parent a parent node
359      * @return the nested text, or null if none was found
360      */

361     private static String JavaDoc findText(Node JavaDoc parent) {
362         NodeList JavaDoc l = parent.getChildNodes();
363         for (int i = 0; i < l.getLength(); i++) {
364             if (l.item(i).getNodeType() == Node.TEXT_NODE) {
365                 Text JavaDoc text = (Text JavaDoc)l.item(i);
366                 return text.getNodeValue();
367             }
368         }
369         return null;
370     }
371
372     /**
373      * Interface used by the UpdateHelper to ask user about
374      * the project update.
375      */

376     public static interface Notifier {
377         /**
378          * Asks user to update the project
379          * @return true if the project should be updated
380          */

381         public boolean canUpdate ();
382     }
383     
384     private ProjectUpdateListener projectUpdateListener;
385     
386     public void setProjectUpdateListener(ProjectUpdateListener l) {
387         this.projectUpdateListener = l;
388     }
389     
390     /** Used to notify someone that the project needs to be updated.
391      * A workaround for #54077 - Import 4.0 project - remove Servlet/JSP APIs */

392     public static interface ProjectUpdateListener {
393         public void projectUpdated();
394     }
395     
396 }
397
Popular Tags