001: /*
002: * Copyright 2006 Day Management AG, Switzerland. All rights reserved.
003: */
004: package javax.jcr.util;
005:
006: import javax.jcr.*;
007: import java.util.LinkedList;
008:
009: /**
010: * An implementation of <code>ItemVisitor</code>.
011: * <p/>
012: * <code>TraversingItemVisitor</code> is an abstract utility class
013: * which allows to easily traverse an <code>Item</code> hierarchy.
014: * <p/>
015: * <p><code>TraversingItemVisitor</code> makes use of the Visitor Pattern
016: * as described in the book 'Design Patterns' by the Gang Of Four
017: * (Gamma et al.).
018: * <p/>
019: * <p>Tree traversal is done observing the left-to-right order of
020: * child <code>Item</code>s if such an order is supported and exists.
021: *
022: */
023: public abstract class TraversingItemVisitor implements ItemVisitor {
024:
025: /**
026: * indicates if traversal should be done in a breadth-first
027: * manner rather than depth-first (which is the default)
028: */
029: final protected boolean breadthFirst;
030:
031: /**
032: * the 0-based level up to which the hierarchy should be traversed
033: * (if it's -1, the hierarchy will be traversed until there are no
034: * more children of the current item)
035: */
036: final protected int maxLevel;
037:
038: /**
039: * queues used to implement breadth-first traversal
040: */
041: private LinkedList currentQueue;
042: private LinkedList nextQueue;
043:
044: /**
045: * used to track hierarchy level of item currently being processed
046: */
047: private int currentLevel;
048:
049: /**
050: * Constructs a new instance of this class.
051: * <p/>
052: * The tree of <code>Item</code>s will be traversed in a
053: * depth-first manner (default behaviour).
054: */
055: public TraversingItemVisitor() {
056: this (false, -1);
057: }
058:
059: /**
060: * Constructs a new instance of this class.
061: *
062: * @param breadthFirst if <code>breadthFirst</code> is true then traversal
063: * is done in a breadth-first manner; otherwise it is done in a
064: * depth-first manner (which is the default behaviour).
065: */
066: public TraversingItemVisitor(boolean breadthFirst) {
067: this (breadthFirst, -1);
068: }
069:
070: /**
071: * Constructs a new instance of this class.
072: *
073: * @param breadthFirst if <code>breadthFirst</code> is true then traversal
074: * is done in a breadth-first manner; otherwise it is
075: * done in a depth-first manner (which is the default
076: * behaviour).
077: * @param maxLevel the 0-based level up to which the hierarchy should be
078: * traversed (if it's -1, the hierarchy will be traversed
079: * until there are no more children of the current item)
080: */
081: public TraversingItemVisitor(boolean breadthFirst, int maxLevel) {
082: this .breadthFirst = breadthFirst;
083: if (breadthFirst) {
084: currentQueue = new LinkedList();
085: nextQueue = new LinkedList();
086: }
087: currentLevel = 0;
088: this .maxLevel = maxLevel;
089: }
090:
091: /**
092: * Implement this method to add behaviour performed before a
093: * <code>Property</code> is visited.
094: *
095: * @param property the <code>Property</code> that is accepting this visitor.
096: * @param level hierarchy level of this property (the root node starts at level 0)
097: * @throws RepositoryException if an error occurrs
098: */
099: protected abstract void entering(Property property, int level)
100: throws RepositoryException;
101:
102: /**
103: * Implement this method to add behaviour performed before a
104: * <code>Node</code> is visited.
105: *
106: * @param node the <code>Node</code> that is accepting this visitor.
107: * @param level hierarchy level of this node (the root node starts at level 0)
108: * @throws RepositoryException if an error occurrs
109: */
110: protected abstract void entering(Node node, int level)
111: throws RepositoryException;
112:
113: /**
114: * Implement this method to add behaviour performed after a
115: * <code>Property</code> is visited.
116: *
117: * @param property the <code>Property</code> that is accepting this visitor.
118: * @param level hierarchy level of this property (the root node starts at level 0)
119: * @throws RepositoryException if an error occurrs
120: */
121: protected abstract void leaving(Property property, int level)
122: throws RepositoryException;
123:
124: /**
125: * Implement this method to add behaviour performed after a
126: * <code>Node</code> is visited.
127: *
128: * @param node the <code>Node</code> that is accepting this visitor.
129: * @param level hierarchy level of this node (the root node starts at level 0)
130: * @throws RepositoryException if an error occurrs
131: */
132: protected abstract void leaving(Node node, int level)
133: throws RepositoryException;
134:
135: /**
136: * Called when the Visitor is passed to a <code>Property</code>.
137: * <p/>
138: * It calls <code>TraversingItemVisitor.entering(Property, int)</code> followed by
139: * <code>TraversingItemVisitor.leaving(Property, int)</code>. Implement these abstract methods to
140: * specify behaviour on 'arrival at' and 'after leaving' the <code>Property</code>.
141: * <p/>
142: * <p/>
143: * If this method throws, the visiting process is aborted.
144: *
145: * @param property the <code>Property</code> that is accepting this visitor.
146: * @throws RepositoryException if an error occurrs
147: */
148: public void visit(Property property) throws RepositoryException {
149: entering(property, currentLevel);
150: leaving(property, currentLevel);
151: }
152:
153: /**
154: * Called when the Visitor is passed to a <code>Node</code>.
155: * <p/>
156: * It calls <code>TraversingItemVisitor.entering(Node, int)</code> followed by
157: * <code>TraversingItemVisitor.leaving(Node, int)</code>. Implement these abstract methods to
158: * specify behaviour on 'arrival at' and 'after leaving' the <code>Node</code>.
159: * <p/>
160: * If this method throws, the visiting process is aborted.
161: *
162: * @param node the <code>Node</code> that is accepting this visitor.
163: * @throws RepositoryException if an error occurrs
164: */
165: public void visit(Node node) throws RepositoryException {
166: try {
167: if (!breadthFirst) {
168: // depth-first traversal
169: entering(node, currentLevel);
170: if (maxLevel == -1 || currentLevel < maxLevel) {
171: currentLevel++;
172: PropertyIterator propIter = node.getProperties();
173: while (propIter.hasNext()) {
174: propIter.nextProperty().accept(this );
175: }
176: NodeIterator nodeIter = node.getNodes();
177: while (nodeIter.hasNext()) {
178: nodeIter.nextNode().accept(this );
179: }
180: currentLevel--;
181: }
182: leaving(node, currentLevel);
183: } else {
184: // breadth-first traversal
185: entering(node, currentLevel);
186: leaving(node, currentLevel);
187:
188: if (maxLevel == -1 || currentLevel < maxLevel) {
189: PropertyIterator propIter = node.getProperties();
190: while (propIter.hasNext()) {
191: nextQueue.addLast(propIter.nextProperty());
192: }
193: NodeIterator nodeIter = node.getNodes();
194: while (nodeIter.hasNext()) {
195: nextQueue.addLast(nodeIter.nextNode());
196: }
197: }
198:
199: while (!currentQueue.isEmpty() || !nextQueue.isEmpty()) {
200: if (currentQueue.isEmpty()) {
201: currentLevel++;
202: currentQueue = nextQueue;
203: nextQueue = new LinkedList();
204: }
205: Item e = (Item) currentQueue.removeFirst();
206: e.accept(this );
207: }
208: currentLevel = 0;
209: }
210: } catch (RepositoryException re) {
211: currentLevel = 0;
212: throw re;
213: }
214: }
215:
216: /**
217: * Convenience class providing default implementations of the abstract methods
218: * of <code>TraversingItemVisitor</code>.
219: */
220: public static class Default extends TraversingItemVisitor {
221:
222: /**
223: * @see TraversingItemVisitor#TraversingItemVisitor()
224: */
225: public Default() {
226: }
227:
228: /**
229: * @see TraversingItemVisitor#TraversingItemVisitor()
230: */
231: public Default(boolean breadthFirst) {
232: super (breadthFirst);
233: }
234:
235: /**
236: * @see TraversingItemVisitor#TraversingItemVisitor(boolean, int)
237: */
238: public Default(boolean breadthFirst, int maxLevel) {
239: super (breadthFirst, maxLevel);
240: }
241:
242: /**
243: * @see TraversingItemVisitor#entering(Node, int)
244: */
245: protected void entering(Node node, int level)
246: throws RepositoryException {
247: }
248:
249: /**
250: * @see TraversingItemVisitor#entering(Property, int)
251: */
252: protected void entering(Property property, int level)
253: throws RepositoryException {
254: }
255:
256: /**
257: * @see TraversingItemVisitor#leaving(Node, int)
258: */
259: protected void leaving(Node node, int level)
260: throws RepositoryException {
261: }
262:
263: /**
264: * @see TraversingItemVisitor#leaving(Property, int)
265: */
266: protected void leaving(Property property, int level)
267: throws RepositoryException {
268: }
269: }
270: }
|