KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > apisupport > beanbrowser > LookupNode


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.beanbrowser;
21
22 import java.awt.event.ActionEvent JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Arrays JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.Comparator JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Set JavaDoc;
32 import java.util.SortedSet JavaDoc;
33 import java.util.TreeSet JavaDoc;
34 import javax.swing.AbstractAction JavaDoc;
35 import javax.swing.Action JavaDoc;
36 import javax.swing.event.ChangeEvent JavaDoc;
37 import javax.swing.event.ChangeListener JavaDoc;
38 import org.openide.DialogDisplayer;
39 import org.openide.ErrorManager;
40 import org.openide.NotifyDescriptor;
41 import org.openide.nodes.AbstractNode;
42 import org.openide.nodes.Children;
43 import org.openide.nodes.Node;
44 import org.openide.util.HelpCtx;
45 import org.openide.util.Lookup;
46 import org.openide.util.Lookup.Item;
47 import org.openide.util.LookupEvent;
48 import org.openide.util.LookupListener;
49 import org.openide.util.RequestProcessor;
50 import org.openide.util.Utilities;
51 import org.openide.util.WeakListeners;
52 import org.openide.util.lookup.AbstractLookup;
53 import org.openide.util.lookup.InstanceContent;
54
55 public final class LookupNode extends AbstractNode {
56
57     private static Class JavaDoc[] GLOBAL_CLAZZES;
58     private static Class JavaDoc[] COOKIE_CLAZZES;
59     
60     // See #24609.
61
// This is just compiled from a list of META-INF/services/ dirs in sources.
62
// (for i in */{,*/,*/*/}src/META-INF/services/*; do if [ -f $i ]; then echo " "'"'"`basename $i`"'"'", // NOI18N"; fi; done) | sort | uniq
63
// trimmed to deprecated, private, or experimental interfaces.
64
// Plus some custom additions like ServiceType, SystemOption, HelpSet.
65
private static final String JavaDoc[] GLOBAL_SERVICE_NAMES = {
66         "java.awt.datatransfer.Clipboard", // NOI18N
67
"java.net.URLStreamHandlerFactory", // NOI18N
68
"javax.help.HelpSet", // NOI18N
69
"javax.jmi.xmi.XmiReader", // NOI18N
70
"javax.jmi.xmi.XmiWriter", // NOI18N
71
"javax.naming.spi.InitialContextFactoryBuilder", // NOI18N
72
"javax.swing.LookAndFeel", // NOI18N
73
"javax.swing.PopupFactory", // NOI18N
74
"javax.swing.text.Keymap", // NOI18N
75
"org.apache.tools.ant.module.spi.AntLogger", // NOI18N
76
"org.apache.tools.ant.module.spi.AutomaticExtraClasspathProvider", // NOI18N
77
"org.netbeans.CLIHandler", // NOI18N
78
"org.netbeans.ModuleFactory", // NOI18N
79
"org.netbeans.api.mdr.DTDProducer", // NOI18N
80
"org.netbeans.api.mdr.JMIMapper", // NOI18N
81
"org.netbeans.api.mdr.MDRManager", // NOI18N
82
"org.netbeans.api.xmi.XMIReaderFactory", // NOI18N
83
"org.netbeans.api.xmi.XMIWriterFactory", // NOI18N
84
"org.netbeans.api.xmi.sax.XMIConsumerFactory", // NOI18N
85
"org.netbeans.api.xmi.sax.XMIProducerFactory", // NOI18N
86
"org.netbeans.core.NbTopManager$WindowSystem", // NOI18N
87
"org.netbeans.core.modules.TestModuleDeployer", // NOI18N
88
"org.netbeans.core.startup.CoreBridge", // NOI18N
89
"org.netbeans.core.startup.RunLevel", // NOI18N
90
"org.netbeans.lib.editor.hyperlink.HyperlinkProviderManager", // NOI18N
91
"org.netbeans.modules.ant.freeform.spi.ProjectNature", // NOI18N
92
"org.netbeans.modules.db.spi.sql.editor.SQLEditorProvider", // NOI18N
93
"org.netbeans.modules.j2ee.spi.ejbjar.EarProvider", // NOI18N
94
"org.netbeans.modules.j2ee.spi.ejbjar.EjbJarProvider", // NOI18N
95
"org.netbeans.modules.j2ee.spi.ejbjar.EjbNodesFactory", // NOI18N
96
"org.netbeans.modules.masterfs.providers.AnnotationProvider", // NOI18N
97
"org.netbeans.modules.refactoring.spi.ReadOnlyFilesHandler", // NOI18N
98
"org.netbeans.modules.refactoring.spi.RefactoringPluginFactory", // NOI18N
99
"org.netbeans.modules.versioning.spi.VersioningSystem", // NOI18N
100
"org.netbeans.modules.web.spi.webmodule.RequestParametersProvider", // NOI18N
101
"org.netbeans.modules.web.spi.webmodule.WebModuleProvider", // NOI18N
102
"org.netbeans.modules.websvc.api.client.WsCompileClientEditorSupport", // NOI18N
103
"org.netbeans.modules.websvc.api.registry.WebServicesRegistryView", // NOI18N
104
"org.netbeans.modules.websvc.api.webservices.WsCompileEditorSupport", // NOI18N
105
"org.netbeans.modules.websvc.spi.client.WebServicesClientSupportProvider", // NOI18N
106
"org.netbeans.modules.websvc.spi.client.WebServicesClientViewProvider", // NOI18N
107
"org.netbeans.modules.websvc.spi.webservices.WebServicesSupportProvider", // NOI18N
108
"org.netbeans.modules.websvc.spi.webservices.WebServicesViewProvider", // NOI18N
109
"org.netbeans.modules.xml.wsdl.model.spi.ElementFactoryProvider", // NOI18N
110
"org.netbeans.spi.editor.mimelookup.Class2LayerFolder", // NOI18N
111
"org.netbeans.spi.editor.mimelookup.MimeLookupInitializer", // NOI18N
112
"org.netbeans.spi.java.classpath.ClassPathProvider", // NOI18N
113
"org.netbeans.spi.java.project.support.ui.PackageRenameHandler", // NOI18N
114
"org.netbeans.spi.java.queries.AccessibilityQueryImplementation", // NOI18N
115
"org.netbeans.spi.java.queries.JavadocForBinaryQueryImplementation", // NOI18N
116
"org.netbeans.spi.java.queries.MultipleRootsUnitTestForSourceQueryImplementation", // NOI18N
117
"org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation", // NOI18N
118
"org.netbeans.spi.java.queries.SourceLevelQueryImplementation", // NOI18N
119
"org.netbeans.spi.java.queries.UnitTestForSourceQueryImplementation", // NOI18N
120
"org.netbeans.spi.project.FileOwnerQueryImplementation", // NOI18N
121
"org.netbeans.spi.project.ProjectFactory", // NOI18N
122
"org.netbeans.spi.project.ant.AntArtifactQueryImplementation", // NOI18N
123
"org.netbeans.spi.project.libraries.LibraryProvider", // NOI18N
124
"org.netbeans.spi.project.support.ant.AntBasedProjectType", // NOI18N
125
"org.netbeans.spi.queries.CollocationQueryImplementation", // NOI18N
126
"org.netbeans.spi.queries.FileBuiltQueryImplementation", // NOI18N
127
"org.netbeans.spi.queries.SharabilityQueryImplementation", // NOI18N
128
"org.netbeans.spi.queries.VisibilityQueryImplementation", // NOI18N
129
"org.netbeans.swing.menus.spi.MenuTreeModel", // NOI18N
130
"org.openide.DialogDisplayer", // NOI18N
131
"org.openide.ErrorManager", // NOI18N
132
"org.openide.LifecycleManager", // NOI18N
133
"org.openide.ServiceType", // NOI18N
134
"org.openide.ServiceType$Registry", // NOI18N
135
"org.openide.actions.ActionManager", // NOI18N
136
"org.openide.awt.HtmlBrowser$URLDisplayer", // NOI18N
137
"org.openide.awt.StatusDisplayer", // NOI18N
138
"org.openide.awt.StatusLineElementProvider", // NOI18N
139
"org.openide.execution.ExecutionEngine", // NOI18N
140
"org.openide.execution.ScriptType", // NOI18N
141
"org.openide.filesystems.MIMEResolver", // NOI18N
142
"org.openide.filesystems.Repository", // NOI18N
143
"org.openide.filesystems.URLMapper", // NOI18N
144
"org.openide.loaders.DataLoaderPool", // NOI18N
145
"org.openide.loaders.Environment$Provider", // NOI18N
146
"org.openide.loaders.FolderRenameHandler", // NOI18N
147
"org.openide.loaders.RepositoryNodeFactory", // NOI18N
148
"org.openide.modules.InstalledFileLocator", // NOI18N
149
"org.openide.nodes.NodeOperation", // NOI18N
150
"org.openide.options.SystemOption", // NOI18N
151
"org.openide.text.AnnotationProvider", // NOI18N
152
"org.openide.util.ContextGlobalProvider", // NOI18N
153
"org.openide.util.Lookup", // NOI18N
154
"org.openide.util.datatransfer.ExClipboard$Convertor", // NOI18N
155
"org.openide.windows.IOProvider", // NOI18N
156
"org.openide.windows.TopComponent$Registry", // NOI18N
157
"org.openide.windows.WindowManager", // NOI18N
158
"org.openide.xml.EntityCatalog", // NOI18N
159
};
160     
161     private static Class JavaDoc[] globalClazzes() {
162         if (GLOBAL_CLAZZES == null) {
163             Set JavaDoc clazzes = new HashSet JavaDoc();
164             ClassLoader JavaDoc l = (ClassLoader JavaDoc)Lookup.getDefault().lookup(ClassLoader JavaDoc.class);
165             for (int i = 0; i < GLOBAL_SERVICE_NAMES.length; i++) {
166                 try {
167                     clazzes.add(Class.forName(GLOBAL_SERVICE_NAMES[i], false, l));
168                 } catch (ClassNotFoundException JavaDoc e) {
169                     // OK, maybe missing for some reason. Ignore.
170
}
171             }
172             GLOBAL_CLAZZES = (Class JavaDoc[])clazzes.toArray(new Class JavaDoc[clazzes.size()]);
173         }
174         return GLOBAL_CLAZZES;
175     }
176     
177     private static Class JavaDoc[] cookieClazzes() {
178         if (COOKIE_CLAZZES == null) {
179             // #29851: just Object may not be enough, because the query may
180
// not return everything! Everything in the CookieSet is probably
181
// there, but certainly not accurate if you override getCookie.
182
Class JavaDoc[] clazzes = CookieClassList.getCookieClasses();
183             COOKIE_CLAZZES = new Class JavaDoc[clazzes.length + 1];
184             COOKIE_CLAZZES[0] = Object JavaDoc.class;
185             System.arraycopy(clazzes, 0, COOKIE_CLAZZES, 1, clazzes.length);
186         }
187         return COOKIE_CLAZZES;
188     }
189     
190     /**
191      * Create a node displaying default lookup.
192      * Will start off showing standard singletons.
193      */

194     public static Node globalLookupNode() {
195         Node n = new LookupNode(Lookup.getDefault(), globalClazzes());
196         n.setDisplayName("Global Lookup");
197         n.setShortDescription("The contents of Lookup.getDefault().");
198         return n;
199     }
200
201     /**
202      * Create a node displaying default action lookup.
203      */

204     public static Node actionsGlobalContextLookupNode() {
205         Node n = new LookupNode(ignoreBbNodes(Utilities.actionsGlobalContext()), cookieClazzes());
206         n.setDisplayName("Action Lookup");
207         n.setShortDescription("The contents of Utilities.actionsGlobalContext().");
208         return n;
209     }
210     
211     /**
212      * Create a node displaying the specified lookup.
213      * Will start off showing an Object query, i.e. all items, and probe for common cookies.
214      */

215     public static Node localLookupNode(Lookup l) {
216         Node n = new LookupNode(l, cookieClazzes());
217         n.setDisplayName("Local Lookup");
218         n.setShortDescription("The contents of a local Lookup.");
219         return n;
220     }
221     
222     private LookupNode(Lookup l, Class JavaDoc[] initClazzes) {
223         this(l, Object JavaDoc.class, new ClassSet(initClazzes));
224     }
225     
226     private final Lookup l;
227     private final Class JavaDoc clazz;
228     private final ClassSet clazzes;
229     
230     LookupNode(Lookup l, Class JavaDoc clazz, ClassSet clazzes) {
231         super(new LookupChildren(l, clazz, clazzes));
232         this.l = l;
233         this.clazz = clazz;
234         this.clazzes = clazzes;
235         setIconBaseWithExtension("org/netbeans/modules/apisupport/beanbrowser/BeanBrowserIcon.gif");
236         setName("LookupNode:" + clazz.getName()); // NOI18N
237
setDisplayName((clazz.isInterface() ? "interface " : "class ") + clazz.getName().replace('$', '.'));
238     }
239     
240     public Action JavaDoc[] getActions(boolean context) {
241         if (clazz == Object JavaDoc.class) {
242             return new Action JavaDoc[] {
243                 new AddClassAction(),
244             };
245         } else {
246             return new Action JavaDoc[0];
247         }
248     }
249     
250     private final class AddClassAction extends AbstractAction JavaDoc {
251         public AddClassAction() {
252             super("Add Superclass/interface");
253         }
254         public void actionPerformed(ActionEvent JavaDoc e) {
255             NotifyDescriptor.InputLine desc = new NotifyDescriptor.InputLine("Superclass or interface:", "Add New Lookup Class");
256             if (DialogDisplayer.getDefault().notify(desc) == NotifyDescriptor.OK_OPTION) {
257                 try {
258                     Class JavaDoc clazz = ((ClassLoader JavaDoc) Lookup.getDefault().lookup(ClassLoader JavaDoc.class)).loadClass(desc.getInputText());
259                     clazzes.add(clazz);
260                 } catch (ClassNotFoundException JavaDoc cnfe) {
261                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, cnfe);
262                 }
263             }
264         }
265     }
266     
267     public HelpCtx getHelpCtx() {
268         return new HelpCtx("org.netbeans.modules.apisupport.beanbrowser.lookup");
269     }
270
271     private static final class ClassSet {
272         
273         private final Set JavaDoc/*<Class>*/ clazzes;
274         private final List JavaDoc/*<ChangeListener>*/ listeners;
275         
276         public ClassSet(Class JavaDoc[] initClazzes) {
277             clazzes = new HashSet JavaDoc(Arrays.asList(initClazzes));
278             listeners = new ArrayList JavaDoc();
279         }
280         
281         public void addChangeListener(ChangeListener JavaDoc l) {
282             listeners.add(l);
283         }
284         
285         public void removeChangeListener(ChangeListener JavaDoc l) {
286             listeners.remove(l);
287         }
288         
289         private void fireChange() {
290             ChangeEvent JavaDoc ev = new ChangeEvent JavaDoc(this);
291             Iterator JavaDoc it = listeners.iterator();
292             while (it.hasNext()) {
293                 ((ChangeListener JavaDoc)it.next()).stateChanged(ev);
294             }
295         }
296         
297         public synchronized void add(Class JavaDoc c) {
298             if (clazzes.add(c)) {
299                 fireChange();
300             }
301         }
302         
303         public synchronized void remove(Class JavaDoc c) {
304             if (clazzes.remove(c)) {
305                 fireChange();
306             }
307         }
308         
309         public synchronized void addAll(Class JavaDoc c) {
310             if (addAll0(c)) {
311                 fireChange();
312             }
313         }
314         
315         private boolean addAll0(Class JavaDoc clazz) {
316             boolean success = clazzes.add(clazz);
317             Class JavaDoc s = clazz.getSuperclass();
318             if (s != null) {
319                 success |= addAll0(s);
320             }
321             Class JavaDoc[] is = clazz.getInterfaces();
322             for (int i = 0; i < is.length; i++) {
323                 success |= addAll0(is[i]);
324             }
325             return success;
326         }
327         
328         public synchronized Collection JavaDoc/*<Class>*/ getSubtypes(Class JavaDoc c) {
329             Comparator JavaDoc comp = new Comparator JavaDoc() {
330                 public int compare(Object JavaDoc o1, Object JavaDoc o2) {
331                     Class JavaDoc c1 = (Class JavaDoc)o1;
332                     Class JavaDoc c2 = (Class JavaDoc)o2;
333                     if (c1.isInterface() && !c2.isInterface()) {
334                         return 1;
335                     } else if (!c1.isInterface() && c2.isInterface()) {
336                         return -1;
337                     } else {
338                         return c1.getName().compareTo(c2.getName());
339                     }
340                 }
341             };
342             SortedSet JavaDoc/*<Class>*/ s = new TreeSet JavaDoc(comp);
343             Iterator JavaDoc it = clazzes.iterator();
344             while (it.hasNext()) {
345                 Class JavaDoc c2 = (Class JavaDoc)it.next();
346                 if (c2 == c) {
347                     continue;
348                 }
349                 if (c == Object JavaDoc.class) {
350                     // All top-level classes and interfaces.
351
if (c2.isInterface()) {
352                         if (c2.getInterfaces().length == 0) {
353                             s.add(c2);
354                         }
355                     } else {
356                         if (c2.getSuperclass() == c) {
357                             s.add(c2);
358                         }
359                     }
360                 } else if (c.isInterface()) {
361                     // Direct subinterfaces and directly implementing classes.
362
if (Arrays.asList(c2.getInterfaces()).contains(c)) {
363                         s.add(c2);
364                     }
365                 } else {
366                     // Direct subclasses.
367
if (c2.getSuperclass() == c) {
368                         s.add(c2);
369                     }
370                 }
371             }
372             return s;
373         }
374         
375     }
376     
377     private static final class LookupChildren extends Children.Keys/*<Class|Lookup.Item>*/ implements ChangeListener JavaDoc, LookupListener {
378         
379         private static final Object JavaDoc KEY_PLEASE_WAIT = "wait"; // NOI18N
380
private static final RequestProcessor RP = new RequestProcessor(LookupChildren.class.getName());
381         
382         private final Lookup l;
383         private final Class JavaDoc clazz;
384         private final ClassSet clazzes;
385         private Lookup.Result result;
386         
387         public LookupChildren(Lookup l, Class JavaDoc clazz, ClassSet clazzes) {
388             this.l = l;
389             this.clazz = clazz;
390             this.clazzes = clazzes;
391         }
392         
393         private void updateKeys() {
394             RP.post(new Runnable JavaDoc() {
395                 public void run() {
396                     List JavaDoc keys = new ArrayList JavaDoc();
397                     Iterator JavaDoc it = result.allItems().iterator();
398                     while (it.hasNext()) {
399                         Lookup.Item item = (Item) it.next();
400                         Object JavaDoc o = item.getInstance();
401                         if (o == null) { // dead item, rare but possible
402
continue;
403                         }
404                         Class JavaDoc c = o.getClass();
405                         if (c == clazz) {
406                             keys.add(item);
407                         }
408                         clazzes.addAll(c);
409                     }
410                     it = clazzes.getSubtypes(clazz).iterator();
411                     while (it.hasNext()) {
412                         Class JavaDoc c = (Class JavaDoc) it.next();
413                         clazzes.addAll(c);
414                         if (!l.lookup(new Lookup.Template(c)).allItems().isEmpty()) {
415                             keys.add(c);
416                         }
417                     }
418                     setKeys(keys);
419                 }
420             });
421         }
422         
423         protected void addNotify() {
424             result = l.lookup(new Lookup.Template(clazz));
425             result.addLookupListener(this);
426             clazzes.addChangeListener(this);
427             setKeys(Collections.singleton(KEY_PLEASE_WAIT));
428             updateKeys();
429         }
430         
431         protected void removeNotify() {
432             clazzes.removeChangeListener(this);
433             result.removeLookupListener(this);
434             setKeys(Collections.EMPTY_SET);
435         }
436         
437         protected Node[] createNodes(Object JavaDoc key) {
438             if (key == KEY_PLEASE_WAIT) {
439                 return new Node[] {PropSetKids.makePlainNode("Please wait...")};
440             } else if (key instanceof Class JavaDoc) {
441                 return new Node[] {new LookupNode(l, (Class JavaDoc) key, clazzes)};
442             } else {
443                 Lookup.Item item = (Item) key;
444                 Node n = PropSetKids.makeObjectNode(item.getInstance());
445                 n.setShortDescription("Lookup item ID: " + item.getId());
446                 return new Node[] {n};
447             }
448         }
449         
450         public void stateChanged(ChangeEvent JavaDoc e) {
451             updateKeys();
452         }
453         
454         public void resultChanged(LookupEvent ev) {
455             updateKeys();
456         }
457         
458     }
459     
460     /** Hack to exclude BB-related nodes from lookup view. */
461     static final class BbMarker implements Node.Cookie {}
462     private static boolean containsBbNode(Lookup context) {
463         Iterator JavaDoc/*<Node>*/ nodes = context.lookup(new Lookup.Template(Node.class)).allInstances().iterator();
464         while (nodes.hasNext()) {
465             for (Node n = (Node) nodes.next(); n != null; n = n.getParentNode()) {
466                 if (n.getCookie(BbMarker.class) != null) {
467                     return true;
468                 }
469             }
470         }
471         return false;
472     }
473     private static Lookup ignoreBbNodes(final Lookup orig) {
474         class Proxy extends AbstractLookup implements LookupListener {
475             private final InstanceContent content;
476             private Collection JavaDoc copy = Collections.EMPTY_SET;
477             private final Lookup.Result master = orig.lookup(new Lookup.Template(Object JavaDoc.class));
478             public Proxy() {
479                 this(new InstanceContent());
480             }
481             private Proxy(InstanceContent content) {
482                 super(content);
483                 this.content = content;
484                 Lookup.Result r = orig.lookup(new Lookup.Template(Node.class));
485                 r.addLookupListener((LookupListener) WeakListeners.create(LookupListener.class, this, r));
486                 resultChanged(null);
487             }
488             public void resultChanged(LookupEvent ignore) {
489                 if (!containsBbNode(orig)) {
490                     copy = master.allInstances();
491                 }
492                 content.set(copy, null);
493             }
494         }
495         return new Proxy();
496     }
497
498 }
499
Popular Tags