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]