/** * Return a method handle that takes the indicated number of typed arguments and returns an array * of them. The type argument is the array type. */ public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { Class<?> elemType = arrayType.getComponentType(); if (elemType == null) throw new IllegalArgumentException("not an array: " + arrayType); // FIXME: Need more special casing and caching here. if (nargs >= MAX_JVM_ARITY / 2 - 1) { int slots = nargs; final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH if (arrayType == double[].class || arrayType == long[].class) slots *= 2; if (slots > MAX_ARRAY_SLOTS) throw new IllegalArgumentException( "too many arguments: " + arrayType.getSimpleName() + ", length " + nargs); } if (elemType == Object.class) return varargsArray(nargs); // other cases: primitive arrays, subtypes of Object[] MethodHandle cache[] = TYPED_COLLECTORS.get(elemType); MethodHandle mh = nargs < cache.length ? cache[nargs] : null; if (mh != null) return mh; if (elemType.isPrimitive()) { MethodHandle builder = FILL_NEW_ARRAY; MethodHandle producer = buildArrayProducer(arrayType); mh = buildVarargsArray(builder, producer, nargs); } else { @SuppressWarnings("unchecked") Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType; Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example); MethodHandle producer = ARRAY_IDENTITY; mh = buildVarargsArray(builder, producer, nargs); } mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); assert (assertCorrectArity(mh, nargs)); if (nargs < cache.length) cache[nargs] = mh; return mh; }
public List<ReferenceType> visibleClasses() { List<ReferenceType> classes = null; try { Cache local = (Cache) getCache(); if (local != null) { classes = local.visibleClasses; } if (classes == null) { JDWP.ClassLoaderReference.VisibleClasses.ClassInfo[] jdwpClasses = JDWP.ClassLoaderReference.VisibleClasses.process(vm, this).classes; classes = new ArrayList<ReferenceType>(jdwpClasses.length); for (int i = 0; i < jdwpClasses.length; ++i) { classes.add(vm.referenceType(jdwpClasses[i].typeID, jdwpClasses[i].refTypeTag)); } classes = Collections.unmodifiableList(classes); if (local != null) { local.visibleClasses = classes; if ((vm.traceFlags & VirtualMachine.TRACE_OBJREFS) != 0) { vm.printTrace( description() + " temporarily caching visible classes (count = " + classes.size() + ")"); } } } } catch (JDWPException exc) { throw exc.toJDIException(); } return classes; }
/* * Returns a keystore entry alias and a list of target keystores. * When the supplied alias prefix identifies a keystore then that single * keystore is returned. When no alias prefix is supplied then all the * keystores are returned. */ private AbstractMap.SimpleEntry<String, Collection<KeyStore>> getKeystoresForReading( String alias) { String[] splits = alias.split(this.entryNameSeparatorRegEx, 2); if (splits.length == 2) { // prefixed alias KeyStore keystore = keystores.get(splits[0]); if (keystore != null) { return new AbstractMap.SimpleEntry<>( splits[1], (Collection<KeyStore>) Collections.singleton(keystore)); } } else if (splits.length == 1) { // unprefixed alias // Check all keystores for the first occurrence of the alias return new AbstractMap.SimpleEntry<>(alias, keystores.values()); } return new AbstractMap.SimpleEntry<>( "", (Collection<KeyStore>) Collections.<KeyStore>emptyList()); }
/** * Gets the valid offsets during this transition. * * <p>A gap will return an empty list, while an overlap will return both offsets. * * @return the list of valid offsets */ List<ZoneOffset> getValidOffsets() { if (isGap()) { return Collections.emptyList(); } return Arrays.asList(getOffsetBefore(), getOffsetAfter()); }
/** * Returns a set of entries from the map. Each entry is a pair consisted of the property name and * the corresponding list of listeners. * * @return a set of entries from the map */ public final Set<Entry<String, L[]>> getEntries() { return (this.map != null) ? this.map.entrySet() : Collections.<Entry<String, L[]>>emptySet(); }
static { List<StorageResolver> list = new ArrayList<StorageResolver>(1); list.add(null); nullList = j86.java.util.Collections.unmodifiableList(list); }
/** * Returns an unmodifiable Collection view of the item values contained in this * <tt>CompositeData</tt> instance. The returned collection's iterator will return the values in * the ascending lexicographic order of the corresponding item names. */ public Collection<?> values() { return Collections.unmodifiableCollection(contents.values()); }
/** * A <code>DefaultMutableTreeNode</code> is a general-purpose node in a tree data structure. For * examples of using default mutable tree nodes, see <a * href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Trees</a> * in <em>The Java Tutorial.</em> * * <p>A tree node may have at most one parent and 0 or more children. <code>DefaultMutableTreeNode * </code> provides operations for examining and modifying a node's parent and children and also * operations for examining the tree that the node is a part of. A node's tree is the set of all * nodes that can be reached by starting at the node and following all the possible links to parents * and children. A node with no parent is the root of its tree; a node with no children is a leaf. A * tree may consist of many subtrees, each node acting as the root for its own subtree. * * <p>This class provides enumerations for efficiently traversing a tree or subtree in various * orders or for following the path between two nodes. A <code>DefaultMutableTreeNode</code> may * also hold a reference to a user object, the use of which is left to the user. Asking a <code> * DefaultMutableTreeNode</code> for its string representation with <code>toString()</code> returns * the string representation of its user object. * * <p><b>This is not a thread safe class.</b>If you intend to use a DefaultMutableTreeNode (or a * tree of TreeNodes) in more than one thread, you need to do your own synchronizing. A good * convention to adopt is synchronizing on the root node of a tree. * * <p>While DefaultMutableTreeNode implements the MutableTreeNode interface and will allow you to * add in any implementation of MutableTreeNode not all of the methods in DefaultMutableTreeNode * will be applicable to all MutableTreeNodes implementations. Especially with some of the * enumerations that are provided, using some of these methods assumes the DefaultMutableTreeNode * contains only DefaultMutableNode instances. All of the TreeNode/MutableTreeNode methods will * behave as defined no matter what implementations are added. * * <p><strong>Warning:</strong> Serialized objects of this class will not be compatible with future * Swing releases. The current serialization support is appropriate for short term storage or RMI * between applications running the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans™ has been added to the <code>j86.java.beans</code> package. Please see * {@link j86.java.beans.XMLEncoder}. * * @see MutableTreeNode * @author Rob Davis */ public class DefaultMutableTreeNode implements Cloneable, MutableTreeNode, Serializable { private static final long serialVersionUID = -4298474751201349152L; /** * An enumeration that is always empty. This is used when an enumeration of a leaf node's children * is requested. */ public static final Enumeration<TreeNode> EMPTY_ENUMERATION = Collections.emptyEnumeration(); /** this node's parent, or null if this node has no parent */ protected MutableTreeNode parent; /** array of children, may be null if this node has no children */ protected Vector children; /** optional user object */ protected transient Object userObject; /** true if the node is able to have children */ protected boolean allowsChildren; /** Creates a tree node that has no parent and no children, but which allows children. */ public DefaultMutableTreeNode() { this(null); } /** * Creates a tree node with no parent, no children, but which allows children, and initializes it * with the specified user object. * * @param userObject an Object provided by the user that constitutes the node's data */ public DefaultMutableTreeNode(Object userObject) { this(userObject, true); } /** * Creates a tree node with no parent, no children, initialized with the specified user object, * and that allows children only if specified. * * @param userObject an Object provided by the user that constitutes the node's data * @param allowsChildren if true, the node is allowed to have child nodes -- otherwise, it is * always a leaf node */ public DefaultMutableTreeNode(Object userObject, boolean allowsChildren) { super(); parent = null; this.allowsChildren = allowsChildren; this.userObject = userObject; } // // Primitives // /** * Removes <code>newChild</code> from its present parent (if it has a parent), sets the child's * parent to this node, and then adds the child to this node's child array at index <code> * childIndex</code>. <code>newChild</code> must not be null and must not be an ancestor of this * node. * * @param newChild the MutableTreeNode to insert under this node * @param childIndex the index in this node's child array where this node is to be inserted * @exception ArrayIndexOutOfBoundsException if <code>childIndex</code> is out of bounds * @exception IllegalArgumentException if <code>newChild</code> is null or is an ancestor of this * node * @exception IllegalStateException if this node does not allow children * @see #isNodeDescendant */ public void insert(MutableTreeNode newChild, int childIndex) { if (!allowsChildren) { throw new IllegalStateException("node does not allow children"); } else if (newChild == null) { throw new IllegalArgumentException("new child is null"); } else if (isNodeAncestor(newChild)) { throw new IllegalArgumentException("new child is an ancestor"); } MutableTreeNode oldParent = (MutableTreeNode) newChild.getParent(); if (oldParent != null) { oldParent.remove(newChild); } newChild.setParent(this); if (children == null) { children = new Vector(); } children.insertElementAt(newChild, childIndex); } /** * Removes the child at the specified index from this node's children and sets that node's parent * to null. The child node to remove must be a <code>MutableTreeNode</code>. * * @param childIndex the index in this node's child array of the child to remove * @exception ArrayIndexOutOfBoundsException if <code>childIndex</code> is out of bounds */ public void remove(int childIndex) { MutableTreeNode child = (MutableTreeNode) getChildAt(childIndex); children.removeElementAt(childIndex); child.setParent(null); } /** * Sets this node's parent to <code>newParent</code> but does not change the parent's child array. * This method is called from <code>insert()</code> and <code>remove()</code> to reassign a * child's parent, it should not be messaged from anywhere else. * * @param newParent this node's new parent */ @Transient public void setParent(MutableTreeNode newParent) { parent = newParent; } /** * Returns this node's parent or null if this node has no parent. * * @return this node's parent TreeNode, or null if this node has no parent */ public TreeNode getParent() { return parent; } /** * Returns the child at the specified index in this node's child array. * * @param index an index into this node's child array * @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds * @return the TreeNode in this node's child array at the specified index */ public TreeNode getChildAt(int index) { if (children == null) { throw new ArrayIndexOutOfBoundsException("node has no children"); } return (TreeNode) children.elementAt(index); } /** * Returns the number of children of this node. * * @return an int giving the number of children of this node */ public int getChildCount() { if (children == null) { return 0; } else { return children.size(); } } /** * Returns the index of the specified child in this node's child array. If the specified node is * not a child of this node, returns <code>-1</code>. This method performs a linear search and is * O(n) where n is the number of children. * * @param aChild the TreeNode to search for among this node's children * @exception IllegalArgumentException if <code>aChild</code> is null * @return an int giving the index of the node in this node's child array, or <code>-1</code> if * the specified node is a not a child of this node */ public int getIndex(TreeNode aChild) { if (aChild == null) { throw new IllegalArgumentException("argument is null"); } if (!isNodeChild(aChild)) { return -1; } return children.indexOf(aChild); // linear search } /** * Creates and returns a forward-order enumeration of this node's children. Modifying this node's * child array invalidates any child enumerations created before the modification. * * @return an Enumeration of this node's children */ public Enumeration children() { if (children == null) { return EMPTY_ENUMERATION; } else { return children.elements(); } } /** * Determines whether or not this node is allowed to have children. If <code>allows</code> is * false, all of this node's children are removed. * * <p>Note: By default, a node allows children. * * @param allows true if this node is allowed to have children */ public void setAllowsChildren(boolean allows) { if (allows != allowsChildren) { allowsChildren = allows; if (!allowsChildren) { removeAllChildren(); } } } /** * Returns true if this node is allowed to have children. * * @return true if this node allows children, else false */ public boolean getAllowsChildren() { return allowsChildren; } /** * Sets the user object for this node to <code>userObject</code>. * * @param userObject the Object that constitutes this node's user-specified data * @see #getUserObject * @see #toString */ public void setUserObject(Object userObject) { this.userObject = userObject; } /** * Returns this node's user object. * * @return the Object stored at this node by the user * @see #setUserObject * @see #toString */ public Object getUserObject() { return userObject; } // // Derived methods // /** * Removes the subtree rooted at this node from the tree, giving this node a null parent. Does * nothing if this node is the root of its tree. */ public void removeFromParent() { MutableTreeNode parent = (MutableTreeNode) getParent(); if (parent != null) { parent.remove(this); } } /** * Removes <code>aChild</code> from this node's child array, giving it a null parent. * * @param aChild a child of this node to remove * @exception IllegalArgumentException if <code>aChild</code> is null or is not a child of this * node */ public void remove(MutableTreeNode aChild) { if (aChild == null) { throw new IllegalArgumentException("argument is null"); } if (!isNodeChild(aChild)) { throw new IllegalArgumentException("argument is not a child"); } remove(getIndex(aChild)); // linear search } /** * Removes all of this node's children, setting their parents to null. If this node has no * children, this method does nothing. */ public void removeAllChildren() { for (int i = getChildCount() - 1; i >= 0; i--) { remove(i); } } /** * Removes <code>newChild</code> from its parent and makes it a child of this node by adding it to * the end of this node's child array. * * @see #insert * @param newChild node to add as a child of this node * @exception IllegalArgumentException if <code>newChild</code> is null * @exception IllegalStateException if this node does not allow children */ public void add(MutableTreeNode newChild) { if (newChild != null && newChild.getParent() == this) insert(newChild, getChildCount() - 1); else insert(newChild, getChildCount()); } // // Tree Queries // /** * Returns true if <code>anotherNode</code> is an ancestor of this node -- if it is this node, * this node's parent, or an ancestor of this node's parent. (Note that a node is considered an * ancestor of itself.) If <code>anotherNode</code> is null, this method returns false. This * operation is at worst O(h) where h is the distance from the root to this node. * * @see #isNodeDescendant * @see #getSharedAncestor * @param anotherNode node to test as an ancestor of this node * @return true if this node is a descendant of <code>anotherNode</code> */ public boolean isNodeAncestor(TreeNode anotherNode) { if (anotherNode == null) { return false; } TreeNode ancestor = this; do { if (ancestor == anotherNode) { return true; } } while ((ancestor = ancestor.getParent()) != null); return false; } /** * Returns true if <code>anotherNode</code> is a descendant of this node -- if it is this node, * one of this node's children, or a descendant of one of this node's children. Note that a node * is considered a descendant of itself. If <code>anotherNode</code> is null, returns false. This * operation is at worst O(h) where h is the distance from the root to <code>anotherNode</code>. * * @see #isNodeAncestor * @see #getSharedAncestor * @param anotherNode node to test as descendant of this node * @return true if this node is an ancestor of <code>anotherNode</code> */ public boolean isNodeDescendant(DefaultMutableTreeNode anotherNode) { if (anotherNode == null) return false; return anotherNode.isNodeAncestor(this); } /** * Returns the nearest common ancestor to this node and <code>aNode</code>. Returns null, if no * such ancestor exists -- if this node and <code>aNode</code> are in different trees or if <code> * aNode</code> is null. A node is considered an ancestor of itself. * * @see #isNodeAncestor * @see #isNodeDescendant * @param aNode node to find common ancestor with * @return nearest ancestor common to this node and <code>aNode</code>, or null if none */ public TreeNode getSharedAncestor(DefaultMutableTreeNode aNode) { if (aNode == this) { return this; } else if (aNode == null) { return null; } int level1, level2, diff; TreeNode node1, node2; level1 = getLevel(); level2 = aNode.getLevel(); if (level2 > level1) { diff = level2 - level1; node1 = aNode; node2 = this; } else { diff = level1 - level2; node1 = this; node2 = aNode; } // Go up the tree until the nodes are at the same level while (diff > 0) { node1 = node1.getParent(); diff--; } // Move up the tree until we find a common ancestor. Since we know // that both nodes are at the same level, we won't cross paths // unknowingly (if there is a common ancestor, both nodes hit it in // the same iteration). do { if (node1 == node2) { return node1; } node1 = node1.getParent(); node2 = node2.getParent(); } while (node1 != null); // only need to check one -- they're at the // same level so if one is null, the other is if (node1 != null || node2 != null) { throw new Error("nodes should be null"); } return null; } /** * Returns true if and only if <code>aNode</code> is in the same tree as this node. Returns false * if <code>aNode</code> is null. * * @see #getSharedAncestor * @see #getRoot * @return true if <code>aNode</code> is in the same tree as this node; false if <code>aNode * </code> is null */ public boolean isNodeRelated(DefaultMutableTreeNode aNode) { return (aNode != null) && (getRoot() == aNode.getRoot()); } /** * Returns the depth of the tree rooted at this node -- the longest distance from this node to a * leaf. If this node has no children, returns 0. This operation is much more expensive than * <code>getLevel()</code> because it must effectively traverse the entire tree rooted at this * node. * * @see #getLevel * @return the depth of the tree whose root is this node */ public int getDepth() { Object last = null; Enumeration enum_ = breadthFirstEnumeration(); while (enum_.hasMoreElements()) { last = enum_.nextElement(); } if (last == null) { throw new Error("nodes should be null"); } return ((DefaultMutableTreeNode) last).getLevel() - getLevel(); } /** * Returns the number of levels above this node -- the distance from the root to this node. If * this node is the root, returns 0. * * @see #getDepth * @return the number of levels above this node */ public int getLevel() { TreeNode ancestor; int levels = 0; ancestor = this; while ((ancestor = ancestor.getParent()) != null) { levels++; } return levels; } /** * Returns the path from the root, to get to this node. The last element in the path is this node. * * @return an array of TreeNode objects giving the path, where the first element in the path is * the root and the last element is this node. */ public TreeNode[] getPath() { return getPathToRoot(this, 0); } /** * Builds the parents of node up to and including the root node, where the original node is the * last element in the returned array. The length of the returned array gives the node's depth in * the tree. * * @param aNode the TreeNode to get the path for * @param depth an int giving the number of steps already taken towards the root (on recursive * calls), used to size the returned array * @return an array of TreeNodes giving the path from the root to the specified node */ protected TreeNode[] getPathToRoot(TreeNode aNode, int depth) { TreeNode[] retNodes; /* Check for null, in case someone passed in a null node, or they passed in an element that isn't rooted at root. */ if (aNode == null) { if (depth == 0) return null; else retNodes = new TreeNode[depth]; } else { depth++; retNodes = getPathToRoot(aNode.getParent(), depth); retNodes[retNodes.length - depth] = aNode; } return retNodes; } /** * Returns the user object path, from the root, to get to this node. If some of the TreeNodes in * the path have null user objects, the returned path will contain nulls. */ public Object[] getUserObjectPath() { TreeNode[] realPath = getPath(); Object[] retPath = new Object[realPath.length]; for (int counter = 0; counter < realPath.length; counter++) retPath[counter] = ((DefaultMutableTreeNode) realPath[counter]).getUserObject(); return retPath; } /** * Returns the root of the tree that contains this node. The root is the ancestor with a null * parent. * * @see #isNodeAncestor * @return the root of the tree that contains this node */ public TreeNode getRoot() { TreeNode ancestor = this; TreeNode previous; do { previous = ancestor; ancestor = ancestor.getParent(); } while (ancestor != null); return previous; } /** * Returns true if this node is the root of the tree. The root is the only node in the tree with a * null parent; every tree has exactly one root. * * @return true if this node is the root of its tree */ public boolean isRoot() { return getParent() == null; } /** * Returns the node that follows this node in a preorder traversal of this node's tree. Returns * null if this node is the last node of the traversal. This is an inefficient way to traverse the * entire tree; use an enumeration, instead. * * @see #preorderEnumeration * @return the node that follows this node in a preorder traversal, or null if this node is last */ public DefaultMutableTreeNode getNextNode() { if (getChildCount() == 0) { // No children, so look for nextSibling DefaultMutableTreeNode nextSibling = getNextSibling(); if (nextSibling == null) { DefaultMutableTreeNode aNode = (DefaultMutableTreeNode) getParent(); do { if (aNode == null) { return null; } nextSibling = aNode.getNextSibling(); if (nextSibling != null) { return nextSibling; } aNode = (DefaultMutableTreeNode) aNode.getParent(); } while (true); } else { return nextSibling; } } else { return (DefaultMutableTreeNode) getChildAt(0); } } /** * Returns the node that precedes this node in a preorder traversal of this node's tree. Returns * <code>null</code> if this node is the first node of the traversal -- the root of the tree. This * is an inefficient way to traverse the entire tree; use an enumeration, instead. * * @see #preorderEnumeration * @return the node that precedes this node in a preorder traversal, or null if this node is the * first */ public DefaultMutableTreeNode getPreviousNode() { DefaultMutableTreeNode previousSibling; DefaultMutableTreeNode myParent = (DefaultMutableTreeNode) getParent(); if (myParent == null) { return null; } previousSibling = getPreviousSibling(); if (previousSibling != null) { if (previousSibling.getChildCount() == 0) return previousSibling; else return previousSibling.getLastLeaf(); } else { return myParent; } } /** * Creates and returns an enumeration that traverses the subtree rooted at this node in preorder. * The first node returned by the enumeration's <code>nextElement()</code> method is this node. * * <p>Modifying the tree by inserting, removing, or moving a node invalidates any enumerations * created before the modification. * * @see #postorderEnumeration * @return an enumeration for traversing the tree in preorder */ public Enumeration preorderEnumeration() { return new PreorderEnumeration(this); } /** * Creates and returns an enumeration that traverses the subtree rooted at this node in postorder. * The first node returned by the enumeration's <code>nextElement()</code> method is the leftmost * leaf. This is the same as a depth-first traversal. * * <p>Modifying the tree by inserting, removing, or moving a node invalidates any enumerations * created before the modification. * * @see #depthFirstEnumeration * @see #preorderEnumeration * @return an enumeration for traversing the tree in postorder */ public Enumeration postorderEnumeration() { return new PostorderEnumeration(this); } /** * Creates and returns an enumeration that traverses the subtree rooted at this node in * breadth-first order. The first node returned by the enumeration's <code>nextElement()</code> * method is this node. * * <p>Modifying the tree by inserting, removing, or moving a node invalidates any enumerations * created before the modification. * * @see #depthFirstEnumeration * @return an enumeration for traversing the tree in breadth-first order */ public Enumeration breadthFirstEnumeration() { return new BreadthFirstEnumeration(this); } /** * Creates and returns an enumeration that traverses the subtree rooted at this node in * depth-first order. The first node returned by the enumeration's <code>nextElement()</code> * method is the leftmost leaf. This is the same as a postorder traversal. * * <p>Modifying the tree by inserting, removing, or moving a node invalidates any enumerations * created before the modification. * * @see #breadthFirstEnumeration * @see #postorderEnumeration * @return an enumeration for traversing the tree in depth-first order */ public Enumeration depthFirstEnumeration() { return postorderEnumeration(); } /** * Creates and returns an enumeration that follows the path from <code>ancestor</code> to this * node. The enumeration's <code>nextElement()</code> method first returns <code>ancestor</code>, * then the child of <code>ancestor</code> that is an ancestor of this node, and so on, and * finally returns this node. Creation of the enumeration is O(m) where m is the number of nodes * between this node and <code>ancestor</code>, inclusive. Each <code>nextElement()</code> message * is O(1). * * <p>Modifying the tree by inserting, removing, or moving a node invalidates any enumerations * created before the modification. * * @see #isNodeAncestor * @see #isNodeDescendant * @exception IllegalArgumentException if <code>ancestor</code> is not an ancestor of this node * @return an enumeration for following the path from an ancestor of this node to this one */ public Enumeration pathFromAncestorEnumeration(TreeNode ancestor) { return new PathBetweenNodesEnumeration(ancestor, this); } // // Child Queries // /** * Returns true if <code>aNode</code> is a child of this node. If <code>aNode</code> is null, this * method returns false. * * @return true if <code>aNode</code> is a child of this node; false if <code>aNode</code> is null */ public boolean isNodeChild(TreeNode aNode) { boolean retval; if (aNode == null) { retval = false; } else { if (getChildCount() == 0) { retval = false; } else { retval = (aNode.getParent() == this); } } return retval; } /** * Returns this node's first child. If this node has no children, throws NoSuchElementException. * * @return the first child of this node * @exception NoSuchElementException if this node has no children */ public TreeNode getFirstChild() { if (getChildCount() == 0) { throw new NoSuchElementException("node has no children"); } return getChildAt(0); } /** * Returns this node's last child. If this node has no children, throws NoSuchElementException. * * @return the last child of this node * @exception NoSuchElementException if this node has no children */ public TreeNode getLastChild() { if (getChildCount() == 0) { throw new NoSuchElementException("node has no children"); } return getChildAt(getChildCount() - 1); } /** * Returns the child in this node's child array that immediately follows <code>aChild</code>, * which must be a child of this node. If <code>aChild</code> is the last child, returns null. * This method performs a linear search of this node's children for <code>aChild</code> and is * O(n) where n is the number of children; to traverse the entire array of children, use an * enumeration instead. * * @see #children * @exception IllegalArgumentException if <code>aChild</code> is null or is not a child of this * node * @return the child of this node that immediately follows <code>aChild</code> */ public TreeNode getChildAfter(TreeNode aChild) { if (aChild == null) { throw new IllegalArgumentException("argument is null"); } int index = getIndex(aChild); // linear search if (index == -1) { throw new IllegalArgumentException("node is not a child"); } if (index < getChildCount() - 1) { return getChildAt(index + 1); } else { return null; } } /** * Returns the child in this node's child array that immediately precedes <code>aChild</code>, * which must be a child of this node. If <code>aChild</code> is the first child, returns null. * This method performs a linear search of this node's children for <code>aChild</code> and is * O(n) where n is the number of children. * * @exception IllegalArgumentException if <code>aChild</code> is null or is not a child of this * node * @return the child of this node that immediately precedes <code>aChild</code> */ public TreeNode getChildBefore(TreeNode aChild) { if (aChild == null) { throw new IllegalArgumentException("argument is null"); } int index = getIndex(aChild); // linear search if (index == -1) { throw new IllegalArgumentException("argument is not a child"); } if (index > 0) { return getChildAt(index - 1); } else { return null; } } // // Sibling Queries // /** * Returns true if <code>anotherNode</code> is a sibling of (has the same parent as) this node. A * node is its own sibling. If <code>anotherNode</code> is null, returns false. * * @param anotherNode node to test as sibling of this node * @return true if <code>anotherNode</code> is a sibling of this node */ public boolean isNodeSibling(TreeNode anotherNode) { boolean retval; if (anotherNode == null) { retval = false; } else if (anotherNode == this) { retval = true; } else { TreeNode myParent = getParent(); retval = (myParent != null && myParent == anotherNode.getParent()); if (retval && !((DefaultMutableTreeNode) getParent()).isNodeChild(anotherNode)) { throw new Error("sibling has different parent"); } } return retval; } /** * Returns the number of siblings of this node. A node is its own sibling (if it has no parent or * no siblings, this method returns <code>1</code>). * * @return the number of siblings of this node */ public int getSiblingCount() { TreeNode myParent = getParent(); if (myParent == null) { return 1; } else { return myParent.getChildCount(); } } /** * Returns the next sibling of this node in the parent's children array. Returns null if this node * has no parent or is the parent's last child. This method performs a linear search that is O(n) * where n is the number of children; to traverse the entire array, use the parent's child * enumeration instead. * * @see #children * @return the sibling of this node that immediately follows this node */ public DefaultMutableTreeNode getNextSibling() { DefaultMutableTreeNode retval; DefaultMutableTreeNode myParent = (DefaultMutableTreeNode) getParent(); if (myParent == null) { retval = null; } else { retval = (DefaultMutableTreeNode) myParent.getChildAfter(this); // linear search } if (retval != null && !isNodeSibling(retval)) { throw new Error("child of parent is not a sibling"); } return retval; } /** * Returns the previous sibling of this node in the parent's children array. Returns null if this * node has no parent or is the parent's first child. This method performs a linear search that is * O(n) where n is the number of children. * * @return the sibling of this node that immediately precedes this node */ public DefaultMutableTreeNode getPreviousSibling() { DefaultMutableTreeNode retval; DefaultMutableTreeNode myParent = (DefaultMutableTreeNode) getParent(); if (myParent == null) { retval = null; } else { retval = (DefaultMutableTreeNode) myParent.getChildBefore(this); // linear search } if (retval != null && !isNodeSibling(retval)) { throw new Error("child of parent is not a sibling"); } return retval; } // // Leaf Queries // /** * Returns true if this node has no children. To distinguish between nodes that have no children * and nodes that <i>cannot</i> have children (e.g. to distinguish files from empty directories), * use this method in conjunction with <code>getAllowsChildren</code> * * @see #getAllowsChildren * @return true if this node has no children */ public boolean isLeaf() { return (getChildCount() == 0); } /** * Finds and returns the first leaf that is a descendant of this node -- either this node or its * first child's first leaf. Returns this node if it is a leaf. * * @see #isLeaf * @see #isNodeDescendant * @return the first leaf in the subtree rooted at this node */ public DefaultMutableTreeNode getFirstLeaf() { DefaultMutableTreeNode node = this; while (!node.isLeaf()) { node = (DefaultMutableTreeNode) node.getFirstChild(); } return node; } /** * Finds and returns the last leaf that is a descendant of this node -- either this node or its * last child's last leaf. Returns this node if it is a leaf. * * @see #isLeaf * @see #isNodeDescendant * @return the last leaf in the subtree rooted at this node */ public DefaultMutableTreeNode getLastLeaf() { DefaultMutableTreeNode node = this; while (!node.isLeaf()) { node = (DefaultMutableTreeNode) node.getLastChild(); } return node; } /** * Returns the leaf after this node or null if this node is the last leaf in the tree. * * <p>In this implementation of the <code>MutableNode</code> interface, this operation is very * inefficient. In order to determine the next node, this method first performs a linear search in * the parent's child-list in order to find the current node. * * <p>That implementation makes the operation suitable for short traversals from a known position. * But to traverse all of the leaves in the tree, you should use <code>depthFirstEnumeration * </code> to enumerate the nodes in the tree and use <code>isLeaf</code> on each node to * determine which are leaves. * * @see #depthFirstEnumeration * @see #isLeaf * @return returns the next leaf past this node */ public DefaultMutableTreeNode getNextLeaf() { DefaultMutableTreeNode nextSibling; DefaultMutableTreeNode myParent = (DefaultMutableTreeNode) getParent(); if (myParent == null) return null; nextSibling = getNextSibling(); // linear search if (nextSibling != null) return nextSibling.getFirstLeaf(); return myParent.getNextLeaf(); // tail recursion } /** * Returns the leaf before this node or null if this node is the first leaf in the tree. * * <p>In this implementation of the <code>MutableNode</code> interface, this operation is very * inefficient. In order to determine the previous node, this method first performs a linear * search in the parent's child-list in order to find the current node. * * <p>That implementation makes the operation suitable for short traversals from a known position. * But to traverse all of the leaves in the tree, you should use <code>depthFirstEnumeration * </code> to enumerate the nodes in the tree and use <code>isLeaf</code> on each node to * determine which are leaves. * * @see #depthFirstEnumeration * @see #isLeaf * @return returns the leaf before this node */ public DefaultMutableTreeNode getPreviousLeaf() { DefaultMutableTreeNode previousSibling; DefaultMutableTreeNode myParent = (DefaultMutableTreeNode) getParent(); if (myParent == null) return null; previousSibling = getPreviousSibling(); // linear search if (previousSibling != null) return previousSibling.getLastLeaf(); return myParent.getPreviousLeaf(); // tail recursion } /** * Returns the total number of leaves that are descendants of this node. If this node is a leaf, * returns <code>1</code>. This method is O(n) where n is the number of descendants of this node. * * @see #isNodeAncestor * @return the number of leaves beneath this node */ public int getLeafCount() { int count = 0; TreeNode node; Enumeration enum_ = breadthFirstEnumeration(); // order matters not while (enum_.hasMoreElements()) { node = (TreeNode) enum_.nextElement(); if (node.isLeaf()) { count++; } } if (count < 1) { throw new Error("tree has zero leaves"); } return count; } // // Overrides // /** * Returns the result of sending <code>toString()</code> to this node's user object, or the empty * string if the node has no user object. * * @see #getUserObject */ public String toString() { if (userObject == null) { return ""; } else { return userObject.toString(); } } /** * Overridden to make clone public. Returns a shallow copy of this node; the new node has no * parent or children and has a reference to the same user object, if any. * * @return a copy of this node */ public Object clone() { DefaultMutableTreeNode newNode; try { newNode = (DefaultMutableTreeNode) super.clone(); // shallow copy -- the new node has no parent or children newNode.children = null; newNode.parent = null; } catch (CloneNotSupportedException e) { // Won't happen because we implement Cloneable throw new Error(e.toString()); } return newNode; } // Serialization support. private void writeObject(ObjectOutputStream s) throws IOException { Object[] tValues; s.defaultWriteObject(); // Save the userObject, if its Serializable. if (userObject != null && userObject instanceof Serializable) { tValues = new Object[2]; tValues[0] = "userObject"; tValues[1] = userObject; } else tValues = new Object[0]; s.writeObject(tValues); } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { Object[] tValues; s.defaultReadObject(); tValues = (Object[]) s.readObject(); if (tValues.length > 0 && tValues[0].equals("userObject")) userObject = tValues[1]; } private final class PreorderEnumeration implements Enumeration<TreeNode> { private final Stack<Enumeration> stack = new Stack<Enumeration>(); public PreorderEnumeration(TreeNode rootNode) { super(); Vector<TreeNode> v = new Vector<TreeNode>(1); v.addElement(rootNode); // PENDING: don't really need a vector stack.push(v.elements()); } public boolean hasMoreElements() { return (!stack.empty() && stack.peek().hasMoreElements()); } public TreeNode nextElement() { Enumeration enumer = stack.peek(); TreeNode node = (TreeNode) enumer.nextElement(); Enumeration children = node.children(); if (!enumer.hasMoreElements()) { stack.pop(); } if (children.hasMoreElements()) { stack.push(children); } return node; } } // End of class PreorderEnumeration final class PostorderEnumeration implements Enumeration<TreeNode> { protected TreeNode root; protected Enumeration<TreeNode> children; protected Enumeration<TreeNode> subtree; public PostorderEnumeration(TreeNode rootNode) { super(); root = rootNode; children = root.children(); subtree = EMPTY_ENUMERATION; } public boolean hasMoreElements() { return root != null; } public TreeNode nextElement() { TreeNode retval; if (subtree.hasMoreElements()) { retval = subtree.nextElement(); } else if (children.hasMoreElements()) { subtree = new PostorderEnumeration(children.nextElement()); retval = subtree.nextElement(); } else { retval = root; root = null; } return retval; } } // End of class PostorderEnumeration final class BreadthFirstEnumeration implements Enumeration<TreeNode> { protected Queue queue; public BreadthFirstEnumeration(TreeNode rootNode) { super(); Vector<TreeNode> v = new Vector<TreeNode>(1); v.addElement(rootNode); // PENDING: don't really need a vector queue = new Queue(); queue.enqueue(v.elements()); } public boolean hasMoreElements() { return (!queue.isEmpty() && ((Enumeration) queue.firstObject()).hasMoreElements()); } public TreeNode nextElement() { Enumeration enumer = (Enumeration) queue.firstObject(); TreeNode node = (TreeNode) enumer.nextElement(); Enumeration children = node.children(); if (!enumer.hasMoreElements()) { queue.dequeue(); } if (children.hasMoreElements()) { queue.enqueue(children); } return node; } // A simple queue with a linked list data structure. final class Queue { QNode head; // null if empty QNode tail; final class QNode { public Object object; public QNode next; // null if end public QNode(Object object, QNode next) { this.object = object; this.next = next; } } public void enqueue(Object anObject) { if (head == null) { head = tail = new QNode(anObject, null); } else { tail.next = new QNode(anObject, null); tail = tail.next; } } public Object dequeue() { if (head == null) { throw new NoSuchElementException("No more elements"); } Object retval = head.object; QNode oldHead = head; head = head.next; if (head == null) { tail = null; } else { oldHead.next = null; } return retval; } public Object firstObject() { if (head == null) { throw new NoSuchElementException("No more elements"); } return head.object; } public boolean isEmpty() { return head == null; } } // End of class Queue } // End of class BreadthFirstEnumeration final class PathBetweenNodesEnumeration implements Enumeration<TreeNode> { protected Stack<TreeNode> stack; public PathBetweenNodesEnumeration(TreeNode ancestor, TreeNode descendant) { super(); if (ancestor == null || descendant == null) { throw new IllegalArgumentException("argument is null"); } TreeNode current; stack = new Stack<TreeNode>(); stack.push(descendant); current = descendant; while (current != ancestor) { current = current.getParent(); if (current == null && descendant != ancestor) { throw new IllegalArgumentException( "node " + ancestor + " is not an ancestor of " + descendant); } stack.push(current); } } public boolean hasMoreElements() { return stack.size() > 0; } public TreeNode nextElement() { try { return stack.pop(); } catch (EmptyStackException e) { throw new NoSuchElementException("No more elements"); } } } // End of class PathBetweenNodesEnumeration } // End of class DefaultMutableTreeNode