1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.kuali.rice.kns.util.cache;
22
23
24 import java.io.Serializable;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.SortedMap;
31 import java.util.SortedSet;
32
33 import org.aopalliance.intercept.MethodInterceptor;
34 import org.aopalliance.intercept.MethodInvocation;
35 import org.apache.log4j.Logger;
36 import org.springframework.beans.factory.InitializingBean;
37 import org.springframework.util.Assert;
38
39 import com.opensymphony.oscache.base.Cache;
40 import com.opensymphony.oscache.base.NeedsRefreshException;
41
42
43
44
45
46
47
48
49
50
51
52 public class MethodCacheNoCopyInterceptor implements MethodInterceptor, InitializingBean {
53 private static final Logger LOG = Logger.getLogger(MethodCacheNoCopyInterceptor.class);
54
55 private Cache cache;
56
57 private int expirationTimeInSeconds = 1000;
58
59
60
61
62
63
64
65 public void setCache(Cache cache) {
66 this.cache = cache;
67 }
68
69
70
71
72
73
74
75 public void setExpirationTimeInSeconds(int expirationTimeInSeconds) {
76 this.expirationTimeInSeconds = expirationTimeInSeconds;
77 }
78
79
80
81
82
83
84
85
86
87
88
89 public void afterPropertiesSet() throws Exception {
90 Assert.notNull(cache, "A cache is required. Use setCache(Cache) to provide one.");
91 }
92
93
94
95
96
97
98
99
100
101
102
103 @SuppressWarnings("unchecked")
104 public Object invoke(MethodInvocation invocation) throws Throwable {
105
106 boolean cancelUpdate = true;
107
108 Object methodResult = null;
109 String cacheKey = buildCacheKey(invocation);
110
111
112 if (LOG.isDebugEnabled()) {
113 LOG.debug("looking for method result for invocation '" + cacheKey + "'");
114 }
115 try {
116 methodResult = cache.getFromCache(cacheKey, expirationTimeInSeconds);
117 if (LOG.isDebugEnabled()) {
118 LOG.debug("using cached result invocation '" + cacheKey + "'");
119 }
120
121 cancelUpdate = false;
122 }
123 catch (NeedsRefreshException e) {
124
125 try {
126 if (LOG.isDebugEnabled()) {
127 LOG.debug("calling intercepted method for invocation '" + cacheKey + "'");
128 }
129 methodResult = invocation.proceed();
130 }
131 catch (Exception invocationException) {
132 LOG.warn("unable to cache methodResult: caught exception invoking intercepted method: '" + invocationException);
133 throw invocationException;
134 }
135
136
137 if ( methodResult == null || Serializable.class.isAssignableFrom(methodResult.getClass() ) ) {
138 try {
139 if (LOG.isDebugEnabled()) {
140 LOG.debug("caching results for invocation '" + cacheKey + "'");
141 }
142
143 if ( methodResult != null ) {
144 if ( methodResult instanceof SortedMap ) {
145 methodResult = Collections.unmodifiableSortedMap((SortedMap)methodResult);
146 } else if ( methodResult instanceof Map ) {
147 methodResult = Collections.unmodifiableMap((Map)methodResult);
148 } else if ( methodResult instanceof List ) {
149 methodResult = Collections.unmodifiableList((List)methodResult);
150 } else if ( methodResult instanceof SortedSet ) {
151 methodResult = Collections.unmodifiableSortedSet((SortedSet)methodResult);
152 } else if ( methodResult instanceof Set ) {
153 methodResult = Collections.unmodifiableSet((Set)methodResult);
154 } else if ( methodResult instanceof Collection ) {
155 methodResult = Collections.unmodifiableCollection((Collection)methodResult);
156 }
157 }
158 cache.putInCache(cacheKey, methodResult);
159
160
161 cancelUpdate = false;
162 } catch (Exception cacheException) {
163 LOG.error("unable to cache methodResult: caught exception invoking putInCache: '" + cacheException);
164 throw cacheException;
165 }
166 }
167 }
168 finally {
169
170 if (cancelUpdate) {
171 cache.cancelUpdate(cacheKey);
172 }
173 }
174
175
176 return methodResult;
177
178 }
179
180
181
182
183
184
185 private String buildCacheKey(MethodInvocation invocation) {
186 return buildCacheKey(invocation.getStaticPart().toString(), invocation.getArguments());
187 }
188
189
190
191
192
193
194
195
196
197 public String buildCacheKey(String methodSignature, Object[] argValues) {
198 StringBuffer cacheKey = new StringBuffer(methodSignature);
199 cacheKey.append(": ");
200 if (argValues != null) {
201 for (int i = 0; i < argValues.length; i++) {
202 if (i > 0) {
203 cacheKey.append(",");
204 }
205
206
207
208
209
210
211
212
213 if (argValues[i] == null) {
214 cacheKey.append("<literal null>");
215 }
216 else {
217 cacheKey.append(argValues[i]);
218 }
219 }
220 }
221 return cacheKey.toString();
222 }
223
224
225
226
227
228
229 public boolean containsCacheKey(String key) {
230 boolean contains = false;
231
232 try {
233 cache.getFromCache(key);
234 contains = true;
235 }
236 catch (NeedsRefreshException e) {
237
238
239 cache.cancelUpdate(key);
240 contains = false;
241 }
242
243 return contains;
244 }
245
246
247
248
249 public void removeCacheKey(String cacheKey) {
250 if (!containsCacheKey(cacheKey)) {
251 return;
252 }
253
254 if ( LOG.isDebugEnabled() ) {
255 LOG.debug("removing method cache for key: " + cacheKey);
256 }
257 cache.cancelUpdate(cacheKey);
258 cache.flushEntry(cacheKey);
259 }
260
261
262
263 }