Skip to content

Commit 28fa257

Browse files
committed
Defines interfaces for walking an collection tree (#8)
Signed-off-by: Patrick Reinhart <patrick@reini.net>
1 parent d5129e2 commit 28fa257

File tree

4 files changed

+285
-1
lines changed

4 files changed

+285
-1
lines changed

src/main/java/org/xmldb/api/base/Collection.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ public interface Collection extends Configurable, AutoCloseable, ServiceProvider
221221
@Override
222222
void close() throws XMLDBException;
223223

224-
225224
/**
226225
* Returns the time of creation of the collection.
227226
*
@@ -232,4 +231,44 @@ public interface Collection extends Configurable, AutoCloseable, ServiceProvider
232231
* @since 2.0
233232
*/
234233
Instant getCreationTime() throws XMLDBException;
234+
235+
/**
236+
* Walks a file tree.
237+
* <p>
238+
* This method works as if invoking it were equivalent to evaluating the expression: <blockquote>
239+
*
240+
* <pre>
241+
* walkCollectionTree(Integer.MAX_VALUE, visitor)
242+
* </pre>
243+
*
244+
* </blockquote> In other words, it does not follow symbolic links, and visits all levels of the
245+
* file tree.
246+
*
247+
* @param collectionVisitor the file visitor to invoke for each file
248+
* @throws XMLDBException if an XML DB error is thrown by a visitor method
249+
*
250+
* @since 2.0
251+
*/
252+
default void walkCollectionTree(CollectionVisitor collectionVisitor) throws XMLDBException {
253+
walkCollectionTree(Integer.MAX_VALUE, collectionVisitor);
254+
}
255+
256+
/**
257+
* Walks a file tree.
258+
* <p>
259+
* The {@code maxDepth} parameter is the maximum number of levels of directories to visit. A value
260+
* of {@code 0} means that only the starting file is visited, unless denied by the security
261+
* manager. A value of {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all levels
262+
* should be visited. The {@code visitResource} method is invoked for all files, including
263+
* directories, encountered at {@code maxDepth}, unless the basic file attributes cannot be read,
264+
* in which case the {@code visitResourceFailed} method is invoked.
265+
*
266+
* @param maxDepth the maximum number of collection levels to visit
267+
* @param collectionVisitor the file visitor to invoke for each file
268+
* @throws IllegalArgumentException if the {@code maxDepth} parameter is negative
269+
* @throws XMLDBException if an XML DB error is thrown by a visitor method
270+
*
271+
* @since 2.0
272+
*/
273+
void walkCollectionTree(int maxDepth, CollectionVisitor collectionVisitor) throws XMLDBException;
235274
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* The XML:DB Initiative Software License, Version 1.0
3+
*
4+
* Copyright (c) 2000-2022 The XML:DB Initiative. All rights reserved.
5+
*
6+
* Redistribution and use in source and binary forms, with or without modification, are permitted
7+
* provided that the following conditions are met:
8+
*
9+
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
10+
* and the following disclaimer.
11+
*
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided with
14+
* the distribution.
15+
*
16+
* 3. The end-user documentation included with the redistribution, if any, must include the
17+
* following acknowledgment: "This product includes software developed by the XML:DB Initiative
18+
* (http://www.xmldb.org/)." Alternately, this acknowledgment may appear in the software itself, if
19+
* and wherever such third-party acknowledgments normally appear.
20+
*
21+
* 4. The name "XML:DB Initiative" must not be used to endorse or promote products derived from this
22+
* software without prior written permission. For written permission, please contact info@xmldb.org.
23+
*
24+
* 5. Products derived from this software may not be called "XML:DB", nor may "XML:DB" appear in
25+
* their name, without prior written permission of the XML:DB Initiative.
26+
*
27+
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29+
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR
30+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
32+
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35+
* =================================================================================================
36+
* This software consists of voluntary contributions made by many individuals on behalf of the
37+
* XML:DB Initiative. For more information on the XML:DB Initiative, please see
38+
* <https://github.com/xmldb-org/>
39+
*/
40+
package org.xmldb.api.base;
41+
42+
import java.nio.file.FileVisitor;
43+
44+
/**
45+
* The result type of a {@link CollectionVisitor}.
46+
*
47+
* @since 2.0
48+
*
49+
* @see Collection#walkCollectionTree
50+
*/
51+
public enum CollectionVisitResult {
52+
/**
53+
* Continue. When returned from a {@link CollectionVisitor#preVisitCollection preVisitCollection}
54+
* method then the entries in the directory should also be visited.
55+
*/
56+
CONTINUE,
57+
/**
58+
* Terminate.
59+
*/
60+
TERMINATE,
61+
/**
62+
* Continue without visiting the entries in this directory. This result is only meaningful when
63+
* returned from the {@link CollectionVisitor#preVisitCollection preVisitCollection} method;
64+
* otherwise this result type is the same as returning {@link #CONTINUE}.
65+
*/
66+
SKIP_SUBTREE,
67+
/**
68+
* Continue without visiting the <em>siblings</em> of this file or directory. If returned from the
69+
* {@link FileVisitor#preVisitDirectory preVisitDirectory} method then the entries in the
70+
* directory are also skipped and the {@link FileVisitor#postVisitDirectory postVisitDirectory}
71+
* method is not invoked.
72+
*/
73+
SKIP_SIBLINGS;
74+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* The XML:DB Initiative Software License, Version 1.0
3+
*
4+
* Copyright (c) 2000-2022 The XML:DB Initiative. All rights reserved.
5+
*
6+
* Redistribution and use in source and binary forms, with or without modification, are permitted
7+
* provided that the following conditions are met:
8+
*
9+
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
10+
* and the following disclaimer.
11+
*
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided with
14+
* the distribution.
15+
*
16+
* 3. The end-user documentation included with the redistribution, if any, must include the
17+
* following acknowledgment: "This product includes software developed by the XML:DB Initiative
18+
* (http://www.xmldb.org/)." Alternately, this acknowledgment may appear in the software itself, if
19+
* and wherever such third-party acknowledgments normally appear.
20+
*
21+
* 4. The name "XML:DB Initiative" must not be used to endorse or promote products derived from this
22+
* software without prior written permission. For written permission, please contact info@xmldb.org.
23+
*
24+
* 5. Products derived from this software may not be called "XML:DB", nor may "XML:DB" appear in
25+
* their name, without prior written permission of the XML:DB Initiative.
26+
*
27+
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29+
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR
30+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
32+
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35+
* =================================================================================================
36+
* This software consists of voluntary contributions made by many individuals on behalf of the
37+
* XML:DB Initiative. For more information on the XML:DB Initiative, please see
38+
* <https://github.com/xmldb-org/>
39+
*/
40+
package org.xmldb.api.base;
41+
42+
/**
43+
* A visitor of collections. An implementation of this interface is provided to the
44+
* {@link Collection#walkCollectionTree} methods to visit each resource in a collection tree.
45+
*
46+
* <p>
47+
* <b>Usage Examples:</b>
48+
* <p>
49+
* Suppose we want to delete a collection tree. In that case, each collection should be deleted
50+
* after the resources in the collection are deleted.
51+
*
52+
* <pre>
53+
* collection.walkCollectionTree(new SimpleCollectionVisitor() {
54+
* &#64;Override
55+
* public CollectionVisitResult visitResource(Resource resource) throws XMLDBException {
56+
* resource.getParentCollection().removeResource(resource);
57+
* return CollectionVisitResult.CONTINUE;
58+
* }
59+
*
60+
* &#64;Override
61+
* public CollectionVisitResult postVisitCollection(Collection collection, XMLDBException e)
62+
* throws XMLDBException {
63+
* if (e == null) {
64+
* String collectionName = collection.getName()
65+
* resource.getParentCollection().getService(CollectionManagementService.class).removeCollection(collectionName);
66+
* return CollectionVisitResult.CONTINUE;
67+
* } else {
68+
* // collection iteration failed
69+
* throw e;
70+
* }
71+
* }
72+
* });
73+
* </pre>
74+
* <p>
75+
* Furthermore, suppose we want to copy a collection tree to a target location. In that case,
76+
* symbolic links should be followed and the target collection should be created before the
77+
* resources in the collection are copied.
78+
*
79+
* <pre>
80+
* sourceColelction.walkCollectionTree(Integer.MAX_VALUE, new SimpleFileVisitor&lt;Path&gt;() {
81+
* &#64;Override
82+
* public CollectionVisitResult preVisitCollection(Collection collection) throws XMLDBException {
83+
* Path targetcollection = target.resolve(source.relativize(collection));
84+
* try {
85+
* Files.copy(collection, targetcollection);
86+
* } catch (FileAlreadyExistsException e) {
87+
* if (!Files.isDirectory(targetcollection))
88+
* throw e;
89+
* }
90+
* return CONTINUE;
91+
* }
92+
*
93+
* &#64;Override
94+
* public CollectionVisitResult visitFile(Resource resource) throws XMLDBException {
95+
* Files.copy(resource, target.resolve(source.relativize(resource)));
96+
* return CONTINUE;
97+
* }
98+
* });
99+
* </pre>
100+
*
101+
* @since 2.0
102+
*/
103+
public interface CollectionVisitor {
104+
/**
105+
* Invoked for a collection before resources in the collection are visited.
106+
*
107+
* <p>
108+
* If this method returns {@link CollectionVisitResult#CONTINUE CONTINUE}, then resources in the
109+
* collection are visited. If this method returns {@link CollectionVisitResult#SKIP_SUBTREE
110+
* SKIP_SUBTREE} or {@link CollectionVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS} then resources in
111+
* the collection (and any descendants) will not be visited.
112+
*
113+
* @param collection a reference to the collection
114+
*
115+
* @return the visit result
116+
*
117+
* @throws XMLDBException if an XML DB error occurs
118+
*/
119+
Collection preVisitCollection(Collection collection) throws XMLDBException;
120+
121+
/**
122+
* Invoked for a resource in a collection.
123+
*
124+
* @param resource a reference to the resource
125+
*
126+
* @return the visit result
127+
*
128+
* @throws XMLDBException if an XML DB error occurs
129+
*/
130+
Collection visitResource(Resource resource) throws XMLDBException;
131+
132+
/**
133+
* Invoked for a resource that could not be visited. This method is invoked if the resource's
134+
* attributes could not be read, the resource is a collection that could not be opened, and other
135+
* reasons.
136+
*
137+
* @param resource a reference to the resource
138+
* @param exc the XML DB exception that prevented the resource from being visited
139+
*
140+
* @return the visit result
141+
*
142+
* @throws XMLDBException if an XML DB error occurs
143+
*/
144+
Collection visitResourceFailed(Resource resource, XMLDBException exc) throws XMLDBException;
145+
146+
/**
147+
* Invoked for a collection after resources in the collection, and all of their descendants, have
148+
* been visited. This method is also invoked when iteration of the collection completes
149+
* prematurely (by a {@link #visitResource visitFile} method returning
150+
* {@link CollectionVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS}, or an XML DB error when iterating
151+
* over the collection).
152+
*
153+
* @param collection a reference to the collection
154+
* @param exc {@code null} if the iteration of the collection completes without an error;
155+
* otherwise the XML DB exception that caused the iteration of the collection to complete
156+
* prematurely
157+
*
158+
* @return the visit result
159+
*
160+
* @throws XMLDBException if an XML DB error occurs
161+
*/
162+
Collection postVisitCollection(Collection collection, XMLDBException exc) throws XMLDBException;
163+
164+
}

src/test/java/org/xmldb/api/TestCollection.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import java.util.Optional;
4848

4949
import org.xmldb.api.base.Collection;
50+
import org.xmldb.api.base.CollectionVisitor;
5051
import org.xmldb.api.base.Resource;
5152
import org.xmldb.api.base.Service;
5253
import org.xmldb.api.base.XMLDBException;
@@ -157,4 +158,10 @@ public void close() throws XMLDBException {
157158
public Instant getCreationTime() throws XMLDBException {
158159
return creation;
159160
}
161+
162+
@Override
163+
public void walkCollectionTree(int maxDepth, CollectionVisitor collectionVisitor)
164+
throws XMLDBException {
165+
throw new XMLDBException(NOT_IMPLEMENTED);
166+
}
160167
}

0 commit comments

Comments
 (0)