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.ri.EvalContext;
19  import org.apache.commons.jxpath.ri.axes.InitialContext;
20  import org.apache.commons.jxpath.ri.axes.NodeSetContext;
21  import org.apache.commons.jxpath.ri.axes.PredicateContext;
22  import org.apache.commons.jxpath.ri.axes.SimplePathInterpreter;
23  import org.apache.commons.jxpath.ri.axes.UnionContext;
24  import org.apache.commons.jxpath.ri.model.NodePointer;
25  
26  /***
27   * An  element of the parse tree that represents an expression path, which is a
28   * path that starts with an expression like a function call: <code>getFoo(.)
29   * /bar</code>.
30   *
31   * @author Dmitri Plotnikov
32   * @version $Revision: 1.11 $ $Date: 2004/02/29 14:17:39 $
33   */
34  public class ExpressionPath extends Path {
35  
36      private Expression expression;
37      private Expression predicates[];
38  
39      private boolean basicKnown = false;
40      private boolean basic;
41  
42      public ExpressionPath(
43          Expression expression,
44          Expression[] predicates,
45          Step[] steps) 
46      {
47          super(steps);
48          this.expression = expression;
49          this.predicates = predicates;
50      }
51  
52      public Expression getExpression() {
53          return expression;
54      }
55  
56      /***
57       * Predicates are the expressions in brackets that may follow
58       * the root expression of the path.
59       */
60      public Expression[] getPredicates() {
61          return predicates;
62      }
63  
64      /***
65       * Returns true if the root expression or any of the
66       * predicates or the path steps are context dependent.
67       */
68      public boolean computeContextDependent() {
69          if (expression.isContextDependent()) {
70              return true;
71          }
72          if (predicates != null) {
73              for (int i = 0; i < predicates.length; i++) {
74                  if (predicates[i].isContextDependent()) {
75                      return true;
76                  }
77              }
78          }
79          return super.computeContextDependent();
80      }
81  
82      /***
83       * Recognized paths formatted as <code>$x[3]/foo[2]</code>.  The
84       * evaluation of such "simple" paths is optimized and streamlined.
85       */
86      public boolean isSimpleExpressionPath() {
87          if (!basicKnown) {
88              basicKnown = true;
89              basic = isSimplePath() && areBasicPredicates(getPredicates());
90          }
91          return basic;
92      }
93  
94      public String toString() {
95          StringBuffer buffer = new StringBuffer();
96          if (expression instanceof CoreOperation
97              || expression instanceof ExpressionPath
98              || expression instanceof LocationPath) {
99              buffer.append('(');
100             buffer.append(expression);
101             buffer.append(')');
102         }
103         else {
104             buffer.append(expression);
105         }
106         if (predicates != null) {
107             for (int i = 0; i < predicates.length; i++) {
108                 buffer.append('[');
109                 buffer.append(predicates[i]);
110                 buffer.append(']');
111             }
112         }
113 
114         Step steps[] = getSteps();
115         if (steps != null) {
116             for (int i = 0; i < steps.length; i++) {
117                 buffer.append("/");
118                 buffer.append(steps[i]);
119             }
120         }
121         return buffer.toString();
122     }
123 
124     public Object compute(EvalContext context) {
125         return expressionPath(context, false);
126     }
127 
128     public Object computeValue(EvalContext context) {
129         return expressionPath(context, true);
130     }
131 
132     /***
133      * Walks an expression path (a path that starts with an expression)
134      */
135     protected Object expressionPath(
136         EvalContext evalContext,
137         boolean firstMatch) 
138     {
139         Object value = expression.compute(evalContext);
140         EvalContext context;
141         if (value instanceof InitialContext) {
142             // This is an optimization. We can avoid iterating through a 
143             // collection if the context bean is in fact one.
144             context = (InitialContext) value;
145         }
146         else if (value instanceof EvalContext) {
147             // UnionContext will collect all values from the "value" context
148             // and treat the whole thing as a big collection.
149             context =
150                 new UnionContext(
151                     evalContext,
152                     new EvalContext[] {(EvalContext) value });
153         }
154         else {
155             context = evalContext.getRootContext().getConstantContext(value);
156         }
157 
158         if (firstMatch
159             && isSimpleExpressionPath()
160             && !(context instanceof NodeSetContext)) {
161             EvalContext ctx = context;
162             NodePointer ptr = (NodePointer) ctx.getSingleNodePointer();
163             if (ptr != null
164                 && (ptr.getIndex() == NodePointer.WHOLE_COLLECTION
165                     || predicates == null
166                     || predicates.length == 0)) {
167                 return SimplePathInterpreter.interpretSimpleExpressionPath(
168                     evalContext,
169                     ptr,
170                     predicates,
171                     getSteps());
172             }
173         }
174         if (predicates != null) {
175             for (int j = 0; j < predicates.length; j++) {
176                 context = new PredicateContext(context, predicates[j]);
177             }
178         }
179         if (firstMatch) {
180             return getSingleNodePointerForSteps(context);
181         }
182         else {
183             return evalSteps(context);
184         }
185     }
186 }