    1   /*
    2    * Copyright 1999-2004 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jxpath.ri.compiler;
    17
    18  import org.apache.commons.jxpath.Pointer;
    19  import org.apache.commons.jxpath.ri.EvalContext;
    20  import org.apache.commons.jxpath.ri.model.NodePointer;
    21  import org.apache.commons.jxpath.ri.QName;
    22  import org.apache.commons.jxpath.util.ValueUtils;
    23
    24  import java.util.Collections;
    25  import java.util.Iterator;
    26  import java.util.Locale;
    27
    28  /***
    29   * Common superclass for several types of nodes in the parse tree. Provides
    30   * APIs for optimization of evaluation of expressions.  Specifically, an
    31   * expression only needs to executed once during the evaluation of an xpath
    32   * if that expression is context-independent.  Expression.isContextDependent()
    33   * provides that hint.
    34   *
    35   * @author Dmitri Plotnikov
    36   * @version $Revision: 1.10 $ $Date: 2004/02/29 14:17:38 $
    37   */
    38  public abstract class Expression {
    39
    40      protected static final Double ZERO = new Double(0);
    41      protected static final Double ONE = new Double(1);
    42      protected static final Double NOT_A_NUMBER = new Double(Double.NaN);
    43
    44      private boolean contextDependencyKnown = false;
    45      private boolean contextDependent;
    46
    47      /***
    48       * Returns true if this expression should be re-evaluated
    49       * each time the current position in the context changes.
    50       */
    51      public boolean isContextDependent() {
    52          if (!contextDependencyKnown) {
    53              contextDependent = computeContextDependent();
    54              contextDependencyKnown = true;
    55          }
    56          return contextDependent;
    57      }
    58
    59      /***
    60       * Implemented by subclasses and result is cached by isContextDependent()
    61       */
    62      public abstract boolean computeContextDependent();
    63
    64      /***
    65       * Evaluates the expression. If the result is a node set, returns
    66       * the first element of the node set.
    67       */
    68      public abstract Object computeValue(EvalContext context);
    69      public abstract Object compute(EvalContext context);
    70
    71      public Iterator iterate(EvalContext context) {
    72          Object result = compute(context);
    73          if (result instanceof EvalContext) {
    74              return new ValueIterator((EvalContext) result);
    75          }
    76          return ValueUtils.iterate(result);
    77      }
    78
    79      public Iterator iteratePointers(EvalContext context) {
    80          Object result = compute(context);
    81          if (result == null) {
    82              return Collections.EMPTY_LIST.iterator();
    83          }
    84          if (result instanceof EvalContext) {
    85              return (EvalContext) result;
    86          }
    87          return new PointerIterator(ValueUtils.iterate(result),
    88                  new QName(null, "value"),
    89                  context.getRootContext().getCurrentNodePointer().getLocale());
    90      }
    91
    92      public static class PointerIterator implements Iterator {
    93          private Iterator iterator;
    94          private QName qname;
    95          private Locale locale;
    96
    97          /***
    98           * @deprecated Use the method that takes a NamespaceManager
    99           */
    100         public PointerIterator(Iterator it, QName qname, Locale locale) {
    101             this.iterator = it;
    102             this.qname = qname;
    103             this.locale = locale;
    104         }
    105
    106         public boolean hasNext() {
    107             return iterator.hasNext();
    108         }
    109
    110         public Object next() {
    111             Object o = iterator.next();
    112             return NodePointer.newNodePointer(qname, o, locale);
    113         }
    114
    115         public void remove() {
    116             throw new UnsupportedOperationException();
    117         }
    118     }
    119
    120     public static class ValueIterator implements Iterator {
    121         private Iterator iterator;
    122
    123         public ValueIterator(Iterator it) {
    124             this.iterator = it;
    125         }
    126
    127         public boolean hasNext() {
    128             return iterator.hasNext();
    129         }
    130
    131         public Object next() {
    132             Object o = iterator.next();
    133             if (o instanceof Pointer) {
    134                 return ((Pointer) o).getValue();
    135             }
    136             return o;
    137         }
    138
    139         public void remove() {
    140             throw new UnsupportedOperationException();
    141         }
    142     }
    143 }