001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.el.lang;
019:
020: import java.io.StringReader;
021: import java.lang.reflect.Method;
022:
023: import javax.el.ELContext;
024: import javax.el.ELException;
025: import javax.el.FunctionMapper;
026: import javax.el.MethodExpression;
027: import javax.el.ValueExpression;
028: import javax.el.VariableMapper;
029:
030: import org.apache.el.MethodExpressionImpl;
031: import org.apache.el.MethodExpressionLiteral;
032: import org.apache.el.ValueExpressionImpl;
033: import org.apache.el.parser.AstCompositeExpression;
034: import org.apache.el.parser.AstDeferredExpression;
035: import org.apache.el.parser.AstDynamicExpression;
036: import org.apache.el.parser.AstFunction;
037: import org.apache.el.parser.AstIdentifier;
038: import org.apache.el.parser.AstLiteralExpression;
039: import org.apache.el.parser.AstValue;
040: import org.apache.el.parser.ELParser;
041: import org.apache.el.parser.Node;
042: import org.apache.el.parser.NodeVisitor;
043: import org.apache.el.parser.ParseException;
044: import org.apache.el.util.ConcurrentCache;
045: import org.apache.el.util.MessageFactory;
046:
047: /**
048: * @author Jacob Hookom [jacob@hookom.net]
049: * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: markt $
050: */
051: public final class ExpressionBuilder implements NodeVisitor {
052:
053: private static final ConcurrentCache cache = new ConcurrentCache(
054: 5000);
055:
056: private FunctionMapper fnMapper;
057:
058: private VariableMapper varMapper;
059:
060: private String expression;
061:
062: /**
063: *
064: */
065: public ExpressionBuilder(String expression, ELContext ctx)
066: throws ELException {
067: this .expression = expression;
068:
069: FunctionMapper ctxFn = ctx.getFunctionMapper();
070: VariableMapper ctxVar = ctx.getVariableMapper();
071:
072: if (ctxFn != null) {
073: this .fnMapper = new FunctionMapperFactory(ctxFn);
074: }
075: if (ctxVar != null) {
076: this .varMapper = new VariableMapperFactory(ctxVar);
077: }
078: }
079:
080: public final static Node createNode(String expr) throws ELException {
081: Node n = createNodeInternal(expr);
082: return n;
083: }
084:
085: private final static Node createNodeInternal(String expr)
086: throws ELException {
087: if (expr == null) {
088: throw new ELException(MessageFactory.get("error.null"));
089: }
090:
091: Node n = (Node) cache.get(expr);
092: if (n == null) {
093: try {
094: n = (new ELParser(new StringReader(expr)))
095: .CompositeExpression();
096:
097: // validate composite expression
098: if (n instanceof AstCompositeExpression) {
099: int numChildren = n.jjtGetNumChildren();
100: if (numChildren == 1) {
101: n = n.jjtGetChild(0);
102: } else {
103: Class type = null;
104: Node child = null;
105: for (int i = 0; i < numChildren; i++) {
106: child = n.jjtGetChild(i);
107: if (child instanceof AstLiteralExpression)
108: continue;
109: if (type == null)
110: type = child.getClass();
111: else {
112: if (!type.equals(child.getClass())) {
113: throw new ELException(
114: MessageFactory
115: .get("error.mixed",
116: expr));
117: }
118: }
119: }
120: }
121: }
122: if (n instanceof AstDeferredExpression
123: || n instanceof AstDynamicExpression) {
124: n = n.jjtGetChild(0);
125: }
126: cache.put(expr, n);
127: } catch (ParseException pe) {
128: throw new ELException("Error Parsing: " + expr, pe);
129: }
130: }
131: return n;
132: }
133:
134: private void prepare(Node node) throws ELException {
135: try {
136: node.accept(this );
137: } catch (Exception e) {
138: throw (ELException) e;
139: }
140: if (this .fnMapper instanceof FunctionMapperFactory) {
141: this .fnMapper = ((FunctionMapperFactory) this .fnMapper)
142: .create();
143: }
144: if (this .varMapper instanceof VariableMapperFactory) {
145: this .varMapper = ((VariableMapperFactory) this .varMapper)
146: .create();
147: }
148: }
149:
150: private Node build() throws ELException {
151: Node n = createNodeInternal(this .expression);
152: this .prepare(n);
153: if (n instanceof AstDeferredExpression
154: || n instanceof AstDynamicExpression) {
155: n = n.jjtGetChild(0);
156: }
157: return n;
158: }
159:
160: /*
161: * (non-Javadoc)
162: *
163: * @see com.sun.el.parser.NodeVisitor#visit(com.sun.el.parser.Node)
164: */
165: public void visit(Node node) throws ELException {
166: if (node instanceof AstFunction) {
167:
168: AstFunction funcNode = (AstFunction) node;
169:
170: if (this .fnMapper == null) {
171: throw new ELException(MessageFactory
172: .get("error.fnMapper.null"));
173: }
174: Method m = fnMapper.resolveFunction(funcNode.getPrefix(),
175: funcNode.getLocalName());
176: if (m == null) {
177: throw new ELException(MessageFactory.get(
178: "error.fnMapper.method", funcNode
179: .getOutputName()));
180: }
181: int pcnt = m.getParameterTypes().length;
182: if (node.jjtGetNumChildren() != pcnt) {
183: throw new ELException(MessageFactory.get(
184: "error.fnMapper.paramcount", funcNode
185: .getOutputName(), "" + pcnt, ""
186: + node.jjtGetNumChildren()));
187: }
188: } else if (node instanceof AstIdentifier
189: && this .varMapper != null) {
190: String variable = ((AstIdentifier) node).getImage();
191:
192: // simply capture it
193: this .varMapper.resolveVariable(variable);
194: }
195: }
196:
197: public ValueExpression createValueExpression(Class expectedType)
198: throws ELException {
199: Node n = this .build();
200: return new ValueExpressionImpl(this .expression, n,
201: this .fnMapper, this .varMapper, expectedType);
202: }
203:
204: public MethodExpression createMethodExpression(
205: Class expectedReturnType, Class[] expectedParamTypes)
206: throws ELException {
207: Node n = this .build();
208: if (n instanceof AstValue || n instanceof AstIdentifier) {
209: return new MethodExpressionImpl(expression, n,
210: this .fnMapper, this .varMapper, expectedReturnType,
211: expectedParamTypes);
212: } else if (n instanceof AstLiteralExpression) {
213: return new MethodExpressionLiteral(expression,
214: expectedReturnType, expectedParamTypes);
215: } else {
216: throw new ELException("Not a Valid Method Expression: "
217: + expression);
218: }
219: }
220: }
|