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 */ 017package org.apache.commons.el; 018 019import java.lang.reflect.InvocationTargetException; 020import java.lang.reflect.Method; 021import java.util.Iterator; 022import java.util.List; 023import java.util.ArrayList; 024 025import javax.servlet.jsp.el.ELException; 026import javax.servlet.jsp.el.FunctionMapper; 027import javax.servlet.jsp.el.VariableResolver; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031 032/** 033 * 034 * <p>Represents a function call.</p> 035 * 036 * @author Shawn Bayern (in the style of Nathan's other classes) 037 **/ 038 039public class FunctionInvocation 040 extends Expression 041{ 042 //------------------------------------- 043 // Constants 044 //------------------------------------- 045 private static Log log = LogFactory.getLog(FunctionInvocation.class); 046 047 //------------------------------------- 048 // Properties 049 //------------------------------------- 050 // property index 051 052 private String functionName; 053 private List argumentList; 054 public String getFunctionName() { return functionName; } 055 public void setFunctionName(String f) { functionName = f; } 056 public List getArgumentList() { return argumentList; } 057 public void setArgumentList(List l) { argumentList = l; } 058 059 //------------------------------------- 060 /** 061 * Constructor 062 **/ 063 public FunctionInvocation (String functionName, List argumentList) 064 { 065 this.functionName = functionName; 066 this.argumentList = argumentList; 067 } 068 069 //------------------------------------- 070 // Expression methods 071 //------------------------------------- 072 /** 073 * Returns the expression in the expression language syntax 074 **/ 075 public String getExpressionString () 076 { 077 StringBuffer b = new StringBuffer(); 078 b.append(functionName); 079 b.append("("); 080 Iterator i = argumentList.iterator(); 081 while (i.hasNext()) { 082 b.append(((Expression) i.next()).getExpressionString()); 083 if (i.hasNext()) 084 b.append(", "); 085 } 086 b.append(")"); 087 return b.toString(); 088 } 089 090 091 //------------------------------------- 092 /** 093 * 094 * Evaluates by looking up the name in the VariableResolver 095 **/ 096 public Object evaluate (VariableResolver pResolver, 097 FunctionMapper functions) 098 throws ELException 099 { 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}