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.xalan.internal.xsltc.dom;
23 
24 import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
25 import com.sun.org.apache.xalan.internal.xsltc.util.IntegerArray;
26 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
27 import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase;
28 import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
29 
30 /**
31  * Removes duplicates and sorts a source iterator. The nodes from the
32  * source are collected in an array upon calling setStartNode(). This
33  * array is later sorted and duplicates are ignored in next().
34  * @author G. Todd Miller
35  */
36 public final class DupFilterIterator extends DTMAxisIteratorBase {
37 
38     /**
39      * Reference to source iterator.
40      */
41     private DTMAxisIterator _source;
42 
43     /**
44      * Array to cache all nodes from source.
45      */
46     private IntegerArray _nodes = new IntegerArray();
47 
48     /**
49      * Index in _nodes array to current node.
50      */
51     private int _current = 0;
52 
53     /**
54      * Cardinality of _nodes array.
55      */
56     private int _nodesSize = 0;
57 
58     /**
59      * Last value returned by next().
60      */
61     private int _lastNext = END;
62 
63     /**
64      * Temporary variable to store _lastNext.
65      */
66     private int _markedLastNext = END;
67 
DupFilterIterator(DTMAxisIterator source)68     public DupFilterIterator(DTMAxisIterator source) {
69         _source = source;
70 // System.out.println("DFI source = " + source + " this = " + this);
71 
72         // Cache contents of id() or key() index right away. Necessary for
73         // union expressions containing multiple calls to the same index, and
74         // correct as well since start-node is irrelevant for id()/key() exrp.
75         if (source instanceof KeyIndex) {
76             setStartNode(DTMDefaultBase.ROOTNODE);
77         }
78     }
79 
80     /**
81      * Set the start node for this iterator
82      * @param node The start node
83      * @return A reference to this node iterator
84      */
setStartNode(int node)85     public DTMAxisIterator setStartNode(int node) {
86         if (_isRestartable) {
87             // KeyIndex iterators are always relative to the root node, so there
88             // is never any point in re-reading the iterator (and we SHOULD NOT).
89             boolean sourceIsKeyIndex = _source instanceof KeyIndex;
90 
91             if (sourceIsKeyIndex
92                     && _startNode == DTMDefaultBase.ROOTNODE) {
93                 return this;
94             }
95 
96             if (node != _startNode) {
97                 _source.setStartNode(_startNode = node);
98 
99                 _nodes.clear();
100                 while ((node = _source.next()) != END) {
101                     _nodes.add(node);
102                 }
103 
104                 // Nodes produced by KeyIndex are known to be in document order.
105                 // Take advantage of it.
106                 if (!sourceIsKeyIndex) {
107                     _nodes.sort();
108                 }
109                 _nodesSize = _nodes.cardinality();
110                 _current = 0;
111                 _lastNext = END;
112                 resetPosition();
113             }
114         }
115         return this;
116     }
117 
next()118     public int next() {
119         while (_current < _nodesSize) {
120             final int next = _nodes.at(_current++);
121             if (next != _lastNext) {
122                 return returnNode(_lastNext = next);
123             }
124         }
125         return END;
126     }
127 
cloneIterator()128     public DTMAxisIterator cloneIterator() {
129         try {
130             final DupFilterIterator clone =
131                 (DupFilterIterator) super.clone();
132             clone._nodes = (IntegerArray) _nodes.clone();
133             clone._source = _source.cloneIterator();
134             clone._isRestartable = false;
135             return clone.reset();
136         }
137         catch (CloneNotSupportedException e) {
138             BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
139                                       e.toString());
140             return null;
141         }
142     }
143 
setRestartable(boolean isRestartable)144     public void setRestartable(boolean isRestartable) {
145         _isRestartable = isRestartable;
146         _source.setRestartable(isRestartable);
147     }
148 
setMark()149     public void setMark() {
150         _markedNode = _current;
151         _markedLastNext = _lastNext;    // Bugzilla 25924
152     }
153 
gotoMark()154     public void gotoMark() {
155         _current = _markedNode;
156         _lastNext = _markedLastNext;    // Bugzilla 25924
157     }
158 
reset()159     public DTMAxisIterator reset() {
160         _current = 0;
161         _lastNext = END;
162         return resetPosition();
163     }
164 }
165