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.AbstractTranslet;
  25 import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
  26 import com.sun.org.apache.xalan.internal.xsltc.util.IntegerArray;
  27 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  28 import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase;
  29 
  30 /**
  31  * Iterators of this kind use a CurrentNodeListFilter to filter a subset of
  32  * nodes from a source iterator. For each node from the source, the boolean
  33  * method CurrentNodeListFilter.test() is called.
  34  *
  35  * All nodes from the source are read into an array upon calling setStartNode()
  36  * (this is needed to determine the value of last, a parameter to
  37  * CurrentNodeListFilter.test()). The method getLast() returns the last element
  38  * after applying the filter.
  39  * @author Jacek Ambroziak
  40  * @author Santiago Pericas-Geertsen
  41  * @author Morten Jorgensen
  42  */
  43 
  44 public final class CurrentNodeListIterator extends DTMAxisIteratorBase {
  45     /**
  46      * A flag indicating if nodes are returned in document order.
  47      */
  48     private boolean _docOrder;
  49 
  50     /**
  51      * The source for this iterator.
  52      */
  53     private DTMAxisIterator _source;
  54 
  55     /**
  56      * A reference to a filter object.
  57      */
  58     private final CurrentNodeListFilter _filter;
  59 
  60     /**
  61      * An integer array to store nodes from source iterator.
  62      */
  63     private IntegerArray _nodes = new IntegerArray();
  64 
  65     /**
  66      * Index in _nodes of the next node to filter.
  67      */
  68     private int _currentIndex;
  69 
  70     /**
  71      * The current node in the stylesheet at the time of evaluation.
  72      */
  73     private final int _currentNode;
  74 
  75     /**
  76      * A reference to the translet.
  77      */
  78     private AbstractTranslet _translet;
  79 
  80     public CurrentNodeListIterator(DTMAxisIterator source,
  81                                    CurrentNodeListFilter filter,
  82                                    int currentNode,
  83                                    AbstractTranslet translet)
  84     {
  85         this(source, !source.isReverse(), filter, currentNode, translet);
  86     }
  87 
  88     public CurrentNodeListIterator(DTMAxisIterator source, boolean docOrder,
  89                                    CurrentNodeListFilter filter,
  90                                    int currentNode,
  91                                    AbstractTranslet translet)
  92     {
  93         _source = source;
  94         _filter = filter;
  95         _translet = translet;
  96         _docOrder = docOrder;
  97         _currentNode = currentNode;
  98     }
  99 
 100     public DTMAxisIterator forceNaturalOrder() {
 101         _docOrder = true;
 102         return this;
 103     }
 104 
 105     public void setRestartable(boolean isRestartable) {
 106         _isRestartable = isRestartable;
 107         _source.setRestartable(isRestartable);
 108     }
 109 
 110     public boolean isReverse() {
 111         return !_docOrder;
 112     }
 113 
 114     public DTMAxisIterator cloneIterator() {
 115         try {
 116             final CurrentNodeListIterator clone =
 117                 (CurrentNodeListIterator) super.clone();
 118             clone._nodes = (IntegerArray) _nodes.clone();
 119             clone._source = _source.cloneIterator();
 120             clone._isRestartable = false;
 121             return clone.reset();
 122         }
 123         catch (CloneNotSupportedException e) {
 124             BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
 125                                       e.toString());
 126             return null;
 127         }
 128     }
 129 
 130     public DTMAxisIterator reset() {
 131         _currentIndex = 0;
 132         return resetPosition();
 133     }
 134 
 135     public int next() {
 136         final int last = _nodes.cardinality();
 137         final int currentNode = _currentNode;
 138         final AbstractTranslet translet = _translet;
 139 
 140         for (int index = _currentIndex; index < last; ) {
 141             final int position = _docOrder ? index + 1 : last - index;
 142             final int node = _nodes.at(index++);        // note increment
 143 
 144             if (_filter.test(node, position, last, currentNode, translet,
 145                              this)) {
 146                 _currentIndex = index;
 147                 return returnNode(node);
 148             }
 149         }
 150         return END;
 151     }
 152 
 153     public DTMAxisIterator setStartNode(int node) {
 154         if (_isRestartable) {
 155             _source.setStartNode(_startNode = node);
 156 
 157             _nodes.clear();
 158             while ((node = _source.next()) != END) {
 159                 _nodes.add(node);
 160             }
 161             _currentIndex = 0;
 162             resetPosition();
 163         }
 164         return this;
 165     }
 166 
 167     public int getLast() {
 168         if (_last == -1) {
 169             _last = computePositionOfLast();
 170         }
 171         return _last;
 172     }
 173 
 174     public void setMark() {
 175         _markedNode = _currentIndex;
 176     }
 177 
 178     public void gotoMark() {
 179         _currentIndex = _markedNode;
 180     }
 181 
 182     private int computePositionOfLast() {
 183         final int last = _nodes.cardinality();
 184         final int currNode = _currentNode;
 185         final AbstractTranslet translet = _translet;
 186 
 187         int lastPosition = _position;
 188         for (int index = _currentIndex; index < last; ) {
 189             final int position = _docOrder ? index + 1 : last - index;
 190             int nodeIndex = _nodes.at(index++);         // note increment
 191 
 192             if (_filter.test(nodeIndex, position, last, currNode, translet,
 193                              this)) {
 194                 lastPosition++;
 195             }
 196         }
 197         return lastPosition;
 198     }
 199 }