KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > el > MethodExpressionImpl


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.el;
19
20 import java.io.Externalizable JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.ObjectInput JavaDoc;
23 import java.io.ObjectOutput JavaDoc;
24
25 import javax.el.ELContext;
26 import javax.el.ELException;
27 import javax.el.ELResolver;
28 import javax.el.Expression;
29 import javax.el.ExpressionFactory;
30 import javax.el.FunctionMapper;
31 import javax.el.MethodExpression;
32 import javax.el.MethodInfo;
33 import javax.el.MethodNotFoundException;
34 import javax.el.PropertyNotFoundException;
35 import javax.el.VariableMapper;
36
37 import org.apache.el.lang.ELSupport;
38 import org.apache.el.lang.EvaluationContext;
39 import org.apache.el.lang.ExpressionBuilder;
40 import org.apache.el.parser.Node;
41 import org.apache.el.util.ReflectionUtil;
42
43
44 /**
45  * An <code>Expression</code> that refers to a method on an object.
46  *
47  * <p>
48  * <code>The {@link ExpressionFactory#createMethodExpression} method
49  * can be used to parse an expression string and return a concrete instance
50  * of <code>MethodExpression</code> that encapsulates the parsed expression.
51  * The {@link FunctionMapper} is used at parse time, not evaluation time,
52  * so one is not needed to evaluate an expression using this class.
53  * However, the {@link ELContext} is needed at evaluation time.</p>
54  *
55  * <p>The {@link #getMethodInfo} and {@link #invoke} methods will evaluate the
56  * expression each time they are called. The {@link ELResolver} in the
57  * <code>ELContext</code> is used to resolve the top-level variables and to
58  * determine the behavior of the <code>.</code> and <code>[]</code>
59  * operators. For any of the two methods, the {@link ELResolver#getValue}
60  * method is used to resolve all properties up to but excluding the last
61  * one. This provides the <code>base</code> object on which the method
62  * appears. If the <code>base</code> object is null, a
63  * <code>NullPointerException</code> must be thrown. At the last resolution,
64  * the final <code>property</code> is then coerced to a <code>String</code>,
65  * which provides the name of the method to be found. A method matching the
66  * name and expected parameters provided at parse time is found and it is
67  * either queried or invoked (depending on the method called on this
68  * <code>MethodExpression</code>).</p>
69  *
70  * <p>See the notes about comparison, serialization and immutability in
71  * the {@link Expression} javadocs.
72  *
73  * @see javax.el.ELResolver
74  * @see javax.el.Expression
75  * @see javax.el.ExpressionFactory
76  * @see javax.el.MethodExpression
77  *
78  * @author Jacob Hookom [jacob@hookom.net]
79  * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: markt $
80  */

81 public final class MethodExpressionImpl extends MethodExpression implements
82         Externalizable JavaDoc {
83
84     private Class JavaDoc expectedType;
85
86     private String JavaDoc expr;
87
88     private FunctionMapper fnMapper;
89
90     private VariableMapper varMapper;
91
92     private transient Node node;
93
94     private Class JavaDoc[] paramTypes;
95
96     /**
97      *
98      */

99     public MethodExpressionImpl() {
100         super();
101     }
102
103     /**
104      * @param expr
105      * @param node
106      * @param fnMapper
107      * @param expectedType
108      * @param paramTypes
109      */

110     public MethodExpressionImpl(String JavaDoc expr, Node node,
111             FunctionMapper fnMapper, VariableMapper varMapper,
112             Class JavaDoc expectedType, Class JavaDoc[] paramTypes) {
113         super();
114         this.expr = expr;
115         this.node = node;
116         this.fnMapper = fnMapper;
117         this.varMapper = varMapper;
118         this.expectedType = expectedType;
119         this.paramTypes = paramTypes;
120     }
121
122     /**
123      * Determines whether the specified object is equal to this
124      * <code>Expression</code>.
125      *
126      * <p>
127      * The result is <code>true</code> if and only if the argument is not
128      * <code>null</code>, is an <code>Expression</code> object that is the
129      * of the same type (<code>ValueExpression</code> or
130      * <code>MethodExpression</code>), and has an identical parsed
131      * representation.
132      * </p>
133      *
134      * <p>
135      * Note that two expressions can be equal if their expression Strings are
136      * different. For example, <code>${fn1:foo()}</code> and
137      * <code>${fn2:foo()}</code> are equal if their corresponding
138      * <code>FunctionMapper</code>s mapped <code>fn1:foo</code> and
139      * <code>fn2:foo</code> to the same method.
140      * </p>
141      *
142      * @param obj
143      * the <code>Object</code> to test for equality.
144      * @return <code>true</code> if <code>obj</code> equals this
145      * <code>Expression</code>; <code>false</code> otherwise.
146      * @see java.util.Hashtable
147      * @see java.lang.Object#equals(java.lang.Object)
148      */

149     public boolean equals(Object JavaDoc obj) {
150         return (obj instanceof MethodExpressionImpl && obj.hashCode() == this
151                 .hashCode());
152     }
153
154     /**
155      * Returns the original String used to create this <code>Expression</code>,
156      * unmodified.
157      *
158      * <p>
159      * This is used for debugging purposes but also for the purposes of
160      * comparison (e.g. to ensure the expression in a configuration file has not
161      * changed).
162      * </p>
163      *
164      * <p>
165      * This method does not provide sufficient information to re-create an
166      * expression. Two different expressions can have exactly the same
167      * expression string but different function mappings. Serialization should
168      * be used to save and restore the state of an <code>Expression</code>.
169      * </p>
170      *
171      * @return The original expression String.
172      *
173      * @see javax.el.Expression#getExpressionString()
174      */

175     public String JavaDoc getExpressionString() {
176         return this.expr;
177     }
178
179     /**
180      * Evaluates the expression relative to the provided context, and returns
181      * information about the actual referenced method.
182      *
183      * @param context
184      * The context of this evaluation
185      * @return an instance of <code>MethodInfo</code> containing information
186      * about the method the expression evaluated to.
187      * @throws NullPointerException
188      * if context is <code>null</code> or the base object is
189      * <code>null</code> on the last resolution.
190      * @throws PropertyNotFoundException
191      * if one of the property resolutions failed because a specified
192      * variable or property does not exist or is not readable.
193      * @throws MethodNotFoundException
194      * if no suitable method can be found.
195      * @throws ELException
196      * if an exception was thrown while performing property or
197      * variable resolution. The thrown exception must be included as
198      * the cause property of this exception, if available.
199      * @see javax.el.MethodExpression#getMethodInfo(javax.el.ELContext)
200      */

201     public MethodInfo getMethodInfo(ELContext context)
202             throws PropertyNotFoundException, MethodNotFoundException,
203             ELException {
204         Node n = this.getNode();
205         EvaluationContext ctx = new EvaluationContext(context, this.fnMapper,
206                 this.varMapper);
207         return n.getMethodInfo(ctx, this.paramTypes);
208     }
209
210     /**
211      * @return
212      * @throws ELException
213      */

214     private Node getNode() throws ELException {
215         if (this.node == null) {
216             this.node = ExpressionBuilder.createNode(this.expr);
217         }
218         return this.node;
219     }
220
221     /**
222      * Returns the hash code for this <code>Expression</code>.
223      *
224      * <p>
225      * See the note in the {@link #equals} method on how two expressions can be
226      * equal if their expression Strings are different. Recall that if two
227      * objects are equal according to the <code>equals(Object)</code> method,
228      * then calling the <code>hashCode</code> method on each of the two
229      * objects must produce the same integer result. Implementations must take
230      * special note and implement <code>hashCode</code> correctly.
231      * </p>
232      *
233      * @return The hash code for this <code>Expression</code>.
234      * @see #equals
235      * @see java.util.Hashtable
236      * @see java.lang.Object#hashCode()
237      */

238     public int hashCode() {
239         return this.expr.hashCode();
240     }
241
242     /**
243      * Evaluates the expression relative to the provided context, invokes the
244      * method that was found using the supplied parameters, and returns the
245      * result of the method invocation.
246      *
247      * @param context
248      * The context of this evaluation.
249      * @param params
250      * The parameters to pass to the method, or <code>null</code>
251      * if no parameters.
252      * @return the result of the method invocation (<code>null</code> if the
253      * method has a <code>void</code> return type).
254      * @throws NullPointerException
255      * if context is <code>null</code> or the base object is
256      * <code>null</code> on the last resolution.
257      * @throws PropertyNotFoundException
258      * if one of the property resolutions failed because a specified
259      * variable or property does not exist or is not readable.
260      * @throws MethodNotFoundException
261      * if no suitable method can be found.
262      * @throws ELException
263      * if an exception was thrown while performing property or
264      * variable resolution. The thrown exception must be included as
265      * the cause property of this exception, if available. If the
266      * exception thrown is an <code>InvocationTargetException</code>,
267      * extract its <code>cause</code> and pass it to the
268      * <code>ELException</code> constructor.
269      * @see javax.el.MethodExpression#invoke(javax.el.ELContext,
270      * java.lang.Object[])
271      */

272     public Object JavaDoc invoke(ELContext context, Object JavaDoc[] params)
273             throws PropertyNotFoundException, MethodNotFoundException,
274             ELException {
275         EvaluationContext ctx = new EvaluationContext(context, this.fnMapper,
276                 this.varMapper);
277         return this.getNode().invoke(ctx, this.paramTypes, params);
278     }
279
280     /*
281      * (non-Javadoc)
282      *
283      * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
284      */

285     public void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc,
286             ClassNotFoundException JavaDoc {
287         this.expr = in.readUTF();
288         String JavaDoc type = in.readUTF();
289         if (!"".equals(type)) {
290             this.expectedType = ReflectionUtil.forName(type);
291         }
292         this.paramTypes = ReflectionUtil.toTypeArray(((String JavaDoc[]) in
293                 .readObject()));
294         this.fnMapper = (FunctionMapper) in.readObject();
295         this.varMapper = (VariableMapper) in.readObject();
296     }
297
298     /*
299      * (non-Javadoc)
300      *
301      * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
302      */

303     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
304         out.writeUTF(this.expr);
305         out.writeUTF((this.expectedType != null) ? this.expectedType.getName()
306                 : "");
307         out.writeObject(ReflectionUtil.toTypeNameArray(this.paramTypes));
308         out.writeObject(this.fnMapper);
309         out.writeObject(this.varMapper);
310     }
311
312     public boolean isLiteralText() {
313         return false;
314     }
315 }
316
Popular Tags