? X.diff ? arch/arch-openide-nodes.xml ? arch/arch-openide-explorer.xml ? arch/arch-openide-utilities.xml ? arch/arch-openide-compiler.xml Index: src/org/openide/loaders/FolderChildren.java =================================================================== RCS file: /cvs/openide/src/org/openide/loaders/FolderChildren.java,v retrieving revision 1.57 diff -u -r1.57 FolderChildren.java --- src/org/openide/loaders/FolderChildren.java 3 Dec 2002 14:11:52 -0000 1.57 +++ src/org/openide/loaders/FolderChildren.java 5 Feb 2003 08:45:10 -0000 @@ -191,7 +191,7 @@ /** Initializes the children. */ protected void addNotify () { - initialize (true, true); + initialize (true, false); // add as a listener for changes on nodes folder.addPropertyChangeListener (listener); } @@ -243,7 +243,7 @@ } /** time delay between two inserts of nodes */ - private static final int TIME_DELAY = 256; + private static final int TIME_DELAY = 1024; /** Private req processor for Addition's refresh tasks */ private static RequestProcessor refRP = Index: src/org/openide/nodes/ChildrenArray.java =================================================================== RCS file: /cvs/openide/src/org/openide/nodes/ChildrenArray.java,v retrieving revision 1.8 diff -u -r1.8 ChildrenArray.java --- src/org/openide/nodes/ChildrenArray.java 10 Jan 2002 15:22:23 -0000 1.8 +++ src/org/openide/nodes/ChildrenArray.java 5 Feb 2003 08:45:10 -0000 @@ -31,6 +31,10 @@ /** Creates new ChildrenArray */ private ChildrenArray () { } + + public Children getChildren () { + return children; + } /** When finalized notify the children. */ @@ -68,7 +72,9 @@ if (nodes == null) { nodes = children.justComputeNodes (); for (int i = 0; i < nodes.length; i++) { - nodes[i].addNodeListener (this); + // keeps a hard reference from the children node to this + // so we can be GCed only when child nodes are gone + nodes[i].reassignTo (children, this); } // if at least one node => be weak children.registerChildrenArray (this, nodes.length > 0); Index: src/org/openide/nodes/FilterNode.java =================================================================== RCS file: /cvs/openide/src/org/openide/nodes/FilterNode.java,v retrieving revision 1.69 diff -u -r1.69 FilterNode.java --- src/org/openide/nodes/FilterNode.java 9 Jan 2003 17:08:51 -0000 1.69 +++ src/org/openide/nodes/FilterNode.java 5 Feb 2003 08:45:15 -0000 @@ -152,7 +152,6 @@ /** Initializes the node. */ private void init () { - original.addNodeListener (getNodeListener ()); delegateMask = DELEGATE_ALL; } @@ -328,57 +327,69 @@ * @param s the string */ public void setName (String s) { - if (delegating (DELEGATE_SET_NAME)) + if (delegating (DELEGATE_SET_NAME)) { + getNodeListener (); original.setName (s); - else + } else { super.setName (s); + } } /* @return the name of the original node */ public String getName () { - if (delegating (DELEGATE_GET_NAME)) + if (delegating (DELEGATE_GET_NAME)) { + getNodeListener (); return original.getName (); - else + } else { return super.getName (); + } } /* Setter for display name. Fires info about property change. * @param s the string */ public void setDisplayName (String s) { - if (delegating (DELEGATE_SET_DISPLAY_NAME)) + if (delegating (DELEGATE_SET_DISPLAY_NAME)) { + getNodeListener (); original.setDisplayName (s); - else + } else { super.setDisplayName (s); + } } /* @return the display name of the original node */ public String getDisplayName () { - if (delegating (DELEGATE_GET_DISPLAY_NAME)) + if (delegating (DELEGATE_GET_DISPLAY_NAME)) { + getNodeListener (); return original.getDisplayName (); - else + } else { return super.getDisplayName (); + } } /* Setter for short description. Fires info about property change. * @param s the string */ public void setShortDescription (String s) { - if (delegating (DELEGATE_SET_SHORT_DESCRIPTION)) + if (delegating (DELEGATE_SET_SHORT_DESCRIPTION)) { + getNodeListener (); original.setShortDescription (s); - else + } else { super.setShortDescription (s); + } } /* @return the description of the original node */ public String getShortDescription () { - if (delegating (DELEGATE_GET_SHORT_DESCRIPTION)) + if (delegating (DELEGATE_GET_SHORT_DESCRIPTION)) { + getNodeListener (); return original.getShortDescription (); - else + } else { return super.getShortDescription (); + } } /* Finds an icon for this node. Delegates to the original. @@ -388,6 +399,7 @@ * @return icon to use to represent the bean */ public Image getIcon (int type) { + getNodeListener (); return original.getIcon (type); } @@ -399,6 +411,7 @@ * @return icon to use to represent the bean when opened */ public Image getOpenedIcon (int type) { + getNodeListener (); return original.getOpenedIcon (type); } @@ -446,6 +459,7 @@ * @return the array of property sets. */ public PropertySet[] getPropertySets () { + getNodeListener (); return original.getPropertySets (); } @@ -566,6 +580,7 @@ * is not supported */ public Node.Cookie getCookie (Class type) { + getNodeListener (); return original.getCookie (type); } @@ -689,9 +704,18 @@ synchronized NodeListener getNodeListener () { if (nodeL == null) { nodeL = createNodeListener (); + getOriginal().addNodeListener(nodeL); } return nodeL; } + + /** Notified from Node that a listener has been added. + * Thus we force initialization of listeners. + */ + final void listenerAdded () { + getNodeListener (); + } + /** Check method whether the node has default behaviour or * if it is either subclass of uses different children. Index: src/org/openide/nodes/Node.java =================================================================== RCS file: /cvs/openide/src/org/openide/nodes/Node.java,v retrieving revision 1.60 diff -u -r1.60 Node.java --- src/org/openide/nodes/Node.java 16 Jan 2003 15:13:22 -0000 1.60 +++ src/org/openide/nodes/Node.java 5 Feb 2003 08:45:16 -0000 @@ -106,10 +106,11 @@ /** cache of all created lookups */ private static WeakHashMap lookups = new WeakHashMap (37); - /** children representing parent node, for synchronization reasons must be changed only + /** children representing parent node (Children or ChildrenArray), + * for synchronization reasons must be changed only * under the Children.MUTEX lock */ - private Children parent; + private Object parent; /** children list, for synch. reasons change only under Children.MUTEX * lock @@ -224,6 +225,13 @@ */ public abstract Node cloneNode (); + + /** Finds the children we are attached to. + * @return children + */ + private Children getParentChildren () { + return this.parent instanceof ChildrenArray ? ((ChildrenArray)this.parent).getChildren () : (Children)this.parent; + } /** Method that allows Children to change the parent children of * the node when the node is add to a children. @@ -233,18 +241,30 @@ * @exception IllegalStateException if this node already belongs to a children */ final synchronized void assignTo (Children parent, int index) { - if (this.parent != null && this.parent != parent) { - throw new IllegalStateException ("Cannot initialize " + index + "th child of node " + parent.getNode () + "; it already belongs to node " + this.parent.getNode ()); // NOI18N + Children ch = getParentChildren (); + if (ch != null && ch != parent) { + throw new IllegalStateException ("Cannot initialize " + index + "th child of node " + parent.getNode () + "; it already belongs to node " + ch.getNode ()); // NOI18N } this.parent = parent; } + + /** Code that reasignes the reference from to parent from its + * Children to its ChildrenArray. + */ + final synchronized void reassignTo (Children currentParent, ChildrenArray itsArray) { + if (this.parent != currentParent) { + throw new IllegalStateException ("Unauthorized call to change parent: " + this.parent + " and should be: " + currentParent); + } + this.parent = itsArray; + } /** Deassignes the node from a children, when it is removed from * a children. */ final synchronized void deassignFrom (Children parent) { - if (parent != this.parent) { - throw new IllegalArgumentException ("Deassign from wrong parent. Old: " + this.parent + " Caller: " + parent); //NOI18N + Children p = getParentChildren (); + if (parent != p) { + throw new IllegalArgumentException ("Deassign from wrong parent. Old: " + p + " Caller: " + parent); //NOI18N } this.parent = null; } @@ -364,7 +384,8 @@ */ public final Node getParentNode () { // if contained in a list return its parent node - return parent == null ? null : parent.getNode (); + Children ch = getParentChildren (); + return ch == null ? null : ch.getNode (); } /** Test whether this node can be renamed. @@ -395,9 +416,10 @@ public void destroy () throws IOException { Children.MUTEX.postWriteRequest (new Runnable () { public void run () { - if (parent != null) { + Children p = getParentChildren (); + if (p != null) { // remove itself from parent - parent.remove (new Node[] {Node.this} ); + p.remove (new Node[] {Node.this} ); } // sets the valid flag to false and fires prop. change fireNodeDestroyed (); @@ -653,6 +675,11 @@ ((LookupEventList)listeners).init (); } listeners.add (NodeListener.class, l); + listenerAdded (); + } + + /** A method to notify FilterNode that a listenerAdded has been added */ + void listenerAdded () { } /** Remove a node listener. Index: src/org/openide/util/RequestProcessor.java =================================================================== RCS file: /cvs/openide/src/org/openide/util/RequestProcessor.java,v retrieving revision 1.64 diff -u -r1.64 RequestProcessor.java --- src/org/openide/util/RequestProcessor.java 15 Jan 2003 11:55:54 -0000 1.64 +++ src/org/openide/util/RequestProcessor.java 5 Feb 2003 08:45:16 -0000 @@ -76,6 +76,9 @@ /** A shared timer used to pass timeouted tasks to pending queue */ private static Timer starterThread = new Timer(true); + /** logger */ + private static ErrorManager logger; + /** The name of the RequestProcessor instance */ String name; @@ -284,6 +287,18 @@ public static Task createRequest (Runnable run) { return DEFAULT.create (run); } + + + /** Logger for the error manager. + */ + private static ErrorManager logger () { + synchronized (starterThread) { + if (logger == null) { + logger = ErrorManager.getDefault ().getInstance ("org.openide.util.RequestProcessor"); // NOI18N + } + return logger; + } + } // The task is the implementation of most of the RP semantics /** The task describing the request sent to the processor. */ @@ -596,8 +611,21 @@ /** setPriority wrapper that skips setting the same priority * we'return already running at */ - void setPrio(int priority) { + void setPrio(int priority, int[] counts) { if (priority != getPriority()) setPriority(priority); + + if (++counts[priority - Thread.MIN_PRIORITY] == priority - Thread.MIN_PRIORITY + 1) { + logger().log (ErrorManager.INFORMATIONAL, "Priority exhausted " + counts[priority - Thread.MIN_PRIORITY] + " do yield: " + getName ()); // NOI18N + counts[priority - Thread.MIN_PRIORITY] = 0; + + long now = System.currentTimeMillis(); + for (int i = Thread.MAX_PRIORITY; i >= priority; i--) { + Thread.yield(); + } + long after = System.currentTimeMillis(); + + logger ().log (ErrorManager.INFORMATIONAL, "Yield: " + (after - now) + " ms for thread: " + getName ()); // NOI18N + } } /** @@ -642,12 +670,16 @@ Task todo; + int[] counts = new int[Thread.MAX_PRIORITY - Thread.MIN_PRIORITY + 1]; + logger ().log (ErrorManager.INFORMATIONAL, "Begining work " + getName ()); // NOI18N // while we have something to do - while((todo = current.askForWork(this)) != null) { + while((todo = current.askForWork(this)) != null) { if(todo != null) { - setPrio(todo.getPriority()); + setPrio(todo.getPriority(), counts); try { + logger ().log (" Executing " + todo); // NOI18N todo.run (); + logger ().log (" Execution finished in" + getName ()); // NOI18N } catch (ThreadDeath td) { throw td; // do not catch this } catch (Throwable ex) { @@ -659,6 +691,7 @@ } } } + logger ().log (ErrorManager.INFORMATIONAL, "Work finished " + getName ()); // NOI18N } } Index: test/unit/src/org/openide/nodes/NodeLookupTest.java =================================================================== RCS file: /cvs/openide/test/unit/src/org/openide/nodes/NodeLookupTest.java,v retrieving revision 1.8 diff -u -r1.8 NodeLookupTest.java --- test/unit/src/org/openide/nodes/NodeLookupTest.java 27 Nov 2002 11:03:04 -0000 1.8 +++ test/unit/src/org/openide/nodes/NodeLookupTest.java 5 Feb 2003 08:45:17 -0000 @@ -36,35 +36,37 @@ public static void main(String[] args) { TestRunner.run(new NbTestSuite(NodeLookupTest.class)); } - + public void testChangesAreFiredFromLookup () { - InstanceContent ic = new InstanceContent (); - AbstractLookup lookup = new AbstractLookup (ic); - Node node = new AbstractNode (Children.LEAF, lookup); + CountableLookup lkp = new CountableLookup (); + Node node = new AbstractNode (createChildren (), lkp); - checkInstanceInGetCookie (new Node.Cookie () {}, ic, node); - checkInstanceInGetLookup (new Node.Cookie () {}, ic, node, true); - checkInstanceInGetLookup ("Some string", ic, node, true); + checkGetNodesDoesNotInitializeLookup (node, lkp.queries); + checkInstanceInGetCookie (new Node.Cookie () {}, lkp.ic, node); + checkInstanceInGetLookup (new Node.Cookie () {}, lkp.ic, node, true); + checkInstanceInGetLookup ("Some string", lkp.ic, node, true); } public void testChangesAreFiredFromLookupThruFilterNode () { - InstanceContent ic = new InstanceContent (); - AbstractLookup lookup = new AbstractLookup (ic); - Node node = new FilterNode (new AbstractNode (Children.LEAF, lookup)); + CountableLookup lkp = new CountableLookup (); + Node node = new FilterNode (new AbstractNode (createChildren (), lkp)); + checkGetNodesDoesNotInitializeLookup (node, lkp.queries); //checkInstanceInGetCookie (new Node.Cookie () {}, ic, node); - checkInstanceInGetLookup (new Node.Cookie () {}, ic, node, true); - checkInstanceInGetLookup ("Some string", ic, node, true); + checkInstanceInGetLookup (new Node.Cookie () {}, lkp.ic, node, true); + checkInstanceInGetLookup ("Some string", lkp.ic, node, true); } public void testChangesAreFiredFromLookupThruFilterNodeWithOverWrittenGetCookie () { final Node.Cookie myInstance = new Node.Cookie () { }; - + final ArrayList queries = new ArrayList (); InstanceContent ic = new InstanceContent (); AbstractLookup lookup = new AbstractLookup (ic); - Node node = new FilterNode (new AbstractNode (Children.LEAF, lookup)) { + Node node = new FilterNode (new AbstractNode (createChildren (), lookup)) { public Node.Cookie getCookie (Class clazz) { + queries.add (clazz); + if (clazz == myInstance.getClass ()) { return myInstance; } @@ -72,6 +74,7 @@ } }; + checkGetNodesDoesNotInitializeLookup (node, queries); checkInstanceInGetCookie (new Node.Cookie () {}, ic, node); checkInstanceInGetLookup (new Node.Cookie () {}, ic, node, true); // by overwriting the FilterNode.getCookie we disable enhanced support @@ -133,18 +136,23 @@ public void testFilterNodeWithOverridenGetCookieIsInTheLookup () { CookieNode n = new CookieNode (); - + + final ArrayList queries = new ArrayList (); class MyFN extends FilterNode { public MyFN (Node n) { super (n); } public Node.Cookie getCookie (Class clazz) { + queries.add (clazz); return super.getCookie (clazz); } } FilterNode fn = new MyFN (n); + checkGetNodesDoesNotInitializeLookup (fn, queries); + checkGetNodesDoesNotInitializeLookup (fn, n.queries); + Lookup l = fn.getLookup (); // == must be used instead of equals for nodes!!! @@ -158,8 +166,9 @@ CookieNode n = new CookieNode (); FilterNode fn = new FilterNode (n); - Lookup l = fn.getLookup (); + checkGetNodesDoesNotInitializeLookup (fn, n.queries); + Lookup l = fn.getLookup (); // == must be used instead of equals for nodes!!! assertTrue ("Node is there", fn == l.lookup (Node.class)); Collection c = l.lookup (new Lookup.Template (Node.class)).allInstances (); @@ -229,6 +238,32 @@ ic.remove (obj); listener.assertEvents ("One change in lookup", -1, 1); + } + + private static void checkGetNodesDoesNotInitializeLookup (final org.openide.nodes.Node n, java.util.List queried) { + assertEquals ("No queries before", Collections.EMPTY_LIST, queried); + + class MyCh extends Children.Keys { + protected void addNotify () { + setKeys (java.util.Collections.singleton(n)); + } + + public void clear () { + setKeys (java.util.Collections.EMPTY_LIST); + } + + protected Node[] createNodes (Object key) { + return new Node[] { n }; + } + }; + MyCh ch = new MyCh (); + + // initialize the node N + new AbstractNode (ch).getChildren().getNodes (); + + assertEquals ("No queries after", Collections.EMPTY_LIST, queried); + ch.clear (); + assertEquals ("No queries after clean either", Collections.EMPTY_LIST, queried); } @@ -261,7 +296,7 @@ public void testBackwardCompatibleAbstractNodeLookupCanBeGarbageCollected () { - AbstractNode n = new AbstractNode (Children.LEAF); + AbstractNode n = new AbstractNode (createChildren ()); Lookup l = n.getLookup (); assertEquals ("Two invocations share the same lookup", l, n.getLookup ()); @@ -271,6 +306,7 @@ assertGC ("Lookup can be GCed", ref); } + /** Assert GC. */ private static void assertGC (String text, java.lang.ref.Reference ref) { @@ -284,6 +320,10 @@ fail (text + " " + ref.get ()); } + private static Children createChildren () { + return Children.LEAF; + } + private static class Listener extends Object implements LookupListener, NodeListener { @@ -326,11 +366,13 @@ } // end of Listener private static class CookieNode extends AbstractNode { + public ArrayList queries = new ArrayList (); + public CookieNode () { - super (Children.LEAF); + super (createChildren ()); } public CookieNode (Lookup l) { - super (Children.LEAF, l); + super (createChildren (), l); } public CookieSet cookieSet () { @@ -339,6 +381,32 @@ public void setSet (CookieSet s) { super.setCookieSet (s); } + + public Node.Cookie getCookie (Class c) { + queries.add (c); + return super.getCookie (c); + } } // end of CookieNode + + + private static class CountableLookup extends AbstractLookup { + public final InstanceContent ic; + public final ArrayList queries; + + public CountableLookup () { + this (new InstanceContent (), new ArrayList ()); + } + + private CountableLookup (InstanceContent ic, ArrayList queries) { + super (ic); + this.ic = ic; + this.queries = queries; + } + + protected void beforeLookup (Lookup.Template t) { + super.beforeLookup (t); + queries.add (t.getType ()); + } + } }