### Eclipse Workspace Patch 1.0
#P jackrabbit-jcr-commons
Index: src/main/java/org/apache/jackrabbit/flat/PropertySequence.java
===================================================================
--- src/main/java/org/apache/jackrabbit/flat/PropertySequence.java (revision 0)
+++ src/main/java/org/apache/jackrabbit/flat/PropertySequence.java (revision 0)
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.jackrabbit.flat;
+
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+/**
+ * Extension of {@link Sequence Sequence<Property>} which provides methods
+ * for adding and removing properties by key.
+ */
+public interface PropertySequence extends Sequence
+ * This class serves as main entry point for obtaining sequences of {@link Node}
+ * s and {@link Property}s. It provides factory methods for creating
+ * {@link NodeSequence}s and {@link PropertySequence}s.
+ *
+ * NodeSequence and PropertySequence instances provide a flat representation of
+ * a JCR hierarchy rooted at a certain node. They allow iterating over all
+ * items, retrieving items by key, checking whether a given key is mapped,
+ * adding new items and removing existing items.
+ *
+ * The specifics of the mapping from the flat representation to the JCR
+ * hierarchy are delegated to a {@link TreeManager}. Particularly the
+ * TreeManager specifies the order of the items when retrieved as sequence and
+ * when and how to add and remove intermediate nodes when new items are inserted
+ * or removed.
+ *
+ * An {@link ErrorHandler} is used to handle exceptions which occur while
+ * traversing the hierarchy.
+ *
+ * Utility class for traversing the {@link Item}s of a JCR hierarchy rooted at a
+ * specific {@link Node}.
+ *
+ * This class provides an {@link Iterator} of JCR items either through its
+ * implementation of {@link Iterable} or through various static factory methods.
+ * The iterators return its elements in pre-order. That is, each node occurs
+ * before its child nodes are traversed. The order in which child nodes are
+ * traversed is determined by the underlying JCR implementation. Generally the
+ * order is not specified unless a {@link Node} has orderable child nodes.
+ *
+ * Whether a specific node is included is determined by an
+ * {@link #InclusionPolicy}. Error occurring while traversing are delegated to
+ * an {@link #ErrorHandler}.
+ *
+ * This class does efficient ranking of values of type
+ * Note: The values may not contain duplicates or the behavior
+ * of
+ * This {@link TreeManager} implementation provides B+-tree like behavior. That
+ * is items of a sequence (i.e. {@link NodeSequence} or {@link PropertySequence})
+ * are mapped to a sub-tree in JCR in a way such that only leave nodes carry
+ * actual values, the sub-tree is always balanced and ordered. This
+ * implementation does in contrast to a full B+-tree implementation not
+ * join nodes after deletions. This does not affect the order of items and also
+ * leaves the tree balanced wrt. its depths. It might however result in a sparse
+ * tree. That is, the tree might get unbalanced wrt. its weights.
+ *
+ * The nodes in the JCR sub tree are arranged such that any node named
+ * Example usage:
+ *
+ * key and value.
+ *
+ * @param key key of the property to add
+ * @param value value of the property to add
+ * @return the newly added property
+ * @throws RepositoryException
+ */
+ Property addProperty(String key, Value value) throws RepositoryException;
+
+ /**
+ * Remove the property with the given key.
+ *
+ * @param key The key of the property to remove
+ * @throws RepositoryException If there is no property with such a key or
+ * another error occurs.
+ */
+ void removeProperty(String key) throws RepositoryException;
+}
\ No newline at end of file
Index: src/test/java/btree/RankTest.java
===================================================================
--- src/test/java/btree/RankTest.java (revision 0)
+++ src/test/java/btree/RankTest.java (revision 0)
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package btree;
+
+import org.apache.jackrabbit.flat.Rank;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+public class RankTest extends TestCase {
+ private static final Random rnd = new Random();
+
+ public void testEmpty() {
+ Ranknode is the root node of the
+ * JCR sub-tree.
+ *
+ * @param node Node to test for root
+ * @return getRoot().isSame(node).
+ * @throws RepositoryException
+ */
+ boolean isRoot(Node node) throws RepositoryException;
+
+ /**
+ * Determines whether the given node is a leaf. Leaf nodes are
+ * the nodes which are actually part of a {@link NodeSequence} or the
+ * parents of the properties of a {@link PropertySequence}.
+ *
+ * @param node Node to test for leaf
+ * @return true if node is a leaf node,
+ * false otherwise.
+ * @throws RepositoryException
+ */
+ boolean isLeaf(Node node) throws RepositoryException;
+
+ /**
+ * {@link Comparator} used for establishing the order of the keys in the
+ * sequence.
+ *
+ * @return a Comparator<String> instance
+ */
+ Comparatorcause has been inserted into the sequence
+ * itemSequence, the implementation of this method may decide
+ * to split the parent node of cause into two or
+ * more new nodes. Splitting must be done such that the overall order of the
+ * keys in this sequence obeys the order given by {@link #getOrder()} as
+ * much as possible.
+ *
+ * @param itemSequence the {@link ItemSequence} where the new node
+ * cause has been inserted.
+ * @param node the parent node of the newly inserted node
+ * @param cause the newly inserted node or null if not known.
+ * @throws RepositoryException
+ */
+ void split(ItemSequence itemSequence, Node node, Node cause) throws RepositoryException;
+
+ /**
+ * After the property cause has been inserted into the sequence
+ * itemSequence, the implementation of this method may decide
+ * to split the parent node of cause into two or
+ * more new nodes. Splitting must be done such that the overall order of the
+ * keys in this sequence obeys the order given by {@link #getOrder()} as
+ * much as possible.
+ *
+ * @param itemSequence the {@link ItemSequence} where the new property
+ * cause has been inserted.
+ * @param node the parent node of the newly inserted property
+ * @param cause the newly inserted property or null if not
+ * known.
+ * @throws RepositoryException
+ */
+ void split(ItemSequence itemSequence, Node node, Property cause) throws RepositoryException;
+
+ /**
+ * After the node cause has been deleted from the sequence
+ * itemSequence, the implementation of this method may decide
+ * to join the parent node of cause with some
+ * other nodes. Joining must be done such that the overall order of the keys
+ * in this sequence obeys the order given by {@link #getOrder()} as much as
+ * possible.
+ *
+ * @param itemSequence the {@link ItemSequence} where the node
+ * cause has been deleted from.
+ * @param node the parent node from which cause has been
+ * deleted.
+ * @param cause the deleted node or null if not known.
+ * Note: cause might be stale.
+ * @throws RepositoryException
+ */
+ void join(ItemSequence itemSequence, Node node, Node cause) throws RepositoryException;
+
+ /**
+ * After the property cause has been deleted from the sequence
+ * itemSequence, the implementation of this method may decide
+ * to join the parent node of cause with some
+ * other nodes. Joining must be done such that the overall order of the keys
+ * in this sequence obeys the order given by {@link #getOrder()} as much as
+ * possible.
+ *
+ * @param itemSequence the {@link ItemSequence} where the property
+ * cause has been deleted from.
+ * @param node the parent node from which cause has been
+ * deleted.
+ * @param cause the deleted property or null if not known.
+ * Note: cause might be stale.
+ * @throws RepositoryException
+ */
+ void join(ItemSequence itemSequence, Node node, Property cause) throws RepositoryException;
+
+ /**
+ * Whether to automatically save changes of the current session occurring
+ * from adding/removing nodes and properties.
+ *
+ * @return true if changes should be automatically saved,
+ * false otherwiese.
+ */
+ boolean getAutoSave();
+}
Index: src/main/java/org/apache/jackrabbit/flat/NodeSequence.java
===================================================================
--- src/main/java/org/apache/jackrabbit/flat/NodeSequence.java (revision 0)
+++ src/main/java/org/apache/jackrabbit/flat/NodeSequence.java (revision 0)
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.jackrabbit.flat;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/**
+ * Extension of {@link Sequence Sequence<Node>} which provides methods for
+ * adding and removing nodes by key.
+ */
+public interface NodeSequence extends Sequencekey and primary node type name.
+ *
+ * @param key key of the node to add
+ * @param primaryNodeTypeName primary node type of the node to add
+ * @return the newly added node
+ * @throws RepositoryException
+ */
+ Node addNode(String key, String primaryNodeTypeName) throws RepositoryException;
+
+ /**
+ * Remove the node with the given key.
+ *
+ * @param key The key of the node to remove
+ * @throws RepositoryException If there is no node with such a key or
+ * another error occurs.
+ */
+ void removeNode(String key) throws RepositoryException;
+}
\ No newline at end of file
Index: src/main/java/org/apache/jackrabbit/flat/Sequence.java
===================================================================
--- src/main/java/org/apache/jackrabbit/flat/Sequence.java (revision 0)
+++ src/main/java/org/apache/jackrabbit/flat/Sequence.java (revision 0)
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.jackrabbit.flat;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Item;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+
+import java.util.Iterator;
+
+/**
+ * Interface for accessing JCR {@link Item}s sequentially through an
+ * {@link Iterator} or looking them up through a key.
+ *
+ * @param key. If
+ * the sequence does not contain the key this method throws an
+ * {@link ItemNotFoundException}.
+ *
+ * @param key The key of the item to retrieve. Must not be
+ * null.
+ * @return The item belonging to key.
+ * @throws ItemNotFoundException
+ * @throws RepositoryException
+ */
+ T getItem(String key) throws AccessDeniedException, PathNotFoundException, ItemNotFoundException,
+ RepositoryException;
+
+ /**
+ * Determine whether this sequence contains a specific key.
+ *
+ * @param key The key to look up.
+ * @return true if this sequence contains key.
+ * False otherwise.
+ * @throws RepositoryException
+ */
+ boolean hasItem(String key) throws RepositoryException;
+}
\ No newline at end of file
Index: src/main/java/org/apache/jackrabbit/flat/ItemSequence.java
===================================================================
--- src/main/java/org/apache/jackrabbit/flat/ItemSequence.java (revision 0)
+++ src/main/java/org/apache/jackrabbit/flat/ItemSequence.java (revision 0)
@@ -0,0 +1,508 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.jackrabbit.flat;
+
+import org.apache.jackrabbit.flat.TreeTraverser.ErrorHandler;
+import org.apache.jackrabbit.flat.TreeTraverser.InclusionPolicy;
+
+import javax.jcr.ItemExistsException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+
+import java.util.Comparator;
+import java.util.Iterator;
+
+/**
+ * treeManager is
+ * null or {@link TreeManager#getRoot()} return
+ * null or {@link TreeManager#getOrder()} return
+ * null.
+ */
+ protected ItemSequence(TreeManager treeManager, ErrorHandler errorHandler) {
+ super();
+
+ if (treeManager == null) {
+ throw new IllegalArgumentException("tree manager must not be null");
+ }
+ if (treeManager.getRoot() == null) {
+ throw new IllegalArgumentException("root must not be null");
+ }
+ if (treeManager.getOrder() == null) {
+ throw new IllegalArgumentException("order must not be null");
+ }
+
+ this.treeManager = treeManager;
+ this.errorHandler = errorHandler;
+ this.root = treeManager.getRoot();
+ this.order = treeManager.getOrder();
+ this.autoSave = treeManager.getAutoSave();
+ }
+
+ /**
+ * Create a new {@link NodeSequence} instance.
+ *
+ * @param treeManager The {@link TreeManager} for managing the mapping
+ * between the sequence view and the JCR hierarchy.
+ * @param errorHandler The {@link ErrorHandler} for handling exceptions
+ * occurring while
+ * @return
+ */
+ public static NodeSequence createNodeSequence(TreeManager treeManager, ErrorHandler errorHandler) {
+ return new NodeSequenceImpl(treeManager, errorHandler);
+ }
+
+ /**
+ * Create a new {@link NodeSequence} instance.
+ *
+ * @param treeManager The {@link TreeManager} for managing the mapping
+ * between the sequence view and the JCR hierarchy.
+ * @return
+ */
+ public static NodeSequence createNodeSequence(TreeManager treeManager) {
+ return new NodeSequenceImpl(treeManager, ErrorHandler.IGNORE);
+ }
+
+ /**
+ * Create a new {@link PropertySequence} instance.
+ *
+ * @param treeManager The {@link TreeManager} for managing the mapping
+ * between the sequence view and the JCR hierarchy.
+ * @param errorHandler The {@link ErrorHandler} for handling exceptions
+ * occurring while
+ * @return
+ */
+ public static PropertySequence createPropertySequence(TreeManager treeManager, ErrorHandler errorHandler) {
+ return new PropertySequenceImpl(treeManager, errorHandler);
+ }
+
+ /**
+ * Create a new {@link PropertySequence} instance.
+ *
+ * @param treeManager The {@link TreeManager} for managing the mapping
+ * between the sequence view and the JCR hierarchy.
+ * @return
+ */
+ public static PropertySequence createPropertySequence(TreeManager treeManager) {
+ return new PropertySequenceImpl(treeManager, ErrorHandler.IGNORE);
+ }
+
+ /**
+ * Create a new {@link NodeSequence} instance with the same parametrization
+ * as this instance.
+ *
+ * @return
+ */
+ public NodeSequence getNodeSequence() {
+ return new NodeSequenceImpl(treeManager, errorHandler);
+ }
+
+ /**
+ * Create a new {@link PropertySequence} instance with the same
+ * parametrization as this instance.
+ *
+ * @return
+ */
+ public PropertySequence getPropertySequence() {
+ return new PropertySequenceImpl(treeManager, errorHandler);
+ }
+
+ // -----------------------------------------------------< internal >---
+
+ /**
+ * Returns the parent node for the given key. When the key is not present in
+ * this sequence already, the returned node is the node that would contain
+ * that key if it where present.
+ */
+ protected abstract Node getParent(String key) throws RepositoryException;
+
+ /**
+ * Returns the predecessor node for the given
+ * key. That is the node
+ * whose key directly precedes the passed key in the order
+ * determined by {@link TreeManager#getOrder()}. There are two cases:
+ *
+ *
+ */
+ protected final Node getPredecessor(String key) throws RepositoryException {
+ Node p = root;
+ Node n;
+ while ((n = getPredecessor(p, key)) != null) {
+ p = n;
+ }
+
+ return p;
+ }
+
+ /**
+ * Returns the direct predecessor of key is mapped: then that node is
+ * returned.key is not mapped: the the node
+ * where that would contain that key if present is returned.key amongst
+ * node's child nodes wrt. to {@link TreeManager#getOrder()}.
+ * Returns null if either node has no child nodes
+ * or node is a leaf (see {@link TreeManager#isLeaf(Node)}) or
+ * key is smaller than all the keys of all child nodes of
+ * node.
+ */
+ protected final Node getPredecessor(Node node, String key) throws RepositoryException {
+ if (!node.hasNodes() || treeManager.isLeaf(node)) {
+ return null;
+ }
+
+ // Shortcut for exact match
+ try {
+ return node.getNode(key);
+ }
+ catch (PathNotFoundException ignore) { }
+
+ // Search for direct predecessor of key in the nodes children
+ // todo performance: for ordered nodes use binary search
+ NodeIterator childNodes = node.getNodes();
+ Node p = null;
+ while (childNodes.hasNext()) {
+ Node n = childNodes.nextNode();
+ String childKey = n.getName();
+ if (order.compare(key, childKey) > 0 && (p == null || order.compare(childKey, p.getName()) > 0)) {
+ p = n;
+ }
+ }
+
+ return p;
+ }
+
+ /**
+ * Returns the successor node for the given
+ * key. That is the node
+ * whose key directly succeeds the passed key in the order
+ * determined by {@link TreeManager#getOrder()}. There are two cases:
+ *
+ *
+ */
+ protected final Node getSuccessor(Node node, String key) throws RepositoryException {
+ if (!node.hasNodes() || treeManager.isLeaf(node)) {
+ return null;
+ }
+
+ // Shortcut for exact match
+ try {
+ return node.getNode(key);
+ }
+ catch (PathNotFoundException ignore) { }
+
+ // Search for direct succecessor of key in the nodes children
+ // todo performance: for ordered nodes use binary search
+ NodeIterator childNodes = node.getNodes();
+ Node s = null;
+ while (childNodes.hasNext()) {
+ Node n = childNodes.nextNode();
+ String childKey = n.getName();
+ if (order.compare(key, childKey) < 0 && (s == null || order.compare(childKey, s.getName()) < 0)) {
+ s = n;
+ }
+ }
+
+ return s;
+ }
+
+ /**
+ * Returns the node with the minimal key wrt. {@link TreeManager#getOrder()}.
+ * For the empty sequence this is {@link TreeManager#getRoot()}.
+ */
+ protected final Node getMinimal() throws RepositoryException {
+ Node p = null;
+ Node n = root;
+ while ((n = getMinimal(n)) != null) {
+ p = n;
+ }
+
+ return p;
+ }
+
+ /**
+ * Returns the node amongst the child nodes of key is mapped: then that node is
+ * returned.key is not mapped: the the node
+ * where that would contain that key if present is returned.node whose key
+ * is minimal wrt. {@link TreeManager#getOrder()}. Returns null
+ * id either node has no child nodes or node is a
+ * leaf (see {@link TreeManager#isLeaf(Node)}).
+ */
+ protected final Node getMinimal(Node node) throws RepositoryException {
+ if (!node.hasNodes() || treeManager.isLeaf(node)) {
+ return null;
+ }
+
+ // Search for minimal key in the nodes children
+ // todo performance: for ordered nodes use binary search
+ NodeIterator childNodes = node.getNodes();
+ Node p = childNodes.nextNode();
+ String minKey = p.getName();
+ while (childNodes.hasNext()) {
+ Node n = childNodes.nextNode();
+ if (order.compare(n.getName(), minKey) < 0) {
+ p = n;
+ minKey = p.getName();
+ }
+ }
+
+ return p;
+ }
+
+ /**
+ * Rename the path of the node with the minimal key. That is, assuming
+ * node is the node with the minimal key (see
+ * {@link #getMinimal()}), this method renames every segment of the path of
+ * node up to {@link TreeManager#getRoot()} to key
+ * . Note: If node is not the node with the minimal
+ * key, the behavior of this method is not specified.
+ */
+ protected final void renamePath(Node node, String key) throws RepositoryException {
+ if (!treeManager.isRoot(node)) {
+ Node p = node.getParent();
+ renamePath(p, key);
+ Session s = node.getSession();
+ s.move(node.getPath(), p.getPath() + "/" + key);
+
+ // If orderable, move to first child node
+ if (p.getPrimaryNodeType().hasOrderableChildNodes()) {
+ p.orderBefore(key, p.getNodes().nextNode().getName());
+ }
+ }
+ }
+
+ protected static class NodeSequenceImpl extends ItemSequence implements NodeSequence {
+
+ public NodeSequenceImpl(TreeManager treeManager, ErrorHandler errorHandler) {
+ super(treeManager, errorHandler);
+ }
+
+ public Iteratornode.
+ *
+ * @param root The root node of the sub-tree to traverse
+ * @param errorHandler Handler for errors while traversing
+ * @param inclusionPolicy Inclusion policy to determine which nodes to
+ * include
+ */
+ public TreeTraverser(Node root, ErrorHandler errorHandler, InclusionPolicy inclusionPolicy) {
+ super();
+ this.root = root;
+ this.errorHandler = errorHandler == null? ErrorHandler.IGNORE : errorHandler;
+ this.inclusionPolicy = inclusionPolicy;
+ }
+
+ /**
+ * Create a new instance of a TreeTraverser rooted at node.
+ *
+ * @param root The root node of the sub-tree to traverse
+ */
+ public TreeTraverser(Node root) {
+ this(root, ErrorHandler.IGNORE, InclusionPolicy.ALL);
+ }
+
+ /**
+ * Error handler for handling {@link RepositoryException}s occurring on
+ * traversal. The predefined {@link #IGNORE} error handler can be used to
+ * ignore all exceptions.
+ */
+ public interface ErrorHandler {
+
+ /**
+ * Predefined error handler which ignores all exceptions.
+ */
+ public static ErrorHandler IGNORE = new ErrorHandler() {
+ public void call(Item item, RepositoryException exception) { /* ignore */ }
+ };
+
+ /**
+ * This call back method is called whenever an error occurs while
+ * traversing.
+ *
+ * @param item The item which was the target of an operation which
+ * failed and caused the exception.
+ * @param exception The exception which occurred.
+ */
+ void call(Item item, RepositoryException exception);
+ }
+
+ /**
+ * Inclusion policy to determine which nodes to include when traversing.
+ * There a two predefined inclusion policies:
+ *
+ *
+ */
+ public interface InclusionPolicy {
+
+ /**
+ * This inclusions policy includes all nodes.
+ */
+ public static InclusionPolicy ALL = new InclusionPolicy() {
+ public boolean include(Node node) {
+ return true;
+ }
+ };
+
+ /**
+ * This inclusion policy only includes leave nodes. A leaf node is a
+ * node which does not have child nodes.
+ */
+ public static InclusionPolicy LEAVES = new InclusionPolicy() {
+ public boolean include(Node node) throws RepositoryException {
+ return !node.hasNodes();
+ }
+ };
+
+ /**
+ * Call back method to determine whether to include a given node.
+ *
+ * @param node The node under consideration
+ * @return true when node should be included.
+ * false otherwise.
+ *
+ * @throws RepositoryException
+ */
+ boolean include(Node node) throws RepositoryException;
+ }
+
+ /**
+ * Create an iterator for the nodes of the sub-tree rooted at
+ * root.
+ *
+ * @param root root node of the sub-tree to traverse
+ * @param errorHandler handler for exceptions occurring on traversal
+ * @param inclusionPolicy inclusion policy to determine which nodes to
+ * include
+ * @return iterator of {@link Node}
+ */
+ public static Iteratorroot. Exceptions occurring on traversal are ignored.
+ *
+ * @param root root node of the sub-tree to traverse
+ * @return iterator of {@link Node}
+ */
+ public static Iteratorn1 occurs before node n2 in the iterator of
+ * nodes, then any property of n1 will occur before any
+ * property of n2.
+ *
+ * @param nodes nodes whose properties to chain
+ * @param errorHandler handler for exceptions occurring on traversal
+ * @return iterator of {@link Property}
+ */
+ public static Iteratorn1 occurs before node n2 in the iterator of
+ * nodes, then any property of n1 will occur before any
+ * property of n2. Exceptions occurring on traversal are
+ * ignored.
+ *
+ * @param nodes nodes whose properties to chain
+ * @return iterator of {@link Property}
+ */
+ public static Iteratorroot.
+ *
+ * @param root root node of the sub-tree to traverse
+ * @param errorHandler handler for exceptions occurring on traversal
+ * @param inclusionPolicy inclusion policy to determine which nodes to
+ * include
+ * @return iterator of {@link Property}
+ */
+ public static Iteratorroot. Exceptions occurring on traversal are ignored.
+ *
+ * @param root root node of the sub-tree to traverse
+ * @return iterator of {@link Property}
+ */
+ public static Iteratornode.
+ */
+ private Iteratorelement.
+ */
+ @SuppressWarnings("unchecked")
+ private static node.
+ */
+ private Iteratornodes. For node
+ * n1 occurring before node n2 in
+ * nodes, any property of n1 will occur before any
+ * property of n2 in the iterator.
+ */
+ private static Iteratoriterator with the concatenation
+ * of all iterators in iterators.
+ */
+ @SuppressWarnings("unchecked")
+ private static iterators.
+ */
+ private static T wrt. to a
+ * {@link Comparator} for T. After creating an instance of
+ * Rank, the {@link #take(int)} method returns the next
+ * k smallest values. That is, each of these values is smaller than
+ * every value not yet retrieved. The order of the values returned by
+ * take is not specified in general. However if the values are in
+ * increasing order, the values returned by take will also be in
+ * increasing order.
+ * take is not defined.
+ * Rank.
+ */
+public class RankRank for a given array of
+ * values and a given order. The
+ * values are manipulated in place, no copying is performed.
+ *
+ * @param values values for ranking. Duplicates are not allowed.
+ * @param order Ordering for ranking
+ */
+ public Rank(T[] values, Comparator super T> order) {
+ super();
+ this.values = values;
+ this.order = order;
+ }
+
+ /**
+ * Create a new instance of Rank for a given collection of
+ * values and a given order. The
+ * values are copied into an internal array before they are
+ * manipulated.
+ *
+ * @param values values for ranking. Duplicates are not allowed.
+ * @param componentType type evidence for the values
+ * @param order Ordering for ranking
+ */
+ @SuppressWarnings("unchecked")
+ public Rank(CollectionRank for the first
+ * count values in a a given iterator of values
+ * and a given order. The values are copied into
+ * an internal array before they are manipulated.
+ *
+ * @param values values for ranking. Duplicates are not allowed.
+ * @param componentType type evidence for the values
+ * @param count Number of items to include. -1 for all.
+ * @param order Ordering for ranking
+ */
+ @SuppressWarnings("unchecked")
+ public Rank(IteratorRank for a given array of
+ * values. The order is determined by the natural ordering of
+ * the values (i.e. through {@link Comparable}). The values are
+ * manipulated in place, no copying is performed.
+ *
+ * @param extends Comparable<S>
+ * @param values values for ranking. Duplicates are not allowed.
+ * @return A new instance of Rank.
+ */
+ public static > Rank rank(S[] values) {
+ return new Rank(values, Rank.comparableComparator());
+ }
+
+ /**
+ * Create a new instance of Rank for a given collection of
+ * values. The order is determined by the natural ordering of
+ * the values (i.e. through {@link Comparable}). The values are
+ * copied into an internal array before they are manipulated.
+ *
+ * @param extends Comparable<S>
+ * @param values values for ranking. Duplicates are not allowed.
+ * @param componentType type evidence for the values
+ * @return A new instance of Rank.
+ */
+ public static > Rank rank(Collection values, Class componentType) {
+ return new Rank(values, componentType, Rank.comparableComparator());
+ }
+
+ /**
+ * Create a new instance of Rank for the first
+ * count values in a a given iterator of values.
+ * The order is determined by the natural ordering of the values (i.e.
+ * through {@link Comparable}). The values are copied into an
+ * internal array before they are manipulated.
+ *
+ * @param extends Comparable<S>
+ * @param values values for ranking. Duplicates are not allowed.
+ * @param componentType type evidence for the values
+ * @param count Number of items to include. -1 for all.
+ * @return A new instance of Rank.
+ */
+ public static > Rank rank(Iterator values, Class componentType, int count) {
+ return new Rank(values, componentType, count, Rank.comparableComparator());
+ }
+
+ /**
+ * Utility method for creating a {@link Comparator} of T from a
+ * {@link Comparable} of type T.
+ *
+ * @param T.
+ */
+ public static n-th smallest values remaining in this
+ * Rank.
+ *
+ * @param n Number of values to return
+ * @return An iterator containing the next n smallest values.
+ * @throws NoSuchElementException if this Rank has not enough
+ * remaining elements or when n is negative.
+ */
+ public IteratorRank.
+ *
+ * @return number of remaining items.
+ */
+ public int size() {
+ return values.length - first;
+ }
+
+ // -----------------------------------------------------< internal >---
+
+ /**
+ * Rearrange {@link #values} such that each of the n first
+ * values starting at from is smaller that all the remaining
+ * items up to to.
+ */
+ private void take(int n, int from, int to) {
+ // Shortcut for all values
+ if (n >= to - from + 1) {
+ return;
+ }
+
+ // Choosing the n-th value as pivot results in correct partitioning after one pass
+ // for already ordered values.
+ int pivot = from + n - 1;
+ int lo = from;
+ int hi = to;
+
+ // Partition values around pivot
+ while (lo < hi) {
+ // Find values to swap around the pivot
+ while (order.compare(values[lo], values[pivot]) < 0) lo++;
+ while (order.compare(values[hi], values[pivot]) > 0) hi--;
+ if (lo < hi) {
+ // Swap values and keep track of pivot position in case the pivot itself is swapped
+ if (lo == pivot) pivot = hi;
+ else if (hi == pivot) pivot = lo;
+ swap(lo, hi);
+ lo++;
+ hi--;
+ }
+ }
+
+ // Actual number of values taken
+ int nn = pivot + 1 - from;
+ if (nn > n) { // Recurse: take first n elements from first partition
+ take(n, from, pivot);
+ }
+ else if (nn < n) { // Recurse: take first n - nn elements from second partition
+ take(n - nn, pivot + 1, to);
+ }
+ // else done
+ }
+
+ private void swap(int lo, int hi) {
+ T t1 = values[lo];
+ T t2 = values[hi];
+ if (order.compare(t1, t2) == 0) {
+ throw new IllegalStateException("Detected duplicates " + t1);
+ }
+ values[lo] = t2;
+ values[hi] = t1;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static x
+ * only contains child nodes with names greater or equal to x.
+ * The implementation keeps the child nodes in the sub tree ordered if the
+ * respective node type supports ordering of child nodes.
+ * Ordering is always wrt. to a {@link Comparator} on the respective keys.
+ * For lexical order this arrangement corresponds to how words are arranged in a multi
+ * volume encyclopedia.
+ *
+ * // Create a new TreeManager instance rooted at node. Splitting of nodes takes place
+ * // when the number of children of a node exceeds 40 and is done such that each new
+ * // node has at least 40 child nodes. The keys are ordered according to the natural
+ * // order of java.lang.String.
+ * TreeManager treeManager = new BTreeManager(node, 20, 40, Rank.<String>comparableComparator(), true);
+ *
+ * // Create a new NodeSequence with that tree manager
+ * NodeSequence nodes = ItemSequence.createNodeSequence(treeManager);
+ *
+ * // Add nodes with key "jcr" and "day"
+ * nodes.addNode("jcr", NodeType.NT_UNSTRUCTURED);
+ * nodes.addNode("day", NodeType.NT_UNSTRUCTURED);
+ *
+ * // Iterate over the node in the sequence.
+ * // Prints "day jcr "
+ * for (Node n : nodes) {
+ * System.out.print(n.getName() + " ");
+ * }
+ *
+ * // Retrieve node with key "jcr"
+ * Node n = nodes.getItem("jcr");
+ *
+ * // Remove node with key "day"
+ * nodes.removeNode("day");
+ *
+ *
+ *
root.
+ *
+ * @param root the root of the JCR sub-tree where the items of the sequence
+ * are stored.
+ * @param minChildren minimal number of children for a node after splitting.
+ * @param maxChildren maximal number of children for a node after which
+ * splitting occurs.
+ * @param order order according to which the keys are stored
+ * @param autoSave determines whether the current session is saved after
+ * add/delete operations.
+ * @throws RepositoryException
+ */
+ public BTreeManager(Node root, int minChildren, int maxChildren, Comparatornode when its number of child
+ * nodes exceeds the maximum number specified in the constructor. Splitting
+ * is done such that after the split each of the new child nodes contains at
+ * least as many nodes as specified in the constructor.
+ *
+ * @see org.apache.jackrabbit.flat.TreeManager#split(org.apache.jackrabbit.flat.ItemSequence,
+ * javax.jcr.Node, javax.jcr.Node)
+ */
+ public void split(ItemSequence itemSequence, Node node, Node cause) throws RepositoryException {
+ SizedIteratornode when its number of
+ * properties exceeds the maximum number specified in the constructor.
+ * Splitting is done such that after the split each of the new child nodes
+ * contains at least as many nodes as specified in the constructor.
+ *
+ * @see org.apache.jackrabbit.flat.TreeManager#split(org.apache.jackrabbit.flat.ItemSequence,
+ * javax.jcr.Node, javax.jcr.Property)
+ */
+ public void split(ItemSequence itemSequence, Node node, Property cause) throws RepositoryException {
+ SizedIteratornode if {@link #getNodes(Node)} returns an empty
+ * iterator. It does further recursively delete any parent of
+ * node which does not have any child node.
+ *
+ * @see org.apache.jackrabbit.flat.TreeManager#join(org.apache.jackrabbit.flat.ItemSequence,
+ * javax.jcr.Node, javax.jcr.Node)
+ */
+ public void join(ItemSequence itemSequence, Node node, Node cause) throws RepositoryException {
+ SizedIteratornode if {@link #getProperties(Node)} returns an empty
+ * iterator. It does further recursively delete any parent of
+ * node which does not have any child node.
+ *
+ * @see org.apache.jackrabbit.flat.TreeManager#join(org.apache.jackrabbit.flat.ItemSequence,
+ * javax.jcr.Node, javax.jcr.Property)
+ */
+ public void join(ItemSequence itemSequence, Node node, Property cause) throws RepositoryException {
+ SizedIterator!node.hasNodes()
+ * @see org.apache.jackrabbit.flat.TreeManager#isLeaf(javax.jcr.Node)
+ */
+ public boolean isLeaf(Node node) throws RepositoryException {
+ return !node.hasNodes();
+ }
+
+ public Comparatornode.
+ */
+ @SuppressWarnings("unchecked")
+ protected SizedIteratornode which
+ * excludes the jcr.primaryType property.
+ */
+ protected SizedIteratorname
+ * as child node of parent.
+ */
+ protected Node createIntermediateNode(Node parent, String name) throws RepositoryException {
+ return parent.addNode(name);
+ }
+
+ /**
+ * Move node to the new parent.
+ */
+ protected void move(Node node, Node parent) throws RepositoryException {
+ String oldPath = node.getPath();
+ String newPath = parent.getPath() + "/" + node.getName();
+ node.getSession().move(oldPath, newPath);
+ }
+
+ /**
+ * Move property to the new parent.
+ */
+ protected void move(Property property, Node parent) throws RepositoryException {
+ parent.setProperty(property.getName(), property.getValue());
+ property.remove();
+ }
+
+ /**
+ * Wraps iterator into a {@link SizedIterator} given a
+ * size. The value of the size parameter must
+ * correctly reflect the number of items in iterator.Ê
+ */
+ protected final SizedIterator extends {@link Iterator} with a
+ * getSize method.
+ *
+ * @param