1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 /*
6  * Licensed to the Apache Software Foundation (ASF) under one or more
7  * contributor license agreements.  See the NOTICE file distributed with
8  * this work for additional information regarding copyright ownership.
9  * The ASF licenses this file to You under the Apache License, Version 2.0
10  * (the "License"); you may not use this file except in compliance with
11  * the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 package com.sun.org.apache.xml.internal.dtm.ref;
23 
24 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
25 
26 /**
27  * This class serves as a default base for implementations of mutable
28  * DTMAxisIterators.
29  */
30 public abstract class DTMAxisIteratorBase implements DTMAxisIterator
31 {
32 
33   /** The position of the last node within the iteration, as defined by XPath.
34    * Note that this is _not_ the node's handle within the DTM. Also, don't
35    * confuse it with the current (most recently returned) position.
36    */
37   protected int _last = -1;
38 
39   /** The position of the current node within the iteration, as defined by XPath.
40    * Note that this is _not_ the node's handle within the DTM!
41    */
42   protected int _position = 0;
43 
44   /** The position of the marked node within the iteration;
45    * a saved itaration state that we may want to come back to.
46    * Note that only one mark is maintained; there is no stack.
47    */
48   protected int _markedNode;
49 
50   /** The handle to the start, or root, of the iteration.
51    * Set this to END to construct an empty iterator.
52    */
53   protected int _startNode = DTMAxisIterator.END;
54 
55   /** True if the start node should be considered part of the iteration.
56    * False will cause it to be skipped.
57    */
58   protected boolean _includeSelf = false;
59 
60   /** True if this iteration can be restarted. False otherwise (eg, if
61    * we are iterating over a stream that can not be re-scanned, or if
62    * the iterator was produced by cloning another iterator.)
63    */
64   protected boolean _isRestartable = true;
65 
66   /**
67    * Get start to END should 'close' the iterator,
68    * i.e. subsequent call to next() should return END.
69    *
70    * @return The root node of the iteration.
71    */
getStartNode()72   public int getStartNode()
73   {
74     return _startNode;
75   }
76 
77   /**
78    * @return A DTMAxisIterator which has been reset to the start node,
79    * which may or may not be the same as this iterator.
80    * */
reset()81   public DTMAxisIterator reset()
82   {
83 
84     final boolean temp = _isRestartable;
85 
86     _isRestartable = true;
87 
88     setStartNode(_startNode);
89 
90     _isRestartable = temp;
91 
92     return this;
93   }
94 
95   /**
96    * Set the flag to include the start node in the iteration.
97    *
98    *
99    * @return This default method returns just returns this DTMAxisIterator,
100    * after setting the flag.
101    * (Returning "this" permits C++-style chaining of
102    * method calls into a single expression.)
103    */
includeSelf()104   public DTMAxisIterator includeSelf()
105   {
106 
107     _includeSelf = true;
108 
109     return this;
110   }
111 
112   /** Returns the position of the last node within the iteration, as
113    * defined by XPath.  In a forward iterator, I believe this equals the number of nodes which this
114    * iterator will yield. In a reverse iterator, I believe it should return
115    * 1 (since the "last" is the first produced.)
116    *
117    * This may be an expensive operation when called the first time, since
118    * it may have to iterate through a large part of the document to produce
119    * its answer.
120    *
121    * @return The number of nodes in this iterator (forward) or 1 (reverse).
122    */
getLast()123   public int getLast()
124   {
125 
126     if (_last == -1)            // Not previously established
127     {
128       // Note that we're doing both setMark() -- which saves _currentChild
129       // -- and explicitly saving our position counter (number of nodes
130       // yielded so far).
131       //
132       // %REVIEW% Should position also be saved by setMark()?
133       // (It wasn't in the XSLTC version, but I don't understand why not.)
134 
135       final int temp = _position; // Save state
136       setMark();
137 
138       reset();                  // Count the nodes found by this iterator
139       do
140       {
141         _last++;
142       }
143       while (next() != END);
144 
145       gotoMark();               // Restore saved state
146       _position = temp;
147     }
148 
149     return _last;
150   }
151 
152   /**
153    * @return The position of the current node within the set, as defined by
154    * XPath. Note that this is one-based, not zero-based.
155    */
getPosition()156   public int getPosition()
157   {
158     return _position == 0 ? 1 : _position;
159   }
160 
161   /**
162    * @return true if this iterator has a reversed axis, else false
163    */
isReverse()164   public boolean isReverse()
165   {
166     return false;
167   }
168 
169   /**
170    * Returns a deep copy of this iterator. Cloned iterators may not be
171    * restartable. The iterator being cloned may or may not become
172    * non-restartable as a side effect of this operation.
173    *
174    * @return a deep copy of this iterator.
175    */
cloneIterator()176   public DTMAxisIterator cloneIterator()
177   {
178 
179     try
180     {
181       final DTMAxisIteratorBase clone = (DTMAxisIteratorBase) super.clone();
182 
183       clone._isRestartable = false;
184 
185       // return clone.reset();
186       return clone;
187     }
188     catch (CloneNotSupportedException e)
189     {
190       throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
191     }
192   }
193 
194   /**
195    * Do any final cleanup that is required before returning the node that was
196    * passed in, and then return it. The intended use is
197    * <br />
198    * <code>return returnNode(node);</code>
199    *
200    * %REVIEW% If we're calling it purely for side effects, should we really
201    * be bothering with a return value? Something like
202    * <br />
203    * <code> accept(node); return node; </code>
204    * <br />
205    * would probably optimize just about as well and avoid questions
206    * about whether what's returned could ever be different from what's
207    * passed in.
208    *
209    * @param node Node handle which iteration is about to yield.
210    *
211    * @return The node handle passed in.  */
returnNode(final int node)212   protected final int returnNode(final int node)
213   {
214     _position++;
215 
216     return node;
217   }
218 
219   /**
220    * Reset the position to zero. NOTE that this does not change the iteration
221    * state, only the position number associated with that state.
222    *
223    * %REVIEW% Document when this would be used?
224    *
225    * @return This instance.
226    */
resetPosition()227   protected final DTMAxisIterator resetPosition()
228   {
229 
230     _position = 0;
231 
232     return this;
233   }
234 
235   /**
236    * Returns true if all the nodes in the iteration well be returned in document
237    * order.
238    *
239    * @return true as a default.
240    */
isDocOrdered()241   public boolean isDocOrdered()
242   {
243     return true;
244   }
245 
246   /**
247    * Returns the axis being iterated, if it is known.
248    *
249    * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
250    * types.
251    */
getAxis()252   public int getAxis()
253   {
254     return -1;
255   }
256 
setRestartable(boolean isRestartable)257   public void setRestartable(boolean isRestartable) {
258     _isRestartable = isRestartable;
259   }
260 
261   /**
262    * Return the node at the given position.
263    *
264    * @param position The position
265    * @return The node at the given position.
266    */
getNodeByPosition(int position)267   public int getNodeByPosition(int position)
268   {
269     if (position > 0) {
270       final int pos = isReverse() ? getLast() - position + 1
271                                    : position;
272       int node;
273       while ((node = next()) != DTMAxisIterator.END) {
274         if (pos == getPosition()) {
275           return node;
276         }
277       }
278     }
279     return END;
280   }
281 
282 }
283