View Javadoc

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 }