1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts2.jasper.runtime;
19
20 import org.apache.struts2.jasper.security.SecurityUtil;
21
22 import javax.servlet.jsp.el.FunctionMapper;
23 import java.lang.reflect.Method;
24 import java.security.AccessController;
25 import java.security.PrivilegedAction;
26 import java.security.PrivilegedActionException;
27 import java.security.PrivilegedExceptionAction;
28 import java.util.HashMap;
29
30 /***
31 * Maps EL functions to their Java method counterparts. Keeps the
32 * actual Method objects protected so that JSP pages can't indirectly
33 * do reflection.
34 *
35 * @author Mark Roth
36 * @author Kin-man Chung
37 */
38 public final class ProtectedFunctionMapper implements FunctionMapper {
39
40 /***
41 * Maps "prefix:name" to java.lang.Method objects.
42 */
43 private HashMap fnmap = null;
44
45 /***
46 * If there is only one function in the map, this is the Method for it.
47 */
48 private Method theMethod = null;
49
50 /***
51 * Constructor has protected access.
52 */
53 private ProtectedFunctionMapper() {
54 }
55
56 /***
57 * Generated Servlet and Tag Handler implementations call this
58 * method to retrieve an instance of the ProtectedFunctionMapper.
59 * This is necessary since generated code does not have access to
60 * create instances of classes in this package.
61 *
62 * @return A new protected function mapper.
63 */
64 public static ProtectedFunctionMapper getInstance() {
65 ProtectedFunctionMapper funcMapper;
66 if (SecurityUtil.isPackageProtectionEnabled()) {
67 funcMapper = (ProtectedFunctionMapper) AccessController.doPrivileged(
68 new PrivilegedAction() {
69 public Object run() {
70 return new ProtectedFunctionMapper();
71 }
72 });
73 } else {
74 funcMapper = new ProtectedFunctionMapper();
75 }
76 funcMapper.fnmap = new java.util.HashMap();
77 return funcMapper;
78 }
79
80 /***
81 * Stores a mapping from the given EL function prefix and name to
82 * the given Java method.
83 *
84 * @param fnQName The EL function qualified name (including prefix)
85 * @param c The class containing the Java method
86 * @param methodName The name of the Java method
87 * @param args The arguments of the Java method
88 * @throws RuntimeException if no method with the given signature
89 * could be found.
90 */
91 public void mapFunction(String fnQName, final Class c,
92 final String methodName, final Class[] args) {
93 java.lang.reflect.Method method;
94 if (SecurityUtil.isPackageProtectionEnabled()) {
95 try {
96 method = (java.lang.reflect.Method) AccessController.doPrivileged(new PrivilegedExceptionAction() {
97
98 public Object run() throws Exception {
99 return c.getDeclaredMethod(methodName, args);
100 }
101 });
102 } catch (PrivilegedActionException ex) {
103 throw new RuntimeException(
104 "Invalid function mapping - no such method: "
105 + ex.getException().getMessage());
106 }
107 } else {
108 try {
109 method = c.getDeclaredMethod(methodName, args);
110 } catch (NoSuchMethodException e) {
111 throw new RuntimeException(
112 "Invalid function mapping - no such method: "
113 + e.getMessage());
114 }
115 }
116
117 this.fnmap.put(fnQName, method);
118 }
119
120 /***
121 * Creates an instance for this class, and stores the Method for
122 * the given EL function prefix and name. This method is used for
123 * the case when there is only one function in the EL expression.
124 *
125 * @param fnQName The EL function qualified name (including prefix)
126 * @param c The class containing the Java method
127 * @param methodName The name of the Java method
128 * @param args The arguments of the Java method
129 * @throws RuntimeException if no method with the given signature
130 * could be found.
131 */
132 public static ProtectedFunctionMapper getMapForFunction(
133 String fnQName, final Class c,
134 final String methodName, final Class[] args) {
135 java.lang.reflect.Method method;
136 ProtectedFunctionMapper funcMapper;
137 if (SecurityUtil.isPackageProtectionEnabled()) {
138 funcMapper = (ProtectedFunctionMapper) AccessController.doPrivileged(
139 new PrivilegedAction() {
140 public Object run() {
141 return new ProtectedFunctionMapper();
142 }
143 });
144
145 try {
146 method = (java.lang.reflect.Method) AccessController.doPrivileged
147 (new PrivilegedExceptionAction() {
148
149 public Object run() throws Exception {
150 return c.getDeclaredMethod(methodName, args);
151 }
152 });
153 } catch (PrivilegedActionException ex) {
154 throw new RuntimeException(
155 "Invalid function mapping - no such method: "
156 + ex.getException().getMessage());
157 }
158 } else {
159 funcMapper = new ProtectedFunctionMapper();
160 try {
161 method = c.getDeclaredMethod(methodName, args);
162 } catch (NoSuchMethodException e) {
163 throw new RuntimeException(
164 "Invalid function mapping - no such method: "
165 + e.getMessage());
166 }
167 }
168 funcMapper.theMethod = method;
169 return funcMapper;
170 }
171
172 /***
173 * Resolves the specified local name and prefix into a Java.lang.Method.
174 * Returns null if the prefix and local name are not found.
175 *
176 * @param prefix the prefix of the function
177 * @param localName the short name of the function
178 * @return the result of the method mapping. Null means no entry found.
179 */
180 public Method resolveFunction(String prefix, String localName) {
181 if (this.fnmap != null) {
182 return (Method) this.fnmap.get(prefix + ":" + localName);
183 }
184 return theMethod;
185 }
186 }
187