KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > form > palette > BeanInstaller


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.form.palette;
21
22 import com.sun.source.tree.ClassTree;
23 import com.sun.source.tree.Tree;
24 import com.sun.source.util.TreePath;
25 import java.lang.ref.WeakReference JavaDoc;
26 import java.util.jar.*;
27 import java.util.*;
28 import java.io.*;
29 import java.lang.reflect.Modifier JavaDoc;
30 import java.text.MessageFormat JavaDoc;
31 import java.util.logging.Level JavaDoc;
32 import java.util.logging.Logger JavaDoc;
33 import javax.lang.model.element.Element;
34 import javax.lang.model.element.ElementKind;
35 import javax.lang.model.element.ExecutableElement;
36 import javax.lang.model.element.TypeElement;
37 import org.netbeans.api.java.source.CancellableTask;
38 import org.netbeans.api.java.source.CompilationController;
39 import org.netbeans.api.java.source.JavaSource;
40 import org.netbeans.api.java.source.JavaSource.Phase;
41 import org.netbeans.modules.classfile.ClassFile;
42 import org.netbeans.modules.classfile.Method;
43
44 import org.openide.*;
45 import org.openide.nodes.Node;
46 import org.openide.filesystems.*;
47 import org.openide.loaders.DataObject;
48
49 import org.netbeans.modules.form.project.*;
50
51 /**
52  * This class provides methods for installing new items to Palete.
53  *
54  * @author Tomas Pavek
55  */

56
57 public final class BeanInstaller {
58
59     private static WeakReference JavaDoc wizardRef;
60
61     private BeanInstaller() {
62     }
63
64     // --------
65

66     /** Installs beans from given source type. Lets the user choose the source,
67      * the beans, and the target category in a wizard. */

68     public static void installBeans(String JavaDoc sourceType) {
69         AddToPaletteWizard wizard = getAddWizard();
70         if (wizard.show(sourceType))
71             createPaletteItems(sourceType,
72                                wizard.getSelectedBeans(),
73                                wizard.getSelectedCategory());
74     }
75
76     /** Installs beans represented by given nodes (selected by the user). Lets
77      * the user choose the palette category. */

78     public static void installBeans(Node[] nodes) {
79         final List<ClassSource> beans = new LinkedList<ClassSource>();
80         final List<String JavaDoc> unableToInstall = new LinkedList<String JavaDoc>();
81         for (int i=0; i < nodes.length; i++) {
82             DataObject dobj = (DataObject) nodes[i].getCookie(DataObject.class);
83             if (dobj == null)
84                 continue;
85
86             final FileObject fo = dobj.getPrimaryFile();
87             JavaClassHandler handler = new JavaClassHandler() {
88                 public void handle(String JavaDoc className) {
89                     ClassSource classSource =
90                             ClassPathUtils.getProjectClassSource(fo, className);
91                     if (classSource == null) {
92                         // Issue 47947
93
unableToInstall.add(className);
94                     } else {
95                         beans.add(classSource);
96                     }
97                 }
98             };
99             scanFileObject(fo.getParent(), fo, handler);
100         }
101         
102         if (unableToInstall.size() > 0) {
103             Iterator iter = unableToInstall.iterator();
104             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
105             while (iter.hasNext()) {
106                 sb.append(iter.next()+", "); // NOI18N
107
}
108             sb.delete(sb.length()-2, sb.length());
109             String JavaDoc messageFormat = PaletteUtils.getBundleString("MSG_cannotInstallBeans"); // NOI18N
110
String JavaDoc message = MessageFormat.format(messageFormat, new Object JavaDoc[] {sb.toString()});
111             NotifyDescriptor nd = new NotifyDescriptor.Message(message);
112             DialogDisplayer.getDefault().notify(nd);
113             if (beans.size() == 0) return;
114         }
115
116         if (beans.size() == 0) {
117             NotifyDescriptor nd = new NotifyDescriptor.Message(PaletteUtils.getBundleString("MSG_noBeansUnderNodes")); // NOI18N
118
DialogDisplayer.getDefault().notify(nd);
119             return;
120         }
121
122         String JavaDoc category = CategorySelector.selectCategory();
123         if (category == null)
124             return; // canceled by user
125

126         final FileObject categoryFolder = PaletteUtils.getPaletteFolder()
127                                                        .getFileObject(category);
128         try {
129             Repository.getDefault().getDefaultFileSystem().runAtomicAction(
130             new FileSystem.AtomicAction () {
131                 public void run() {
132                     Iterator it = beans.iterator();
133                     while (it.hasNext()) {
134                         ClassSource classSource = (ClassSource)it.next();
135                         try {
136                             PaletteItemDataObject.createFile(categoryFolder, classSource);
137                             // TODO check the class if it can be loaded?
138
}
139                         catch (java.io.IOException JavaDoc ex) {
140                             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
141                         }
142                     }
143                 }
144             });
145         }
146         catch (java.io.IOException JavaDoc ex) {} // should not happen
147
}
148
149     /** Finds available JavaBeans in given JAR files. Looks for beans
150      * specified in the JAR manifest only.
151      * @return list of ItemInfo */

152     static List findJavaBeansInJar(File[] jarFiles) {
153         Map beans = null;
154
155         for (int i=0; i < jarFiles.length; i++) {
156             Manifest manifest;
157             try {
158                 manifest = new JarFile(jarFiles[i]).getManifest();
159             }
160             catch (java.io.IOException JavaDoc ex) {
161                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
162                 continue;
163             }
164             if (manifest == null)
165                 continue;
166
167             String JavaDoc jarPath = jarFiles[i].getAbsolutePath();
168             Map entries = manifest.getEntries();
169             Iterator it = entries.entrySet().iterator();
170             while (it.hasNext()) {
171                 Map.Entry entry = (Map.Entry)it.next();
172                 String JavaDoc key = (String JavaDoc)entry.getKey();
173                 if (!key.endsWith(".class")) // NOI18N
174
continue;
175
176                 String JavaDoc value = ((Attributes)entry.getValue()).getValue("Java-Bean"); // NOI18N
177
if (!"True".equalsIgnoreCase(value)) // NOI18N
178
continue;
179
180                 String JavaDoc classname = key.substring(0, key.length()-6) // cut off ".class"
181
.replace('\\', '/').replace('/', '.');
182                 if (classname.startsWith(".")) // NOI18N
183
classname = classname.substring(1);
184
185                 ItemInfo ii = new ItemInfo();
186                 ii.classname = classname;
187                 ii.source = jarPath;
188
189                 if (beans == null)
190                     beans = new HashMap(100);
191                 beans.put(ii.classname, ii);
192             }
193         }
194
195         return beans != null ? new ArrayList(beans.values()) : null;
196     }
197
198     /** Collects all classes under given roots that could be used as JavaBeans.
199      * This method is supposed to search in JAR files or folders containing
200      * built classes.
201      * @return list of ItemInfo */

202     static List findJavaBeans(File[] roots) {
203         Map beans = new HashMap(100);
204
205         for (int i=0; i < roots.length; i++) {
206             FileObject foRoot = FileUtil.toFileObject(roots[i]);
207             if (foRoot != null) {
208                 if (FileUtil.isArchiveFile(foRoot))
209                     foRoot = FileUtil.getArchiveRoot(foRoot);
210                 if (foRoot != null && foRoot.isFolder()) {
211                     scanFolderForBeans(foRoot, beans, roots[i].getAbsolutePath());
212                 }
213             }
214         }
215
216         return new ArrayList(beans.values());
217     }
218
219     // --------
220
// private methods
221

222     /** Installs given beans (described by ItemInfo in array). */
223     private static void createPaletteItems(final String JavaDoc sourceType,
224                                            final ItemInfo[] beans,
225                                            String JavaDoc category)
226     {
227         if (beans.length == 0)
228             return;
229
230         final FileObject categoryFolder =
231             PaletteUtils.getPaletteFolder().getFileObject(category);
232         if (categoryFolder == null)
233             return;
234
235         try {
236             Repository.getDefault().getDefaultFileSystem().runAtomicAction(
237             new FileSystem.AtomicAction () {
238                 public void run() {
239                     String JavaDoc[] cpTypes = new String JavaDoc[] { sourceType };
240                     for (int i=0; i < beans.length; i++)
241                         try {
242                             PaletteItemDataObject.createFile(
243                                 categoryFolder,
244                                 new ClassSource(beans[i].classname,
245                                                 cpTypes,
246                                                 new String JavaDoc[] { beans[i].source} ));
247                             // TODO check the class if it can be loaded?
248
}
249                         catch (java.io.IOException JavaDoc ex) {
250                             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
251                         }
252                 }
253             });
254         }
255         catch (java.io.IOException JavaDoc ex) {} // should not happen
256
}
257
258     /** Recursive method scanning folders for classes (class files) that could
259      * be JavaBeans. */

260     private static void scanFolderForBeans(FileObject folder, final Map beans, final String JavaDoc root) {
261         JavaClassHandler handler = new JavaClassHandler() {
262             public void handle(String JavaDoc className) {
263                 ItemInfo ii = new ItemInfo();
264                 ii.classname = className;
265                 ii.source = root;
266                 beans.put(ii.classname, ii);
267             }
268         };
269                     
270         FileObject[] files = folder.getChildren();
271         for (int i=0; i < files.length; i++) {
272             FileObject fo = files[i];
273             if (fo.isFolder()) {
274                 scanFolderForBeans(fo, beans, root);
275             }
276             else try {
277                 if ("class".equals(fo.getExt()) // NOI18N
278
&& (DataObject.find(fo) != null))
279                 {
280                     scanFileObject(folder, fo, handler);
281                 }
282             }
283             catch (org.openide.loaders.DataObjectNotFoundException ex) {} // should not happen
284
}
285     }
286     
287     private static void scanFileObject(FileObject folder, final FileObject fileObject, final JavaClassHandler handler) {
288         if ("class".equals(fileObject.getExt())) { // NOI18N
289
processClassFile(fileObject, handler);
290         } else if ("java".equals(fileObject.getExt())) { // NOI18N
291
processJavaFile(fileObject, handler);
292         }
293     }
294     
295     /**
296      * finds bean's FQN if there is any.
297      * @param file file to search a bean
298      * @return null or the fqn
299      */

300     public static String JavaDoc findJavaBeanName(FileObject file) {
301         final String JavaDoc[] fqn = new String JavaDoc[1];
302         scanFileObject(null, file, new JavaClassHandler() {
303             public void handle(String JavaDoc className) {
304                 fqn[0] = className;
305             }
306         });
307         return fqn[0];
308     }
309     
310     private static void processJavaFile(final FileObject javaFO, final JavaClassHandler handler) {
311         try {
312             JavaSource js = JavaSource.forFileObject(javaFO);
313             js.runUserActionTask(new CancellableTask<CompilationController>() {
314                 public void cancel() {
315                 }
316
317                 public void run(CompilationController ctrl) throws Exception JavaDoc {
318                     ctrl.toPhase(Phase.ELEMENTS_RESOLVED);
319                     TypeElement clazz = findClass(ctrl, javaFO.getName());
320                     if (clazz != null && isDeclaredAsJavaBean(clazz)) {
321                         handler.handle(clazz.getQualifiedName().toString());
322                     }
323                 }
324             }, true);
325         } catch (IOException ex) {
326             Logger.getLogger(BeanInstaller.class.getClass().getName()).
327                     log(Level.SEVERE, javaFO.toString(), ex);
328         }
329     }
330     
331     private static TypeElement findClass(CompilationController ctrl, String JavaDoc className) {
332         for (Tree decl : ctrl.getCompilationUnit().getTypeDecls()) {
333             if (className.equals(((ClassTree) decl).getSimpleName().toString())) {
334                 TreePath path = ctrl.getTrees().getPath(ctrl.getCompilationUnit(), decl);
335                 TypeElement clazz = (TypeElement) ctrl.getTrees().getElement(path);
336                 return clazz;
337             }
338         }
339         return null;
340     }
341     
342     private static void processClassFile(FileObject classFO, JavaClassHandler handler) {
343         try {
344             // XXX rewrite this to use javax.lang.model.element.* as soon as JavaSource introduce .class files support
345
InputStream is = null;
346             ClassFile clazz;
347             try {
348                 is = classFO.getInputStream();
349                 clazz = new ClassFile(is, false);
350             } finally {
351                 if (is != null) {
352                     is.close();
353                 }
354             }
355             if (clazz != null && isDeclaredAsJavaBean(clazz)) {
356                 handler.handle(clazz.getName().getExternalName());
357             }
358         } catch (IOException ex) {
359             Logger.getLogger(BeanInstaller.class.getClass().getName()).
360                     log(Level.SEVERE, classFO.toString(), ex);
361         }
362         
363     }
364         
365     public static boolean isDeclaredAsJavaBean(TypeElement clazz) {
366         Set<javax.lang.model.element.Modifier> mods = clazz.getModifiers();
367         if (ElementKind.CLASS != clazz.getKind() ||
368                 !mods.contains(javax.lang.model.element.Modifier.PUBLIC) ||
369                 mods.contains(javax.lang.model.element.Modifier.ABSTRACT)) {
370             return false;
371         }
372         
373         for (Element member : clazz.getEnclosedElements()) {
374             mods = member.getModifiers();
375             if (ElementKind.CONSTRUCTOR == member.getKind() &&
376                     mods.contains(javax.lang.model.element.Modifier.PUBLIC) &&
377                     ((ExecutableElement) member).getParameters().isEmpty()) {
378                 return true;
379             }
380         }
381         
382         return false;
383     }
384     
385     public static boolean isDeclaredAsJavaBean(ClassFile clazz) {
386         int access = clazz.getAccess();
387         
388         if (!Modifier.isPublic(access) || Modifier.isAbstract(access) ||
389                 Modifier.isInterface(access) || clazz.isAnnotation() ||
390                 clazz.isEnum() || clazz.isSynthetic() ) {
391             return false;
392         }
393         
394         for (Object JavaDoc omethod : clazz.getMethods()) {
395             Method method = (Method) omethod;
396             if (method.isPublic() && method.getParameters().isEmpty() &&
397                     "<init>".equals(method.getName())) { // NOI18N
398
return true;
399             }
400         }
401         return false;
402     }
403     
404     private static AddToPaletteWizard getAddWizard() {
405         AddToPaletteWizard wizard = null;
406         if (wizardRef != null)
407             wizard = (AddToPaletteWizard) wizardRef.get();
408         if (wizard == null) {
409             wizard = new AddToPaletteWizard();
410             wizardRef = new WeakReference JavaDoc(wizard);
411         }
412         return wizard;
413     }
414
415     // --------
416

417     static class ItemInfo implements Comparable JavaDoc {
418         String JavaDoc classname;
419         String JavaDoc source; // full file path or library name
420

421         public int compareTo(Object JavaDoc o) {
422             ItemInfo ii = (ItemInfo) o;
423             int i;
424             i = classname.lastIndexOf('.');
425             String JavaDoc name1 = i >= 0 ? classname.substring(i+1) : classname;
426             i = ii.classname.lastIndexOf('.');
427             String JavaDoc name2 = i >= 0 ? ii.classname.substring(i+1) : ii.classname;
428             return name1.compareTo(name2);
429         }
430     }
431     
432     private interface JavaClassHandler {
433         public void handle(String JavaDoc className);
434     }
435     
436 }
437
Popular Tags