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: FilterExprIteratorSimple.java 468655 2006-10-28 07:12:06Z minchau $
020     */
021    package org.apache.xpath.axes;
022    
023    import org.apache.xml.dtm.Axis;
024    import org.apache.xml.dtm.DTM;
025    import org.apache.xml.utils.PrefixResolver;
026    import org.apache.xpath.Expression;
027    import org.apache.xpath.ExpressionOwner;
028    import org.apache.xpath.VariableStack;
029    import org.apache.xpath.XPathContext;
030    import org.apache.xpath.XPathVisitor;
031    import org.apache.xpath.objects.XNodeSet;
032    
033    /**
034     * Class to use for one-step iteration that doesn't have a predicate, and 
035     * doesn't need to set the context.
036     */
037    public class FilterExprIteratorSimple extends LocPathIterator
038    {
039        static final long serialVersionUID = -6978977187025375579L;
040      /** The contained expression. Should be non-null.
041       *  @serial   */
042      private Expression m_expr;
043    
044      /** The result of executing m_expr.  Needs to be deep cloned on clone op.  */
045      transient private XNodeSet m_exprObj;
046    
047      private boolean m_mustHardReset = false;
048      private boolean m_canDetachNodeset = true;
049    
050      /**
051       * Create a FilterExprIteratorSimple object.
052       *
053       */
054      public FilterExprIteratorSimple()
055      {
056        super(null);
057      }
058      
059      /**
060       * Create a FilterExprIteratorSimple object.
061       *
062       */
063      public FilterExprIteratorSimple(Expression expr)
064      {
065        super(null);
066        m_expr = expr;
067      }
068      
069      /**
070       * Initialize the context values for this expression
071       * after it is cloned.
072       *
073       * @param context The XPath runtime context for this
074       * transformation.
075       */
076      public void setRoot(int context, Object environment)
077      {
078            super.setRoot(context, environment);
079            m_exprObj = executeFilterExpr(context, m_execContext, getPrefixResolver(), 
080                              getIsTopLevel(), m_stackFrame, m_expr);
081      }
082    
083      /**
084       * Execute the expression.  Meant for reuse by other FilterExpr iterators 
085       * that are not derived from this object.
086       */
087      public static XNodeSet executeFilterExpr(int context, XPathContext xctxt, 
088                                                                                                    PrefixResolver prefixResolver,
089                                                                                                    boolean isTopLevel,
090                                                                                                    int stackFrame,
091                                                                                                    Expression expr )
092        throws org.apache.xml.utils.WrappedRuntimeException
093      {
094        PrefixResolver savedResolver = xctxt.getNamespaceContext();
095        XNodeSet result = null;
096    
097        try
098        {
099          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