View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: DupFilterIterator.java,v 1.2.4.1 2005/09/06 06:16:11 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.dom;
25  
26  import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
27  import com.sun.org.apache.xalan.internal.xsltc.util.IntegerArray;
28  import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
29  import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase;
30  import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
31  
32  /**
33   * Removes duplicates and sorts a source iterator. The nodes from the
34   * source are collected in an array upon calling setStartNode(). This
35   * array is later sorted and duplicates are ignored in next().
36   * @author G. Todd Miller
37   */
38  public final class DupFilterIterator extends DTMAxisIteratorBase {
39  
40      /**
41       * Reference to source iterator.
42       */
43      private DTMAxisIterator _source;
44  
45      /**
46       * Array to cache all nodes from source.
47       */
48      private IntegerArray _nodes = new IntegerArray();
49  
50      /**
51       * Index in _nodes array to current node.
52       */
53      private int _current = 0;
54  
55      /**
56       * Cardinality of _nodes array.
57       */
58      private int _nodesSize = 0;
59  
60      /**
61       * Last value returned by next().
62       */
63      private int _lastNext = END;
64  
65      /**
66       * Temporary variable to store _lastNext.
67       */
68      private int _markedLastNext = END;
69  
70      public DupFilterIterator(DTMAxisIterator source) {
71          _source = source;
72  // System.out.println("DFI source = " + source + " this = " + this);
73  
74          // Cache contents of id() or key() index right away. Necessary for
75          // union expressions containing multiple calls to the same index, and
76          // correct as well since start-node is irrelevant for id()/key() exrp.
77          if (source instanceof KeyIndex) {
78              setStartNode(DTMDefaultBase.ROOTNODE);
79          }
80      }
81  
82      /**
83       * Set the start node for this iterator
84       * @param node The start node
85       * @return A reference to this node iterator
86       */
87      public DTMAxisIterator setStartNode(int node) {
88          if (_isRestartable) {
89              // KeyIndex iterators are always relative to the root node, so there
90              // is never any point in re-reading the iterator (and we SHOULD NOT).
91              boolean sourceIsKeyIndex = _source instanceof KeyIndex;
92  
93              if (sourceIsKeyIndex
94                      && _startNode == DTMDefaultBase.ROOTNODE) {
95                  return this;
96              }
97  
98              if (node != _startNode) {
99                  _source.setStartNode(_startNode = node);
100 
101                 _nodes.clear();
102                 while ((node = _source.next()) != END) {
103                     _nodes.add(node);
104                 }
105 
106                 // Nodes produced by KeyIndex are known to be in document order.
107                 // Take advantage of it.
108                 if (!sourceIsKeyIndex) {
109                     _nodes.sort();
110                 }
111                 _nodesSize = _nodes.cardinality();
112                 _current = 0;
113                 _lastNext = END;
114                 resetPosition();
115             }
116         }
117         return this;
118     }
119 
120     public int next() {
121         while (_current < _nodesSize) {
122             final int next = _nodes.at(_current++);
123             if (next != _lastNext) {
124                 return returnNode(_lastNext = next);
125             }
126         }
127         return END;
128     }
129 
130     public DTMAxisIterator cloneIterator() {
131         try {
132             final DupFilterIterator clone =
133                 (DupFilterIterator) super.clone();
134             clone._nodes = (IntegerArray) _nodes.clone();
135             clone._source = _source.cloneIterator();
136             clone._isRestartable = false;
137             return clone.reset();
138         }
139         catch (CloneNotSupportedException e) {
140             BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
141                                       e.toString());
142             return null;
143         }
144     }
145 
146     public void setRestartable(boolean isRestartable) {
147         _isRestartable = isRestartable;
148         _source.setRestartable(isRestartable);
149     }
150 
151     public void setMark() {
152         _markedNode = _current;
153         _markedLastNext = _lastNext;    // Bugzilla 25924
154     }
155 
156     public void gotoMark() {
157         _current = _markedNode;
158         _lastNext = _markedLastNext;    // Bugzilla 25924
159     }
160 
161     public DTMAxisIterator reset() {
162         _current = 0;
163         _lastNext = END;
164         return resetPosition();
165     }
166 }