1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.security.intercept.method;
17
18 import java.lang.reflect.Method;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.springframework.beans.factory.BeanClassLoaderAware;
30 import org.springframework.security.ConfigAttributeDefinition;
31 import org.springframework.util.Assert;
32 import org.springframework.util.ClassUtils;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefinitionSource implements BeanClassLoaderAware {
49
50
51 private static final Log logger = LogFactory.getLog(MapBasedMethodDefinitionSource.class);
52
53
54 private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
55
56
57 protected Map methodMap = new HashMap();
58
59
60 private Map nameMap = new HashMap();
61
62
63
64 public MapBasedMethodDefinitionSource() {
65 }
66
67
68
69
70
71 public MapBasedMethodDefinitionSource(Map methodMap) {
72 Iterator iterator = methodMap.entrySet().iterator();
73
74 while (iterator.hasNext()) {
75 Map.Entry entry = (Map.Entry) iterator.next();
76 addSecureMethod((String)entry.getKey(), (ConfigAttributeDefinition)entry.getValue());
77 }
78 }
79
80
81
82
83 protected ConfigAttributeDefinition findAttributes(Class clazz) {
84 return null;
85 }
86
87
88
89
90 protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
91 if (targetClass == null) {
92 return null;
93 }
94
95 return findAttributesSpecifiedAgainst(method, targetClass);
96 }
97
98 private ConfigAttributeDefinition findAttributesSpecifiedAgainst(Method method, Class clazz) {
99 RegisteredMethod registeredMethod = new RegisteredMethod(method, clazz);
100 if (methodMap.containsKey(registeredMethod)) {
101 return (ConfigAttributeDefinition) methodMap.get(registeredMethod);
102 }
103
104 if (clazz.getSuperclass() != null) {
105 return findAttributesSpecifiedAgainst(method, clazz.getSuperclass());
106 }
107 return null;
108 }
109
110
111
112
113
114
115
116
117 public void addSecureMethod(String name, ConfigAttributeDefinition attr) {
118 int lastDotIndex = name.lastIndexOf(".");
119
120 if (lastDotIndex == -1) {
121 throw new IllegalArgumentException("'" + name + "' is not a valid method name: format is FQN.methodName");
122 }
123
124 String methodName = name.substring(lastDotIndex + 1);
125 Assert.hasText(methodName, "Method not found for '" + name + "'");
126
127 String typeName = name.substring(0, lastDotIndex);
128 Class type = ClassUtils.resolveClassName(typeName, this.beanClassLoader);
129
130 addSecureMethod(type, methodName, attr);
131 }
132
133
134
135
136
137
138
139
140
141 public void addSecureMethod(Class javaType, String mappedName, ConfigAttributeDefinition attr) {
142 String name = javaType.getName() + '.' + mappedName;
143
144 if (logger.isDebugEnabled()) {
145 logger.debug("Request to add secure method [" + name + "] with attributes [" + attr + "]");
146 }
147
148 Method[] methods = javaType.getMethods();
149 List matchingMethods = new ArrayList();
150
151 for (int i = 0; i < methods.length; i++) {
152 if (methods[i].getName().equals(mappedName) || isMatch(methods[i].getName(), mappedName)) {
153 matchingMethods.add(methods[i]);
154 }
155 }
156
157 if (matchingMethods.isEmpty()) {
158 throw new IllegalArgumentException("Couldn't find method '" + mappedName + "' on '" + javaType + "'");
159 }
160
161
162 for (Iterator it = matchingMethods.iterator(); it.hasNext();) {
163 Method method = (Method) it.next();
164 RegisteredMethod registeredMethod = new RegisteredMethod(method, javaType);
165 String regMethodName = (String) this.nameMap.get(registeredMethod);
166
167 if ((regMethodName == null) || (!regMethodName.equals(name) && (regMethodName.length() <= name.length()))) {
168
169
170 if (regMethodName != null) {
171 logger.debug("Replacing attributes for secure method [" + method + "]: current name [" + name
172 + "] is more specific than [" + regMethodName + "]");
173 }
174
175 this.nameMap.put(registeredMethod, name);
176 addSecureMethod(registeredMethod, attr);
177 } else {
178 logger.debug("Keeping attributes for secure method [" + method + "]: current name [" + name
179 + "] is not more specific than [" + regMethodName + "]");
180 }
181 }
182 }
183
184
185
186
187
188
189
190 public void addSecureMethod(Class javaType, Method method, ConfigAttributeDefinition attr) {
191 RegisteredMethod key = new RegisteredMethod(method, javaType);
192
193 if (methodMap.containsKey(key)) {
194 logger.debug("Method [" + method + "] is already registered with attributes [" + methodMap.get(key) + "]");
195 return;
196 }
197
198 methodMap.put(key, attr);
199 }
200
201
202
203
204
205
206
207 private void addSecureMethod(RegisteredMethod method, ConfigAttributeDefinition attr) {
208 Assert.notNull(method, "RegisteredMethod required");
209 Assert.notNull(attr, "Configuration attribute required");
210 if (logger.isInfoEnabled()) {
211 logger.info("Adding secure method [" + method + "] with attributes [" + attr + "]");
212 }
213 this.methodMap.put(method, attr);
214 }
215
216
217
218
219
220
221 public Collection getConfigAttributeDefinitions() {
222 return Collections.unmodifiableCollection(methodMap.values());
223 }
224
225
226
227
228
229
230
231
232
233
234 private boolean isMatch(String methodName, String mappedName) {
235 return (mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0, mappedName.length() - 1)))
236 || (mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1, mappedName.length())));
237 }
238
239 public void setBeanClassLoader(ClassLoader beanClassLoader) {
240 Assert.notNull(beanClassLoader, "Bean class loader required");
241 this.beanClassLoader = beanClassLoader;
242 }
243
244
245
246
247 public int getMethodMapSize() {
248 return methodMap.size();
249 }
250
251
252
253
254
255
256
257
258 private class RegisteredMethod {
259 private Method method;
260 private Class registeredJavaType;
261
262 public RegisteredMethod(Method method, Class registeredJavaType) {
263 Assert.notNull(method, "Method required");
264 Assert.notNull(registeredJavaType, "Registered Java Type required");
265 this.method = method;
266 this.registeredJavaType = registeredJavaType;
267 }
268
269 public boolean equals(Object obj) {
270 if (this == obj) {
271 return true;
272 }
273 if (obj != null && obj instanceof RegisteredMethod) {
274 RegisteredMethod rhs = (RegisteredMethod) obj;
275 return method.equals(rhs.method) && registeredJavaType.equals(rhs.registeredJavaType);
276 }
277 return false;
278 }
279
280 public int hashCode() {
281 return method.hashCode() * registeredJavaType.hashCode();
282 }
283
284 public String toString() {
285 return "RegisteredMethod[" + registeredJavaType.getName() + "; " + method + "]";
286 }
287 }
288
289 }