All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jackrabbit.commons.flat.TreeTraverser Maven / Gradle / Ivy

The newest version!
/*
 * 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.commons.flat;

import static org.apache.jackrabbit.commons.iterator.LazyIteratorChain.chain;

import org.apache.jackrabbit.commons.iterator.FilterIterator;
import org.apache.jackrabbit.commons.predicate.Predicate;

import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.RepositoryException;

import java.util.Collections;
import java.util.Iterator;

/**
 * 

* 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}. *

*/ public final class TreeTraverser implements Iterable { private final Node root; private final ErrorHandler errorHandler; private final InclusionPolicy inclusionPolicy; /** * Create a new instance of a TreeTraverser rooted at node. * * @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 items to include when traversing. * There a two predefined inclusion policies: *
    *
  • {@link #ALL} includes all items.
  • *
  • {@link #LEAVES} includes only leave nodes. A leaf node is a node * which does not have child nodes.
  • *
*/ public interface InclusionPolicy { /** * This inclusions policy includes all items. */ public static InclusionPolicy ALL = new InclusionPolicy() { public boolean include(Item item) { return true; } }; /** * This inclusion policy includes leave nodes only. A leaf * node is a node which does not have child nodes. */ public static InclusionPolicy LEAVES = new InclusionPolicy() { public boolean include(Node node) { try { return !node.hasNodes(); } catch (RepositoryException e) { return false; } } }; /** * Call back method to determine whether to include a given item. * * @param item The item under consideration * @return true when item should be included. * false otherwise. */ boolean include(T item); } /** * 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 Iterator nodeIterator(Node root, ErrorHandler errorHandler, InclusionPolicy inclusionPolicy) { return new TreeTraverser(root, errorHandler, inclusionPolicy).iterator(); } /** * Create an iterator for the nodes of the sub-tree rooted at * root. Exceptions occurring on traversal are ignored. * * @param root root node of the sub-tree to traverse * @return iterator of {@link Node} */ public static Iterator nodeIterator(Node root) { return nodeIterator(root, ErrorHandler.IGNORE, InclusionPolicy.ALL); } /** * Create an iterator of the properties for a given iterator of nodes. The * order of the returned properties is only specified so far that if node * n1 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 * @param inclusionPolicy inclusion policy to determine properties items to include * * @return iterator of {@link Property} */ public static Iterator propertyIterator(Iterator nodes, ErrorHandler errorHandler, InclusionPolicy inclusionPolicy) { return filter(chain(propertyIterators(nodes, errorHandler)), inclusionPolicy); } /** * Create an iterator of the properties for a given iterator of nodes. The * order of the returned properties is only specified so far that if node * n1 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 Iterator propertyIterator(Iterator nodes) { return propertyIterator(nodes, ErrorHandler.IGNORE, InclusionPolicy.ALL); } /** * Create an iterator of the properties of all 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 items to * include * @return iterator of {@link Property} */ public static Iterator propertyIterator(Node root, ErrorHandler errorHandler, InclusionPolicy inclusionPolicy) { return propertyIterator(nodeIterator(root, errorHandler, inclusionPolicy), errorHandler, inclusionPolicy); } /** * Create an iterator of the properties of all nodes of the sub-tree rooted * at root. Exceptions occurring on traversal are ignored. * * @param root root node of the sub-tree to traverse * @return iterator of {@link Property} */ public static Iterator propertyIterator(Node root) { return propertyIterator(root, ErrorHandler.IGNORE, InclusionPolicy.ALL); } /** * Returns an iterator of {@link Node} for this instance. * * @see TreeTraverser#TreeTraverser(Node, ErrorHandler, InclusionPolicy) * @see java.lang.Iterable#iterator() */ public Iterator iterator() { return iterator(root); } // -----------------------------------------------------< internal >--- /** * Returns an iterator of the nodes of the sub-tree rooted at * node. */ @SuppressWarnings("unchecked") private Iterator iterator(Node node) { if (inclusionPolicy.include(node)) { return chain(singleton(node), chain(childIterators(node))); } else { return chain(childIterators(node)); } } /** * Returns an iterator of iterators of the child nodes of node. */ private Iterator> childIterators(Node node) { try { final NodeIterator childNodes = node.getNodes(); return new Iterator>() { public boolean hasNext() { return childNodes.hasNext(); } public Iterator next() { return iterator(childNodes.nextNode()); } public void remove() { throw new UnsupportedOperationException(); } }; } catch (RepositoryException e) { errorHandler.call(node, e); return empty(); } } /** * Returns an iterator of all properties of all nodes. 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 Iterator> propertyIterators(final Iterator nodes, final ErrorHandler errorHandler) { return new Iterator>() { public boolean hasNext() { return nodes.hasNext(); } @SuppressWarnings("unchecked") public Iterator next() { Node n = nodes.next(); try { return n.getProperties(); } catch (RepositoryException e) { errorHandler.call(n, e); return empty(); } } public void remove() { throw new UnsupportedOperationException(); } }; } // -----------------------------------------------------< utility >--- private static Iterator empty() { return Collections.emptySet().iterator(); } private Iterator singleton(T value) { return Collections.singleton(value).iterator(); } /** * Filtering items not matching the inclusionPolicy from * iterator. */ private static Iterator filter(final Iterator iterator, final InclusionPolicy inclusionPolicy) { return new FilterIterator(iterator, new Predicate() { @SuppressWarnings("unchecked") public boolean evaluate(Object object) { return inclusionPolicy.include((T) object); } }); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy