/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jasper.runtime; import java.lang.reflect.Method; import java.util.HashMap; import javax.servlet.jsp.el.FunctionMapper; /** * Maps EL functions to their Java method counterparts. Keeps the actual Method * objects protected so that JSP pages can't indirectly do reflection. * * @author Mark Roth * @author Kin-man Chung */ @SuppressWarnings("deprecation") // Have to support old JSP EL API public final class ProtectedFunctionMapper extends javax.el.FunctionMapper implements FunctionMapper { /** * Maps "prefix:name" to java.lang.Method objects. */ private HashMap<String,Method> fnmap = null; /** * If there is only one function in the map, this is the Method for it. */ private Method theMethod = null; /** * Constructor has protected access. */ private ProtectedFunctionMapper() { } /** * Generated Servlet and Tag Handler implementations call this method to * retrieve an instance of the ProtectedFunctionMapper. * * @return A new protected function mapper. */ public static ProtectedFunctionMapper getInstance() { ProtectedFunctionMapper funcMapper = new ProtectedFunctionMapper(); funcMapper.fnmap = new HashMap<>(); return funcMapper; } /** * Stores a mapping from the given EL function prefix and name to the given * Java method. * * @param fnQName * The EL function qualified name (including prefix) * @param c * The class containing the Java method * @param methodName * The name of the Java method * @param args * The arguments of the Java method * @throws RuntimeException * if no method with the given signature could be found. */ public void mapFunction(String fnQName, final Class<?> c, final String methodName, final Class<?>[] args) { // Skip if null values were passed in. They indicate a function // added via a lambda or ImportHandler; nether of which need to be // placed in the Map. if (fnQName == null) { return; } java.lang.reflect.Method method; try { method = c.getMethod(methodName, args); } catch (NoSuchMethodException e) { throw new RuntimeException( "Invalid function mapping - no such method: " + e.getMessage()); } this.fnmap.put(fnQName, method); } /** * Creates an instance for this class, and stores the Method for the given * EL function prefix and name. This method is used for the case when there * is only one function in the EL expression. * * @param fnQName * The EL function qualified name (including prefix) * @param c * The class containing the Java method * @param methodName * The name of the Java method * @param args * The arguments of the Java method * @throws RuntimeException * if no method with the given signature could be found. * @return the mapped function */ public static ProtectedFunctionMapper getMapForFunction(String fnQName, final Class<?> c, final String methodName, final Class<?>[] args) { java.lang.reflect.Method method = null; ProtectedFunctionMapper funcMapper = new ProtectedFunctionMapper(); // Skip if null values were passed in. They indicate a function // added via a lambda or ImportHandler; nether of which need to be // placed in the Map. if (fnQName != null) { try { method = c.getMethod(methodName, args); } catch (NoSuchMethodException e) { throw new RuntimeException( "Invalid function mapping - no such method: " + e.getMessage()); } } funcMapper.theMethod = method; return funcMapper; } /** * Resolves the specified local name and prefix into a Java.lang.Method. * Returns null if the prefix and local name are not found. * * @param prefix * the prefix of the function * @param localName * the short name of the function * @return the result of the method mapping. Null means no entry found. */ @Override public Method resolveFunction(String prefix, String localName) { if (this.fnmap != null) { return this.fnmap.get(prefix + ":" + localName); } return theMethod; } }