Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » el » [javadoc | source]
    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;
   21   import java.io.IOException;
   22   import java.io.ObjectInput;
   23   import java.io.ObjectOutput;
   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.EvaluationContext;
   38   import org.apache.el.lang.ExpressionBuilder;
   39   import org.apache.el.parser.Node;
   40   import org.apache.el.util.ReflectionUtil;
   41   
   42   
   43   /**
   44    * An <code>Expression</code> that refers to a method on an object.
   45    * 
   46    * <p>
   47    * <code>The {@link ExpressionFactory#createMethodExpression} method
   48    * can be used to parse an expression string and return a concrete instance
   49    * of <code>MethodExpression</code> that encapsulates the parsed expression.
   50    * The {@link FunctionMapper} is used at parse time, not evaluation time, 
   51    * so one is not needed to evaluate an expression using this class.  
   52    * However, the {@link ELContext} is needed at evaluation time.</p>
   53    *
   54    * <p>The {@link #getMethodInfo} and {@link #invoke} methods will evaluate the 
   55    * expression each time they are called. The {@link ELResolver} in the 
   56    * <code>ELContext</code> is used to resolve the top-level variables and to 
   57    * determine the behavior of the <code>.</code> and <code>[]</code> 
   58    * operators. For any of the two methods, the {@link ELResolver#getValue} 
   59    * method is used to resolve all properties up to but excluding the last 
   60    * one. This provides the <code>base</code> object on which the method
   61    * appears. If the <code>base</code> object is null, a 
   62    * <code>NullPointerException</code> must be thrown. At the last resolution, 
   63    * the final <code>property</code> is then coerced to a <code>String</code>,
   64    * which provides the name of the method to be found. A method matching the 
   65    * name and expected parameters provided at parse time is found and it is 
   66    * either queried or invoked (depending on the method called on this
   67    * <code>MethodExpression</code>).</p>
   68    *
   69    * <p>See the notes about comparison, serialization and immutability in 
   70    * the {@link Expression} javadocs.
   71    *
   72    * @see javax.el.ELResolver
   73    * @see javax.el.Expression
   74    * @see javax.el.ExpressionFactory
   75    * @see javax.el.MethodExpression
   76    * 
   77    * @author Jacob Hookom [jacob@hookom.net]
   78    * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: markt $
   79    */
   80   public final class MethodExpressionImpl extends MethodExpression implements
   81           Externalizable {
   82   
   83       private Class expectedType;
   84   
   85       private String expr;
   86   
   87       private FunctionMapper fnMapper;
   88   
   89       private VariableMapper varMapper;
   90   
   91       private transient Node node;
   92   
   93       private Class[] paramTypes;
   94   
   95       /**
   96        * 
   97        */
   98       public MethodExpressionImpl() {
   99           super();
  100       }
  101   
  102       /**
  103        * @param expr
  104        * @param node
  105        * @param fnMapper
  106        * @param expectedType
  107        * @param paramTypes
  108        */
  109       public MethodExpressionImpl(String expr, Node node,
  110               FunctionMapper fnMapper, VariableMapper varMapper,
  111               Class expectedType, Class[] paramTypes) {
  112           super();
  113           this.expr = expr;
  114           this.node = node;
  115           this.fnMapper = fnMapper;
  116           this.varMapper = varMapper;
  117           this.expectedType = expectedType;
  118           this.paramTypes = paramTypes;
  119       }
  120   
  121       /**
  122        * Determines whether the specified object is equal to this
  123        * <code>Expression</code>.
  124        * 
  125        * <p>
  126        * The result is <code>true</code> if and only if the argument is not
  127        * <code>null</code>, is an <code>Expression</code> object that is the
  128        * of the same type (<code>ValueExpression</code> or
  129        * <code>MethodExpression</code>), and has an identical parsed
  130        * representation.
  131        * </p>
  132        * 
  133        * <p>
  134        * Note that two expressions can be equal if their expression Strings are
  135        * different. For example, <code>${fn1:foo()}</code> and
  136        * <code>${fn2:foo()}</code> are equal if their corresponding
  137        * <code>FunctionMapper</code>s mapped <code>fn1:foo</code> and
  138        * <code>fn2:foo</code> to the same method.
  139        * </p>
  140        * 
  141        * @param obj
  142        *            the <code>Object</code> to test for equality.
  143        * @return <code>true</code> if <code>obj</code> equals this
  144        *         <code>Expression</code>; <code>false</code> otherwise.
  145        * @see java.util.Hashtable
  146        * @see java.lang.Object#equals(java.lang.Object)
  147        */
  148       public boolean equals(Object obj) {
  149           return (obj instanceof MethodExpressionImpl && obj.hashCode() == this
  150                   .hashCode());
  151       }
  152   
  153       /**
  154        * Returns the original String used to create this <code>Expression</code>,
  155        * unmodified.
  156        * 
  157        * <p>
  158        * This is used for debugging purposes but also for the purposes of
  159        * comparison (e.g. to ensure the expression in a configuration file has not
  160        * changed).
  161        * </p>
  162        * 
  163        * <p>
  164        * This method does not provide sufficient information to re-create an
  165        * expression. Two different expressions can have exactly the same
  166        * expression string but different function mappings. Serialization should
  167        * be used to save and restore the state of an <code>Expression</code>.
  168        * </p>
  169        * 
  170        * @return The original expression String.
  171        * 
  172        * @see javax.el.Expression#getExpressionString()
  173        */
  174       public String getExpressionString() {
  175           return this.expr;
  176       }
  177   
  178       /**
  179        * Evaluates the expression relative to the provided context, and returns
  180        * information about the actual referenced method.
  181        * 
  182        * @param context
  183        *            The context of this evaluation
  184        * @return an instance of <code>MethodInfo</code> containing information
  185        *         about the method the expression evaluated to.
  186        * @throws NullPointerException
  187        *             if context is <code>null</code> or the base object is
  188        *             <code>null</code> on the last resolution.
  189        * @throws PropertyNotFoundException
  190        *             if one of the property resolutions failed because a specified
  191        *             variable or property does not exist or is not readable.
  192        * @throws MethodNotFoundException
  193        *             if no suitable method can be found.
  194        * @throws ELException
  195        *             if an exception was thrown while performing property or
  196        *             variable resolution. The thrown exception must be included as
  197        *             the cause property of this exception, if available.
  198        * @see javax.el.MethodExpression#getMethodInfo(javax.el.ELContext)
  199        */
  200       public MethodInfo getMethodInfo(ELContext context)
  201               throws PropertyNotFoundException, MethodNotFoundException,
  202               ELException {
  203           Node n = this.getNode();
  204           EvaluationContext ctx = new EvaluationContext(context, this.fnMapper,
  205                   this.varMapper);
  206           return n.getMethodInfo(ctx, this.paramTypes);
  207       }
  208   
  209       /**
  210        * @return
  211        * @throws ELException
  212        */
  213       private Node getNode() throws ELException {
  214           if (this.node == null) {
  215               this.node = ExpressionBuilder.createNode(this.expr);
  216           }
  217           return this.node;
  218       }
  219   
  220       /**
  221        * Returns the hash code for this <code>Expression</code>.
  222        * 
  223        * <p>
  224        * See the note in the {@link #equals} method on how two expressions can be
  225        * equal if their expression Strings are different. Recall that if two
  226        * objects are equal according to the <code>equals(Object)</code> method,
  227        * then calling the <code>hashCode</code> method on each of the two
  228        * objects must produce the same integer result. Implementations must take
  229        * special note and implement <code>hashCode</code> correctly.
  230        * </p>
  231        * 
  232        * @return The hash code for this <code>Expression</code>.
  233        * @see #equals
  234        * @see java.util.Hashtable
  235        * @see java.lang.Object#hashCode()
  236        */
  237       public int hashCode() {
  238           return this.expr.hashCode();
  239       }
  240   
  241       /**
  242        * Evaluates the expression relative to the provided context, invokes the
  243        * method that was found using the supplied parameters, and returns the
  244        * result of the method invocation.
  245        * 
  246        * @param context
  247        *            The context of this evaluation.
  248        * @param params
  249        *            The parameters to pass to the method, or <code>null</code>
  250        *            if no parameters.
  251        * @return the result of the method invocation (<code>null</code> if the
  252        *         method has a <code>void</code> return type).
  253        * @throws NullPointerException
  254        *             if context is <code>null</code> or the base object is
  255        *             <code>null</code> on the last resolution.
  256        * @throws PropertyNotFoundException
  257        *             if one of the property resolutions failed because a specified
  258        *             variable or property does not exist or is not readable.
  259        * @throws MethodNotFoundException
  260        *             if no suitable method can be found.
  261        * @throws ELException
  262        *             if an exception was thrown while performing property or
  263        *             variable resolution. The thrown exception must be included as
  264        *             the cause property of this exception, if available. If the
  265        *             exception thrown is an <code>InvocationTargetException</code>,
  266        *             extract its <code>cause</code> and pass it to the
  267        *             <code>ELException</code> constructor.
  268        * @see javax.el.MethodExpression#invoke(javax.el.ELContext,
  269        *      java.lang.Object[])
  270        */
  271       public Object invoke(ELContext context, Object[] params)
  272               throws PropertyNotFoundException, MethodNotFoundException,
  273               ELException {
  274           EvaluationContext ctx = new EvaluationContext(context, this.fnMapper,
  275                   this.varMapper);
  276           return this.getNode().invoke(ctx, this.paramTypes, params);
  277       }
  278   
  279       /*
  280        * (non-Javadoc)
  281        * 
  282        * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
  283        */
  284       public void readExternal(ObjectInput in) throws IOException,
  285               ClassNotFoundException {
  286           this.expr = in.readUTF();
  287           String type = in.readUTF();
  288           if (!"".equals(type)) {
  289               this.expectedType = ReflectionUtil.forName(type);
  290           }
  291           this.paramTypes = ReflectionUtil.toTypeArray(((String[]) in
  292                   .readObject()));
  293           this.fnMapper = (FunctionMapper) in.readObject();
  294           this.varMapper = (VariableMapper) in.readObject();
  295       }
  296   
  297       /*
  298        * (non-Javadoc)
  299        * 
  300        * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
  301        */
  302       public void writeExternal(ObjectOutput out) throws IOException {
  303           out.writeUTF(this.expr);
  304           out.writeUTF((this.expectedType != null) ? this.expectedType.getName()
  305                   : "");
  306           out.writeObject(ReflectionUtil.toTypeNameArray(this.paramTypes));
  307           out.writeObject(this.fnMapper);
  308           out.writeObject(this.varMapper);
  309       }
  310   
  311       public boolean isLiteralText() {
  312           return false;
  313       }
  314   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » el » [javadoc | source]