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;
  22 
  23 import com.sun.org.apache.xalan.internal.res.XSLMessages;
  24 import com.sun.org.apache.xml.internal.dtm.DTM;
  25 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  26 import com.sun.org.apache.xml.internal.utils.QName;
  27 import com.sun.org.apache.xml.internal.utils.XMLString;
  28 import com.sun.org.apache.xpath.internal.objects.XNodeSet;
  29 import com.sun.org.apache.xpath.internal.objects.XObject;
  30 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  31 import java.util.List;
  32 import javax.xml.transform.ErrorListener;
  33 import javax.xml.transform.TransformerException;
  34 import org.xml.sax.ContentHandler;
  35 
  36 /**
  37  * This abstract class serves as the base for all expression objects.  An
  38  * Expression can be executed to return a {@link com.sun.org.apache.xpath.internal.objects.XObject},
  39  * normally has a location within a document or DOM, can send error and warning
  40  * events, and normally do not hold state and are meant to be immutable once
  41  * construction has completed.  An exception to the immutibility rule is iterators
  42  * and walkers, which must be cloned in order to be used -- the original must
  43  * still be immutable.
  44  *
  45  * @LastModified: Oct 2017
  46  */
  47 public abstract class Expression implements java.io.Serializable, ExpressionNode, XPathVisitable
  48 {
  49     static final long serialVersionUID = 565665869777906902L;
  50   /**
  51    * The location where this expression was built from.  Need for diagnostic
  52    *  messages. May be null.
  53    *  @serial
  54    */
  55   private ExpressionNode m_parent;
  56 
  57   /**
  58    * Tell if this expression or it's subexpressions can traverse outside
  59    * the current subtree.
  60    *
  61    * @return true if traversal outside the context node's subtree can occur.
  62    */
  63   public boolean canTraverseOutsideSubtree()
  64   {
  65     return false;
  66   }
  67 
  68 //  /**
  69 //   * Set the location where this expression was built from.
  70 //   *
  71 //   *
  72 //   * @param locator the location where this expression was built from, may be
  73 //   *                null.
  74 //   */
  75 //  public void setSourceLocator(SourceLocator locator)
  76 //  {
  77 //    m_slocator = locator;
  78 //  }
  79 
  80   /**
  81    * Execute an expression in the XPath runtime context, and return the
  82    * result of the expression.
  83    *
  84    *
  85    * @param xctxt The XPath runtime context.
  86    * @param currentNode The currentNode.
  87    *
  88    * @return The result of the expression in the form of a <code>XObject</code>.
  89    *
  90    * @throws javax.xml.transform.TransformerException if a runtime exception
  91    *         occurs.
  92    */
  93   public XObject execute(XPathContext xctxt, int currentNode)
  94           throws javax.xml.transform.TransformerException
  95   {
  96 
  97     // For now, the current node is already pushed.
  98     return execute(xctxt);
  99   }
 100 
 101   /**
 102    * Execute an expression in the XPath runtime context, and return the
 103    * result of the expression.
 104    *
 105    *
 106    * @param xctxt The XPath runtime context.
 107    * @param currentNode The currentNode.
 108    * @param dtm The DTM of the current node.
 109    * @param expType The expanded type ID of the current node.
 110    *
 111    * @return The result of the expression in the form of a <code>XObject</code>.
 112    *
 113    * @throws javax.xml.transform.TransformerException if a runtime exception
 114    *         occurs.
 115    */
 116   public XObject execute(
 117           XPathContext xctxt, int currentNode, DTM dtm, int expType)
 118             throws javax.xml.transform.TransformerException
 119   {
 120 
 121     // For now, the current node is already pushed.
 122     return execute(xctxt);
 123   }
 124 
 125   /**
 126    * Execute an expression in the XPath runtime context, and return the
 127    * result of the expression.
 128    *
 129    *
 130    * @param xctxt The XPath runtime context.
 131    *
 132    * @return The result of the expression in the form of a <code>XObject</code>.
 133    *
 134    * @throws javax.xml.transform.TransformerException if a runtime exception
 135    *         occurs.
 136    */
 137   public abstract XObject execute(XPathContext xctxt)
 138     throws javax.xml.transform.TransformerException;
 139 
 140   /**
 141    * Execute an expression in the XPath runtime context, and return the
 142    * result of the expression, but tell that a "safe" object doesn't have
 143    * to be returned.  The default implementation just calls execute(xctxt).
 144    *
 145    *
 146    * @param xctxt The XPath runtime context.
 147    * @param destructiveOK true if a "safe" object doesn't need to be returned.
 148    *
 149    * @return The result of the expression in the form of a <code>XObject</code>.
 150    *
 151    * @throws javax.xml.transform.TransformerException if a runtime exception
 152    *         occurs.
 153    */
 154   public XObject execute(XPathContext xctxt, boolean destructiveOK)
 155     throws javax.xml.transform.TransformerException
 156   {
 157         return execute(xctxt);
 158   }
 159 
 160 
 161   /**
 162    * Evaluate expression to a number.
 163    *
 164    *
 165    * @param xctxt The XPath runtime context.
 166    * @return The expression evaluated as a double.
 167    *
 168    * @throws javax.xml.transform.TransformerException
 169    */
 170   public double num(XPathContext xctxt)
 171           throws javax.xml.transform.TransformerException
 172   {
 173     return execute(xctxt).num();
 174   }
 175 
 176   /**
 177    * Evaluate expression to a boolean.
 178    *
 179    *
 180    * @param xctxt The XPath runtime context.
 181    * @return false
 182    *
 183    * @throws javax.xml.transform.TransformerException
 184    */
 185   public boolean bool(XPathContext xctxt)
 186           throws javax.xml.transform.TransformerException
 187   {
 188     return execute(xctxt).bool();
 189   }
 190 
 191   /**
 192    * Cast result object to a string.
 193    *
 194    *
 195    * @param xctxt The XPath runtime context.
 196    * @return The string this wraps or the empty string if null
 197    *
 198    * @throws javax.xml.transform.TransformerException
 199    */
 200   public XMLString xstr(XPathContext xctxt)
 201           throws javax.xml.transform.TransformerException
 202   {
 203     return execute(xctxt).xstr();
 204   }
 205 
 206   /**
 207    * Tell if the expression is a nodeset expression.  In other words, tell
 208    * if you can execute {@link #asNode(XPathContext) asNode} without an exception.
 209    * @return true if the expression can be represented as a nodeset.
 210    */
 211   public boolean isNodesetExpr()
 212   {
 213     return false;
 214   }
 215 
 216   /**
 217    * Return the first node out of the nodeset, if this expression is
 218    * a nodeset expression.
 219    * @param xctxt The XPath runtime context.
 220    * @return the first node out of the nodeset, or DTM.NULL.
 221    *
 222    * @throws javax.xml.transform.TransformerException
 223    */
 224   public int asNode(XPathContext xctxt)
 225           throws javax.xml.transform.TransformerException
 226   {
 227         DTMIterator iter = execute(xctxt).iter();
 228     return iter.nextNode();
 229   }
 230 
 231   /**
 232    * Given an select expression and a context, evaluate the XPath
 233    * and return the resulting iterator.
 234    *
 235    * @param xctxt The execution context.
 236    * @param contextNode The node that "." expresses.
 237    *
 238    *
 239    * @return A valid DTMIterator.
 240    * @throws TransformerException thrown if the active ProblemListener decides
 241    * the error condition is severe enough to halt processing.
 242    *
 243    * @throws javax.xml.transform.TransformerException
 244    * @xsl.usage experimental
 245    */
 246   public DTMIterator asIterator(XPathContext xctxt, int contextNode)
 247           throws javax.xml.transform.TransformerException
 248   {
 249 
 250     try
 251     {
 252       xctxt.pushCurrentNodeAndExpression(contextNode, contextNode);
 253 
 254       return execute(xctxt).iter();
 255     }
 256     finally
 257     {
 258       xctxt.popCurrentNodeAndExpression();
 259     }
 260   }
 261 
 262   /**
 263    * Given an select expression and a context, evaluate the XPath
 264    * and return the resulting iterator, but do not clone.
 265    *
 266    * @param xctxt The execution context.
 267    * @param contextNode The node that "." expresses.
 268    *
 269    *
 270    * @return A valid DTMIterator.
 271    * @throws TransformerException thrown if the active ProblemListener decides
 272    * the error condition is severe enough to halt processing.
 273    *
 274    * @throws javax.xml.transform.TransformerException
 275    * @xsl.usage experimental
 276    */
 277   public DTMIterator asIteratorRaw(XPathContext xctxt, int contextNode)
 278           throws javax.xml.transform.TransformerException
 279   {
 280 
 281     try
 282     {
 283       xctxt.pushCurrentNodeAndExpression(contextNode, contextNode);
 284 
 285       XNodeSet nodeset = (XNodeSet)execute(xctxt);
 286       return nodeset.iterRaw();
 287     }
 288     finally
 289     {
 290       xctxt.popCurrentNodeAndExpression();
 291     }
 292   }
 293 
 294 
 295   /**
 296    * Execute an expression in the XPath runtime context, and return the
 297    * result of the expression.
 298    *
 299    *
 300    * @param xctxt The XPath runtime context.
 301    * NEEDSDOC @param handler
 302    *
 303    * @return The result of the expression in the form of a <code>XObject</code>.
 304    *
 305    * @throws javax.xml.transform.TransformerException if a runtime exception
 306    *         occurs.
 307    * @throws org.xml.sax.SAXException
 308    */
 309   public void executeCharsToContentHandler(
 310           XPathContext xctxt, ContentHandler handler)
 311             throws javax.xml.transform.TransformerException,
 312                    org.xml.sax.SAXException
 313   {
 314 
 315     XObject obj = execute(xctxt);
 316 
 317     obj.dispatchCharactersEvents(handler);
 318     obj.detach();
 319   }
 320 
 321   /**
 322    * Tell if this expression returns a stable number that will not change during
 323    * iterations within the expression.  This is used to determine if a proximity
 324    * position predicate can indicate that no more searching has to occur.
 325    *
 326    *
 327    * @return true if the expression represents a stable number.
 328    */
 329   public boolean isStableNumber()
 330   {
 331     return false;
 332   }
 333 
 334   /**
 335    * This function is used to fixup variables from QNames to stack frame
 336    * indexes at stylesheet build time.
 337    * @param vars List of QNames that correspond to variables.  This list
 338    * should be searched backwards for the first qualified name that
 339    * corresponds to the variable reference qname.  The position of the
 340    * QName in the vector from the start of the vector will be its position
 341    * in the stack frame (but variables above the globalsTop value will need
 342    * to be offset to the current stack frame).
 343    * NEEDSDOC @param globalsSize
 344    */
 345   public abstract void fixupVariables(List<QName> vars, int globalsSize);
 346 
 347   /**
 348    * Compare this object with another object and see
 349    * if they are equal, include the sub heararchy.
 350    *
 351    * @param expr Another expression object.
 352    * @return true if this objects class and the expr
 353    * object's class are the same, and the data contained
 354    * within both objects are considered equal.
 355    */
 356   public abstract boolean deepEquals(Expression expr);
 357 
 358   /**
 359    * This is a utility method to tell if the passed in
 360    * class is the same class as this.  It is to be used by
 361    * the deepEquals method.  I'm bottlenecking it here
 362    * because I'm not totally confident that comparing the
 363    * class objects is the best way to do this.
 364    * @return true of the passed in class is the exact same
 365    * class as this class.
 366    */
 367   protected final boolean isSameClass(Expression expr)
 368   {
 369         if(null == expr)
 370           return false;
 371 
 372         return (getClass() == expr.getClass());
 373   }
 374 
 375   /**
 376    * Warn the user of an problem.
 377    *
 378    * @param xctxt The XPath runtime context.
 379    * @param msg An error msgkey that corresponds to one of the conststants found
 380    *            in {@link com.sun.org.apache.xpath.internal.res.XPATHErrorResources}, which is
 381    *            a key for a format string.
 382    * @param args An array of arguments represented in the format string, which
 383    *             may be null.
 384    *
 385    * @throws TransformerException if the current ErrorListoner determines to
 386    *                              throw an exception.
 387    *
 388    * @throws javax.xml.transform.TransformerException
 389    */
 390   public void warn(XPathContext xctxt, String msg, Object[] args)
 391           throws javax.xml.transform.TransformerException
 392   {
 393 
 394     java.lang.String fmsg = XSLMessages.createXPATHWarning(msg, args);
 395 
 396     if (null != xctxt)
 397     {
 398       ErrorListener eh = xctxt.getErrorListener();
 399 
 400       // TO DO: Need to get stylesheet Locator from here.
 401       eh.warning(new TransformerException(fmsg, xctxt.getSAXLocator()));
 402     }
 403   }
 404 
 405   /**
 406    * Tell the user of an assertion error, and probably throw an
 407    * exception.
 408    *
 409    * @param b  If false, a runtime exception will be thrown.
 410    * @param msg The assertion message, which should be informative.
 411    *
 412    * @throws RuntimeException if the b argument is false.
 413    *
 414    * @throws javax.xml.transform.TransformerException
 415    */
 416   public void assertion(boolean b, java.lang.String msg)
 417   {
 418 
 419     if (!b)
 420     {
 421       java.lang.String fMsg = XSLMessages.createXPATHMessage(
 422         XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
 423         new Object[]{ msg });
 424 
 425       throw new RuntimeException(fMsg);
 426     }
 427   }
 428 
 429   /**
 430    * Tell the user of an error, and probably throw an
 431    * exception.
 432    *
 433    * @param xctxt The XPath runtime context.
 434    * @param msg An error msgkey that corresponds to one of the constants found
 435    *            in {@link com.sun.org.apache.xpath.internal.res.XPATHErrorResources}, which is
 436    *            a key for a format string.
 437    * @param args An array of arguments represented in the format string, which
 438    *             may be null.
 439    *
 440    * @throws TransformerException if the current ErrorListoner determines to
 441    *                              throw an exception.
 442    *
 443    * @throws javax.xml.transform.TransformerException
 444    */
 445   public void error(XPathContext xctxt, String msg, Object[] args)
 446           throws javax.xml.transform.TransformerException
 447   {
 448 
 449     java.lang.String fmsg = XSLMessages.createXPATHMessage(msg, args);
 450 
 451     if (null != xctxt)
 452     {
 453       ErrorListener eh = xctxt.getErrorListener();
 454       TransformerException te = new TransformerException(fmsg, this);
 455 
 456       eh.fatalError(te);
 457     }
 458   }
 459 
 460   /**
 461    * Get the first non-Expression parent of this node.
 462    * @return null or first ancestor that is not an Expression.
 463    */
 464   public ExpressionNode getExpressionOwner()
 465   {
 466         ExpressionNode parent = exprGetParent();
 467         while((null != parent) && (parent instanceof Expression))
 468                 parent = parent.exprGetParent();
 469         return parent;
 470   }
 471 
 472   //=============== ExpressionNode methods ================
 473 
 474   /** This pair of methods are used to inform the node of its
 475     parent. */
 476   public void exprSetParent(ExpressionNode n)
 477   {
 478         assertion(n != this, "Can not parent an expression to itself!");
 479         m_parent = n;
 480   }
 481 
 482   public ExpressionNode exprGetParent()
 483   {
 484         return m_parent;
 485   }
 486 
 487   /** This method tells the node to add its argument to the node's
 488     list of children.  */
 489   public void exprAddChild(ExpressionNode n, int i)
 490   {
 491         assertion(false, "exprAddChild method not implemented!");
 492   }
 493 
 494   /** This method returns a child node.  The children are numbered
 495      from zero, left to right. */
 496   public ExpressionNode exprGetChild(int i)
 497   {
 498         return null;
 499   }
 500 
 501   /** Return the number of children the node has. */
 502   public int exprGetNumChildren()
 503   {
 504         return 0;
 505   }
 506 
 507   //=============== SourceLocator methods ================
 508 
 509   /**
 510    * Return the public identifier for the current document event.
 511    *
 512    * <p>The return value is the public identifier of the document
 513    * entity or of the external parsed entity in which the markup that
 514    * triggered the event appears.</p>
 515    *
 516    * @return A string containing the public identifier, or
 517    *         null if none is available.
 518    * @see #getSystemId
 519    */
 520   public String getPublicId()
 521   {
 522         if(null == m_parent)
 523           return null;
 524         return m_parent.getPublicId();
 525   }
 526 
 527   /**
 528    * Return the system identifier for the current document event.
 529    *
 530    * <p>The return value is the system identifier of the document
 531    * entity or of the external parsed entity in which the markup that
 532    * triggered the event appears.</p>
 533    *
 534    * <p>If the system identifier is a URL, the parser must resolve it
 535    * fully before passing it to the application.</p>
 536    *
 537    * @return A string containing the system identifier, or null
 538    *         if none is available.
 539    * @see #getPublicId
 540    */
 541   public String getSystemId()
 542   {
 543         if(null == m_parent)
 544           return null;
 545         return m_parent.getSystemId();
 546   }
 547 
 548   /**
 549    * Return the line number where the current document event ends.
 550    *
 551    * <p><strong>Warning:</strong> The return value from the method
 552    * is intended only as an approximation for the sake of error
 553    * reporting; it is not intended to provide sufficient information
 554    * to edit the character content of the original XML document.</p>
 555    *
 556    * <p>The return value is an approximation of the line number
 557    * in the document entity or external parsed entity where the
 558    * markup that triggered the event appears.</p>
 559    *
 560    * @return The line number, or -1 if none is available.
 561    * @see #getColumnNumber
 562    */
 563   public int getLineNumber()
 564   {
 565         if(null == m_parent)
 566           return 0;
 567         return m_parent.getLineNumber();
 568   }
 569 
 570   /**
 571    * Return the character position where the current document event ends.
 572    *
 573    * <p><strong>Warning:</strong> The return value from the method
 574    * is intended only as an approximation for the sake of error
 575    * reporting; it is not intended to provide sufficient information
 576    * to edit the character content of the original XML document.</p>
 577    *
 578    * <p>The return value is an approximation of the column number
 579    * in the document entity or external parsed entity where the
 580    * markup that triggered the event appears.</p>
 581    *
 582    * @return The column number, or -1 if none is available.
 583    * @see #getLineNumber
 584    */
 585   public int getColumnNumber()
 586   {
 587         if(null == m_parent)
 588           return 0;
 589         return m_parent.getColumnNumber();
 590   }
 591 }
--- EOF ---