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: */
017:
018: package org.apache.jasper.runtime;
019:
020: import java.util.HashMap;
021: import java.security.AccessController;
022: import java.security.PrivilegedAction;
023: import java.security.PrivilegedExceptionAction;
024: import java.security.PrivilegedActionException;
025: import java.lang.reflect.Method;
026: import javax.servlet.jsp.el.FunctionMapper;
027:
028: import org.apache.jasper.security.SecurityUtil;
029:
030: /**
031: * Maps EL functions to their Java method counterparts. Keeps the actual Method
032: * objects protected so that JSP pages can't indirectly do reflection.
033: *
034: * @author Mark Roth
035: * @author Kin-man Chung
036: */
037: public final class ProtectedFunctionMapper extends
038: javax.el.FunctionMapper implements FunctionMapper {
039:
040: /**
041: * Maps "prefix:name" to java.lang.Method objects.
042: */
043: private HashMap fnmap = null;
044:
045: /**
046: * If there is only one function in the map, this is the Method for it.
047: */
048: private Method theMethod = null;
049:
050: /**
051: * Constructor has protected access.
052: */
053: private ProtectedFunctionMapper() {
054: }
055:
056: /**
057: * Generated Servlet and Tag Handler implementations call this method to
058: * retrieve an instance of the ProtectedFunctionMapper. This is necessary
059: * since generated code does not have access to create instances of classes
060: * in this package.
061: *
062: * @return A new protected function mapper.
063: */
064: public static ProtectedFunctionMapper getInstance() {
065: ProtectedFunctionMapper funcMapper;
066: if (SecurityUtil.isPackageProtectionEnabled()) {
067: funcMapper = (ProtectedFunctionMapper) AccessController
068: .doPrivileged(new PrivilegedAction() {
069: public Object run() {
070: return new ProtectedFunctionMapper();
071: }
072: });
073: } else {
074: funcMapper = new ProtectedFunctionMapper();
075: }
076: funcMapper.fnmap = new java.util.HashMap();
077: return funcMapper;
078: }
079:
080: /**
081: * Stores a mapping from the given EL function prefix and name to the given
082: * Java method.
083: *
084: * @param fnQName
085: * The EL function qualified name (including prefix)
086: * @param c
087: * The class containing the Java method
088: * @param methodName
089: * The name of the Java method
090: * @param args
091: * The arguments of the Java method
092: * @throws RuntimeException
093: * if no method with the given signature could be found.
094: */
095: public void mapFunction(String fnQName, final Class c,
096: final String methodName, final Class[] args) {
097: java.lang.reflect.Method method;
098: if (SecurityUtil.isPackageProtectionEnabled()) {
099: try {
100: method = (java.lang.reflect.Method) AccessController
101: .doPrivileged(new PrivilegedExceptionAction() {
102:
103: public Object run() throws Exception {
104: return c.getDeclaredMethod(methodName,
105: args);
106: }
107: });
108: } catch (PrivilegedActionException ex) {
109: throw new RuntimeException(
110: "Invalid function mapping - no such method: "
111: + ex.getException().getMessage());
112: }
113: } else {
114: try {
115: method = c.getDeclaredMethod(methodName, args);
116: } catch (NoSuchMethodException e) {
117: throw new RuntimeException(
118: "Invalid function mapping - no such method: "
119: + e.getMessage());
120: }
121: }
122:
123: this .fnmap.put(fnQName, method);
124: }
125:
126: /**
127: * Creates an instance for this class, and stores the Method for the given
128: * EL function prefix and name. This method is used for the case when there
129: * is only one function in the EL expression.
130: *
131: * @param fnQName
132: * The EL function qualified name (including prefix)
133: * @param c
134: * The class containing the Java method
135: * @param methodName
136: * The name of the Java method
137: * @param args
138: * The arguments of the Java method
139: * @throws RuntimeException
140: * if no method with the given signature could be found.
141: */
142: public static ProtectedFunctionMapper getMapForFunction(
143: String fnQName, final Class c, final String methodName,
144: final Class[] args) {
145: java.lang.reflect.Method method;
146: ProtectedFunctionMapper funcMapper;
147: if (SecurityUtil.isPackageProtectionEnabled()) {
148: funcMapper = (ProtectedFunctionMapper) AccessController
149: .doPrivileged(new PrivilegedAction() {
150: public Object run() {
151: return new ProtectedFunctionMapper();
152: }
153: });
154:
155: try {
156: method = (java.lang.reflect.Method) AccessController
157: .doPrivileged(new PrivilegedExceptionAction() {
158:
159: public Object run() throws Exception {
160: return c.getDeclaredMethod(methodName,
161: args);
162: }
163: });
164: } catch (PrivilegedActionException ex) {
165: throw new RuntimeException(
166: "Invalid function mapping - no such method: "
167: + ex.getException().getMessage());
168: }
169: } else {
170: funcMapper = new ProtectedFunctionMapper();
171: try {
172: method = c.getDeclaredMethod(methodName, args);
173: } catch (NoSuchMethodException e) {
174: throw new RuntimeException(
175: "Invalid function mapping - no such method: "
176: + e.getMessage());
177: }
178: }
179: funcMapper.theMethod = method;
180: return funcMapper;
181: }
182:
183: /**
184: * Resolves the specified local name and prefix into a Java.lang.Method.
185: * Returns null if the prefix and local name are not found.
186: *
187: * @param prefix
188: * the prefix of the function
189: * @param localName
190: * the short name of the function
191: * @return the result of the method mapping. Null means no entry found.
192: */
193: public Method resolveFunction(String prefix, String localName) {
194: if (this .fnmap != null) {
195: return (Method) this .fnmap.get(prefix + ":" + localName);
196: }
197: return theMethod;
198: }
199: }
|