KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > apisupport > project > ui > customizer > SuiteUtils


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.apisupport.project.ui.customizer;
21
22 import java.io.File JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Arrays JavaDoc;
26 import java.util.Collection JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Set JavaDoc;
31 import org.netbeans.api.project.Project;
32 import org.netbeans.api.project.ProjectManager;
33 import org.netbeans.api.project.ProjectUtils;
34 import org.netbeans.api.queries.CollocationQuery;
35 import org.netbeans.modules.apisupport.project.NbModuleProject;
36 import org.netbeans.modules.apisupport.project.NbModuleProjectGenerator;
37 import org.netbeans.modules.apisupport.project.spi.NbModuleProvider;
38 import org.netbeans.modules.apisupport.project.ProjectXMLManager;
39 import org.netbeans.modules.apisupport.project.SuiteProvider;
40 import org.netbeans.modules.apisupport.project.Util;
41 import org.netbeans.modules.apisupport.project.suite.SuiteProject;
42 import org.netbeans.spi.project.SubprojectProvider;
43 import org.netbeans.spi.project.support.ant.EditableProperties;
44 import org.netbeans.spi.project.support.ant.PropertyUtils;
45 import org.openide.ErrorManager;
46 import org.openide.filesystems.FileObject;
47 import org.openide.filesystems.FileSystem;
48 import org.openide.filesystems.FileUtil;
49 import org.openide.util.Mutex;
50 import org.openide.util.MutexException;
51 import org.openide.util.NbCollections;
52
53 /**
54  * Utility methods for miscellaneous suite module operations like moving its
55  * subModules between individual suites, removing subModules, adding and other
56  * handy methods.<br>
57  * Note that some of the methods may acquire {@link ProjectManager#mutex} read
58  * or write access. See javadoc to individual methods.
59  *
60  *
61  * @author Martin Krauskopf
62  */

63 public final class SuiteUtils {
64     
65     // XXX also match "${dir}/somedir/${anotherdir}"
66
private static final String JavaDoc ANT_PURE_PROPERTY_REFERENCE_REGEXP = "\\$\\{\\p{Graph}+\\}"; // NOI18N
67

68     private static final String JavaDoc PRIVATE_PLATFORM_PROPERTIES = "nbproject/private/platform-private.properties"; // NOI18N
69

70     static final String JavaDoc MODULES_PROPERTY = "modules"; // NOI18N
71

72     private final SuiteProperties suiteProps;
73     
74     private SuiteUtils(final SuiteProperties suiteProps) {
75         this.suiteProps = suiteProps;
76     }
77     
78     /**
79      * Gets suite components from the same suite which have set a given suite
80      * component as a dependency.
81      */

82     public static NbModuleProject[] getDependentModules(final NbModuleProject suiteComponent) throws IOException JavaDoc {
83         final String JavaDoc cnb = suiteComponent.getCodeNameBase();
84         try {
85             return ProjectManager.mutex().readAccess(new Mutex.ExceptionAction<NbModuleProject[]>(){
86                 public NbModuleProject[] run() throws Exception JavaDoc {
87                     Set JavaDoc<NbModuleProject> result = new HashSet JavaDoc<NbModuleProject>();
88                     SuiteProject suite = SuiteUtils.findSuite(suiteComponent);
89                     if (suite == null) { // #88303
90
Util.err.log(ErrorManager.WARNING,
91                                 "Cannot find suite for the given suitecomponent (" + suiteComponent + ')'); // NOI18N
92
} else {
93                         for (NbModuleProject p : SuiteUtils.getSubProjects(suite)) {
94                             for (ModuleDependency dep : new ProjectXMLManager(p).getDirectDependencies()) {
95                                 if (dep.getModuleEntry().getCodeNameBase().equals(cnb)) {
96                                     result.add(p);
97                                     break;
98                                 }
99                             }
100                         }
101                     }
102                     return result.toArray(new NbModuleProject[result.size()]);
103                 }
104             });
105         } catch (MutexException e) {
106             throw (IOException JavaDoc) e.getException();
107         }
108     }
109     
110     /**
111      * Reads needed information from the given {@link SuiteProperties} and
112      * appropriately replace its all modules with new ones.
113      * <p>Acquires write access.</p>
114      */

115     public static void replaceSubModules(final SuiteProperties suiteProps) throws IOException JavaDoc {
116         try {
117             ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Void JavaDoc>() {
118                 public Void JavaDoc run() throws Exception JavaDoc {
119                     SuiteUtils utils = new SuiteUtils(suiteProps);
120                     Set JavaDoc<NbModuleProject> currentModules = suiteProps.getSubModules();
121                     Set JavaDoc<NbModuleProject> origSubModules = suiteProps.getOrigSubModules();
122                     
123                     // remove removed modules
124
for (NbModuleProject origModule : origSubModules) {
125                         if (!currentModules.contains(origModule)) {
126                             Util.err.log("Removing module: " + origModule); // NOI18N
127
removeModule(origModule, suiteProps);
128                         }
129                     }
130                     
131                     // add new modules
132
for (NbModuleProject currentModule : currentModules) {
133                         if (SuiteUtils.contains(suiteProps.getProject(), currentModule)) {
134                             Util.err.log("Module \"" + currentModule + "\" or a module with the same CNB is already contained in the suite."); // NOI18N
135
continue;
136                         }
137                         utils.addModule(currentModule);
138                     }
139                     return null;
140                 }
141             });
142         } catch (MutexException e) {
143             throw (IOException JavaDoc) e.getException();
144         }
145     }
146     
147     /**
148      * Adds the given module to the given suite if it is not already contained
149      * there. If the module is already suite component of another suite it will
150      * be appropriatelly removed from it (i.e moved from module's current suite
151      * to the given suite).
152      * <p>Acquires write access.</p>
153      */

154     public static void addModule(final SuiteProject suite, final NbModuleProject project) throws IOException JavaDoc {
155         try {
156             ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Void JavaDoc>() {
157                 public Void JavaDoc run() throws Exception JavaDoc {
158                     final SuiteProperties suiteProps = new SuiteProperties(suite, suite.getHelper(),
159                             suite.getEvaluator(), getSubProjects(suite));
160                     if (!SuiteUtils.contains(suite, project)) {
161                         SuiteUtils utils = new SuiteUtils(suiteProps);
162                         utils.addModule(project);
163                         suiteProps.storeProperties();
164                     } else {
165                         Util.err.log("Module \"" + project + "\" or a module with the same CNB is already contained in the suite."); // NOI18N
166
}
167                     ProjectManager.getDefault().saveProject(suite);
168                     return null;
169                 }
170             });
171         } catch (MutexException e) {
172             throw (IOException JavaDoc) e.getException();
173         }
174     }
175     
176     /**
177      * Removes module from its current suite if the given module is a suite
178      * component and also remove all dependencies on this module from the suite
179      * components in the same suite.
180      * <p>Acquires write access.</p>
181      */

182     public static void removeModuleFromSuiteWithDependencies(final NbModuleProject suiteComponent) throws IOException JavaDoc {
183         try {
184             ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Void JavaDoc>() {
185                 public Void JavaDoc run() throws Exception JavaDoc {
186                     NbModuleProject[] modules = SuiteUtils.getDependentModules(suiteComponent);
187                     // remove all dependencies on the being removed suite component
188
String JavaDoc cnb = suiteComponent.getCodeNameBase();
189                     for (int j = 0; j < modules.length; j++) {
190                         ProjectXMLManager pxm = new ProjectXMLManager(modules[j]);
191                         pxm.removeDependency(cnb);
192                         ProjectManager.getDefault().saveProject(modules[j]);
193                     }
194                     // finally remove suite component itself
195
SuiteUtils.removeModuleFromSuite(suiteComponent);
196                     return null;
197                 }
198             });
199         } catch (MutexException e) {
200             throw (IOException JavaDoc) e.getException();
201         }
202     }
203     
204     /**
205      * Removes module from its current suite if the given module is a suite
206      * component. Does nothing otherwise.
207      * <p>Acquires write access.</p>
208      */

209     public static void removeModuleFromSuite(final NbModuleProject suiteComponent) throws IOException JavaDoc {
210         try {
211             ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Void JavaDoc>() {
212                 public Void JavaDoc run() throws Exception JavaDoc {
213                     SuiteProject suite = SuiteUtils.findSuite(suiteComponent);
214                     if (suite != null) {
215                         // detach module from its current suite
216
SuiteProperties suiteProps = new SuiteProperties(suite, suite.getHelper(),
217                                 suite.getEvaluator(), getSubProjects(suite));
218                         SuiteUtils utils = new SuiteUtils(suiteProps);
219                         removeModule(suiteComponent, suiteProps);
220                         suiteProps.storeProperties();
221                         ProjectManager.getDefault().saveProject(suite);
222                     } else if (Util.getModuleType(suiteComponent) == NbModuleProvider.SUITE_COMPONENT) {
223                         removeModule(suiteComponent, null);
224                     }
225                     return null;
226                 }
227             });
228         } catch (MutexException e) {
229             throw (IOException JavaDoc) e.getException();
230         }
231     }
232     
233     private void addModule(final NbModuleProject project) throws IOException JavaDoc, IllegalArgumentException JavaDoc {
234         SuiteUtils.removeModuleFromSuite(project);
235         // attach it to the new suite
236
attachSubModuleToSuite(project);
237     }
238     
239     /**
240      * Detach the given <code>subModule</code> from the suite. This actually
241      * means deleting its <em>nbproject/suite.properties</em> and eventually
242      * <em>nbproject/private/suite-private.properties</em> if it exists from
243      * <code>subModule</code>'s base directory. Also set the
244      * <code>subModule</code>'s type to standalone. Then it accordingly set the
245      * <code>suite</code>'s properties (see {@link #removeFromProperties})
246      * for details).
247      * <p>
248      * Also saves <code>subModule</code> using {@link ProjectManager#saveProject}.
249      * </p>
250      */

251     private static void removeModule(final NbModuleProject subModule, final SuiteProperties/*or null*/ suiteProps) {
252         NbModuleProvider.NbModuleType type = Util.getModuleType(subModule);
253         assert type == NbModuleProvider.SUITE_COMPONENT : "Not a suite component: " + subModule;
254         try {
255             subModule.getProjectDirectory().getFileSystem().runAtomicAction(new FileSystem.AtomicAction() {
256                 public void run() throws IOException JavaDoc {
257                     subModule.setRunInAtomicAction(true);
258                     try {
259                         // remove both suite properties files
260
FileObject subModuleDir = subModule.getProjectDirectory();
261                         FileObject fo = subModuleDir.getFileObject(
262                                 "nbproject/suite.properties"); // NOI18N
263
if (fo != null) {
264                             // XXX this is a bit dangerous. Surely would be better to delete just the relevant
265
// property from it, then delete it iff it is empty. (Would require that
266
// NbModuleProjectGenerator.createSuiteProperties accept an existing file.)
267
fo.delete();
268                         }
269                         fo = subModuleDir.getFileObject(
270                                 "nbproject/private/suite-private.properties"); // NOI18N
271
if (fo != null) {
272                             fo.delete();
273                         }
274                         
275                         if (suiteProps != null) {
276                             // copy suite's platform.properties to the module (needed by standalone module)
277
FileObject plafPropsFO = suiteProps.getProject().getProjectDirectory().
278                                     getFileObject("nbproject/platform.properties"); // NOI18N
279
FileObject subModuleNbProject = subModuleDir.getFileObject("nbproject"); // NOI18N
280
if (subModuleNbProject.getFileObject("platform.properties") == null) { // NOI18N
281
FileUtil.copyFile(plafPropsFO, subModuleNbProject, "platform"); // NOI18N
282
}
283                         }
284                         EditableProperties props = subModule.getHelper().getProperties(PRIVATE_PLATFORM_PROPERTIES);
285                         if (props.getProperty("user.properties.file") == null) { // NOI18N
286
String JavaDoc nbuser = System.getProperty("netbeans.user"); // NOI18N
287
if (nbuser != null) {
288                                 props.setProperty("user.properties.file", new File JavaDoc(nbuser, "build.properties").getAbsolutePath()); // NOI18N
289
subModule.getHelper().putProperties(PRIVATE_PLATFORM_PROPERTIES, props);
290                             } else {
291                                 Util.err.log("netbeans.user system property is not defined. Skipping " + PRIVATE_PLATFORM_PROPERTIES + " creation."); // NOI18N
292
}
293                         }
294                         
295                         SuiteUtils.setNbModuleType(subModule, NbModuleProvider.STANDALONE);
296                         // save subModule
297
ProjectManager.getDefault().saveProject(subModule);
298                     } finally {
299                         subModule.setRunInAtomicAction(false);
300                     }
301                 }
302             });
303             
304             // now clean up the suite
305
if (suiteProps != null) {
306                 removeFromProperties(subModule, suiteProps);
307             }
308         } catch (IOException JavaDoc ex) {
309             ErrorManager.getDefault().notify(ex);
310         }
311     }
312     
313     /**
314      * Adjust <em>modules</em> property together with removing appropriate
315      * other properties from <code>projectProps</code> and
316      * <code>privateProps</code>.
317      *
318      * @return wheter something has changed or not
319      */

320     private static boolean removeFromProperties(NbModuleProject moduleToRemove, SuiteProperties suiteProps) {
321         String JavaDoc modulesProp = suiteProps.getProperty(MODULES_PROPERTY);
322         boolean removed = false;
323         if (modulesProp != null) {
324             List JavaDoc<String JavaDoc> pieces = new ArrayList JavaDoc<String JavaDoc>(Arrays.asList(PropertyUtils.tokenizePath(modulesProp)));
325             for (Iterator JavaDoc<String JavaDoc> piecesIt = pieces.iterator(); piecesIt.hasNext(); ) {
326                 String JavaDoc unevaluated = piecesIt.next();
327                 String JavaDoc evaluated = suiteProps.getEvaluator().evaluate(unevaluated);
328                 if (evaluated == null) {
329                     Util.err.log("Cannot evaluate " + unevaluated + " property."); // NOI18N
330
continue;
331                 }
332                 if (moduleToRemove.getProjectDirectory() !=
333                         suiteProps.getHelper().resolveFileObject(evaluated)) {
334                     continue;
335                 }
336                 piecesIt.remove();
337                 String JavaDoc[] newModulesProp = getAntProperty(pieces);
338                 suiteProps.setProperty(MODULES_PROPERTY, newModulesProp);
339                 removed = true;
340                 // if the value is pure reference also tries to remove that
341
// reference which is nice to have. Otherwise just do nothing.
342
if (unevaluated.matches(ANT_PURE_PROPERTY_REFERENCE_REGEXP)) {
343                     String JavaDoc key = unevaluated.substring(2, unevaluated.length() - 1);
344                     suiteProps.removeProperty(key);
345                     suiteProps.removePrivateProperty(key);
346                 }
347                 break;
348             }
349         }
350         if (!removed) {
351             Util.err.log("Removing of " + moduleToRemove + " was unsuccessful."); // NOI18N
352
}
353         return removed;
354     }
355     
356     private void attachSubModuleToSuite(Project subModule) throws IOException JavaDoc {
357         // adjust suite project's properties
358
File JavaDoc projectDirF = FileUtil.toFile(subModule.getProjectDirectory());
359         File JavaDoc suiteDirF = suiteProps.getProjectDirectoryFile();
360         String JavaDoc projectPropKey = generatePropertyKey(subModule);
361         if (CollocationQuery.areCollocated(projectDirF, suiteDirF)) {
362             suiteProps.setProperty(projectPropKey,
363                     PropertyUtils.relativizeFile(suiteDirF, projectDirF));
364         } else {
365             suiteProps.setPrivateProperty(projectPropKey, projectDirF.getAbsolutePath());
366         }
367         String JavaDoc origModules = suiteProps.getProperty(MODULES_PROPERTY);
368         StringBuffer JavaDoc modules = new StringBuffer JavaDoc(origModules == null ? "" : origModules);
369         if (modules.length() > 0) {
370             modules.append(':');
371         }
372         modules.append("${").append(projectPropKey).append('}'); // NOI18N
373
suiteProps.setProperty(MODULES_PROPERTY, modules.toString().split("(?<=:)", -1)); // NOI18N
374

375         // adjust subModule's properties
376
NbModuleProjectGenerator.createSuiteProperties(subModule.getProjectDirectory(), suiteDirF);
377         setNbModuleType(subModule, NbModuleProvider.SUITE_COMPONENT);
378         ProjectManager.getDefault().saveProject(subModule);
379     }
380     
381     /** Generates unique property key suitable for a given modules. */
382     private String JavaDoc generatePropertyKey(final Project subModule) {
383         String JavaDoc key = "project." + ProjectUtils.getInformation(subModule).getName(); // NOI18N
384
String JavaDoc[] keys = suiteProps.getProperty(MODULES_PROPERTY).split("(?<=:)", -1); // NOI18N
385
int index = 0;
386         while (Arrays.binarySearch(keys, "${" + key + "}") >= 0) { // NOI18N
387
key += "_" + ++index; // NOI18N
388
}
389         return key;
390     }
391     
392     private static void setNbModuleType(Project module, NbModuleProvider.NbModuleType type) throws IOException JavaDoc {
393         ProjectXMLManager pxm = new ProjectXMLManager(((NbModuleProject) module));
394         pxm.setModuleType(type);
395     }
396     
397     private static String JavaDoc[] getAntProperty(final Collection JavaDoc<String JavaDoc> pieces) {
398         List JavaDoc<String JavaDoc> l = new ArrayList JavaDoc<String JavaDoc>();
399         for (Iterator JavaDoc<String JavaDoc> it = pieces.iterator(); it.hasNext();) {
400             String JavaDoc piece = it.next() + (it.hasNext() ? ":" : ""); // NOI18N
401
l.add(piece);
402         }
403         return l.toArray(new String JavaDoc[l.size()]);
404     }
405     
406     /**
407      * Returns whether a given directory contains regular <em>suite</em>. Note
408      * it returns <code>false</code> for suite components.
409      *
410      * @return <code>true</code> if a given directory contains regular
411      * <em>suite</em>; <code>false</code> otherwise.
412      */

413     public static boolean isSuite(final File JavaDoc maybeSuiteDir) {
414         boolean isSuite = false;
415         try {
416             FileObject dirFO = FileUtil.toFileObject(maybeSuiteDir);
417             if (dirFO != null) {
418                 Project maybeSuite = ProjectManager.getDefault().findProject(dirFO);
419                 if (maybeSuite != null) {
420                     isSuite = maybeSuiteDir.equals(getSuiteDirectory(maybeSuite));
421                 }
422             }
423         } catch (IOException JavaDoc e) {
424             // leave it false
425
}
426         return isSuite;
427     }
428     
429     /**
430      * Returns suite for the given suite component. May return
431      * <code>null</code>.
432      * <p>Acquires read access.</p>
433      */

434     public static SuiteProject findSuite(final Project suiteComponent) throws IOException JavaDoc {
435         try {
436             return ProjectManager.mutex().readAccess(new Mutex.ExceptionAction<SuiteProject>(){
437                 public SuiteProject run() throws Exception JavaDoc {
438                     Project suite = null;
439                     File JavaDoc suiteDir = SuiteUtils.getSuiteDirectory(suiteComponent);
440                     if (suiteDir != null) {
441                         FileObject fo = FileUtil.toFileObject(suiteDir);
442                         if (fo == null) {
443                             Util.err.log(ErrorManager.WARNING, "Module in the \"" + // NOI18N
444
FileUtil.toFile(suiteComponent.getProjectDirectory()).getAbsolutePath() +
445                                     "\" directory claims to be a subcomponent of a suite in the \"" + // NOI18N
446
suiteDir.getAbsolutePath() + "\" which does not exist however."); // NOI18N
447
} else {
448                             suite = ProjectManager.getDefault().findProject(fo);
449                         }
450                     }
451                     return suite instanceof SuiteProject ? (SuiteProject) suite : /* #80786 */null;
452                 }
453             });
454         } catch (MutexException e) {
455             throw (IOException JavaDoc) e.getException();
456         }
457     }
458     
459     /**
460      * Returns whether a given suite already contains a given project or a
461      * project with the same code name base.
462      */

463     public static boolean contains(final SuiteProject suite, final NbModuleProject project) {
464         Set JavaDoc<NbModuleProject> subModules = getSubProjects(suite);
465         if (subModules.contains(project)) {
466             return true;
467         }
468         for (Iterator JavaDoc it = subModules.iterator(); it.hasNext();) {
469             NbModuleProject p = (NbModuleProject) it.next();
470             if (p.getCodeNameBase().equals(project.getCodeNameBase())) {
471                 return true;
472             }
473         }
474         return false;
475     }
476     
477     /**
478      * Utility method to acquire modules contains within a given suite. Just
479      * delegates to {@link SubprojectProvider#getSubprojects()}.
480      */

481     public static Set JavaDoc<NbModuleProject> getSubProjects(final Project suite) {
482         assert suite != null;
483         SubprojectProvider spp = suite.getLookup().lookup(SubprojectProvider.class);
484         return NbCollections.checkedSetByFilter(spp.getSubprojects(), NbModuleProject.class, true);
485     }
486     
487     /**
488      * Convenient method for getting a suite directory from a given project
489      * which should contain an instance of {@link SuiteProvider} in its lookup.
490      * @return either suite directory or <code>null</code>
491      */

492     public static File JavaDoc getSuiteDirectory(final Project project) {
493         File JavaDoc suiteDir = null;
494         SuiteProvider sp = project.getLookup().lookup(SuiteProvider.class);
495         if (sp != null) {
496             suiteDir = sp.getSuiteDirectory();
497         }
498         return suiteDir;
499     }
500     
501     /**
502      * Returns {@link #getSuiteDirectory}'s absolute path.
503      * @return path or <code>null</code>
504      */

505     public static String JavaDoc getSuiteDirectoryPath(final Project project) {
506         File JavaDoc suiteDir = getSuiteDirectory(project);
507         return suiteDir != null ? suiteDir.getAbsolutePath() : null;
508     }
509     
510 }
511
Popular Tags