001: /*
002: * Copyright 2006, 2007 Odysseus Software GmbH
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 de.odysseus.el.tree;
017:
018: import java.lang.reflect.Method;
019: import java.util.Collection;
020:
021: import javax.el.ELException;
022: import javax.el.FunctionMapper;
023: import javax.el.ValueExpression;
024: import javax.el.VariableMapper;
025:
026: import de.odysseus.el.misc.LocalMessages;
027:
028: /**
029: * Parsed expression, usually created by a {@link de.odysseus.el.tree.TreeBuilder}.
030: * The {@link #bind(FunctionMapper, VariableMapper)} method is used to create
031: * {@link de.odysseus.el.tree.Bindings}, which are needed at evaluation time to
032: * lookup functions and variables. The tree itself does not contain such information,
033: * because it would make the tree depend on the function/variable mapper supplied at
034: * parse time.
035: *
036: * @author Christoph Beck
037: */
038: public class Tree {
039: private final ExpressionNode root;
040: private final Collection<FunctionNode> functions;
041: private final Collection<IdentifierNode> identifiers;
042: private final boolean deferred;
043:
044: /**
045: *
046: * Constructor.
047: * @param root root node
048: * @param functions collection of function nodes
049: * @param identifiers collection of identifier nodes
050: */
051: public Tree(ExpressionNode root,
052: Collection<FunctionNode> functions,
053: Collection<IdentifierNode> identifiers, boolean deferred) {
054: super ();
055: this .root = root;
056: this .functions = functions;
057: this .identifiers = identifiers;
058: this .deferred = deferred;
059: }
060:
061: /**
062: * Get function nodes (in no particular order)
063: */
064: public Iterable<FunctionNode> getFunctionNodes() {
065: return functions;
066: }
067:
068: /**
069: * Get identifier nodes (in no particular order)
070: */
071: public Iterable<IdentifierNode> getIdentifierNodes() {
072: return identifiers;
073: }
074:
075: /**
076: * @return root node
077: */
078: public ExpressionNode getRoot() {
079: return root;
080: }
081:
082: public boolean isDeferred() {
083: return deferred;
084: }
085:
086: @Override
087: public String toString() {
088: return getRoot().getStructuralId(null);
089: }
090:
091: /**
092: * Create a bindings.
093: * @param fnMapper the function mapper to use
094: * @param varMapper the variable mapper to use
095: * @return tree bindings
096: */
097: public Bindings bind(FunctionMapper fnMapper,
098: VariableMapper varMapper) {
099: Method[] methods = null;
100: if (!functions.isEmpty()) {
101: if (fnMapper == null) {
102: throw new ELException(LocalMessages
103: .get("error.function.nomapper"));
104: }
105: methods = new Method[functions.size()];
106: for (FunctionNode node : functions) {
107: String image = node.getName();
108: Method method = null;
109: int colon = image.indexOf(':');
110: if (colon < 0) {
111: method = fnMapper.resolveFunction("", image);
112: } else {
113: method = fnMapper.resolveFunction(image.substring(
114: 0, colon), image.substring(colon + 1));
115: }
116: if (method == null) {
117: throw new ELException(LocalMessages.get(
118: "error.function.notfound", image));
119: }
120: if (method.getParameterTypes().length != node
121: .getParamCount()) {
122: throw new ELException(LocalMessages.get(
123: "error.function.params", image));
124: }
125: methods[node.getIndex()] = method;
126: }
127: }
128: ValueExpression[] expressions = null;
129: if (identifiers.size() > 0) {
130: expressions = new ValueExpression[identifiers.size()];
131: for (IdentifierNode node : identifiers) {
132: ValueExpression expression = null;
133: if (varMapper != null) {
134: expression = varMapper.resolveVariable(node
135: .getName());
136: }
137: expressions[node.getIndex()] = expression;
138: }
139: }
140: return new Bindings(methods, expressions);
141: }
142: }
|