diff --git a/src/main/java/org/xmldb/api/base/Collection.java b/src/main/java/org/xmldb/api/base/Collection.java index 453ec02..dbb5a5c 100644 --- a/src/main/java/org/xmldb/api/base/Collection.java +++ b/src/main/java/org/xmldb/api/base/Collection.java @@ -221,7 +221,6 @@ public interface Collection extends Configurable, AutoCloseable, ServiceProvider @Override void close() throws XMLDBException; - /** * Returns the time of creation of the collection. * @@ -232,4 +231,44 @@ public interface Collection extends Configurable, AutoCloseable, ServiceProvider * @since 2.0 */ Instant getCreationTime() throws XMLDBException; + + /** + * Walks a file tree. + *

+ * This method works as if invoking it were equivalent to evaluating the expression:

+ * + *
+   * walkCollectionTree(Integer.MAX_VALUE, visitor)
+   * 
+ * + *
In other words, it does not follow symbolic links, and visits all levels of the + * file tree. + * + * @param collectionVisitor the file visitor to invoke for each file + * @throws XMLDBException if an XML DB error is thrown by a visitor method + * + * @since 2.0 + */ + default void walkCollectionTree(CollectionVisitor collectionVisitor) throws XMLDBException { + walkCollectionTree(Integer.MAX_VALUE, collectionVisitor); + } + + /** + * Walks a file tree. + *

+ * The {@code maxDepth} parameter is the maximum number of levels of directories to visit. A value + * of {@code 0} means that only the starting file is visited, unless denied by the security + * manager. A value of {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all levels + * should be visited. The {@code visitResource} method is invoked for all files, including + * directories, encountered at {@code maxDepth}, unless the basic file attributes cannot be read, + * in which case the {@code visitResourceFailed} method is invoked. + * + * @param maxDepth the maximum number of collection levels to visit + * @param collectionVisitor the file visitor to invoke for each file + * @throws IllegalArgumentException if the {@code maxDepth} parameter is negative + * @throws XMLDBException if an XML DB error is thrown by a visitor method + * + * @since 2.0 + */ + void walkCollectionTree(int maxDepth, CollectionVisitor collectionVisitor) throws XMLDBException; } diff --git a/src/main/java/org/xmldb/api/base/CollectionVisitResult.java b/src/main/java/org/xmldb/api/base/CollectionVisitResult.java new file mode 100644 index 0000000..aeaa5a3 --- /dev/null +++ b/src/main/java/org/xmldb/api/base/CollectionVisitResult.java @@ -0,0 +1,74 @@ +/* + * The XML:DB Initiative Software License, Version 1.0 + * + * Copyright (c) 2000-2022 The XML:DB Initiative. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must include the + * following acknowledgment: "This product includes software developed by the XML:DB Initiative + * (http://www.xmldb.org/)." Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The name "XML:DB Initiative" must not be used to endorse or promote products derived from this + * software without prior written permission. For written permission, please contact info@xmldb.org. + * + * 5. Products derived from this software may not be called "XML:DB", nor may "XML:DB" appear in + * their name, without prior written permission of the XML:DB Initiative. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ================================================================================================= + * This software consists of voluntary contributions made by many individuals on behalf of the + * XML:DB Initiative. For more information on the XML:DB Initiative, please see + * + */ +package org.xmldb.api.base; + +import java.nio.file.FileVisitor; + +/** + * The result type of a {@link CollectionVisitor}. + * + * @since 2.0 + * + * @see Collection#walkCollectionTree + */ +public enum CollectionVisitResult { + /** + * Continue. When returned from a {@link CollectionVisitor#preVisitCollection preVisitCollection} + * method then the entries in the directory should also be visited. + */ + CONTINUE, + /** + * Terminate. + */ + TERMINATE, + /** + * Continue without visiting the entries in this directory. This result is only meaningful when + * returned from the {@link CollectionVisitor#preVisitCollection preVisitCollection} method; + * otherwise this result type is the same as returning {@link #CONTINUE}. + */ + SKIP_SUBTREE, + /** + * Continue without visiting the siblings of this file or directory. If returned from the + * {@link FileVisitor#preVisitDirectory preVisitDirectory} method then the entries in the + * directory are also skipped and the {@link FileVisitor#postVisitDirectory postVisitDirectory} + * method is not invoked. + */ + SKIP_SIBLINGS; +} diff --git a/src/main/java/org/xmldb/api/base/CollectionVisitor.java b/src/main/java/org/xmldb/api/base/CollectionVisitor.java new file mode 100644 index 0000000..44cc332 --- /dev/null +++ b/src/main/java/org/xmldb/api/base/CollectionVisitor.java @@ -0,0 +1,164 @@ +/* + * The XML:DB Initiative Software License, Version 1.0 + * + * Copyright (c) 2000-2022 The XML:DB Initiative. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must include the + * following acknowledgment: "This product includes software developed by the XML:DB Initiative + * (http://www.xmldb.org/)." Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The name "XML:DB Initiative" must not be used to endorse or promote products derived from this + * software without prior written permission. For written permission, please contact info@xmldb.org. + * + * 5. Products derived from this software may not be called "XML:DB", nor may "XML:DB" appear in + * their name, without prior written permission of the XML:DB Initiative. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ================================================================================================= + * This software consists of voluntary contributions made by many individuals on behalf of the + * XML:DB Initiative. For more information on the XML:DB Initiative, please see + * + */ +package org.xmldb.api.base; + +/** + * A visitor of collections. An implementation of this interface is provided to the + * {@link Collection#walkCollectionTree} methods to visit each resource in a collection tree. + * + *

+ * Usage Examples: + *

+ * Suppose we want to delete a collection tree. In that case, each collection should be deleted + * after the resources in the collection are deleted. + * + *

+ * collection.walkCollectionTree(new SimpleCollectionVisitor() {
+ *   @Override
+ *   public CollectionVisitResult visitResource(Resource resource) throws XMLDBException {
+ *     resource.getParentCollection().removeResource(resource);
+ *     return CollectionVisitResult.CONTINUE;
+ *   }
+ * 
+ *   @Override
+ *   public CollectionVisitResult postVisitCollection(Collection collection, XMLDBException e)
+ *       throws XMLDBException {
+ *     if (e == null) {
+ *       String collectionName = collection.getName()
+ *       resource.getParentCollection().getService(CollectionManagementService.class).removeCollection(collectionName);
+ *       return CollectionVisitResult.CONTINUE;
+ *     } else {
+ *       // collection iteration failed
+ *       throw e;
+ *     }
+ *   }
+ * });
+ * 
+ *

+ * Furthermore, suppose we want to copy a collection tree to a target location. In that case, + * symbolic links should be followed and the target collection should be created before the + * resources in the collection are copied. + * + *

+ * sourceColelction.walkCollectionTree(Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
+ *   @Override
+ *   public CollectionVisitResult preVisitCollection(Collection collection) throws XMLDBException {
+ *     Path targetcollection = target.resolve(source.relativize(collection));
+ *     try {
+ *       Files.copy(collection, targetcollection);
+ *     } catch (FileAlreadyExistsException e) {
+ *       if (!Files.isDirectory(targetcollection))
+ *         throw e;
+ *     }
+ *     return CONTINUE;
+ *   }
+ * 
+ *   @Override
+ *   public CollectionVisitResult visitFile(Resource resource) throws XMLDBException {
+ *     Files.copy(resource, target.resolve(source.relativize(resource)));
+ *     return CONTINUE;
+ *   }
+ * });
+ * 
+ * + * @since 2.0 + */ +public interface CollectionVisitor { + /** + * Invoked for a collection before resources in the collection are visited. + * + *

+ * If this method returns {@link CollectionVisitResult#CONTINUE CONTINUE}, then resources in the + * collection are visited. If this method returns {@link CollectionVisitResult#SKIP_SUBTREE + * SKIP_SUBTREE} or {@link CollectionVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS} then resources in + * the collection (and any descendants) will not be visited. + * + * @param collection a reference to the collection + * + * @return the visit result + * + * @throws XMLDBException if an XML DB error occurs + */ + Collection preVisitCollection(Collection collection) throws XMLDBException; + + /** + * Invoked for a resource in a collection. + * + * @param resource a reference to the resource + * + * @return the visit result + * + * @throws XMLDBException if an XML DB error occurs + */ + Collection visitResource(Resource resource) throws XMLDBException; + + /** + * Invoked for a resource that could not be visited. This method is invoked if the resource's + * attributes could not be read, the resource is a collection that could not be opened, and other + * reasons. + * + * @param resource a reference to the resource + * @param exc the XML DB exception that prevented the resource from being visited + * + * @return the visit result + * + * @throws XMLDBException if an XML DB error occurs + */ + Collection visitResourceFailed(Resource resource, XMLDBException exc) throws XMLDBException; + + /** + * Invoked for a collection after resources in the collection, and all of their descendants, have + * been visited. This method is also invoked when iteration of the collection completes + * prematurely (by a {@link #visitResource visitFile} method returning + * {@link CollectionVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS}, or an XML DB error when iterating + * over the collection). + * + * @param collection a reference to the collection + * @param exc {@code null} if the iteration of the collection completes without an error; + * otherwise the XML DB exception that caused the iteration of the collection to complete + * prematurely + * + * @return the visit result + * + * @throws XMLDBException if an XML DB error occurs + */ + Collection postVisitCollection(Collection collection, XMLDBException exc) throws XMLDBException; + +} diff --git a/src/test/java/org/xmldb/api/TestCollection.java b/src/test/java/org/xmldb/api/TestCollection.java index c50c7cf..05d204e 100644 --- a/src/test/java/org/xmldb/api/TestCollection.java +++ b/src/test/java/org/xmldb/api/TestCollection.java @@ -47,6 +47,7 @@ import java.util.Optional; import org.xmldb.api.base.Collection; +import org.xmldb.api.base.CollectionVisitor; import org.xmldb.api.base.Resource; import org.xmldb.api.base.Service; import org.xmldb.api.base.XMLDBException; @@ -157,4 +158,10 @@ public void close() throws XMLDBException { public Instant getCreationTime() throws XMLDBException { return creation; } + + @Override + public void walkCollectionTree(int maxDepth, CollectionVisitor collectionVisitor) + throws XMLDBException { + throw new XMLDBException(NOT_IMPLEMENTED); + } } diff --git a/src/test/java/org/xmldb/api/base/CollectionTest.java b/src/test/java/org/xmldb/api/base/CollectionTest.java new file mode 100644 index 0000000..98f40f6 --- /dev/null +++ b/src/test/java/org/xmldb/api/base/CollectionTest.java @@ -0,0 +1,62 @@ +/* + * The XML:DB Initiative Software License, Version 1.0 + * + * Copyright (c) 2000-2022 The XML:DB Initiative. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must include the + * following acknowledgment: "This product includes software developed by the XML:DB Initiative + * (http://www.xmldb.org/)." Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The name "XML:DB Initiative" must not be used to endorse or promote products derived from this + * software without prior written permission. For written permission, please contact info@xmldb.org. + * + * 5. Products derived from this software may not be called "XML:DB", nor may "XML:DB" appear in + * their name, without prior written permission of the XML:DB Initiative. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ================================================================================================= + * This software consists of voluntary contributions made by many individuals on behalf of the + * XML:DB Initiative. For more information on the XML:DB Initiative, please see + * + */ +package org.xmldb.api.base; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.mockito.Mockito.verify; + +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoSettings; + +@MockitoSettings +class CollectionTest { + @Spy + Collection collection; + @Mock + CollectionVisitor collectionVisitor; + + @Test + void testWalkCollectionTree() throws XMLDBException { + assertThatNoException().isThrownBy(() -> collection.walkCollectionTree(collectionVisitor)); + verify(collection).walkCollectionTree(Integer.MAX_VALUE, collectionVisitor); + } +} diff --git a/src/test/java/org/xmldb/api/base/CollectionVisitResultTest.java b/src/test/java/org/xmldb/api/base/CollectionVisitResultTest.java new file mode 100644 index 0000000..a1cc47f --- /dev/null +++ b/src/test/java/org/xmldb/api/base/CollectionVisitResultTest.java @@ -0,0 +1,56 @@ +/* + * The XML:DB Initiative Software License, Version 1.0 + * + * Copyright (c) 2000-2022 The XML:DB Initiative. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must include the + * following acknowledgment: "This product includes software developed by the XML:DB Initiative + * (http://www.xmldb.org/)." Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The name "XML:DB Initiative" must not be used to endorse or promote products derived from this + * software without prior written permission. For written permission, please contact info@xmldb.org. + * + * 5. Products derived from this software may not be called "XML:DB", nor may "XML:DB" appear in + * their name, without prior written permission of the XML:DB Initiative. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ================================================================================================= + * This software consists of voluntary contributions made by many individuals on behalf of the + * XML:DB Initiative. For more information on the XML:DB Initiative, please see + * + */ +package org.xmldb.api.base; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.xmldb.api.base.CollectionVisitResult.CONTINUE; +import static org.xmldb.api.base.CollectionVisitResult.SKIP_SIBLINGS; +import static org.xmldb.api.base.CollectionVisitResult.SKIP_SUBTREE; +import static org.xmldb.api.base.CollectionVisitResult.TERMINATE; + +import org.junit.jupiter.api.Test; + +class CollectionVisitResultTest { + @Test + void testValidValues() { + assertThat(CollectionVisitResult.values()).containsExactly(CONTINUE, TERMINATE, SKIP_SUBTREE, + SKIP_SIBLINGS); + } +}