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
22package com.sun.org.apache.xpath.internal.axes;
23
24import com.sun.org.apache.xml.internal.dtm.Axis;
25import com.sun.org.apache.xml.internal.dtm.DTM;
26import com.sun.org.apache.xml.internal.dtm.DTMIterator;
27import com.sun.org.apache.xpath.internal.Expression;
28import com.sun.org.apache.xpath.internal.ExpressionOwner;
29import com.sun.org.apache.xpath.internal.XPathContext;
30import com.sun.org.apache.xpath.internal.XPathVisitor;
31import com.sun.org.apache.xpath.internal.compiler.Compiler;
32import com.sun.org.apache.xpath.internal.compiler.OpCodes;
33import com.sun.org.apache.xpath.internal.objects.XNodeSet;
34
35/**
36 * Walker for the OP_VARIABLE, or OP_EXTFUNCTION, or OP_FUNCTION, or OP_GROUP,
37 * op codes.
38 * @see <a href="http://www.w3.org/TR/xpath#NT-FilterExpr">XPath FilterExpr descriptions</a>
39 */
40public class FilterExprWalker extends AxesWalker
41{
42    static final long serialVersionUID = 5457182471424488375L;
43
44  /**
45   * Construct a FilterExprWalker using a LocPathIterator.
46   *
47   * @param locPathIterator non-null reference to the parent iterator.
48   */
49  public FilterExprWalker(WalkingIterator locPathIterator)
50  {
51    super(locPathIterator, Axis.FILTEREDLIST);
52  }
53
54  /**
55   * Init a FilterExprWalker.
56   *
57   * @param compiler non-null reference to the Compiler that is constructing.
58   * @param opPos positive opcode position for this step.
59   * @param stepType The type of step.
60   *
61   * @throws javax.xml.transform.TransformerException
62   */
63  public void init(Compiler compiler, int opPos, int stepType)
64          throws javax.xml.transform.TransformerException
65  {
66
67    super.init(compiler, opPos, stepType);
68
69    // Smooth over an anomily in the opcode map...
70    switch (stepType)
71    {
72    case OpCodes.OP_FUNCTION :
73    case OpCodes.OP_EXTFUNCTION :
74        m_mustHardReset = true;
75    case OpCodes.OP_GROUP :
76    case OpCodes.OP_VARIABLE :
77      m_expr = compiler.compile(opPos);
78      m_expr.exprSetParent(this);
79      //if((OpCodes.OP_FUNCTION == stepType) && (m_expr instanceof com.sun.org.apache.xalan.internal.templates.FuncKey))
80      if(m_expr instanceof com.sun.org.apache.xpath.internal.operations.Variable)
81      {
82        // hack/temp workaround
83        m_canDetachNodeset = false;
84      }
85      break;
86    default :
87      m_expr = compiler.compile(opPos + 2);
88      m_expr.exprSetParent(this);
89    }
90//    if(m_expr instanceof WalkingIterator)
91//    {
92//      WalkingIterator wi = (WalkingIterator)m_expr;
93//      if(wi.getFirstWalker() instanceof FilterExprWalker)
94//      {
95//              FilterExprWalker fw = (FilterExprWalker)wi.getFirstWalker();
96//              if(null == fw.getNextWalker())
97//              {
98//                      m_expr = fw.m_expr;
99//                      m_expr.exprSetParent(this);
100//              }
101//      }
102//
103//    }
104  }
105
106  /**
107   * Detaches the walker from the set which it iterated over, releasing
108   * any computational resources and placing the iterator in the INVALID
109   * state.
110   */
111  public void detach()
112  {
113        super.detach();
114        if (m_canDetachNodeset)
115        {
116          m_exprObj.detach();
117        }
118        m_exprObj = null;
119  }
120
121  /**
122   *  Set the root node of the TreeWalker.
123   *
124   * @param root non-null reference to the root, or starting point of
125   *        the query.
126   */
127  public void setRoot(int root)
128  {
129
130    super.setRoot(root);
131
132        m_exprObj = FilterExprIteratorSimple.executeFilterExpr(root,
133                          m_lpi.getXPathContext(), m_lpi.getPrefixResolver(),
134                          m_lpi.getIsTopLevel(), m_lpi.m_stackFrame, m_expr);
135
136  }
137
138  /**
139   * Get a cloned FilterExprWalker.
140   *
141   * @return A new FilterExprWalker that can be used without mutating this one.
142   *
143   * @throws CloneNotSupportedException
144   */
145  public Object clone() throws CloneNotSupportedException
146  {
147
148    FilterExprWalker clone = (FilterExprWalker) super.clone();
149
150    // clone.m_expr = (Expression)((Expression)m_expr).clone();
151    if (null != m_exprObj)
152      clone.m_exprObj = (XNodeSet) m_exprObj.clone();
153
154    return clone;
155  }
156
157  /**
158   * This method needs to override AxesWalker.acceptNode because FilterExprWalkers
159   * don't need to, and shouldn't, do a node test.
160   * @param n  The node to check to see if it passes the filter or not.
161   * @return  a constant to determine whether the node is accepted,
162   *   rejected, or skipped, as defined  above .
163   */
164  public short acceptNode(int n)
165  {
166
167    try
168    {
169      if (getPredicateCount() > 0)
170      {
171        countProximityPosition(0);
172
173        if (!executePredicates(n, m_lpi.getXPathContext()))
174          return DTMIterator.FILTER_SKIP;
175      }
176
177      return DTMIterator.FILTER_ACCEPT;
178    }
179    catch (javax.xml.transform.TransformerException se)
180    {
181      throw new RuntimeException(se.getMessage());
182    }
183  }
184
185  /**
186   *  Moves the <code>TreeWalker</code> to the next visible node in document
187   * order relative to the current node, and returns the new node. If the
188   * current node has no next node,  or if the search for nextNode attempts
189   * to step upward from the TreeWalker's root node, returns
190   * <code>null</code> , and retains the current node.
191   * @return  The new node, or <code>null</code> if the current node has no
192   *   next node  in the TreeWalker's logical view.
193   */
194  public int getNextNode()
195  {
196
197    if (null != m_exprObj)
198    {
199       int next = m_exprObj.nextNode();
200       return next;
201    }
202    else
203      return DTM.NULL;
204  }
205
206  /**
207   * Get the index of the last node that can be itterated to.
208   *
209   *
210   * @param xctxt XPath runtime context.
211   *
212   * @return the index of the last node that can be itterated to.
213   */
214  public int getLastPos(XPathContext xctxt)
215  {
216    return m_exprObj.getLength();
217  }
218
219  /** The contained expression. Should be non-null.
220   *  @serial   */
221  private Expression m_expr;
222
223  /** The result of executing m_expr.  Needs to be deep cloned on clone op.  */
224  transient private XNodeSet m_exprObj;
225
226  private boolean m_mustHardReset = false;
227  private boolean m_canDetachNodeset = true;
228
229  /**
230   * This function is used to fixup variables from QNames to stack frame
231   * indexes at stylesheet build time.
232   * @param vars List of QNames that correspond to variables.  This list
233   * should be searched backwards for the first qualified name that
234   * corresponds to the variable reference qname.  The position of the
235   * QName in the vector from the start of the vector will be its position
236   * in the stack frame (but variables above the globalsTop value will need
237   * to be offset to the current stack frame).
238   */
239  public void fixupVariables(java.util.Vector vars, int globalsSize)
240  {
241    super.fixupVariables(vars, globalsSize);
242    m_expr.fixupVariables(vars, globalsSize);
243  }
244
245  /**
246   * Get the inner contained expression of this filter.
247   */
248  public Expression getInnerExpression()
249  {
250        return m_expr;
251  }
252
253  /**
254   * Set the inner contained expression of this filter.
255   */
256  public void setInnerExpression(Expression expr)
257  {
258        expr.exprSetParent(this);
259        m_expr = expr;
260  }
261
262
263  /**
264   * Get the analysis bits for this walker, as defined in the WalkerFactory.
265   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
266   */
267  public int getAnalysisBits()
268  {
269      if (null != m_expr && m_expr instanceof PathComponent)
270      {
271        return ((PathComponent) m_expr).getAnalysisBits();
272      }
273      return WalkerFactory.BIT_FILTER;
274  }
275
276  /**
277   * Returns true if all the nodes in the iteration well be returned in document
278   * order.
279   * Warning: This can only be called after setRoot has been called!
280   *
281   * @return true as a default.
282   */
283  public boolean isDocOrdered()
284  {
285    return m_exprObj.isDocOrdered();
286  }
287
288  /**
289   * Returns the axis being iterated, if it is known.
290   *
291   * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
292   * types.
293   */
294  public int getAxis()
295  {
296    return m_exprObj.getAxis();
297  }
298
299  class filterExprOwner implements ExpressionOwner
300  {
301      /**
302     * @see ExpressionOwner#getExpression()
303     */
304    public Expression getExpression()
305    {
306      return m_expr;
307    }
308
309    /**
310     * @see ExpressionOwner#setExpression(Expression)
311     */
312    public void setExpression(Expression exp)
313    {
314        exp.exprSetParent(FilterExprWalker.this);
315        m_expr = exp;
316    }
317  }
318
319        /**
320         * This will traverse the heararchy, calling the visitor for
321         * each member.  If the called visitor method returns
322         * false, the subtree should not be called.
323         *
324         * @param visitor The visitor whose appropriate method will be called.
325         */
326        public void callPredicateVisitors(XPathVisitor visitor)
327        {
328          m_expr.callVisitors(new filterExprOwner(), visitor);
329
330          super.callPredicateVisitors(visitor);
331        }
332
333
334    /**
335     * @see Expression#deepEquals(Expression)
336     */
337    public boolean deepEquals(Expression expr)
338    {
339      if (!super.deepEquals(expr))
340                return false;
341
342      FilterExprWalker walker = (FilterExprWalker)expr;
343      if(!m_expr.deepEquals(walker.m_expr))
344        return false;
345
346      return true;
347    }
348
349
350
351}
352