1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.cache;
16  
17  import com.liferay.portal.kernel.cache.Lifecycle;
18  import com.liferay.portal.kernel.cache.ThreadLocalCachable;
19  import com.liferay.portal.kernel.cache.ThreadLocalCache;
20  import com.liferay.portal.kernel.cache.ThreadLocalCacheManager;
21  import com.liferay.portal.kernel.util.MethodTargetClassKey;
22  import com.liferay.portal.kernel.util.StringBundler;
23  import com.liferay.portal.kernel.util.StringPool;
24  import com.liferay.portal.spring.aop.AnnotationChainableMethodAdvice;
25  
26  import java.lang.annotation.Annotation;
27  
28  import org.aopalliance.intercept.MethodInvocation;
29  
30  /**
31   * <a href="ThreadLocalCacheAdvice.java.html"><b><i>View Source</i></b></a>
32   *
33   * @author Shuyang Zhou
34   * @author Brian Wing Shun Chan
35   */
36  public class ThreadLocalCacheAdvice
37      extends AnnotationChainableMethodAdvice<ThreadLocalCachable> {
38  
39      public void afterReturning(
40              MethodInvocation methodInvocation, Object result)
41          throws Throwable {
42  
43          MethodTargetClassKey methodTargetClassKey = buildMethodTargetClassKey(
44              methodInvocation);
45  
46          ThreadLocalCachable threadLocalCachable = findAnnotation(
47              methodTargetClassKey);
48  
49          if (threadLocalCachable == _nullThreadLocalCacheable) {
50              return;
51          }
52  
53          ThreadLocalCache<Object> threadLocalCache =
54              ThreadLocalCacheManager.getThreadLocalCache(
55                  threadLocalCachable.scope(), methodTargetClassKey.toString());
56  
57          String cacheKey = _buildCacheKey(methodInvocation.getArguments());
58  
59          if (result == null) {
60              threadLocalCache.put(cacheKey, nullResult);
61          }
62          else {
63              threadLocalCache.put(cacheKey, result);
64          }
65      }
66  
67      public Object before(MethodInvocation methodInvocation) throws Throwable {
68          MethodTargetClassKey methodTargetClassKey = buildMethodTargetClassKey(
69              methodInvocation);
70  
71          ThreadLocalCachable threadLocalCachable = findAnnotation(
72              methodTargetClassKey);
73  
74          if (threadLocalCachable == _nullThreadLocalCacheable) {
75              return null;
76          }
77  
78          ThreadLocalCache<?> threadLocalCache =
79              ThreadLocalCacheManager.getThreadLocalCache(
80                  threadLocalCachable.scope(), methodTargetClassKey.toString());
81  
82          String cacheKey = _buildCacheKey(methodInvocation.getArguments());
83  
84          Object value = threadLocalCache.get(cacheKey);
85  
86          if (value == nullResult) {
87              return null;
88          }
89  
90          return value;
91      }
92  
93      public Class<ThreadLocalCachable> getAnnotationClass() {
94          return ThreadLocalCachable.class;
95      }
96  
97      public ThreadLocalCachable getNullAnnotation() {
98          return _nullThreadLocalCacheable;
99      }
100 
101     private String _buildCacheKey(Object[] arguments) {
102         StringBundler sb = new StringBundler(arguments.length * 2 - 1);
103 
104         for (int i = 0; i < arguments.length; i++) {
105             sb.append(String.valueOf(arguments[i]));
106 
107             if ((i + 1) < arguments.length) {
108                 sb.append(StringPool.POUND);
109             }
110         }
111 
112         return sb.toString();
113     }
114 
115     private static ThreadLocalCachable _nullThreadLocalCacheable =
116         new ThreadLocalCachable() {
117 
118             public Class<? extends Annotation> annotationType() {
119                 return ThreadLocalCachable.class;
120             }
121 
122             public Lifecycle scope() {
123                 return null;
124             }
125 
126         };
127 
128 }