001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jxpath.ri.compiler;
017:
018: import org.apache.commons.jxpath.Pointer;
019: import org.apache.commons.jxpath.ri.EvalContext;
020: import org.apache.commons.jxpath.ri.model.NodePointer;
021: import org.apache.commons.jxpath.ri.QName;
022: import org.apache.commons.jxpath.util.ValueUtils;
023:
024: import java.util.Collections;
025: import java.util.Iterator;
026: import java.util.Locale;
027:
028: /**
029: * Common superclass for several types of nodes in the parse tree. Provides
030: * APIs for optimization of evaluation of expressions. Specifically, an
031: * expression only needs to executed once during the evaluation of an xpath
032: * if that expression is context-independent. Expression.isContextDependent()
033: * provides that hint.
034: *
035: * @author Dmitri Plotnikov
036: * @version $Revision: 1.10 $ $Date: 2004/02/29 14:17:38 $
037: */
038: public abstract class Expression {
039:
040: protected static final Double ZERO = new Double(0);
041: protected static final Double ONE = new Double(1);
042: protected static final Double NOT_A_NUMBER = new Double(Double.NaN);
043:
044: private boolean contextDependencyKnown = false;
045: private boolean contextDependent;
046:
047: /**
048: * Returns true if this expression should be re-evaluated
049: * each time the current position in the context changes.
050: */
051: public boolean isContextDependent() {
052: if (!contextDependencyKnown) {
053: contextDependent = computeContextDependent();
054: contextDependencyKnown = true;
055: }
056: return contextDependent;
057: }
058:
059: /**
060: * Implemented by subclasses and result is cached by isContextDependent()
061: */
062: public abstract boolean computeContextDependent();
063:
064: /**
065: * Evaluates the expression. If the result is a node set, returns
066: * the first element of the node set.
067: */
068: public abstract Object computeValue(EvalContext context);
069:
070: public abstract Object compute(EvalContext context);
071:
072: public Iterator iterate(EvalContext context) {
073: Object result = compute(context);
074: if (result instanceof EvalContext) {
075: return new ValueIterator((EvalContext) result);
076: }
077: return ValueUtils.iterate(result);
078: }
079:
080: public Iterator iteratePointers(EvalContext context) {
081: Object result = compute(context);
082: if (result == null) {
083: return Collections.EMPTY_LIST.iterator();
084: }
085: if (result instanceof EvalContext) {
086: return (EvalContext) result;
087: }
088: return new PointerIterator(ValueUtils.iterate(result),
089: new QName(null, "value"), context.getRootContext()
090: .getCurrentNodePointer().getLocale());
091: }
092:
093: public static class PointerIterator implements Iterator {
094: private Iterator iterator;
095: private QName qname;
096: private Locale locale;
097:
098: /**
099: * @deprecated Use the method that takes a NamespaceManager
100: */
101: public PointerIterator(Iterator it, QName qname, Locale locale) {
102: this .iterator = it;
103: this .qname = qname;
104: this .locale = locale;
105: }
106:
107: public boolean hasNext() {
108: return iterator.hasNext();
109: }
110:
111: public Object next() {
112: Object o = iterator.next();
113: return NodePointer.newNodePointer(qname, o, locale);
114: }
115:
116: public void remove() {
117: throw new UnsupportedOperationException();
118: }
119: }
120:
121: public static class ValueIterator implements Iterator {
122: private Iterator iterator;
123:
124: public ValueIterator(Iterator it) {
125: this .iterator = it;
126: }
127:
128: public boolean hasNext() {
129: return iterator.hasNext();
130: }
131:
132: public Object next() {
133: Object o = iterator.next();
134: if (o instanceof Pointer) {
135: return ((Pointer) o).getValue();
136: }
137: return o;
138: }
139:
140: public void remove() {
141: throw new UnsupportedOperationException();
142: }
143: }
144: }
|