pbwest      2004/01/27 22:19:56

  Modified:    src/java/org/apache/fop/datastructs Tag:
                        FOP_0-20-0_Alt-Design Node.java
  Log:
  Added optional synchronization.
  
  Revision  Changes    Path
  No                   revision
  No                   revision
  1.1.2.4   +357 -190  xml-fop/src/java/org/apache/fop/datastructs/Attic/Node.java
  
  Index: Node.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/datastructs/Attic/Node.java,v
  retrieving revision 1.1.2.3
  retrieving revision 1.1.2.4
  diff -u -r1.1.2.3 -r1.1.2.4
  --- Node.java 26 Jan 2004 23:03:53 -0000      1.1.2.3
  +++ Node.java 28 Jan 2004 06:19:56 -0000      1.1.2.4
  @@ -1,5 +1,5 @@
   /*
  -   Copyright 2004 The Apache Software Foundation.
  +   Copyright 2002-2004 The Apache Software Foundation.
   
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
  @@ -59,135 +59,157 @@
   
   public class Node implements Cloneable {
   
  +    /** The parent of this node.  If null, this is the root node. */
       protected Node parent;
  +    /** An array of the children of this node. */
       protected ArrayList children;     // ArrayList of Node
       /** Creation size of the <i>children</i> <tt>ArrayList</tt>. */
       private static final int FAMILYSIZE = 4;
  +    
  +    /** Constant <code>boolean</code> for synchronization argument.  */
  +    public static final boolean SYNCHRONIZE = true;
  +    /** Constant <code>boolean</code> for synchronization argument.  */
  +    public static final boolean DONT_SYNCHRONIZE = ! SYNCHRONIZE;
  +
  +    public final boolean synchronize;
  +    
  +    /**
  +     * This immutable empty array is provided as a convenient class-level
  +     * synchronization object for circumstances where such synchronization
  +     * is required.
  +     */
  +    public static final boolean[] sync = new boolean[0];
   
       /**
        * No argument constructor.
  -     *
  -     * Assumes that this node is the root, and so will throw a
  -     * <tt>TreeException</tt> when the root node in the enclosing
  -     * <tt>Tree</tt> object is non-null.
  +     * Assumes that this node is the root of a new tree.
        */
   
       public Node() {
  +        synchronize = false;
           parent = null;
       }
   
       /**
  -     * @param parent Node which is the parent of this Node.  if this is
  -     *               null, the generated Node is assumed to be the root
  -     *               node.  If the Tree root node is already set, throws
  -     *               a <tt>TreeException</tt>.
  -     * @param index  int index of child in parent.
  +     * Constructor with specific synchronization flag.
  +     * @param synchronize flag for synchronization
  +     */
  +    public Node(boolean synchronize) {
  +        this.synchronize = synchronize;
  +        parent = null;
  +    }
  +    
  +    /**
  +     * Adds a <code>Node</code> as a child at a given index position among
  +     * its parent's children.
  +     * @param parent of this Node
  +     * @param index of child in parent.  If the parent reference
  +     * is <code>null</code>, an IndexOutOfBoundsException is thrown.
  +     * @param synchronize if true, synchronizes on the parent.
        */
   
  -    public Node(Node parent, int index)
  -        throws IndexOutOfBoundsException {
  +    public Node(Node parent, int index, boolean synchronize)
  +    throws IndexOutOfBoundsException {
           if (parent == null) {
  -            this.parent = null;
  +            throw new IndexOutOfBoundsException("Null parent");
           }
           else {
  +            this.synchronize = synchronize;
               this.parent = parent;
  -            // connect me to my parent
               parent.addChild(index, this);
           }
       }
  -
  +    
       /**
  -     * @param parent Node which is the parent of this Node.  if this is
  +     * Adds a <code>Node</code> as a child of the given parent.
  +     * @param parent of this Node.  if this is
        *               null, the generated Node is assumed to be the root
        *               node. 
  +     * @param synchronize if true, synchronizes on the parent.
        */
   
  -    public Node(Node parent)
  +    public Node(Node parent, boolean synchronize)
           throws IndexOutOfBoundsException {
  -        if (parent == null) {
  -            this.parent = null;
  -        }
  -        else {
  -            this.parent = parent;
  -            // connect me to my parent
  +        this.synchronize = synchronize;
  +        this.parent = parent;
  +        if (parent != null) {
               parent.addChild(this);
           }
       }
   
   
       /**
  -     * Appends a child <tt>Node</tt> to this node.  Synchronized on the
  -     * containing <tt>Tree</tt> object.
  -     *
  -     * Calls the <i>modified</i> method of the containing Tree to
  -     * maintain the value of <i>modCount</i>.
  +     * Appends a child to this node.
        *
        * @param child  Node to be added.
        */
   
  -    public synchronized void addChild(Node child) {
  -        if (children == null)
  -            children = new ArrayList(FAMILYSIZE);
  -        children.add(child);
  +    public void addChild(Node child) {
  +        if (synchronize) {
  +            synchronized (this) {
  +                if (children == null)
  +                    children = new ArrayList(FAMILYSIZE);
  +                children.add(child);
  +            }
  +        } else {
  +            if (children == null)
  +                children = new ArrayList(FAMILYSIZE);
  +            children.add(child);
  +        }
       }
  -
  +    
       /**
        * Adds a child <tt>Node</tt> in this node at a specified index
        * position.
  -     * Synchronized on the containing <tt>Tree</tt> object.
  -     *
  -     * Calls the <i>modified</i> method of the containing Tree to
  -     * maintain the value of <i>modCount</i>.
        *
  -     * @param index  int position of new child
  -     * @param child  Node to be added.
  +     * @param index of position of new child
  +     * @param child to be added
        */
  -
  -    public synchronized void addChild(int index, Node child)
  +    public void addChild(int index, Node child)
       throws IndexOutOfBoundsException {
  -        if (children == null)
  -            children = new ArrayList(FAMILYSIZE);
  -        children.add(index, child);
  -        
  +        if (synchronize) {
  +            synchronized (this) {
  +                if (children == null)
  +                    children = new ArrayList(FAMILYSIZE);
  +                children.add(index, child);
  +            }
  +        } else {
  +            if (children == null)
  +                children = new ArrayList(FAMILYSIZE);
  +            children.add(index, child);
  +        }
       }
   
       /**
        * Insert a subtree at a specified index position in the child list.
  -     * Takes advantage of the synchronization of the actual <i>addChild</i> call.
  +     * @param index position of subtree within children
  +     * @param subtree to insert
  +     * @throws IndexOutOfBoundsException
        */
       public void addSubTree(int index, Node subtree)
           throws IndexOutOfBoundsException
       {
  -        // The subtree must be traversed, and the tree references set
  -        // to the Tree of this node.
           subtree.setParent(this);
           addChild(index, subtree);
       }
   
       /**
        * Add a subtree to the child list.
  -     * Takes advantage of the synchronization of the actual <i>addChild</i> call.
  +     * @param subtree to insert
  +     * @throws IndexOutOfBoundsException
        */
       public void addSubTree(Node subtree)
           throws IndexOutOfBoundsException
       {
  -        // The subtree must be traversed, and the tree references set
  -        // to the Tree of this node.
           subtree.setParent(this);
           addChild(subtree);
       }
   
       /**
        * Copies a subtree of this tree as a new child of this node.
  -     * Synchronized on the containing <tt>Tree</tt> object.
  -     *
  -     * Calls the <tt>modified</tt> method of the containing Tree to
  -     * maintain the value of <tt>modCount</tt>.
        *
        * Note that it is illegal to try to copy a subtree to one of
  -     * its own descendents or itself.  (This restriction could be lifted
  -     * by creating a new Tree containing the subtree, and defining an
  -     * attachTree() method to attach one Tree to another.)
  +     * its own descendents or itself.
        *
        * This is the public entry to copyCheckSubTree.  It will always
        * perform a check for the attempt to copy onto a descendent or
  @@ -206,9 +228,7 @@
        * Copies a subtree of this tree as a new child of this node.
        *
        * Note that it is illegal to try to copy a subtree to one of
  -     * its own descendents or itself.  (This restriction could be lifted
  -     * by creating a new Tree containing the subtree, and defining an
  -     * attachTree() method to attach one Tree to another.)
  +     * its own descendents or itself.
        *
        * WARNING: this version of the method assumes that <tt>Node</tt>
        * will be subclassed; <tt>Node</tt> has no contents, so for
  @@ -235,10 +255,9 @@
        *                     call.
        */
   
  -    private synchronized void copyCheckSubTree(
  +    private void copyCheckSubTree(
               Node subtree, int index, boolean checkLoops)
           throws TreeException {
  -        
               Node newNode = null;
               if (checkLoops) {
                   checkLoops = false;
  @@ -292,10 +311,15 @@
        * @return the node removed.
        */
   
  -    public synchronized Node removeChildAtIndex(int index) {
  -        
  -            Node tmpNode = (Node) children.remove(index);
  -            return tmpNode;
  +    public Node removeChildAtIndex(int index) {
  +        if (synchronize) {
  +            synchronized (sync) {
  +                Node tmpNode = (Node) children.remove(index);
  +                return tmpNode;
  +            }
  +        }
  +        Node tmpNode = (Node) children.remove(index);
  +        return tmpNode;
           
       }
   
  @@ -309,16 +333,24 @@
        * @return the node removed.
        */
   
  -    public synchronized Node removeChild(Node child)
  -        throws NoSuchElementException {
  -        
  -            int index = children.indexOf(child);
  -            if (index == -1) {
  -                throw new NoSuchElementException();
  +    public Node removeChild(Node child)
  +    throws NoSuchElementException {
  +        if (synchronize) {
  +            synchronized (this) {
  +                int index = children.indexOf(child);
  +                if (index == -1) {
  +                    throw new NoSuchElementException();
  +                }
  +                Node tmpNode = removeChildAtIndex(index);
  +                return tmpNode;
               }
  -            Node tmpNode = removeChildAtIndex(index);
  -            return tmpNode;
  -        
  +        }
  +        int index = children.indexOf(child);
  +        if (index == -1) {
  +            throw new NoSuchElementException();
  +        }
  +        Node tmpNode = removeChildAtIndex(index);
  +        return tmpNode;
       }
   
       /**
  @@ -330,7 +362,17 @@
        * <p>As a result, any remaining reference to any element in the
        * subtree will keep the whole subtree from being GCed.
        */
  -    public synchronized Node deleteSubTree() {
  +    public Node deleteSubTree() {
  +        if (synchronize) {
  +            synchronized (this) {
  +                if (parent != null) {
  +                    // Not the root node - remove from parent
  +                    parent.removeChild(this);
  +                    unsetParent();
  +                } // end of else
  +                return this;
  +            }
  +        }
           if (parent != null) {
               // Not the root node - remove from parent
               parent.removeChild(this);
  @@ -346,7 +388,19 @@
        * within the subtree are maintained.
        * @return the number of deleted nodes
        */
  -    public synchronized int deleteCountSubTree() {
  +    public int deleteCountSubTree() {
  +        if (synchronize) {
  +            synchronized (this) {
  +                int count = deleteCount(this);
  +                // nullify the parent reference
  +                if (parent != null) {
  +                    // Not the root node - remove from parent
  +                    parent.removeChild(this);
  +                    unsetParent();
  +                }
  +                return count;
  +            }
  +        }
           int count = deleteCount(this);
           // nullify the parent reference
           if (parent != null) {
  @@ -380,21 +434,37 @@
        * @return the parent <tt>Node</tt>.
        */
       public Node getParent() {
  +        if (synchronize) {
  +            synchronized (this) {
  +                return parent;
  +            }
  +        }
           return parent;
       }
   
       /**
        * Set the <i>parent</i> field of this node.
  -     * @param parent - the <tt>Node</tt> reference to set.
  +     * @param parent the reference to set
        */
       public void setParent(Node parent) {
  -        this.parent = parent;
  +        if (synchronize) {
  +            synchronized (this) {
  +                this.parent = parent;
  +            }
  +        } else {
  +            this.parent = parent;
  +        }
       }
   
       /**
        * Nullify the parent <tt>Node</tt> of this node.
        */
       public void unsetParent() {
  +        if (synchronize) {
  +            synchronized (this) {
  +                parent = null;
  +            }
  +        }
           parent = null;
       }
   
  @@ -404,6 +474,12 @@
        * @return the <tt>Node</tt> reference to the n'th child.
        */
       public Node getChild(int n) {
  +        if (synchronize) {
  +            synchronized (this) {
  +                if (children == null) return null;
  +                return (Node) children.get(n);
  +            }
  +        }
           if (children == null) return null;
           return (Node) children.get(n);
       }
  @@ -413,6 +489,12 @@
        * @return the <tt>Iterator</tt>.
        */
       public Iterator nodeChildren() {
  +        if (synchronize) {
  +            synchronized (this) {
  +                if (children == null) return null;
  +                return children.iterator();
  +            }
  +        }
           if (children == null) return null;
           return children.iterator();
       }
  @@ -422,6 +504,12 @@
        * @return the <tt>int</tt> number of children.
        */
       public int numChildren() {
  +        if (synchronize) {
  +            synchronized (this) {
  +                if (children == null) return 0;
  +                return children.size();
  +            }
  +        }
           if (children == null) return 0;
           return children.size();
       }
  @@ -452,17 +540,33 @@
           private PreOrder nextChildIterator;
           
           /**
  +         * If synchronization is require, sync on the containing
  +         * <code>Node</code>.
  +         */
  +        private final Node sync = Node.this;
  +        /** Are operations on this iterator synchronized? */
  +        private final boolean synchronize;
  +        
  +        /**
            * Constructor for pre-order iterator.
            */
           public PreOrder() {
  +            this.synchronize = Node.this.synchronize;
               hasNext();  // A call to set up the initial iterators
               // so that a call to next() without a preceding call to
               // hasNext() will behave sanely
           }
           
  -        public synchronized boolean hasNext() {
  -            // synchronize this against possible changes to the tree
  -            
  +        public boolean hasNext() {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return doHasNext();
  +                }
  +            }
  +            return doHasNext();
  +        }
  +        
  +        private boolean doHasNext() {
               if (selfNotReturned) {
                   return true;
               }
  @@ -481,14 +585,18 @@
               else { // no kiddies
                   return false;
               }
  -            
           }
   
  -        public synchronized Object next()
  -        throws NoSuchElementException {
  -            
  -            // synchronize the whole against changes to the tree
  -            
  +        public Object next() throws NoSuchElementException {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return doNext();
  +                }
  +            }
  +            return doNext();
  +        }
  +
  +        private Object doNext() {
               if (! hasNext()) {
                   throw new NoSuchElementException();
               }
  @@ -497,10 +605,9 @@
                   if (nextChildIndex < numChildren()) {
                       // We have children - create an iterator
                       // for the first one
  -                    nextChildIterator =
  -                        ((Node)
  -                        (children.get(nextChildIndex))).new
  -                        PreOrder();
  +                    nextChildIterator = (
  +                            (Node)(children.get(nextChildIndex))).new
  +                            PreOrder();
                   }
                   // else do nothing;
                   // the nextChildIndex test in hasNext()
  @@ -510,27 +617,14 @@
               else { // self has been returned
                   // there must be a next available, or we would not have
                   // come this far
  -                /* ---------------------------------
  -                if (! nextChildIterator.hasNext()) {
  -                    // last iterator was exhausted;
  -                    // if there was another child available, an
  -                    //iterator would already have been set up.
  -                    // Every iterator will return at least one node -
  -                    // the node on which it is defined.
  -                    // So why did the initial hasNext succeed?
  -                    throw new NoSuchElementException(
  -                    "Cannot reach this");
  -                }
  -                ----------------------------------- */
                   Object tempNode = nextChildIterator.next();
                   // Check for exhaustion of the child
                   if (! nextChildIterator.hasNext()) {
                       // child iterator empty - another child?
                       if (++nextChildIndex < numChildren()) {
  -                        nextChildIterator =
  -                            ((Node)
  -                            (children.get(nextChildIndex))).new
  -                            PreOrder();
  +                        nextChildIterator = (
  +                                (Node)(children.get(nextChildIndex))).new
  +                                PreOrder();
                       }
                       else {
                           // nullify the iterator
  @@ -539,9 +633,8 @@
                   }
                   return (Node) tempNode;
               }
  -            
           }
  -
  +        
           public void remove()
               throws UnsupportedOperationException {
               throw new UnsupportedOperationException();
  @@ -562,7 +655,7 @@
        * node itself and to trigger the handing of the node's children.
        * Firstly, for each child a new PostOrder is instantiated.
        * That iterator will terminate when the last descendant of that
  -     * child has been returned.  finally, the node itself is returned.
  +     * child has been returned.  Finally, the node itself is returned.
        */
   
       public class PostOrder implements Iterator {
  @@ -573,18 +666,34 @@
           // end of the (empty) child vector
   
           private PostOrder nextChildIterator;
  -
  +        /**
  +         * If synchronization is require, sync on the containing
  +         * <code>Node</code>.
  +         */
  +        private final Node sync = Node.this;
  +        /** Are operations on this iterator synchronized? */
  +        private final boolean synchronize;
  +        
           /**
            * Constructor for post-order iterator.
            */
           public PostOrder() {
  +            this.synchronize = Node.this.synchronize;
               hasNext();  // A call to set up the initial iterators
               // so that a call to next() without a preceding call to
               // hasNext() will behave sanely
           }
   
  -        public synchronized boolean hasNext() {
  -            // Synchronize this against changes in the tree
  +        public boolean hasNext() {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return doHasNext();
  +                }
  +            }
  +            return doHasNext();
  +        }
  +
  +        private boolean doHasNext() {
               // self is always the last to go
               if (selfReturned) { // nothing left
                   return false;
  @@ -593,10 +702,9 @@
               // Check first for children, and set up an iterator if so
               if (nextChildIndex < numChildren()) {
                   if (nextChildIterator == null) {
  -                    nextChildIterator =
  -                        ((Node)
  -                        (children.get(nextChildIndex))).new
  -                        PostOrder();
  +                    nextChildIterator = (
  +                            (Node)(children.get(nextChildIndex))).new
  +                            PostOrder();
                   }
                   // else an iterator exists.
                   // Assume that the next() method
  @@ -606,8 +714,17 @@
               return true;
           }
   
  -        public synchronized Object next()
  +        public Object next()
           throws NoSuchElementException {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return doNext();
  +                }
  +            }
  +            return doNext();
  +        }
  +
  +        private Object doNext() throws NoSuchElementException {
               // synchronize the whole against changes to the tree
               if (! hasNext()) {
                   throw new NoSuchElementException();
  @@ -621,10 +738,9 @@
                       // now check for exhaustion of the iterator
                       if (! nextChildIterator.hasNext()) {
                           if (++nextChildIndex < numChildren()) {
  -                            nextChildIterator =
  -                                ((Node)
  -                                (children.get(nextChildIndex))).new
  -                                PostOrder();
  +                            nextChildIterator = (
  +                                    (Node)(children.get(nextChildIndex))).new
  +                                    PostOrder();
                           }
                           // else leave the iterator bumping on empty
                           // next call will return self
  @@ -658,33 +774,45 @@
        */
   
       public class Ancestor implements Iterator {
  +        
           private Node nextAncestor;
  -
  +        /**
  +         * If synchronization is require, sync on the containing
  +         * <code>Node</code>.
  +         */
  +        private final Node sync = Node.this;
  +        /** Are operations on this iterator synchronized? */
  +        private final boolean synchronize;
  +        
           /**
            * Constructor for ancestors iterator.
            */
           public Ancestor() {
  +            this.synchronize = Node.this.synchronize;
               nextAncestor = Node.this.parent;
           }
   
           public boolean hasNext() {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return nextAncestor != null;
  +                }
  +            }
               return nextAncestor != null;
           }
   
  -        public synchronized Object next()
  -        throws NoSuchElementException {
  -            // The tree is a
  -            // potentially dynanic structure, which could be
  -            // undergoing modification as this method is being
  -            // executed.
  +        public Object next() throws NoSuchElementException {
  +            if (synchronize) {
  +                Node tmpNode = nextAncestor;
  +                nextAncestor = tmpNode.parent;
  +                return tmpNode;
  +            }
               Node tmpNode = nextAncestor;
               nextAncestor = tmpNode.parent;
               return tmpNode;
  -            
           }
   
  -        public void remove()
  -            throws UnsupportedOperationException {
  +        public void remove() throws UnsupportedOperationException {
               throw new UnsupportedOperationException();
           }
       }
  @@ -693,7 +821,7 @@
       /**
        * Class <tt>FollowingSibling</tt> is a member class of <tt>Node</tt>.
        *
  -     * It implements the <tt>ListIterator</tt> interface, but has reports
  +     * It implements the <tt>ListIterator</tt> interface, but reports
        * UnsupportedOperationException for all methods except
        * <tt>hasNext()</tt>, <tt>next()</tt> and <tt>nextIndex()</tt>.
        * These methods are implemented as synchronized wrappers around the
  @@ -707,42 +835,61 @@
       public class FollowingSibling implements ListIterator {
   
           private ListIterator listIterator;
  -        private ArrayList rootDummy = new ArrayList();
  -        // An empty ArrayList for the root listIterator
  -        // hasNext() will always return false
  -
  +        /**
  +         * An empty ArrayList for the root listIterator.
  +         * hasNext() will always return false
  +         */
  +        private ArrayList rootDummy = new ArrayList(0);
  +        /**
  +         * If synchronization is require, sync on the containing
  +         * <code>Node</code>.
  +         */
  +        private final Node sync = Node.this;
  +        /** Are operations on this iterator synchronized? */
  +        private final boolean synchronize;
  +        
           public FollowingSibling() {
  -            synchronized (this) {
  -                // Set up iterator on the parent's arrayList of children
  -                Node refNode = Node.this.parent;
  -                if (refNode != null) {
  -                    // Not the root node; siblings may exist
  -                    // Set up iterator on the parent's children ArrayList
  -                    ArrayList siblings = refNode.children;
  -                    int index = siblings.indexOf(Node.this);
  -                    // if this is invalid, we are in serious trouble
  -                    listIterator = siblings.listIterator(index + 1);
  -                } // end of if (Node.this.parent != null)
  -                else {
  -                    // Root node - no siblings
  -                    listIterator = rootDummy.listIterator();
  -                }
  +            this.synchronize = Node.this.synchronize;
  +            // Set up iterator on the parent's arrayList of children
  +            Node refNode = Node.this.parent;
  +            if (refNode != null) {
  +                // Not the root node; siblings may exist
  +                // Set up iterator on the parent's children ArrayList
  +                ArrayList siblings = refNode.children;
  +                int index = siblings.indexOf(Node.this);
  +                // if this is invalid, we are in serious trouble
  +                listIterator = siblings.listIterator(index + 1);
  +            } // end of if (Node.this.parent != null)
  +            else {
  +                // Root node - no siblings
  +                listIterator = rootDummy.listIterator();
               }
           }
   
  -        public synchronized boolean hasNext() {
  +        public boolean hasNext() {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return listIterator.hasNext();
  +                }
  +            }
               return listIterator.hasNext();
           }
   
  -        public synchronized Object next()
  -        throws NoSuchElementException {
  -            // N.B. synchronization here is on the Node containing
  -            // the children ArryList of interest.  Other ArrayList operations
  -            // throughout the tree are also synchronized on the Node object.
  +        public Object next() throws NoSuchElementException {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return listIterator.next();
  +                }
  +            }
               return listIterator.next();
           }
   
  -        public synchronized int nextIndex() {
  +        public int nextIndex() {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return listIterator.nextIndex();
  +                }
  +            }
               return listIterator.nextIndex();
           }
   
  @@ -780,7 +927,7 @@
       /**
        * Class <tt>PrecedingSibling</tt> is a member class of <tt>Node</tt>.
        *
  -     * It implements the <tt>ListIterator</tt> interface, but has reports
  +     * It implements the <tt>ListIterator</tt> interface, but reports
        * UnsupportedOperationException for all methods except
        * <tt>hasPrevious()</tt>, <tt>previous()</tt> and
        * <tt>previousIndex()</tt>.
  @@ -796,42 +943,62 @@
       public class PrecedingSibling implements ListIterator {
   
           private ListIterator listIterator;
  -        private ArrayList rootDummy = new ArrayList();
  -        // An empty ArrayList for the root listIterator
  -        // hasNext() will always return false
  -
  +        /**
  +         * An empty ArrayList for the root listIterator.
  +         * hasNext() will always return false
  +         */
  +        private ArrayList rootDummy = new ArrayList(0);
  +        /**
  +         * If synchronization is require, sync on the containing
  +         * <code>Node</code>.
  +         */
  +        private final Node sync = Node.this;
  +        /** Are operations on this iterator synchronized? */
  +        private final boolean synchronize;
  +        
           public PrecedingSibling() {
  -            synchronized (this) {
  -                // Set up iterator on the parent's arrayList of children
  -                Node refNode = Node.this.parent;
  -                if (refNode != null) {
  -                    // Not the root node; siblings may exist
  -                    // Set up iterator on the parent's children ArrayList
  -                    ArrayList siblings = refNode.children;
  -                    int index = siblings.indexOf(Node.this);
  -                    // if this is invalid, we are in serious trouble
  -                    listIterator = siblings.listIterator(index);
  -                } // end of if (Node.this.parent != null)
  -                else {
  -                    // Root node - no siblings
  -                    listIterator = rootDummy.listIterator();
  -                }
  +            this.synchronize = Node.this.synchronize;
  +            // Set up iterator on the parent's arrayList of children
  +            Node refNode = Node.this.parent;
  +            if (refNode != null) {
  +                // Not the root node; siblings may exist
  +                // Set up iterator on the parent's children ArrayList
  +                ArrayList siblings = refNode.children;
  +                int index = siblings.indexOf(Node.this);
  +                // if this is invalid, we are in serious trouble
  +                listIterator = siblings.listIterator(index);
  +            } // end of if (Node.this.parent != null)
  +            else {
  +                // Root node - no siblings
  +                listIterator = rootDummy.listIterator();
               }
           }
  +        
   
  -        public synchronized boolean hasPrevious() {
  +        public boolean hasPrevious() {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return listIterator.hasPrevious();
  +                }
  +            }
               return listIterator.hasPrevious();
           }
   
  -        public synchronized Object previous()
  -            throws NoSuchElementException {
  -            // N.B. synchronization here is on the Node containing
  -            // the children ArryList of interest.  Other ArrayList operations
  -            // throughout the tree are also synchronized on the Node object.
  +        public Object previous() throws NoSuchElementException {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return listIterator.previous();
  +                }
  +            }
               return listIterator.previous();
           }
   
  -        public synchronized int previousIndex() {
  +        public int previousIndex() {
  +            if (synchronize) {
  +                synchronized (sync) {
  +                    return listIterator.previousIndex();
  +                }
  +            }
               return listIterator.previousIndex();
           }
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to