KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > ruby > rubyproject > 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.ruby.rubyproject;
21
22 import java.io.IOException JavaDoc;
23 import javax.swing.JButton JavaDoc;
24 import org.netbeans.modules.ruby.rubyproject.ui.customizer.RubyProjectProperties;
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.modules.ruby.spi.project.support.rake.RakeProjectHelper;
41 import org.netbeans.modules.ruby.spi.project.support.rake.EditableProperties;
42 import org.netbeans.modules.ruby.spi.project.support.rake.GeneratedFilesHelper;
43
44
45 /**
46  * (I probably don't need this yet)
47  *
48  * Proxy for the RakeProjectHelper which defers the update of the project metadata
49  * to explicit user action. Currently it is hard coded for update from
50  * "http://www.netbeans.org/ns/j2se-project/1" to "http://www.netbeans.org/ns/j2se-project/2".
51  * In future it should define plugable SPI.
52  */

53 public class UpdateHelper {
54
55     private static final boolean TRANSPARENT_UPDATE = Boolean.getBoolean("j2seproject.transparentUpdate");
56     private static final String JavaDoc BUILD_NUMBER = System.getProperty("netbeans.buildnumber"); // NOI18N
57
private static final String JavaDoc MINIMUM_ANT_VERSION_ELEMENT = "minimum-ant-version";
58
59     private final Project project;
60     private final RakeProjectHelper 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     /**
69      * Creates new UpdateHelper
70      * @param project
71      * @param helper RakeProjectHelper
72      * @param cfg AuxiliaryConfiguration
73      * @param genFileHelper GeneratedFilesHelper
74      * @param notifier used to ask user about project update
75      */

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

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

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

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

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

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

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

207     public synchronized boolean isCurrent () {
208 // if (this.isCurrent == null) {
209
// if ((this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/1",true) != null) ||
210
// (this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/2",true) != null)) {
211
// this.isCurrent = Boolean.FALSE;
212
// } else {
213
// this.isCurrent = Boolean.TRUE;
214
// }
215
// }
216
// return isCurrent.booleanValue();
217
return true;
218     }
219
220     private boolean canUpdate () {
221         if (TRANSPARENT_UPDATE) {
222             return true;
223         }
224         //Ask just once under a single write access
225
if (alreadyAskedInWriteAccess) {
226             return false;
227         }
228         else {
229             boolean canUpdate = this.notifier.canUpdate();
230             if (!canUpdate) {
231                 alreadyAskedInWriteAccess = true;
232                 ProjectManager.mutex().postReadRequest(new Runnable JavaDoc() {
233                     public void run() {
234                         alreadyAskedInWriteAccess = false;
235                     }
236                 });
237             }
238             return canUpdate;
239         }
240     }
241
242     private void saveUpdate () throws IOException JavaDoc {
243         this.helper.putPrimaryConfigurationData(getUpdatedSharedConfigurationData(),true);
244 // this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/1",true); //NOI18N
245
// this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/2",true); //NOI18N
246
ProjectManager.getDefault().saveProject (this.project);
247         synchronized(this) {
248             this.isCurrent = Boolean.TRUE;
249         }
250     }
251
252     private synchronized Element JavaDoc getUpdatedSharedConfigurationData () {
253         if (cachedElement == null) {
254 // Element oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/1",true); //NOI18N
255
// if (oldRoot != null) {
256
// Document doc = oldRoot.getOwnerDocument();
257
// Element newRoot = doc.createElementNS (RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); //NOI18N
258
// copyDocument (doc, oldRoot, newRoot);
259
// Element sourceRoots = doc.createElementNS(RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE,"source-roots"); //NOI18N
260
// Element root = doc.createElementNS (RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE,"root"); //NOI18N
261
// root.setAttribute ("id","src.dir"); //NOI18N
262
// sourceRoots.appendChild(root);
263
// newRoot.appendChild (sourceRoots);
264
// Element testRoots = doc.createElementNS(RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE,"test-roots"); //NOI18N
265
// root = doc.createElementNS (RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE,"root"); //NOI18N
266
// root.setAttribute ("id","test.src.dir"); //NOI18N
267
// testRoots.appendChild (root);
268
// newRoot.appendChild (testRoots);
269
// cachedElement = updateMinAntVersion (newRoot, doc);
270
// } else {
271
// oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/j2se-project/2",true); //NOI18N
272
// if (oldRoot != null) {
273
// Document doc = oldRoot.getOwnerDocument();
274
// Element newRoot = doc.createElementNS (RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); //NOI18N
275
// copyDocument (doc, oldRoot, newRoot);
276
// cachedElement = updateMinAntVersion (newRoot, doc);
277
// }
278
// }
279
}
280         return cachedElement;
281     }
282     
283     private synchronized EditableProperties getUpdatedProjectProperties () {
284         EditableProperties cachedProperties = this.helper.getProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH);
285         return cachedProperties;
286     }
287
288     private static void copyDocument (Document JavaDoc doc, Element JavaDoc from, Element JavaDoc to) {
289         NodeList JavaDoc nl = from.getChildNodes();
290         int length = nl.getLength();
291         for (int i=0; i< length; i++) {
292             Node JavaDoc node = nl.item (i);
293             Node JavaDoc newNode = null;
294             switch (node.getNodeType()) {
295                 case Node.ELEMENT_NODE:
296                     Element JavaDoc oldElement = (Element JavaDoc) node;
297                     newNode = doc.createElementNS(RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE,oldElement.getTagName());
298                     NamedNodeMap JavaDoc m = oldElement.getAttributes();
299                     Element JavaDoc newElement = (Element JavaDoc) newNode;
300                     for (int index = 0; index < m.getLength(); index++) {
301                         Node JavaDoc attr = m.item(index);
302                           newElement.setAttribute(attr.getNodeName(), attr.getNodeValue());
303                     }
304                     copyDocument(doc,oldElement,newElement);
305                     break;
306                 case Node.TEXT_NODE:
307                     Text JavaDoc oldText = (Text JavaDoc) node;
308                     newNode = doc.createTextNode(oldText.getData());
309                     break;
310                 case Node.COMMENT_NODE:
311                     Comment JavaDoc oldComment = (Comment JavaDoc) node;
312                     newNode = doc.createComment(oldComment.getData());
313                     break;
314             }
315             if (newNode != null) {
316                 to.appendChild (newNode);
317             }
318         }
319     }
320     
321 // private static Element updateMinAntVersion (final Element root, final Document doc) {
322
// NodeList list = root.getElementsByTagNameNS (RubyProjectType.PROJECT_CONFIGURATION_NAMESPACE,MINIMUM_ANT_VERSION_ELEMENT);
323
// if (list.getLength() == 1) {
324
// Element me = (Element) list.item(0);
325
// list = me.getChildNodes();
326
// if (list.getLength() == 1) {
327
// me.replaceChild (doc.createTextNode(RubyProjectGenerator.MINIMUM_ANT_VERSION), list.item(0));
328
// return root;
329
// }
330
// }
331
// assert false : "Invalid project file"; //NOI18N
332
// return root;
333
// }
334
//
335
/**
336      * Creates an default Notifier. The default notifier displays a dialog warning user about project update.
337      * @return notifier
338      */

339     public static Notifier createDefaultNotifier () {
340         return new Notifier() {
341             public boolean canUpdate() {
342                 JButton JavaDoc updateOption = new JButton JavaDoc (NbBundle.getMessage(UpdateHelper.class, "CTL_UpdateOption"));
343                 updateOption.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(UpdateHelper.class, "AD_UpdateOption"));
344                 return DialogDisplayer.getDefault().notify(
345                     new NotifyDescriptor (NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdate", BUILD_NUMBER),
346                         NbBundle.getMessage(UpdateHelper.class,"TXT_ProjectUpdateTitle"),
347                         NotifyDescriptor.DEFAULT_OPTION,
348                         NotifyDescriptor.WARNING_MESSAGE,
349                         new Object JavaDoc[] {
350                             updateOption,
351                             NotifyDescriptor.CANCEL_OPTION
352                         },
353                         updateOption)) == updateOption;
354             }
355         };
356     }
357
358     /**
359      * Interface used by the UpdateHelper to ask user about
360      * the project update.
361      */

362     public static interface Notifier {
363         /**
364          * Asks user to update the project
365          * @return true if the project should be updated
366          */

367         public boolean canUpdate ();
368     }
369 }
370
Popular Tags