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