001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: ReverseAxesWalker.java 513117 2007-03-01 03:28:52Z minchau $
020     */
021    package org.apache.xpath.axes;
022    
023    import org.apache.xml.dtm.DTM;
024    import org.apache.xml.dtm.DTMAxisIterator;
025    import org.apache.xpath.XPathContext;
026    
027    /**
028     * Walker for a reverse axes.
029     * @see <a href="http://www.w3.org/TR/xpath#predicates">XPath 2.4 Predicates</a>
030     */
031    public class ReverseAxesWalker extends AxesWalker
032    {
033        static final long serialVersionUID = 2847007647832768941L;
034    
035      /**
036       * Construct an AxesWalker using a LocPathIterator.
037       *
038       * @param locPathIterator The location path iterator that 'owns' this walker.
039       */
040      ReverseAxesWalker(LocPathIterator locPathIterator, int axis)
041      {
042        super(locPathIterator, axis);
043      }
044      
045      /**
046       * Set the root node of the TreeWalker.
047       * (Not part of the DOM2 TreeWalker interface).
048       *
049       * @param root The context node of this step.
050       */
051      public void setRoot(int root)
052      {
053        super.setRoot(root);
054        m_iterator = getDTM(root).getAxisIterator(m_axis);
055        m_iterator.setStartNode(root);
056      }
057    
058      /**
059       * Detaches the walker from the set which it iterated over, releasing
060       * any computational resources and placing the iterator in the INVALID
061       * state.
062       */
063      public void detach()
064      {
065        m_iterator = null;
066        super.detach();
067      }
068      
069      /**
070       * Get the next node in document order on the axes.
071       *
072       * @return the next node in document order on the axes, or null.
073       */
074      protected int getNextNode()
075      {
076        if (m_foundLast)
077          return DTM.NULL;
078    
079        int next = m_iterator.next();
080        
081        if (m_isFresh)
082          m_isFresh = false;
083    
084        if (DTM.NULL == next)
085          this.m_foundLast = true;
086    
087        return next;
088      }
089    
090    
091      /**
092       * Tells if this is a reverse axes.  Overrides AxesWalker#isReverseAxes.
093       *
094       * @return true for this class.
095       */
096      public boolean isReverseAxes()
097      {
098        return true;
099      }
100    
101    //  /**
102    //   *  Set the root node of the TreeWalker.
103    //   *
104    //   * @param root The context node of this step.
105    //   */
106    //  public void setRoot(int root)
107    //  {
108    //    super.setRoot(root);
109    //  }
110    
111      /**
112       * Get the current sub-context position.  In order to do the
113       * reverse axes count, for the moment this re-searches the axes
114       * up to the predicate.  An optimization on this is to cache
115       * the nodes searched, but, for the moment, this case is probably
116       * rare enough that the added complexity isn't worth it.
117       *
118       * @param predicateIndex The predicate index of the proximity position.
119       *
120       * @return The pridicate index, or -1.
121       */
122      protected int getProximityPosition(int predicateIndex)
123      {
124        // A negative predicate index seems to occur with
125        // (preceding-sibling::*|following-sibling::*)/ancestor::*[position()]/*[position()]
126        // -sb
127        if(predicateIndex < 0)
128          return -1;
129          
130        int count = m_proximityPositions[predicateIndex];
131          
132        if (count <= 0)
133        {
134          AxesWalker savedWalker = wi().getLastUsedWalker();
135    
136          try
137          {
138            ReverseAxesWalker clone = (ReverseAxesWalker) this.clone();
139    
140            clone.setRoot(this.getRoot());
141    
142            clone.setPredicateCount(predicateIndex);
143    
144            clone.setPrevWalker(null);
145            clone.setNextWalker(null);
146            wi().setLastUsedWalker(clone);
147    
148            // Count 'em all
149            count++;
150            int next;
151    
152            while (DTM.NULL != (next = clone.nextNode()))
153            {
154              count++;
155            }
156    
157            m_proximityPositions[predicateIndex] = count;
158          }
159          catch (CloneNotSupportedException cnse)
160          {
161    
162            // can't happen
163          }
164          finally
165          {
166            wi().setLastUsedWalker(savedWalker);
167          }
168        }
169        
170        return count;
171      }
172    
173      /**
174       * Count backwards one proximity position.
175       *
176       * @param i The predicate index.
177       */
178      protected void countProximityPosition(int i)
179      {
180        if (i < m_proximityPositions.length)
181          m_proximityPositions[i]--;
182      }
183    
184      /**
185       * Get the number of nodes in this node list.  The function is probably ill
186       * named?
187       *
188       *
189       * @param xctxt The XPath runtime context.
190       *
191       * @return the number of nodes in this node list.
192       */
193      public int getLastPos(XPathContext xctxt)
194      {
195    
196        int count = 0;
197        AxesWalker savedWalker = wi().getLastUsedWalker();
198    
199        try
200        {
201          ReverseAxesWalker clone = (ReverseAxesWalker) this.clone();
202    
203          clone.setRoot(this.getRoot());
204    
205          clone.setPredicateCount(m_predicateIndex);
206    
207          clone.setPrevWalker(null);
208          clone.setNextWalker(null);
209          wi().setLastUsedWalker(clone);
210    
211          // Count 'em all
212          // count = 1;
213          int next;
214    
215          while (DTM.NULL != (next = clone.nextNode()))
216          {
217            count++;
218          }
219        }
220        catch (CloneNotSupportedException cnse)
221        {
222    
223          // can't happen
224        }
225        finally
226        {
227          wi().setLastUsedWalker(savedWalker);
228        }
229    
230        return count;
231      }
232      
233      /**
234       * Returns true if all the nodes in the iteration well be returned in document 
235       * order.
236       * Warning: This can only be called after setRoot has been called!
237       * 
238       * @return false.
239       */
240      public boolean isDocOrdered()
241      {
242        return false;  // I think.
243      }
244      
245      /** The DTM inner traversal class, that corresponds to the super axis. */
246      protected DTMAxisIterator m_iterator;
247    }