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  
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