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: WalkingIterator.java 469314 2006-10-30 23:31:59Z minchau $
020     */
021    package org.apache.xpath.axes;
022    
023    import org.apache.xml.dtm.DTM;
024    import org.apache.xml.utils.PrefixResolver;
025    import org.apache.xpath.Expression;
026    import org.apache.xpath.ExpressionOwner;
027    import org.apache.xpath.VariableStack;
028    import org.apache.xpath.XPathVisitor;
029    import org.apache.xpath.compiler.Compiler;
030    import org.apache.xpath.compiler.OpMap;
031    
032    /**
033     * Location path iterator that uses Walkers.
034     */
035    
036    public class WalkingIterator extends LocPathIterator implements ExpressionOwner
037    {
038        static final long serialVersionUID = 9110225941815665906L;
039      /**
040       * Create a WalkingIterator iterator, including creation
041       * of step walkers from the opcode list, and call back
042       * into the Compiler to create predicate expressions.
043       *
044       * @param compiler The Compiler which is creating
045       * this expression.
046       * @param opPos The position of this iterator in the
047       * opcode list from the compiler.
048       * @param shouldLoadWalkers True if walkers should be
049       * loaded, or false if this is a derived iterator and
050       * it doesn't wish to load child walkers.
051       *
052       * @throws javax.xml.transform.TransformerException
053       */
054      WalkingIterator(
055              Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)
056                throws javax.xml.transform.TransformerException
057      {
058        super(compiler, opPos, analysis, shouldLoadWalkers);
059        
060        int firstStepPos = OpMap.getFirstChildPos(opPos);
061    
062        if (shouldLoadWalkers)
063        {
064          m_firstWalker = WalkerFactory.loadWalkers(this, compiler, firstStepPos, 0);
065          m_lastUsedWalker = m_firstWalker;
066        }
067      }
068      
069      /**
070       * Create a WalkingIterator object.
071       *
072       * @param nscontext The namespace context for this iterator,
073       * should be OK if null.
074       */
075      public WalkingIterator(PrefixResolver nscontext)
076      {
077    
078        super(nscontext);
079      }
080      
081      
082      /** 
083       * Get the analysis bits for this walker, as defined in the WalkerFactory.
084       * @return One of WalkerFactory#BIT_DESCENDANT, etc.
085       */
086      public int getAnalysisBits()
087      {
088        int bits = 0;
089        if (null != m_firstWalker)
090        {           
091          AxesWalker walker = m_firstWalker;
092    
093          while (null != walker)
094          {
095            int bit = walker.getAnalysisBits();
096            bits |= bit;
097            walker = walker.getNextWalker();
098          }       
099        }
100        return bits;
101      }
102      
103      /**
104       * Get a cloned WalkingIterator that holds the same
105       * position as this iterator.
106       *
107       * @return A clone of this iterator that holds the same node position.
108       *
109       * @throws CloneNotSupportedException
110       */
111      public Object clone() throws CloneNotSupportedException
112      {
113    
114        WalkingIterator clone = (WalkingIterator) super.clone();
115    
116        //    clone.m_varStackPos = this.m_varStackPos;
117        //    clone.m_varStackContext = this.m_varStackContext;
118        if (null != m_firstWalker)
119        {
120          clone.m_firstWalker = m_firstWalker.cloneDeep(clone, null);
121        }
122    
123        return clone;
124      }
125      
126      /**
127       * Reset the iterator.
128       */
129      public void reset()
130      {
131    
132        super.reset();
133    
134        if (null != m_firstWalker)
135        {
136          m_lastUsedWalker = m_firstWalker;
137    
138          m_firstWalker.setRoot(m_context);
139        }
140    
141      }
142      
143      /**
144       * Initialize the context values for this expression
145       * after it is cloned.
146       *
147       * @param context The XPath runtime context for this
148       * transformation.
149       */
150      public void setRoot(int context, Object environment)
151      {
152    
153        super.setRoot(context, environment);
154        
155        if(null != m_firstWalker)
156        {
157          m_firstWalker.setRoot(context);
158          m_lastUsedWalker = m_firstWalker;
159        }
160      }
161      
162      /**
163       *  Returns the next node in the set and advances the position of the
164       * iterator in the set. After a NodeIterator is created, the first call
165       * to nextNode() returns the first node in the set.
166       * @return  The next <code>Node</code> in the set being iterated over, or
167       *   <code>null</code> if there are no more members in that set.
168       */
169      public int nextNode()
170      {
171            if(m_foundLast)
172                    return DTM.NULL;
173    
174        // If the variable stack position is not -1, we'll have to 
175        // set our position in the variable stack, so our variable access 
176        // will be correct.  Iterators that are at the top level of the 
177        // expression need to reset the variable stack, while iterators 
178        // in predicates do not need to, and should not, since their execution
179        // may be much later than top-level iterators.  
180        // m_varStackPos is set in setRoot, which is called 
181        // from the execute method.
182        if (-1 == m_stackFrame)
183        {
184          return returnNextNode(m_firstWalker.nextNode());
185        }
186        else
187        {
188          VariableStack vars = m_execContext.getVarStack();
189    
190          // These three statements need to be combined into one operation.
191          int savedStart = vars.getStackFrame();
192    
193          vars.setStackFrame(m_stackFrame);
194    
195          int n = returnNextNode(m_firstWalker.nextNode());
196    
197          // These two statements need to be combined into one operation.
198          vars.setStackFrame(savedStart);
199    
200          return n;
201        }
202      }
203    
204      
205      /**
206       * Get the head of the walker list.
207       *
208       * @return The head of the walker list, or null
209       * if this iterator does not implement walkers.
210       * @xsl.usage advanced
211       */
212      public final AxesWalker getFirstWalker()
213      {
214        return m_firstWalker;
215      }
216      
217      /**
218       * Set the head of the walker list.
219       * 
220       * @param walker Should be a valid AxesWalker.
221       * @xsl.usage advanced
222       */
223      public final void setFirstWalker(AxesWalker walker)
224      {
225        m_firstWalker = walker;
226      }
227    
228    
229      /**
230       * Set the last used walker.
231       *
232       * @param walker The last used walker, or null.
233       * @xsl.usage advanced
234       */
235      public final void setLastUsedWalker(AxesWalker walker)
236      {
237        m_lastUsedWalker = walker;
238      }
239    
240      /**
241       * Get the last used walker.
242       *
243       * @return The last used walker, or null.
244       * @xsl.usage advanced
245       */
246      public final AxesWalker getLastUsedWalker()
247      {
248        return m_lastUsedWalker;
249      }
250      
251      /**
252       *  Detaches the iterator from the set which it iterated over, releasing
253       * any computational resources and placing the iterator in the INVALID
254       * state. After<code>detach</code> has been invoked, calls to
255       * <code>nextNode</code> or<code>previousNode</code> will raise the
256       * exception INVALID_STATE_ERR.
257       */
258      public void detach()
259      {   
260        if(m_allowDetach)
261        {
262                    AxesWalker walker = m_firstWalker; 
263                while (null != walker)
264                {
265                  walker.detach();
266                  walker = walker.getNextWalker();
267                }
268            
269                m_lastUsedWalker = null;
270                
271                // Always call the superclass detach last!
272                super.detach();
273        }
274      }
275      
276      /**
277       * This function is used to fixup variables from QNames to stack frame 
278       * indexes at stylesheet build time.
279       * @param vars List of QNames that correspond to variables.  This list 
280       * should be searched backwards for the first qualified name that 
281       * corresponds to the variable reference qname.  The position of the 
282       * QName in the vector from the start of the vector will be its position 
283       * in the stack frame (but variables above the globalsTop value will need 
284       * to be offset to the current stack frame).
285       */
286      public void fixupVariables(java.util.Vector vars, int globalsSize)
287      {
288        m_predicateIndex = -1;
289    
290        AxesWalker walker = m_firstWalker;
291    
292        while (null != walker)
293        {
294          walker.fixupVariables(vars, globalsSize);
295          walker = walker.getNextWalker();
296        }
297      }
298      
299      /**
300       * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
301       */
302      public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
303      {
304                    if(visitor.visitLocationPath(owner, this))
305                    {
306                            if(null != m_firstWalker)
307                            {
308                                    m_firstWalker.callVisitors(this, visitor);
309                            }
310                    }
311      }
312    
313      
314      /** The last used step walker in the walker list.
315       *  @serial */
316      protected AxesWalker m_lastUsedWalker;
317    
318      /** The head of the step walker list.
319       *  @serial */
320      protected AxesWalker m_firstWalker;
321    
322      /**
323       * @see ExpressionOwner#getExpression()
324       */
325      public Expression getExpression()
326      {
327        return m_firstWalker;
328      }
329    
330      /**
331       * @see ExpressionOwner#setExpression(Expression)
332       */
333      public void setExpression(Expression exp)
334      {
335            exp.exprSetParent(this);
336            m_firstWalker = (AxesWalker)exp;
337      }
338      
339        /**
340         * @see Expression#deepEquals(Expression)
341         */
342        public boolean deepEquals(Expression expr)
343        {
344          if (!super.deepEquals(expr))
345                    return false;
346    
347          AxesWalker walker1 = m_firstWalker;
348          AxesWalker walker2 = ((WalkingIterator)expr).m_firstWalker;
349          while ((null != walker1) && (null != walker2))
350          {
351            if(!walker1.deepEquals(walker2))
352                    return false;
353            walker1 = walker1.getNextWalker();
354            walker2 = walker2.getNextWalker();
355          }
356          
357          if((null != walker1) || (null != walker2))
358            return false;
359    
360          return true;
361        }
362    
363    }