KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > j2ee > ejbjarproject > 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.ejbjarproject;
21
22 import java.io.IOException JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import org.netbeans.modules.j2ee.ejbjarproject.api.EjbJarProjectGenerator;
28 import org.netbeans.modules.websvc.api.jaxws.project.GeneratedFilesHelper;
29 import org.w3c.dom.Comment JavaDoc;
30 import org.w3c.dom.Document JavaDoc;
31 import org.w3c.dom.Element JavaDoc;
32 import org.w3c.dom.NamedNodeMap JavaDoc;
33 import org.w3c.dom.Node JavaDoc;
34 import org.w3c.dom.NodeList JavaDoc;
35 import org.w3c.dom.Text JavaDoc;
36 import org.openide.DialogDisplayer;
37 import org.openide.ErrorManager;
38 import org.openide.NotifyDescriptor;
39 import org.openide.util.NbBundle;
40 import org.openide.util.Mutex;
41 import org.netbeans.api.project.Project;
42 import org.netbeans.api.project.ProjectManager;
43 import org.netbeans.api.project.libraries.LibraryManager;
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.openide.filesystems.FileObject;
48 import org.openide.filesystems.FileUtil;
49
50
51 /**
52  * Proxy for the AntProjectHelper which defers the update of the project metadata
53  * to explicit user action. Currently it is hard coded for update from
54  * "http://www.netbeans.org/ns/j2se-project/1" to "http://www.netbeans.org/ns/j2se-project/2".
55  * In future it should define plugable SPI.
56  */

57 public class UpdateHelper {
58
59     private final Project project;
60     private final AntProjectHelper helper;
61     private final AuxiliaryConfiguration cfg;
62     private final GeneratedFilesHelper genFileHelper;
63     private final Notifier notifier;
64     private boolean alreadyAskedInWriteAccess;
65     private Boolean JavaDoc isCurrent;
66     private Element JavaDoc cachedElement;
67
68     private static final String JavaDoc BUILD_NUMBER = System.getProperty("netbeans.buildnumber"); // NOI18N
69
private static final String JavaDoc INCLUDED_LIBRARY_ELEMENT = "included-library"; //NOI18N
70
private static final String JavaDoc MINIMUM_ANT_VERSION_ELEMENT = "minimum-ant-version"; // 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         assert project != null && helper != null && cfg != null && genFileHelper != null && notifier != 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 j2seproject/1 and j2seproject/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      */

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

203     public synchronized boolean isCurrent () {
204         if (this.isCurrent == null) {
205             this.isCurrent = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-ejbjarproject/1",true) == null
206                     && this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-ejbjarproject/2",true) == null? //NOI18N
207
Boolean.TRUE : Boolean.FALSE;
208         }
209         return isCurrent.booleanValue();
210     }
211
212     private boolean canUpdate () {
213         //Ask just once under a single write access
214
if (alreadyAskedInWriteAccess) {
215             return false;
216         }
217         else {
218             boolean canUpdate = this.notifier.canUpdate();
219             if (!canUpdate) {
220                 alreadyAskedInWriteAccess = true;
221                 ProjectManager.mutex().postReadRequest(new Runnable JavaDoc() {
222                     public void run() {
223                         alreadyAskedInWriteAccess = false;
224                     }
225                 });
226             }
227             return canUpdate;
228         }
229     }
230
231     private void saveUpdate (EditableProperties props) throws IOException JavaDoc {
232         this.helper.putPrimaryConfigurationData(getUpdatedSharedConfigurationData(),true);
233         if (this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-ejbjarproject/1",true) != null) { //NOI18N
234
//version 1
235
this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-ejbjarproject/1",true); //NOI18N
236
} else {
237             //version 2
238
this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-ejbjarproject/2",true); //NOI18N
239
}
240                 
241         boolean putProps = false;
242         
243         // AB: fix for #55597: should not update the project without adding the properties
244
// update is only done once, so if we don't add the properties now, we don't get another chance to do so
245
if (props == null) {
246             props = getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
247             putProps = true;
248         }
249
250         //add properties needed by 4.1 project
251
if(props != null) {
252             props.put("test.src.dir", "test"); //NOI18N
253
}
254
255         if (putProps) {
256             helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, props);
257         }
258         
259         ProjectManager.getDefault().saveProject (this.project);
260         this.genFileHelper.refreshBuildScript(GeneratedFilesHelper.BUILD_IMPL_XML_PATH, UpdateHelper.class.getResource("resources/build-impl.xsl"),
261             ((EjbJarProject)project).findJaxWsFileObject(),
262             true);
263         synchronized(this) {
264             this.isCurrent = Boolean.TRUE;
265         }
266     }
267
268     private synchronized Element JavaDoc getUpdatedSharedConfigurationData () {
269         if (cachedElement == null) {
270             Element JavaDoc oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-ejbjarproject/1",true); //NOI18N
271

272             int version = 1;
273             if (oldRoot == null) {
274                 version = 2;
275                 oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2ee-ejbjarproject/2",true); //NOI18N
276
}
277             final String JavaDoc ns = version == 1 ? "http://www.netbeans.org/ns/j2ee-ejbjarproject/1" : "http://www.netbeans.org/ns/j2ee-ejbjarproject/2"; //NOI18N
278

279             if (oldRoot != null) {
280                 Document JavaDoc doc = oldRoot.getOwnerDocument();
281                 Element JavaDoc newRoot = doc.createElementNS (EjbJarProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); //NOI18N
282
copyDocument (doc, oldRoot, newRoot);
283                 if(version == 1) {
284                     //1=>2 upgrade
285
Element JavaDoc sourceRoots = doc.createElementNS(EjbJarProjectType.PROJECT_CONFIGURATION_NAMESPACE,"source-roots"); //NOI18N
286
Element JavaDoc root = doc.createElementNS (EjbJarProjectType.PROJECT_CONFIGURATION_NAMESPACE,"root"); //NOI18N
287
root.setAttribute ("id","src.dir"); //NOI18N
288
sourceRoots.appendChild(root);
289                     newRoot.appendChild (sourceRoots);
290                     Element JavaDoc testRoots = doc.createElementNS(EjbJarProjectType.PROJECT_CONFIGURATION_NAMESPACE,"test-roots"); //NOI18N
291
root = doc.createElementNS (EjbJarProjectType.PROJECT_CONFIGURATION_NAMESPACE,"root"); //NOI18N
292
root.setAttribute ("id","test.src.dir"); //NOI18N
293
testRoots.appendChild (root);
294                     newRoot.appendChild (testRoots);
295                 }
296                 if(version == 1 || version == 2) {
297                     //2=>3 upgrade
298
NodeList JavaDoc libList = newRoot.getElementsByTagNameNS(ns, INCLUDED_LIBRARY_ELEMENT);
299                     for (int i = 0; i < libList.getLength(); i++) {
300                         if (libList.item(i).getNodeType() == Node.ELEMENT_NODE) {
301                             Element JavaDoc library = (Element JavaDoc) libList.item(i);
302                             String JavaDoc fileText = findText(library);
303                             if (fileText.startsWith ("libs.")) {
304                                 String JavaDoc libName = fileText.substring(6, fileText.indexOf(".classpath")); //NOI18N
305
List JavaDoc/*<URL>*/ roots = LibraryManager.getDefault().getLibrary(libName).getContent("classpath"); //NOI18N
306
ArrayList JavaDoc files = new ArrayList JavaDoc ();
307                                 ArrayList JavaDoc dirs = new ArrayList JavaDoc ();
308                                 for (Iterator JavaDoc it = roots.iterator(); it.hasNext();) {
309                                     URL JavaDoc rootUrl = (URL JavaDoc) it.next();
310                                     FileObject root = org.openide.filesystems.URLMapper.findFileObject (rootUrl);
311                                     if ("jar".equals(rootUrl.getProtocol())) { //NOI18N
312
root = FileUtil.getArchiveFile (root);
313                                     }
314                                     if (root != null) {
315                                         if (root.isData()) {
316                                             files.add(root);
317                                         } else {
318                                             dirs.add(root);
319                                         }
320                                     }
321                                 }
322                                 if (files.size() > 0) {
323                                     library.setAttribute(ATTR_FILES, "" + files.size());
324                                 }
325                                 if (dirs.size() > 0) {
326                                     library.setAttribute(ATTR_DIRS, "" + dirs.size());
327                                 }
328                             }
329                         }
330                     }
331                 }
332                 
333                 cachedElement = updateMinAntVersion(newRoot, doc);
334             }
335         }
336         return cachedElement;
337     }
338
339     private static void copyDocument (Document JavaDoc doc, Element JavaDoc from, Element JavaDoc to) {
340         NodeList JavaDoc nl = from.getChildNodes();
341         int length = nl.getLength();
342         for (int i=0; i< length; i++) {
343             Node JavaDoc node = nl.item (i);
344             Node JavaDoc newNode = null;
345             switch (node.getNodeType()) {
346                 case Node.ELEMENT_NODE:
347                     Element JavaDoc oldElement = (Element JavaDoc) node;
348                     newNode = doc.createElementNS(EjbJarProjectType.PROJECT_CONFIGURATION_NAMESPACE,oldElement.getTagName());
349                     //copy attributes
350
NamedNodeMap JavaDoc m = oldElement.getAttributes();
351                     Element JavaDoc newElement = (Element JavaDoc) newNode;
352                     for (int index = 0; index < m.getLength(); index++) {
353                         Node JavaDoc attr = m.item(index);
354                         newElement.setAttribute(attr.getNodeName(), attr.getNodeValue());
355                     }
356                     copyDocument(doc,oldElement,(Element JavaDoc)newNode);
357                     break;
358                 case Node.TEXT_NODE:
359                     Text JavaDoc oldText = (Text JavaDoc) node;
360                     newNode = doc.createTextNode(oldText.getData());
361                     break;
362                 case Node.COMMENT_NODE:
363                     Comment JavaDoc oldComment = (Comment JavaDoc) node;
364                     newNode = doc.createComment(oldComment.getData());
365                     break;
366             }
367             if (newNode != null) {
368                 to.appendChild (newNode);
369             }
370         }
371     }
372     
373     private static Element JavaDoc updateMinAntVersion (final Element JavaDoc root, final Document JavaDoc doc) {
374         NodeList JavaDoc list = root.getElementsByTagNameNS (EjbJarProjectType.PROJECT_CONFIGURATION_NAMESPACE,MINIMUM_ANT_VERSION_ELEMENT);
375         if (list.getLength() == 1) {
376             Element JavaDoc me = (Element JavaDoc) list.item(0);
377             list = me.getChildNodes();
378             if (list.getLength() == 1) {
379                 me.replaceChild (doc.createTextNode(EjbJarProjectGenerator.MINIMUM_ANT_VERSION), list.item(0));
380                 return root;
381             }
382         }
383         assert false : "Invalid project file"; //NOI18N
384
return root;
385     }
386
387     /**
388      * Creates an default Notifier. The default notifier displays a dialog warning user about project update.
389      * @return notifier
390      */

391     public static Notifier createDefaultNotifier () {
392         return new Notifier() {
393             public boolean canUpdate() {
394                 return DialogDisplayer.getDefault().notify(
395                     new NotifyDescriptor.Confirmation (NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdate",BUILD_NUMBER),
396                         NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdateTitle"),
397                         NotifyDescriptor.YES_NO_OPTION)) == NotifyDescriptor.YES_OPTION;
398             }
399         };
400     }
401
402     /**
403      * Extract nested text from a node.
404      * Currently does not handle coalescing text nodes, CDATA sections, etc.
405      * @param parent a parent node
406      * @return the nested text, or null if none was found
407      */

408     private static String JavaDoc findText(Node JavaDoc parent) {
409         NodeList JavaDoc l = parent.getChildNodes();
410         for (int i = 0; i < l.getLength(); i++) {
411             if (l.item(i).getNodeType() == Node.TEXT_NODE) {
412                 Text JavaDoc text = (Text JavaDoc)l.item(i);
413                 return text.getNodeValue();
414             }
415         }
416         return null;
417     }
418     
419     
420     /**
421      * Interface used by the UpdateHelper to ask user about
422      * the project update.
423      */

424     public static interface Notifier {
425         /**
426          * Asks user to update the project
427          * @return true if the project should be updated
428          */

429         public boolean canUpdate ();
430     }
431 }
432
Popular Tags