KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > j2ee > archive > project > 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.archive.project;
21
22 import java.io.IOException JavaDoc;
23 import javax.swing.JButton JavaDoc;
24 import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
25 import org.w3c.dom.Comment JavaDoc;
26 import org.w3c.dom.Document JavaDoc;
27 import org.w3c.dom.Element JavaDoc;
28 import org.w3c.dom.NamedNodeMap JavaDoc;
29 import org.w3c.dom.Node JavaDoc;
30 import org.w3c.dom.NodeList JavaDoc;
31 import org.w3c.dom.Text JavaDoc;
32 import org.openide.DialogDisplayer;
33 import org.openide.ErrorManager;
34 import org.openide.NotifyDescriptor;
35 import org.openide.util.NbBundle;
36 import org.openide.util.Mutex;
37 import org.netbeans.api.project.Project;
38 import org.netbeans.api.project.ProjectManager;
39 import org.netbeans.spi.project.AuxiliaryConfiguration;
40 import org.netbeans.spi.project.support.ant.AntProjectHelper;
41 import org.netbeans.spi.project.support.ant.EditableProperties;
42
43
44 /**
45  * Proxy for the AntProjectHelper which defers the update of the project metadata
46  * to explicit user action. Currently it is hard coded for update from
47  * "http://www.netbeans.org/ns/j2se-project/1" to "http://www.netbeans.org/ns/j2se-project/2".
48  * In future it should define plugable SPI.
49  */

50 public class UpdateHelper {
51
52     private static final boolean TRANSPARENT_UPDATE = Boolean.getBoolean("carproject.transparentUpdate");
53     private static final String JavaDoc BUILD_NUMBER = System.getProperty("netbeans.buildnumber"); // NOI18N
54
private static final String JavaDoc MINIMUM_ANT_VERSION_ELEMENT = "minimum-ant-version"; // NOI18N
55

56     private final Project project;
57     private final AntProjectHelper helper;
58     private final AuxiliaryConfiguration cfg;
59     private final Notifier notifier;
60     private boolean alreadyAskedInWriteAccess;
61 // private Boolean isCurrent;
62
private Element JavaDoc cachedElement;
63
64     /**
65      * Creates new UpdateHelper
66      * @param project
67      * @param helper AntProjectHelper
68      * @param cfg AuxiliaryConfiguration
69      * @param genFileHelper GeneratedFilesHelper
70      * @param notifier used to ask user about project update
71      */

72     UpdateHelper (Project project, AntProjectHelper helper, AuxiliaryConfiguration cfg, GeneratedFilesHelper genFileHelper, Notifier notifier) {
73         assert project != null && helper != null && cfg != null && genFileHelper != null && notifier != null;
74         this.project = project;
75         this.helper = helper;
76         this.cfg = cfg;
77         this.notifier = notifier;
78     }
79
80     /**
81      * Returns the AntProjectHelper.getProperties(), {@link AntProjectHelper#getProperties(String)}
82      * @param path a relative URI in the project directory.
83      * @return a set of properties
84      */

85     public EditableProperties getProperties (final String JavaDoc path) {
86         //Properties are the same in both j2seproject/1 and j2seproject/2
87
return (EditableProperties) ProjectManager.mutex().readAccess(new Mutex.Action (){
88             public Object JavaDoc run() {
89                 if (!isCurrent() && AntProjectHelper.PROJECT_PROPERTIES_PATH.equals(path)) { //Only project properties were changed
90
return getUpdatedProjectProperties ();
91                 }
92                 else {
93                     return helper.getProperties(path);
94                 }
95             }
96         });
97     }
98
99     /**
100      * In the case that the project is of current version or the properties are not {@link AntProjectHelper#PROJECT_PROPERTIES_PATH}
101      * it calls AntProjectHelper.putProperties(), {@link AntProjectHelper#putProperties(String, EditableProperties)}
102      * otherwise it asks user to updata project. If the user agrees with the project update, it does the update and calls
103      * AntProjectHelper.putProperties().
104      * @param path a relative URI in the project directory.
105      * @param props a set of properties
106      */

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

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

156     public void putPrimaryConfigurationData (final Element JavaDoc element, final boolean shared) {
157         ProjectManager.mutex().writeAccess(new Runnable JavaDoc () {
158             public void run () {
159                 if (!shared || isCurrent()) {
160                     helper.putPrimaryConfigurationData(element, shared);
161                 } else if (canUpdate()) {
162                     try {
163                         saveUpdate ();
164                         helper.putPrimaryConfigurationData(element, shared);
165                     } catch (IOException JavaDoc ioe) {
166                         ErrorManager.getDefault().notify(ioe);
167                     }
168                 }
169             }
170         });
171     }
172
173     /**
174      * Returns an AntProjectHelper. The helper may not be used for accessing/storing project metadata.
175      * For project metadata manipulation the UpdateHelper must be used.
176      * @return AntProjectHelper
177      */

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

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

202     public synchronized boolean isCurrent () {
203         /*
204         if (this.isCurrent == null) {
205             if ((this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/1",true) != null) ||
206                 (this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/2",true) != null)) {
207                 this.isCurrent = Boolean.FALSE;
208             } else {
209                 this.isCurrent = Boolean.TRUE;
210             }
211         }
212         return isCurrent.booleanValue();
213          */

214         //there are no other versions yet => we can always return true
215
return true;
216     }
217
218     private boolean canUpdate () {
219         if (TRANSPARENT_UPDATE) {
220             return true;
221         }
222         //Ask just once under a single write access
223
if (alreadyAskedInWriteAccess) {
224             return false;
225         }
226         else {
227             boolean canUpdate = this.notifier.canUpdate();
228             if (!canUpdate) {
229                 alreadyAskedInWriteAccess = true;
230                 ProjectManager.mutex().postReadRequest(new Runnable JavaDoc() {
231                     public void run() {
232                         alreadyAskedInWriteAccess = false;
233                     }
234                 });
235             }
236             return canUpdate;
237         }
238     }
239
240     private void saveUpdate () throws IOException JavaDoc {
241         this.helper.putPrimaryConfigurationData(getUpdatedSharedConfigurationData(),true);
242         this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/1",true); //NOI18N
243
this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/2",true); //NOI18N
244
ProjectManager.getDefault().saveProject (this.project);
245 // synchronized(this) {
246
// this.isCurrent = Boolean.TRUE;
247
// }
248
}
249
250     private synchronized Element JavaDoc getUpdatedSharedConfigurationData () {
251         if (cachedElement == null) {
252             Element JavaDoc oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/1",true); //NOI18N
253
if (oldRoot != null) {
254                 Document JavaDoc doc = oldRoot.getOwnerDocument();
255                 Element JavaDoc newRoot = doc.createElementNS (ArchiveProjectType.PROJECT_CONFIGURATION_NS,"data"); //NOI18N
256
copyDocument (doc, oldRoot, newRoot);
257                 Element JavaDoc sourceRoots = doc.createElementNS(ArchiveProjectType.PROJECT_CONFIGURATION_NS,"source-roots"); //NOI18N
258
Element JavaDoc root = doc.createElementNS (ArchiveProjectType.PROJECT_CONFIGURATION_NS,"root"); //NOI18N
259
root.setAttribute ("id","src.dir"); //NOI18N
260
sourceRoots.appendChild(root);
261                 newRoot.appendChild (sourceRoots);
262                 Element JavaDoc testRoots = doc.createElementNS(ArchiveProjectType.PROJECT_CONFIGURATION_NS,"test-roots"); //NOI18N
263
root = doc.createElementNS (ArchiveProjectType.PROJECT_CONFIGURATION_NS,"root"); //NOI18N
264
root.setAttribute ("id","test.src.dir"); //NOI18N
265
testRoots.appendChild (root);
266                 newRoot.appendChild (testRoots);
267                 cachedElement = updateMinAntVersion (newRoot, doc);
268             } else {
269                 oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/2",true); //NOI18N
270
if (oldRoot != null) {
271                     Document JavaDoc doc = oldRoot.getOwnerDocument();
272                     Element JavaDoc newRoot = doc.createElementNS (ArchiveProjectType.PROJECT_CONFIGURATION_NS,"data"); //NOI18N
273
copyDocument (doc, oldRoot, newRoot);
274                     cachedElement = updateMinAntVersion (newRoot, doc);
275                 }
276             }
277         }
278         return cachedElement;
279     }
280     
281     private synchronized EditableProperties getUpdatedProjectProperties () {
282         EditableProperties cachedProperties = this.helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
283         //The javadoc.additionalparam was not in NB 4.0
284
// if (cachedProperties.get (ArchiveProjectProperties.JAVADOC_ADDITIONALPARAM)==null) {
285
// cachedProperties.put (ArchiveProjectProperties.JAVADOC_ADDITIONALPARAM,""); //NOI18N
286
// }
287
// if (cachedProperties.get ("build.generated.dir")==null) { //NOI18N
288
// cachedProperties.put ("build.generated.dir","${build.dir}/generated"); //NOI18N
289
// }
290
// if (cachedProperties.get (ArchiveProjectProperties.META_INF)==null) { //NOI18N
291
// cachedProperties.put (ArchiveProjectProperties.META_INF,"${src.dir}/conf"); //NOI18N
292
// }
293
return cachedProperties;
294     }
295
296     private static void copyDocument (Document JavaDoc doc, Element JavaDoc from, Element JavaDoc to) {
297         NodeList JavaDoc nl = from.getChildNodes();
298         int length = nl.getLength();
299         for (int i=0; i< length; i++) {
300             Node JavaDoc node = nl.item (i);
301             Node JavaDoc newNode = null;
302             switch (node.getNodeType()) {
303                 case Node.ELEMENT_NODE:
304                     Element JavaDoc oldElement = (Element JavaDoc) node;
305                     newNode = doc.createElementNS(ArchiveProjectType.PROJECT_CONFIGURATION_NS,oldElement.getTagName());
306                     NamedNodeMap JavaDoc m = oldElement.getAttributes();
307                     Element JavaDoc newElement = (Element JavaDoc) newNode;
308                     for (int index = 0; index < m.getLength(); index++) {
309                         Node JavaDoc attr = m.item(index);
310                           newElement.setAttribute(attr.getNodeName(), attr.getNodeValue());
311                     }
312                     copyDocument(doc,oldElement,newElement);
313                     break;
314                 case Node.TEXT_NODE:
315                     Text JavaDoc oldText = (Text JavaDoc) node;
316                     newNode = doc.createTextNode(oldText.getData());
317                     break;
318                 case Node.COMMENT_NODE:
319                     Comment JavaDoc oldComment = (Comment JavaDoc) node;
320                     newNode = doc.createComment(oldComment.getData());
321                     break;
322             }
323             if (newNode != null) {
324                 to.appendChild (newNode);
325             }
326         }
327     }
328     public static final String JavaDoc MINIMUM_ANT_VERSION = "1.6.5"; // NOI18N
329

330     private static Element JavaDoc updateMinAntVersion (final Element JavaDoc root, final Document JavaDoc doc) {
331         NodeList JavaDoc list = root.getElementsByTagNameNS (ArchiveProjectType.PROJECT_CONFIGURATION_NS,MINIMUM_ANT_VERSION_ELEMENT);
332         if (list.getLength() == 1) {
333             Element JavaDoc me = (Element JavaDoc) list.item(0);
334             list = me.getChildNodes();
335             if (list.getLength() == 1) {
336                 me.replaceChild (doc.createTextNode(MINIMUM_ANT_VERSION), list.item(0));
337                 return root;
338             }
339         }
340         assert false : "Invalid project file"; //NOI18N
341
return root;
342     }
343
344     /**
345      * Creates an default Notifier. The default notifier displays a dialog warning user about project update.
346      * @return notifier
347      */

348     public static Notifier createDefaultNotifier () {
349         return new Notifier() {
350             public boolean canUpdate() {
351                 JButton JavaDoc updateOption = new JButton JavaDoc (NbBundle.getMessage(UpdateHelper.class, "CTL_UpdateOption"));
352                 updateOption.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(UpdateHelper.class, "AD_UpdateOption"));
353                 return DialogDisplayer.getDefault().notify(
354                     new NotifyDescriptor (NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdate", BUILD_NUMBER),
355                         NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdateTitle"),
356                         NotifyDescriptor.DEFAULT_OPTION,
357                         NotifyDescriptor.WARNING_MESSAGE,
358                         new Object JavaDoc[] {
359                             updateOption,
360                             NotifyDescriptor.CANCEL_OPTION
361                         },
362                         updateOption)) == updateOption;
363             }
364         };
365     }
366
367     /**
368      * Interface used by the UpdateHelper to ask user about
369      * the project update.
370      */

371     public static interface Notifier {
372         /**
373          * Asks user to update the project
374          * @return true if the project should be updated
375          */

376         public boolean canUpdate ();
377     }
378 }
379
Popular Tags