View Javadoc

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  package org.apache.commons.el;
18  
19  import java.lang.reflect.InvocationTargetException;
20  import java.lang.reflect.Method;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.ArrayList;
24  
25  import javax.servlet.jsp.el.ELException;
26  import javax.servlet.jsp.el.FunctionMapper;
27  import javax.servlet.jsp.el.VariableResolver;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  
32  /**
33   *
34   * <p>Represents a function call.</p>
35   * 
36   * @author Shawn Bayern (in the style of Nathan's other classes)
37   **/
38  
39  public class FunctionInvocation
40    extends Expression
41  {
42      //-------------------------------------
43      // Constants
44      //-------------------------------------
45      private static Log log = LogFactory.getLog(FunctionInvocation.class);
46      
47    //-------------------------------------
48    // Properties
49    //-------------------------------------
50    // property index
51  
52    private String functionName;
53    private List argumentList;
54    public String getFunctionName() { return functionName; }
55    public void setFunctionName(String f) { functionName = f; }
56    public List getArgumentList() { return argumentList; }
57    public void setArgumentList(List l) { argumentList = l; }
58  
59    //-------------------------------------
60    /**
61     * Constructor
62     **/
63    public FunctionInvocation (String functionName, List argumentList)
64    {
65      this.functionName = functionName;
66      this.argumentList = argumentList;
67    }
68  
69    //-------------------------------------
70    // Expression methods
71    //-------------------------------------
72    /**
73     * Returns the expression in the expression language syntax
74     **/
75    public String getExpressionString ()
76    {
77      StringBuffer b = new StringBuffer();
78      b.append(functionName);
79      b.append("(");
80      Iterator i = argumentList.iterator();
81      while (i.hasNext()) {
82        b.append(((Expression) i.next()).getExpressionString());
83        if (i.hasNext())
84          b.append(", ");
85      }
86      b.append(")");
87      return b.toString();
88    }
89  
90  
91    //-------------------------------------
92    /**
93     *
94     * Evaluates by looking up the name in the VariableResolver
95     **/
96    public Object evaluate (VariableResolver pResolver,
97  			  FunctionMapper functions)
98      throws ELException
99    {
100 
101     Method target = resolveFunction(functions);
102     if (target == null) {
103         if (log.isErrorEnabled()) {
104             String message = MessageUtil.getMessageWithArgs(
105                 Constants.UNKNOWN_FUNCTION, functionName);
106             log.error(message);
107             throw new ELException(message);
108         }
109     }      
110 
111     // ensure that the number of arguments matches the number of parameters
112     Class[] params = target.getParameterTypes();
113     if (params.length != argumentList.size()) {
114         if (log.isErrorEnabled()) {
115             String message = MessageUtil.getMessageWithArgs(
116                 Constants.INAPPROPRIATE_FUNCTION_ARG_COUNT,
117                 functionName, new Integer(params.length),
118                 new Integer(argumentList.size()));
119             log.error(message);
120             throw new ELException(message);
121         }      
122     }
123 
124     // now, walk through each parameter, evaluating and casting its argument
125     Object[] arguments = new Object[argumentList.size()];
126     for (int i = 0; i < params.length; i++) {
127       // evaluate
128       arguments[i] = ((Expression) argumentList.get(i)).evaluate(pResolver,
129 								 functions);
130       // coerce
131       arguments[i] = Coercions.coerce(arguments[i], params[i]);
132     }
133 
134     // finally, invoke the target method, which we know to be static
135     try {
136       return (target.invoke(null, arguments));
137     } catch (InvocationTargetException ex) {
138         if (log.isErrorEnabled()) {
139             String message = MessageUtil.getMessageWithArgs(
140                 Constants.FUNCTION_INVOCATION_ERROR,
141                 functionName);
142             Throwable t = ex.getTargetException();
143             log.error(message, t);
144             throw new ELException(message, t);
145         }      
146       return null;
147     } catch (Throwable t) {
148         if (log.isErrorEnabled()) {
149             String message = MessageUtil.getMessageWithArgs(
150                 Constants.FUNCTION_INVOCATION_ERROR,
151                 functionName);            
152             log.error(message, t);
153             throw new ELException(message, t); 
154         }      
155       return null;
156     }
157   }
158 
159   /**
160    * Returns the <code>Method</code> which is mapped to the function
161    * name used by this <code>FunctionInvocation</code>.
162    * @param functions The function mappings in use for this evaluation
163    * @return the <code>Method</code> to execute 
164    * @throws ELException
165    */
166   protected Method resolveFunction(FunctionMapper functions) throws ELException {
167       // if the Map is null, then the function is invalid 
168       if (functions == null) { 
169           return null;
170       }                    
171 
172       // normalize function name
173       String prefix = null; 
174       String localName = null; 
175       int index = functionName.indexOf( ':' );
176       if (index == -1) {
177         prefix = "";
178         localName = functionName;
179       } else {
180         prefix = functionName.substring( 0, index );
181         localName = functionName.substring( index + 1 );
182       }       
183   
184       // ensure that the function's name is mapped
185       Method target = (Method) functions.resolveFunction(prefix, localName);
186    
187        return target; 
188    }
189 
190    public Expression bindFunctions(final FunctionMapper functions)
191            throws ELException {
192        final List argList = new ArrayList(argumentList.size());
193        for (Iterator argIter = argumentList.iterator(); argIter.hasNext();) {
194            Expression arg = (Expression) argIter.next();
195            argList.add(arg.bindFunctions(functions));
196        }
197        return new BoundFunctionInvocation(
198                resolveFunction(functions),
199                functionName,
200                argList);
201    }
202 
203   //-------------------------------------
204 }