1 package org.springframework.security.intercept.method;
2
3 import java.lang.reflect.Method;
4 import java.util.HashMap;
5 import java.util.Map;
6
7 import org.aopalliance.intercept.MethodInvocation;
8 import org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogFactory;
10 import org.aspectj.lang.JoinPoint;
11 import org.aspectj.lang.reflect.CodeSignature;
12 import org.springframework.security.ConfigAttributeDefinition;
13 import org.springframework.util.Assert;
14 import org.springframework.util.ClassUtils;
15 import org.springframework.util.ObjectUtils;
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 public abstract class AbstractFallbackMethodDefinitionSource implements MethodDefinitionSource {
40
41 private static final Log logger = LogFactory.getLog(AbstractFallbackMethodDefinitionSource.class);
42 private final static Object NULL_CONFIG_ATTRIBUTE = new Object();
43 private final Map attributeCache = new HashMap();
44
45 public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
46 Assert.notNull(object, "Object cannot be null");
47
48 if (object instanceof MethodInvocation) {
49 MethodInvocation mi = (MethodInvocation) object;
50 Object target = mi.getThis();
51 return getAttributes(mi.getMethod(), target == null ? null : target.getClass());
52 }
53
54 if (object instanceof JoinPoint) {
55 JoinPoint jp = (JoinPoint) object;
56 Class targetClass = jp.getTarget().getClass();
57 String targetMethodName = jp.getStaticPart().getSignature().getName();
58 Class[] types = ((CodeSignature) jp.getStaticPart().getSignature()).getParameterTypes();
59 Class declaringType = ((CodeSignature) jp.getStaticPart().getSignature()).getDeclaringType();
60
61 Method method = ClassUtils.getMethodIfAvailable(declaringType, targetMethodName, types);
62 Assert.notNull(method, "Could not obtain target method from JoinPoint: '"+ jp + "'");
63
64 return getAttributes(method, targetClass);
65 }
66
67 throw new IllegalArgumentException("Object must be a MethodInvocation or JoinPoint");
68 }
69
70 public final boolean supports(Class clazz) {
71 return (MethodInvocation.class.isAssignableFrom(clazz) || JoinPoint.class.isAssignableFrom(clazz));
72 }
73
74 public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
75
76 Object cacheKey = new DefaultCacheKey(method, targetClass);
77 synchronized (this.attributeCache) {
78 Object cached = this.attributeCache.get(cacheKey);
79 if (cached != null) {
80
81
82 if (cached == NULL_CONFIG_ATTRIBUTE) {
83 return null;
84 }
85 else {
86 return (ConfigAttributeDefinition) cached;
87 }
88 }
89 else {
90
91 ConfigAttributeDefinition cfgAtt = computeAttributes(method, targetClass);
92
93 if (cfgAtt == null) {
94 this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
95 }
96 else {
97 if (logger.isDebugEnabled()) {
98 logger.debug("Adding security method [" + cacheKey + "] with attribute [" + cfgAtt + "]");
99 }
100 this.attributeCache.put(cacheKey, cfgAtt);
101 }
102 return cfgAtt;
103 }
104 }
105 }
106
107
108
109
110
111
112
113 private ConfigAttributeDefinition computeAttributes(Method method, Class targetClass) {
114
115
116 Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
117
118 ConfigAttributeDefinition attr = findAttributes(specificMethod, targetClass);
119 if (attr != null) {
120 return attr;
121 }
122
123
124 attr = findAttributes(specificMethod.getDeclaringClass());
125 if (attr != null) {
126 return attr;
127 }
128
129 if (specificMethod != method || targetClass == null) {
130
131 attr = findAttributes(method, method.getDeclaringClass());
132 if (attr != null) {
133 return attr;
134 }
135
136 return findAttributes(method.getDeclaringClass());
137 }
138 return null;
139
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 protected abstract ConfigAttributeDefinition findAttributes(Method method, Class targetClass);
156
157
158
159
160
161
162
163
164
165
166
167
168
169 protected abstract ConfigAttributeDefinition findAttributes(Class clazz);
170
171 private static class DefaultCacheKey {
172
173 private final Method method;
174 private final Class targetClass;
175
176 public DefaultCacheKey(Method method, Class targetClass) {
177 this.method = method;
178 this.targetClass = targetClass;
179 }
180
181 public boolean equals(Object other) {
182 if (this == other) {
183 return true;
184 }
185 if (!(other instanceof DefaultCacheKey)) {
186 return false;
187 }
188 DefaultCacheKey otherKey = (DefaultCacheKey) other;
189 return (this.method.equals(otherKey.method) &&
190 ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
191 }
192
193 public int hashCode() {
194 return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
195 }
196
197 public String toString() {
198 return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
199 }
200 }
201
202 }