Index: src/main/java/org/apache/jackrabbit/commons/JcrUtils.java =================================================================== --- src/main/java/org/apache/jackrabbit/commons/JcrUtils.java (revision 1463860) +++ src/main/java/org/apache/jackrabbit/commons/JcrUtils.java (working copy) @@ -49,9 +49,17 @@ import javax.jcr.Session; import javax.jcr.Value; import javax.jcr.nodetype.NodeType; +import javax.jcr.nodetype.NodeTypeIterator; +import javax.jcr.observation.Event; +import javax.jcr.observation.EventIterator; +import javax.jcr.observation.EventListener; +import javax.jcr.observation.EventListenerIterator; import javax.jcr.query.QueryResult; import javax.jcr.query.Row; import javax.jcr.query.RowIterator; +import javax.jcr.security.AccessControlPolicyIterator; +import javax.jcr.version.Version; +import javax.jcr.version.VersionIterator; /** * Collection of static utility methods for use with the JCR API. @@ -721,6 +729,188 @@ } /** + * Transform any type of {@link Iterator} into an {@link Iterable} + * for single use in a Java 5 for-each loop. + *

+ * While general purpose Iterables tend to be reusable, + * this wrapper Iterable consumes the argument + * Iterator, leaving it in a non-reusable state. The returned + * Iterable will throw an IllegalStateException if + * its iterator() method is invoked a second time. + * + * @param iterator + * The input Iterator + * @return The wrapping Iterable + */ + public static Iterable in(final Iterator iterator) { + return new Iterable() { + private boolean stale = false; + + @Override + public synchronized Iterator iterator() { + if (stale) { + throw new IllegalStateException("Cannot reuse Iterable intended for single use"); + } + + stale = true; + return iterator; + } + }; + } + + /** + * Transform an {@link AccessControlPolicyIterator} into an {@link Iterable} + * for single use in a Java 5 for-each loop. + *

+ * While general purpose Iterables tend to be reusable, + * this wrapper Iterable consumes the argument + * Iterator, leaving it in a non-reusable state. The returned + * Iterable will throw an IllegalStateException if + * its iterator() method is invoked a second time. + * + * @param iterator + * The input Iterator + * @return The wrapping Iterable + */ + @SuppressWarnings("unchecked") + public static Iterable in(AccessControlPolicyIterator iterator) { + return in((Iterator) iterator); + } + + /** + * Transform an {@link EventIterator} into an {@link Iterable} + * for single use in a Java 5 for-each loop. + *

+ * While general purpose Iterables tend to be reusable, + * this wrapper Iterable consumes the argument + * Iterator, leaving it in a non-reusable state. The returned + * Iterable will throw an IllegalStateException if + * its iterator() method is invoked a second time. + * + * @param iterator + * The input Iterator + * @return The wrapping Iterable + */ + @SuppressWarnings("unchecked") + public static Iterable in(EventIterator iterator) { + return in((Iterator) iterator); + } + + /** + * Transform an {@link EventListenerIterator} into an {@link Iterable} + * for single use in a Java 5 for-each loop. + *

+ * While general purpose Iterables tend to be reusable, + * this wrapper Iterable consumes the argument + * Iterator, leaving it in a non-reusable state. The returned + * Iterable will throw an IllegalStateException if + * its iterator() method is invoked a second time. + * + * @param iterator + * The input Iterator + * @return The wrapping Iterable + */ + @SuppressWarnings("unchecked") + public static Iterable in(EventListenerIterator iterator) { + return in((Iterator) iterator); + } + + /** + * Transform an {@link NodeIterator} into an {@link Iterable} + * for single use in a Java 5 for-each loop. + *

+ * While general purpose Iterables tend to be reusable, + * this wrapper Iterable consumes the argument + * Iterator, leaving it in a non-reusable state. The returned + * Iterable will throw an IllegalStateException if + * its iterator() method is invoked a second time. + * + * @param iterator + * The input Iterator + * @return The wrapping Iterable + */ + @SuppressWarnings("unchecked") + public static Iterable in(NodeIterator iterator) { + return in((Iterator) iterator); + } + + /** + * Transform an {@link NodeTypeIterator} into an {@link Iterable} + * for single use in a Java 5 for-each loop. + *

+ * While general purpose Iterables tend to be reusable, + * this wrapper Iterable consumes the argument + * Iterator, leaving it in a non-reusable state. The returned + * Iterable will throw an IllegalStateException if + * its iterator() method is invoked a second time. + * + * @param iterator + * The input Iterator + * @return The wrapping Iterable + */ + @SuppressWarnings("unchecked") + public static Iterable in(NodeTypeIterator iterator) { + return in((Iterator) iterator); + } + + /** + * Transform an {@link PropertyIterator} into an {@link Iterable} + * for single use in a Java 5 for-each loop. + *

+ * While general purpose Iterables tend to be reusable, + * this wrapper Iterable consumes the argument + * Iterator, leaving it in a non-reusable state. The returned + * Iterable will throw an IllegalStateException if + * its iterator() method is invoked a second time. + * + * @param iterator + * The input Iterator + * @return The wrapping Iterable + */ + @SuppressWarnings("unchecked") + public static Iterable in(PropertyIterator iterator) { + return in((Iterator) iterator); + } + + /** + * Transform an {@link RowIterator} into an {@link Iterable} + * for single use in a Java 5 for-each loop. + *

+ * While general purpose Iterables tend to be reusable, + * this wrapper Iterable consumes the argument + * Iterator, leaving it in a non-reusable state. The returned + * Iterable will throw an IllegalStateException if + * its iterator() method is invoked a second time. + * + * @param iterator + * The input Iterator + * @return The wrapping Iterable + */ + @SuppressWarnings("unchecked") + public static Iterable in(RowIterator iterator) { + return in((Iterator) iterator); + } + + /** + * Transform an {@link VersionIterator} into an {@link Iterable} + * for single use in a Java 5 for-each loop. + *

+ * While general purpose Iterables tend to be reusable, + * this wrapper Iterable consumes the argument + * Iterator, leaving it in a non-reusable state. The returned + * Iterable will throw an IllegalStateException if + * its iterator() method is invoked a second time. + * + * @param iterator + * The input Iterator + * @return The wrapping Iterable + */ + @SuppressWarnings("unchecked") + public static Iterable in(VersionIterator iterator) { + return in((Iterator) iterator); + } + + /** * Returns the named child of the given node, creating the child if * it does not already exist. If the child node gets added, then its * type will be determined by the child node definitions associated Index: src/main/java/org/apache/jackrabbit/commons/iterator/Iterators.java =================================================================== --- src/main/java/org/apache/jackrabbit/commons/iterator/Iterators.java (revision 1463843) +++ src/main/java/org/apache/jackrabbit/commons/iterator/Iterators.java (working copy) @@ -1,170 +0,0 @@ -/* - * 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.iterator; - -import java.util.Iterator; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Property; -import javax.jcr.PropertyIterator; -import javax.jcr.nodetype.NodeType; -import javax.jcr.nodetype.NodeTypeIterator; -import javax.jcr.observation.Event; -import javax.jcr.observation.EventIterator; -import javax.jcr.observation.EventListener; -import javax.jcr.observation.EventListenerIterator; -import javax.jcr.query.Row; -import javax.jcr.query.RowIterator; -import javax.jcr.security.AccessControlPolicyIterator; -import javax.jcr.version.Version; -import javax.jcr.version.VersionIterator; - -/** - * A utility class providing static access to Iterator wrappers - * that are contained in this package. - *

- * By static importing - * org.apache.jackrabbit.commons.iterator.Iterators.iterable, you - * will be able to transform any {@link Iterator} from the JCR API into a - * corresponding {@link Iterable} for use in a Java 5 foreach loop. - *

- * An example: - *

- *

- * import static org.apache.jackrabbit.commons.iterator.Iterators.iterable;
- *
- * // And then:
- * for (Node n : iterable(parent.getNodes())) {
- *   // Do stuff with n
- * }
- * 
- * - * @since Apache Jackrabbit 2.7 - */ -public class Iterators { - - /** - * Transform any type of {@link Iterator} into an {@link Iterable} - * - * @param iterator - * The input Iterator - * @return The wrapping Iterable - */ - public static Iterable iterable(final Iterator iterator) { - return new Iterable() { - @Override - public Iterator iterator() { - return iterator; - } - }; - } - - /** - * Transform an {@link AccessControlPolicyIterator} into an {@link Iterable} - * - * @param iterator - * The input Iterator - * @return The wrapping Iterable - */ - @SuppressWarnings("unchecked") - public static Iterable iterable(AccessControlPolicyIterator iterator) { - return iterable((Iterator) iterator); - } - - /** - * Transform an {@link EventIterator} into an {@link Iterable} - * - * @param iterator - * The input Iterator - * @return The wrapping Iterable - */ - @SuppressWarnings("unchecked") - public static Iterable iterable(EventIterator iterator) { - return iterable((Iterator) iterator); - } - - /** - * Transform an {@link EventListenerIterator} into an {@link Iterable} - * - * @param iterator - * The input Iterator - * @return The wrapping Iterable - */ - @SuppressWarnings("unchecked") - public static Iterable iterable(EventListenerIterator iterator) { - return iterable((Iterator) iterator); - } - - /** - * Transform an {@link NodeIterator} into an {@link Iterable} - * - * @param iterator - * The input Iterator - * @return The wrapping Iterable - */ - public static Iterable iterable(NodeIterator iterator) { - return new NodeIterable(iterator); - } - - /** - * Transform an {@link NodeTypeIterator} into an {@link Iterable} - * - * @param iterator - * The input Iterator - * @return The wrapping Iterable - */ - @SuppressWarnings("unchecked") - public static Iterable iterable(NodeTypeIterator iterator) { - return iterable((Iterator) iterator); - } - - /** - * Transform an {@link PropertyIterator} into an {@link Iterable} - * - * @param iterator - * The input Iterator - * @return The wrapping Iterable - */ - public static Iterable iterable(PropertyIterator iterator) { - return new PropertyIterable(iterator); - } - - /** - * Transform an {@link RowIterator} into an {@link Iterable} - * - * @param iterator - * The input Iterator - * @return The wrapping Iterable - */ - public static Iterable iterable(RowIterator iterator) { - return new RowIterable(iterator); - } - - /** - * Transform an {@link VersionIterator} into an {@link Iterable} - * - * @param iterator - * The input Iterator - * @return The wrapping Iterable - */ - @SuppressWarnings("unchecked") - public static Iterable iterable(VersionIterator iterator) { - return iterable((Iterator) iterator); - } - -} Index: src/main/java/org/apache/jackrabbit/commons/iterator/NodeIterable.java =================================================================== --- src/main/java/org/apache/jackrabbit/commons/iterator/NodeIterable.java (revision 1463843) +++ src/main/java/org/apache/jackrabbit/commons/iterator/NodeIterable.java (working copy) @@ -21,13 +21,17 @@ import javax.jcr.Node; import javax.jcr.NodeIterator; +import org.apache.jackrabbit.commons.JcrUtils; + /** * Adapter class that adapts a {@link NodeIterator} instance to an * {@link Iterable} instance that always returns the same underlying * iterator. * * @since Apache Jackrabbit 2.0 + * @deprecated - Use {@link JcrUtils#in(NodeIterator)} instead */ +@Deprecated public class NodeIterable implements Iterable { /** Index: src/main/java/org/apache/jackrabbit/commons/iterator/PropertyIterable.java =================================================================== --- src/main/java/org/apache/jackrabbit/commons/iterator/PropertyIterable.java (revision 1463843) +++ src/main/java/org/apache/jackrabbit/commons/iterator/PropertyIterable.java (working copy) @@ -21,13 +21,17 @@ import javax.jcr.Property; import javax.jcr.PropertyIterator; +import org.apache.jackrabbit.commons.JcrUtils; + /** * Adapter class that adapts a {@link PropertyIterator} instance to an * {@link Iterable} instance that always returns the same underlying * iterator. * * @since Apache Jackrabbit 2.0 + * @deprecated - Use {@link JcrUtils#in(PropertyIterator)} instead */ +@Deprecated public class PropertyIterable implements Iterable { /** Index: src/main/java/org/apache/jackrabbit/commons/iterator/RowIterable.java =================================================================== --- src/main/java/org/apache/jackrabbit/commons/iterator/RowIterable.java (revision 1463843) +++ src/main/java/org/apache/jackrabbit/commons/iterator/RowIterable.java (working copy) @@ -21,13 +21,17 @@ import javax.jcr.query.Row; import javax.jcr.query.RowIterator; +import org.apache.jackrabbit.commons.JcrUtils; + /** * Adapter class that adapts a {@link RowIterator} instance to an * {@link Iterable} instance that always returns the same underlying * iterator. * * @since Apache Jackrabbit 2.0 + * @deprecated - Use {@link JcrUtils#in(RowIterator)} instead */ +@Deprecated public class RowIterable implements Iterable { /** Index: src/test/java/org/apache/jackrabbit/commons/JcrUtilsTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/commons/JcrUtilsTest.java (revision 1457742) +++ src/test/java/org/apache/jackrabbit/commons/JcrUtilsTest.java (working copy) @@ -16,8 +16,10 @@ */ package org.apache.jackrabbit.commons; +import java.util.Arrays; import java.util.HashMap; import java.util.Hashtable; +import java.util.Iterator; import java.util.Map; import javax.jcr.PropertyType; @@ -76,4 +78,19 @@ assertEquals(PropertyType.DATE, JcrUtils.getPropertyType( PropertyType.TYPENAME_DATE.toUpperCase())); } + + public void testIn() { + Iterable iterable = JcrUtils.in(Arrays.asList("A").iterator()); + Iterator iterator = iterable.iterator(); + assertNotNull(iterator); + assertTrue(iterator.hasNext()); + assertEquals("A", iterator.next()); + assertFalse(iterator.hasNext()); + + try { + iterable.iterator(); + fail("Second execution of Iterable.iterator() should throw an exception"); + } catch (IllegalStateException expected) { + } + } }