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