View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jxpath.ri.compiler;
18  
19  import org.apache.commons.jxpath.NodeSet;
20  import org.apache.commons.jxpath.Pointer;
21  import org.apache.commons.jxpath.ri.EvalContext;
22  import org.apache.commons.jxpath.ri.model.NodePointer;
23  import org.apache.commons.jxpath.ri.QName;
24  import org.apache.commons.jxpath.util.ValueUtils;
25  
26  import java.util.Collections;
27  import java.util.Iterator;
28  import java.util.Locale;
29  
30  /**
31   * Common superclass for several types of nodes in the parse tree. Provides
32   * APIs for optimization of evaluation of expressions.  Specifically, an
33   * expression only needs to executed once during the evaluation of an xpath
34   * if that expression is context-independent.  Expression.isContextDependent()
35   * provides that hint.
36   *
37   * @author Dmitri Plotnikov
38   * @version $Revision: 652845 $ $Date: 2008-05-02 19:46:46 +0200 (Fr, 02 Mai 2008) $
39   */
40  public abstract class Expression {
41  
42      /** zero */
43      protected static final Double ZERO = new Double(0);
44  
45      /** one */
46      protected static final Double ONE = new Double(1);
47  
48      /** NaN */
49      protected static final Double NOT_A_NUMBER = new Double(Double.NaN);
50  
51      private boolean contextDependencyKnown = false;
52      private boolean contextDependent;
53  
54      /**
55       * Returns true if this expression should be re-evaluated
56       * each time the current position in the context changes.
57       * @return boolean
58       */
59      public synchronized boolean isContextDependent() {
60          if (!contextDependencyKnown) {
61              contextDependent = computeContextDependent();
62              contextDependencyKnown = true;
63          }
64          return contextDependent;
65      }
66  
67      /**
68       * Implemented by subclasses and result is cached by isContextDependent()
69       * @return calculated context-dependentness as boolean
70       */
71      public abstract boolean computeContextDependent();
72  
73      /**
74       * Evaluates the expression. If the result is a node set, returns
75       * the first element of the node set.
76       * @param context evaluation context
77       * @return Object
78       */
79      public abstract Object computeValue(EvalContext context);
80  
81      /**
82       * Evaluates the expression. If the result is a node set, returns
83       * the first element of the node set.
84       * @param context evaluation context
85       * @return Object
86       */
87      public abstract Object compute(EvalContext context);
88  
89      /**
90       * Iterate over the values from the specified context.
91       * @param context evaluation context
92       * @return value Iterator
93       */
94      public Iterator iterate(EvalContext context) {
95          Object result = compute(context);
96          if (result instanceof EvalContext) {
97              return new ValueIterator((EvalContext) result);
98          }
99          if (result instanceof NodeSet) {
100             return new ValueIterator(((NodeSet) result).getPointers().iterator());
101         }
102         return ValueUtils.iterate(result);
103     }
104 
105     /**
106      * Iterate over the pointers from the specified context.
107      * @param context evaluation context
108      * @return pointer Iterator
109      */
110     public Iterator iteratePointers(EvalContext context) {
111         Object result = compute(context);
112         if (result == null) {
113             return Collections.EMPTY_LIST.iterator();
114         }
115         if (result instanceof EvalContext) {
116             return (EvalContext) result;
117         }
118         if (result instanceof NodeSet) {
119             return new PointerIterator(((NodeSet) result).getPointers().iterator(),
120                     new QName(null, "value"),
121                     context.getRootContext().getCurrentNodePointer().getLocale());
122         }
123         return new PointerIterator(ValueUtils.iterate(result),
124                 new QName(null, "value"),
125                 context.getRootContext().getCurrentNodePointer().getLocale());
126     }
127 
128     /**
129      * Pointer iterator
130      */
131     public static class PointerIterator implements Iterator {
132         private Iterator iterator;
133         private QName qname;
134         private Locale locale;
135 
136         //to what method does the following comment refer?
137         /**
138          * Create a new PointerIterator
139          * @param it underlying Iterator
140          * @param qname name
141          * @param locale Locale
142          * @deprecated Use the method that takes a NamespaceManager
143          */
144         public PointerIterator(Iterator it, QName qname, Locale locale) {
145             this.iterator = it;
146             this.qname = qname;
147             this.locale = locale;
148         }
149 
150         public boolean hasNext() {
151             return iterator.hasNext();
152         }
153 
154         public Object next() {
155             Object o = iterator.next();
156             return o instanceof Pointer ? o : NodePointer.newNodePointer(qname, o, locale);
157         }
158 
159         /**
160          * Unsupported.
161          */
162         public void remove() {
163             throw new UnsupportedOperationException();
164         }
165     }
166 
167     /**
168      * Value Iterator
169      */
170     public static class ValueIterator implements Iterator {
171         private Iterator iterator;
172 
173         /**
174          * Create a new ValueIterator.
175          * @param it underlying Iterator, may contain pointers
176          */
177         public ValueIterator(Iterator it) {
178             this.iterator = it;
179         }
180 
181         public boolean hasNext() {
182             return iterator.hasNext();
183         }
184 
185         public Object next() {
186             Object o = iterator.next();
187             return o instanceof Pointer ? ((Pointer) o).getValue() : o;
188         }
189 
190         /**
191          * Unsupported.
192          */
193         public void remove() {
194             throw new UnsupportedOperationException();
195         }
196     }
197 }