1 19 20 package org.netbeans.modules.apisupport.beanbrowser; 21 22 import java.awt.event.ActionEvent ; 23 import java.util.ArrayList ; 24 import java.util.Arrays ; 25 import java.util.Collection ; 26 import java.util.Collections ; 27 import java.util.Comparator ; 28 import java.util.HashSet ; 29 import java.util.Iterator ; 30 import java.util.List ; 31 import java.util.Set ; 32 import java.util.SortedSet ; 33 import java.util.TreeSet ; 34 import javax.swing.AbstractAction ; 35 import javax.swing.Action ; 36 import javax.swing.event.ChangeEvent ; 37 import javax.swing.event.ChangeListener ; 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 [] GLOBAL_CLAZZES; 58 private static Class [] COOKIE_CLAZZES; 59 60 private static final String [] GLOBAL_SERVICE_NAMES = { 66 "java.awt.datatransfer.Clipboard", "java.net.URLStreamHandlerFactory", "javax.help.HelpSet", "javax.jmi.xmi.XmiReader", "javax.jmi.xmi.XmiWriter", "javax.naming.spi.InitialContextFactoryBuilder", "javax.swing.LookAndFeel", "javax.swing.PopupFactory", "javax.swing.text.Keymap", "org.apache.tools.ant.module.spi.AntLogger", "org.apache.tools.ant.module.spi.AutomaticExtraClasspathProvider", "org.netbeans.CLIHandler", "org.netbeans.ModuleFactory", "org.netbeans.api.mdr.DTDProducer", "org.netbeans.api.mdr.JMIMapper", "org.netbeans.api.mdr.MDRManager", "org.netbeans.api.xmi.XMIReaderFactory", "org.netbeans.api.xmi.XMIWriterFactory", "org.netbeans.api.xmi.sax.XMIConsumerFactory", "org.netbeans.api.xmi.sax.XMIProducerFactory", "org.netbeans.core.NbTopManager$WindowSystem", "org.netbeans.core.modules.TestModuleDeployer", "org.netbeans.core.startup.CoreBridge", "org.netbeans.core.startup.RunLevel", "org.netbeans.lib.editor.hyperlink.HyperlinkProviderManager", "org.netbeans.modules.ant.freeform.spi.ProjectNature", "org.netbeans.modules.db.spi.sql.editor.SQLEditorProvider", "org.netbeans.modules.j2ee.spi.ejbjar.EarProvider", "org.netbeans.modules.j2ee.spi.ejbjar.EjbJarProvider", "org.netbeans.modules.j2ee.spi.ejbjar.EjbNodesFactory", "org.netbeans.modules.masterfs.providers.AnnotationProvider", "org.netbeans.modules.refactoring.spi.ReadOnlyFilesHandler", "org.netbeans.modules.refactoring.spi.RefactoringPluginFactory", "org.netbeans.modules.versioning.spi.VersioningSystem", "org.netbeans.modules.web.spi.webmodule.RequestParametersProvider", "org.netbeans.modules.web.spi.webmodule.WebModuleProvider", "org.netbeans.modules.websvc.api.client.WsCompileClientEditorSupport", "org.netbeans.modules.websvc.api.registry.WebServicesRegistryView", "org.netbeans.modules.websvc.api.webservices.WsCompileEditorSupport", "org.netbeans.modules.websvc.spi.client.WebServicesClientSupportProvider", "org.netbeans.modules.websvc.spi.client.WebServicesClientViewProvider", "org.netbeans.modules.websvc.spi.webservices.WebServicesSupportProvider", "org.netbeans.modules.websvc.spi.webservices.WebServicesViewProvider", "org.netbeans.modules.xml.wsdl.model.spi.ElementFactoryProvider", "org.netbeans.spi.editor.mimelookup.Class2LayerFolder", "org.netbeans.spi.editor.mimelookup.MimeLookupInitializer", "org.netbeans.spi.java.classpath.ClassPathProvider", "org.netbeans.spi.java.project.support.ui.PackageRenameHandler", "org.netbeans.spi.java.queries.AccessibilityQueryImplementation", "org.netbeans.spi.java.queries.JavadocForBinaryQueryImplementation", "org.netbeans.spi.java.queries.MultipleRootsUnitTestForSourceQueryImplementation", "org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation", "org.netbeans.spi.java.queries.SourceLevelQueryImplementation", "org.netbeans.spi.java.queries.UnitTestForSourceQueryImplementation", "org.netbeans.spi.project.FileOwnerQueryImplementation", "org.netbeans.spi.project.ProjectFactory", "org.netbeans.spi.project.ant.AntArtifactQueryImplementation", "org.netbeans.spi.project.libraries.LibraryProvider", "org.netbeans.spi.project.support.ant.AntBasedProjectType", "org.netbeans.spi.queries.CollocationQueryImplementation", "org.netbeans.spi.queries.FileBuiltQueryImplementation", "org.netbeans.spi.queries.SharabilityQueryImplementation", "org.netbeans.spi.queries.VisibilityQueryImplementation", "org.netbeans.swing.menus.spi.MenuTreeModel", "org.openide.DialogDisplayer", "org.openide.ErrorManager", "org.openide.LifecycleManager", "org.openide.ServiceType", "org.openide.ServiceType$Registry", "org.openide.actions.ActionManager", "org.openide.awt.HtmlBrowser$URLDisplayer", "org.openide.awt.StatusDisplayer", "org.openide.awt.StatusLineElementProvider", "org.openide.execution.ExecutionEngine", "org.openide.execution.ScriptType", "org.openide.filesystems.MIMEResolver", "org.openide.filesystems.Repository", "org.openide.filesystems.URLMapper", "org.openide.loaders.DataLoaderPool", "org.openide.loaders.Environment$Provider", "org.openide.loaders.FolderRenameHandler", "org.openide.loaders.RepositoryNodeFactory", "org.openide.modules.InstalledFileLocator", "org.openide.nodes.NodeOperation", "org.openide.options.SystemOption", "org.openide.text.AnnotationProvider", "org.openide.util.ContextGlobalProvider", "org.openide.util.Lookup", "org.openide.util.datatransfer.ExClipboard$Convertor", "org.openide.windows.IOProvider", "org.openide.windows.TopComponent$Registry", "org.openide.windows.WindowManager", "org.openide.xml.EntityCatalog", }; 160 161 private static Class [] globalClazzes() { 162 if (GLOBAL_CLAZZES == null) { 163 Set clazzes = new HashSet (); 164 ClassLoader l = (ClassLoader )Lookup.getDefault().lookup(ClassLoader .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 e) { 169 } 171 } 172 GLOBAL_CLAZZES = (Class [])clazzes.toArray(new Class [clazzes.size()]); 173 } 174 return GLOBAL_CLAZZES; 175 } 176 177 private static Class [] cookieClazzes() { 178 if (COOKIE_CLAZZES == null) { 179 Class [] clazzes = CookieClassList.getCookieClasses(); 183 COOKIE_CLAZZES = new Class [clazzes.length + 1]; 184 COOKIE_CLAZZES[0] = Object .class; 185 System.arraycopy(clazzes, 0, COOKIE_CLAZZES, 1, clazzes.length); 186 } 187 return COOKIE_CLAZZES; 188 } 189 190 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 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 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 [] initClazzes) { 223 this(l, Object .class, new ClassSet(initClazzes)); 224 } 225 226 private final Lookup l; 227 private final Class clazz; 228 private final ClassSet clazzes; 229 230 LookupNode(Lookup l, Class 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()); setDisplayName((clazz.isInterface() ? "interface " : "class ") + clazz.getName().replace('$', '.')); 238 } 239 240 public Action [] getActions(boolean context) { 241 if (clazz == Object .class) { 242 return new Action [] { 243 new AddClassAction(), 244 }; 245 } else { 246 return new Action [0]; 247 } 248 } 249 250 private final class AddClassAction extends AbstractAction { 251 public AddClassAction() { 252 super("Add Superclass/interface"); 253 } 254 public void actionPerformed(ActionEvent 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 clazz = ((ClassLoader ) Lookup.getDefault().lookup(ClassLoader .class)).loadClass(desc.getInputText()); 259 clazzes.add(clazz); 260 } catch (ClassNotFoundException 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 clazzes; 274 private final List listeners; 275 276 public ClassSet(Class [] initClazzes) { 277 clazzes = new HashSet (Arrays.asList(initClazzes)); 278 listeners = new ArrayList (); 279 } 280 281 public void addChangeListener(ChangeListener l) { 282 listeners.add(l); 283 } 284 285 public void removeChangeListener(ChangeListener l) { 286 listeners.remove(l); 287 } 288 289 private void fireChange() { 290 ChangeEvent ev = new ChangeEvent (this); 291 Iterator it = listeners.iterator(); 292 while (it.hasNext()) { 293 ((ChangeListener )it.next()).stateChanged(ev); 294 } 295 } 296 297 public synchronized void add(Class c) { 298 if (clazzes.add(c)) { 299 fireChange(); 300 } 301 } 302 303 public synchronized void remove(Class c) { 304 if (clazzes.remove(c)) { 305 fireChange(); 306 } 307 } 308 309 public synchronized void addAll(Class c) { 310 if (addAll0(c)) { 311 fireChange(); 312 } 313 } 314 315 private boolean addAll0(Class clazz) { 316 boolean success = clazzes.add(clazz); 317 Class s = clazz.getSuperclass(); 318 if (s != null) { 319 success |= addAll0(s); 320 } 321 Class [] 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 getSubtypes(Class c) { 329 Comparator comp = new Comparator () { 330 public int compare(Object o1, Object o2) { 331 Class c1 = (Class )o1; 332 Class c2 = (Class )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 s = new TreeSet (comp); 343 Iterator it = clazzes.iterator(); 344 while (it.hasNext()) { 345 Class c2 = (Class )it.next(); 346 if (c2 == c) { 347 continue; 348 } 349 if (c == Object .class) { 350 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 if (Arrays.asList(c2.getInterfaces()).contains(c)) { 363 s.add(c2); 364 } 365 } else { 366 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 implements ChangeListener , LookupListener { 378 379 private static final Object KEY_PLEASE_WAIT = "wait"; private static final RequestProcessor RP = new RequestProcessor(LookupChildren.class.getName()); 381 382 private final Lookup l; 383 private final Class clazz; 384 private final ClassSet clazzes; 385 private Lookup.Result result; 386 387 public LookupChildren(Lookup l, Class 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 () { 395 public void run() { 396 List keys = new ArrayList (); 397 Iterator it = result.allItems().iterator(); 398 while (it.hasNext()) { 399 Lookup.Item item = (Item) it.next(); 400 Object o = item.getInstance(); 401 if (o == null) { continue; 403 } 404 Class 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 c = (Class ) 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 key) { 438 if (key == KEY_PLEASE_WAIT) { 439 return new Node[] {PropSetKids.makePlainNode("Please wait...")}; 440 } else if (key instanceof Class ) { 441 return new Node[] {new LookupNode(l, (Class ) 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 e) { 451 updateKeys(); 452 } 453 454 public void resultChanged(LookupEvent ev) { 455 updateKeys(); 456 } 457 458 } 459 460 461 static final class BbMarker implements Node.Cookie {} 462 private static boolean containsBbNode(Lookup context) { 463 Iterator 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 copy = Collections.EMPTY_SET; 477 private final Lookup.Result master = orig.lookup(new Lookup.Template(Object .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 |