Nodes, Looks, and Explorer in the Event Queue

Version:
January 1, 2005
Author:
Jesse Glick
Abstract:

As part of the general threading rework, the presentation-oriented APIs of Nodes, Looks, and Explorer could be run entirely in the AWT event queue (EQ), rather than partially in EQ and partially in other threads as now. This change should simplify the code in these APIs; make their intended behavior more apparent to module writers; simplify testing; and remove some overhead from the rendering cycle.

Issue:
#35833

Introduction

XXX

API Changes

Here are changes visible to module code.

  1. Most methods in Node, Children, and Look (and subclasses) are no longer thread-safe or synchronized: during construction they may be called in a single thread only, and after display only in EQ. However some event firing methods which were commonly called from other threads can continue to be called in this way; after display they will be automatically replanned to EQ. All methods called on module code will be called in EQ. Incompatible for some modules using Nodes. However most callers of methods that have been incompatibility restricted were failing to honor the separation between model and view and would better have been rewritten anyway.

    // Thread-safe in Node:
    protected final void firePropertyChange(String name, Object o, Object n);
    protected final void fireNameChange(String o, String n);
    protected final void fireDisplayNameChange(String o, String n);
    protected final void fireShortDescriptionChange(String o, String n);
    protected final void fireIconChange();
    protected final void fireOpenedIconChange();
    protected final void firePropertySetsChange(Node.PropertySet[] o,
                                                Node.PropertySet[] n);
    protected final void fireCookieChange();
    // Thread-safe in Children.Keys:
    protected final void refreshKey(Object key);
    protected final void setKeys(Collection keysSet);
    protected final void setKeys(Object[] keys);
    // Thread-safe in Look:
    protected final void fireChange(Object representedObject, long mask);
    protected final void firePropertyChange(Object representedObject,
                                            String propertyName);
    
  2. Visualizer and the entire associated layer of “visualizers” between Explorer and Nodes has been deprecated and is unused. Explorer views now directly render Nodes. Explorer view implementations using only Visualizer.findNode(Object) to map supplied TreePath elements to Nodes should continue to work. NodeListModel and NodeTableModel continue to work; the Object parameters are now instances of Node. NodeTreeModel, however, no longer works and is deprecated (because it extends DefaultTreeModel and the new tree model cannot). Overriding TreeView.createModel() no longer has any effect; there is no longer a way to override the tree model externally. Incompatible for modules casting elements of TreePaths to TreeNode, or supplying a custom NodeTreeModel.

  3. Children.MUTEX is now just Mutex.EVENT and is deprecated. Compatible

  4. Two overridable methods added to Children, with default implementations that should be accurate, if not optimal. Compatible

    /**
     * Get a child node at the specified index.
     * Subclasses may implement this more efficiently than getting all nodes
     * and returning the requested one.
     * @param i the (zero-based) index, less than {@link #getNodesCount}
     * @return the node at that index
     * @throws IndexOutOfBoundsException if the index is invalid
     */
    public Node getNodeAt(int i) throws IndexOutOfBoundsException {
        return getNodes()[i];
    }
    /**
     * Get the index at which a given child node occurs.
     * Subclasses may implement this more efficiently than getting all nodes
     * and doing a linear search.
     * @param n a possible child node
     * @return the index of that node, or -1 if it is not a child
     */
    public int getIndexOfNode(Node n) {
        Node[] nodes = getNodes();
        for (int i = 0; i < nodes.length; i++) {
            if (nodes[i] == n) {
                return i;
            }
        }
        return -1;
    }
    
  5. Some methods in Children that used to be final now are overridable. Compatible

    public Enumeration nodes();
    public Node[] getNodes();
    public int getNodesCount();
    
  6. A final method was added to Children to allow cleanroom implementation of Children subclass outside of the org.openide.nodes package. Compatible

    protected final void attachNode(Node n, int idx);
    
  7. A final method was added to Node to allow cleanroom and more effective implementation of Children subclass outside of the org.openide.nodes package. Compatible

    protected final void fireSubNodesChange(boolean addAction, int[] indices, List from);
    

Performance Impact

XXX

Open Issues

Progress cursor not shown during cursor expansion

This is currently disabled - since getNodes(true) can only be called from EQ, it is impossible to set the wait cursor, forcibly get all the nodes, then reset to the normal cursor, since the EQ is occupied the whole time.

Possible solution: introduce methods on Node or Children which would signal (1) that getNodes(false) did not in fact return all the available children, (2) that at some later point (in EQ) that getNodes(true) may be called to get a full set of children without blocking for a significant amount of time. Children subclasses such as those used for folder children would need to take advantage of these calls.

Unit tests fail off EQ, hard to make nodes off EQ

Currently assertions check that all methods must be called on EQ, except for some that were experimentally found to be called often while constructing nodes (which is common to do off EQ before displaying them); otherwise an assertion failure is thrown, or the method call is replanned to EQ. Node-related unit tests tend to fail as a result, and seemingly harmless code patterns are problematic.

Possible solution: make explorer views notify node trees when they are displayed (and possibly undisplayed). Force EQ-only access only when displayed, and single-threaded (utility-like) access otherwise. Unit tests would run in undisplayed mode.

Project Features

About this Project

core was started in November 2009, is owned by Antonin Nebuzelsky, and has 118 members.
By use of this website, you agree to the NetBeans Policies and Terms of Use (revision 20160708.bf2ac18). © 2014, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo
 
 
Close
loading
Please Confirm
Close