1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the  "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: FilterExprIteratorSimple.java 468655 2006-10-28 07:12:06Z minchau $
20 */
21package org.apache.xpath.axes;
22
23import org.apache.xml.dtm.Axis;
24import org.apache.xml.dtm.DTM;
25import org.apache.xml.utils.PrefixResolver;
26import org.apache.xpath.Expression;
27import org.apache.xpath.ExpressionOwner;
28import org.apache.xpath.VariableStack;
29import org.apache.xpath.XPathContext;
30import org.apache.xpath.XPathVisitor;
31import org.apache.xpath.objects.XNodeSet;
32
33/**
34 * Class to use for one-step iteration that doesn't have a predicate, and
35 * doesn't need to set the context.
36 */
37public class FilterExprIteratorSimple extends LocPathIterator
38{
39    static final long serialVersionUID = -6978977187025375579L;
40  /** The contained expression. Should be non-null.
41   *  @serial   */
42  private Expression m_expr;
43
44  /** The result of executing m_expr.  Needs to be deep cloned on clone op.  */
45  transient private XNodeSet m_exprObj;
46
47  private boolean m_mustHardReset = false;
48  private boolean m_canDetachNodeset = true;
49
50  /**
51   * Create a FilterExprIteratorSimple object.
52   *
53   */
54  public FilterExprIteratorSimple()
55  {
56    super(null);
57  }
58
59  /**
60   * Create a FilterExprIteratorSimple object.
61   *
62   */
63  public FilterExprIteratorSimple(Expression expr)
64  {
65    super(null);
66    m_expr = expr;
67  }
68
69  /**
70   * Initialize the context values for this expression
71   * after it is cloned.
72   *
73   * @param context The XPath runtime context for this
74   * transformation.
75   */
76  public void setRoot(int context, Object environment)
77  {
78  	super.setRoot(context, environment);
79  	m_exprObj = executeFilterExpr(context, m_execContext, getPrefixResolver(),
80  	                  getIsTopLevel(), m_stackFrame, m_expr);
81  }
82
83  /**
84   * Execute the expression.  Meant for reuse by other FilterExpr iterators
85   * that are not derived from this object.
86   */
87  public static XNodeSet executeFilterExpr(int context, XPathContext xctxt,
88  												PrefixResolver prefixResolver,
89  												boolean isTopLevel,
90  												int stackFrame,
91  												Expression expr )
92    throws org.apache.xml.utils.WrappedRuntimeException
93  {
94    PrefixResolver savedResolver = xctxt.getNamespaceContext();
95    XNodeSet result = null;
96
97    try
98    {
99      xctxt.pushCurrentNode(context);
100      xctxt.setNamespaceContext(prefixResolver);
101
102      // The setRoot operation can take place with a reset operation,
103      // and so we may not be in the context of LocPathIterator#nextNode,
104      // so we have to set up the variable context, execute the expression,
105      // and then restore the variable context.
106
107      if (isTopLevel)
108      {
109        // System.out.println("calling m_expr.execute(getXPathContext())");
110        VariableStack vars = xctxt.getVarStack();
111
112        // These three statements need to be combined into one operation.
113        int savedStart = vars.getStackFrame();
114        vars.setStackFrame(stackFrame);
115
116        result = (org.apache.xpath.objects.XNodeSet) expr.execute(xctxt);
117        result.setShouldCacheNodes(true);
118
119        // These two statements need to be combined into one operation.
120        vars.setStackFrame(savedStart);
121      }
122      else
123          result = (org.apache.xpath.objects.XNodeSet) expr.execute(xctxt);
124
125    }
126    catch (javax.xml.transform.TransformerException se)
127    {
128
129      // TODO: Fix...
130      throw new org.apache.xml.utils.WrappedRuntimeException(se);
131    }
132    finally
133    {
134      xctxt.popCurrentNode();
135      xctxt.setNamespaceContext(savedResolver);
136    }
137    return result;
138  }
139
140  /**
141   *  Returns the next node in the set and advances the position of the
142   * iterator in the set. After a NodeIterator is created, the first call
143   * to nextNode() returns the first node in the set.
144   *
145   * @return  The next <code>Node</code> in the set being iterated over, or
146   *   <code>null</code> if there are no more members in that set.
147   */
148  public int nextNode()
149  {
150  	if(m_foundLast)
151  		return DTM.NULL;
152
153    int next;
154
155    if (null != m_exprObj)
156    {
157      m_lastFetched = next = m_exprObj.nextNode();
158    }
159    else
160      m_lastFetched = next = DTM.NULL;
161
162    // m_lastFetched = next;
163    if (DTM.NULL != next)
164    {
165      m_pos++;
166      return next;
167    }
168    else
169    {
170      m_foundLast = true;
171
172      return DTM.NULL;
173    }
174  }
175
176  /**
177   * Detaches the walker from the set which it iterated over, releasing
178   * any computational resources and placing the iterator in the INVALID
179   * state.
180   */
181  public void detach()
182  {
183    if(m_allowDetach)
184    {
185  		super.detach();
186  		m_exprObj.detach();
187  		m_exprObj = null;
188    }
189  }
190
191  /**
192   * This function is used to fixup variables from QNames to stack frame
193   * indexes at stylesheet build time.
194   * @param vars List of QNames that correspond to variables.  This list
195   * should be searched backwards for the first qualified name that
196   * corresponds to the variable reference qname.  The position of the
197   * QName in the vector from the start of the vector will be its position
198   * in the stack frame (but variables above the globalsTop value will need
199   * to be offset to the current stack frame).
200   */
201  public void fixupVariables(java.util.Vector vars, int globalsSize)
202  {
203    super.fixupVariables(vars, globalsSize);
204    m_expr.fixupVariables(vars, globalsSize);
205  }
206
207  /**
208   * Get the inner contained expression of this filter.
209   */
210  public Expression getInnerExpression()
211  {
212    return m_expr;
213  }
214
215  /**
216   * Set the inner contained expression of this filter.
217   */
218  public void setInnerExpression(Expression expr)
219  {
220    expr.exprSetParent(this);
221    m_expr = expr;
222  }
223
224  /**
225   * Get the analysis bits for this walker, as defined in the WalkerFactory.
226   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
227   */
228  public int getAnalysisBits()
229  {
230    if (null != m_expr && m_expr instanceof PathComponent)
231    {
232      return ((PathComponent) m_expr).getAnalysisBits();
233    }
234    return WalkerFactory.BIT_FILTER;
235  }
236
237  /**
238   * Returns true if all the nodes in the iteration well be returned in document
239   * order.
240   * Warning: This can only be called after setRoot has been called!
241   *
242   * @return true as a default.
243   */
244  public boolean isDocOrdered()
245  {
246    return m_exprObj.isDocOrdered();
247  }
248
249  class filterExprOwner implements ExpressionOwner
250  {
251    /**
252    * @see ExpressionOwner#getExpression()
253    */
254    public Expression getExpression()
255    {
256      return m_expr;
257    }
258
259    /**
260     * @see ExpressionOwner#setExpression(Expression)
261     */
262    public void setExpression(Expression exp)
263    {
264      exp.exprSetParent(FilterExprIteratorSimple.this);
265      m_expr = exp;
266    }
267
268  }
269
270  /**
271   * This will traverse the heararchy, calling the visitor for
272   * each member.  If the called visitor method returns
273   * false, the subtree should not be called.
274   *
275   * @param visitor The visitor whose appropriate method will be called.
276   */
277  public void callPredicateVisitors(XPathVisitor visitor)
278  {
279    m_expr.callVisitors(new filterExprOwner(), visitor);
280
281    super.callPredicateVisitors(visitor);
282  }
283
284  /**
285   * @see Expression#deepEquals(Expression)
286   */
287  public boolean deepEquals(Expression expr)
288  {
289    if (!super.deepEquals(expr))
290      return false;
291
292    FilterExprIteratorSimple fet = (FilterExprIteratorSimple) expr;
293    if (!m_expr.deepEquals(fet.m_expr))
294      return false;
295
296    return true;
297  }
298
299  /**
300   * Returns the axis being iterated, if it is known.
301   *
302   * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
303   * types.
304   */
305  public int getAxis()
306  {
307  	if(null != m_exprObj)
308    	return m_exprObj.getAxis();
309    else
310    	return Axis.FILTEREDLIST;
311  }
312
313
314}
315
316