1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
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.kernel.util.StringUtil;
25  import com.liferay.portal.spring.aop.AnnotationChainableMethodAdvice;
26  
27  import java.lang.annotation.Annotation;
28  
29  import org.aopalliance.intercept.MethodInvocation;
30  
31  /**
32   * <a href="ThreadLocalCacheAdvice.java.html"><b><i>View Source</i></b></a>
33   *
34   * @author Shuyang Zhou
35   * @author Brian Wing Shun Chan
36   */
37  public class ThreadLocalCacheAdvice
38      extends AnnotationChainableMethodAdvice<ThreadLocalCachable> {
39  
40      public void afterReturning(
41              MethodInvocation methodInvocation, Object result)
42          throws Throwable {
43  
44          MethodTargetClassKey methodTargetClassKey = buildMethodTargetClassKey(
45              methodInvocation);
46  
47          ThreadLocalCachable threadLocalCachable = findAnnotation(
48              methodTargetClassKey);
49  
50          if (threadLocalCachable == _nullThreadLocalCacheable) {
51              return;
52          }
53  
54          ThreadLocalCache<Object> threadLocalCache =
55              ThreadLocalCacheManager.getThreadLocalCache(
56                  threadLocalCachable.scope(), methodTargetClassKey.toString());
57  
58          String cacheKey = _buildCacheKey(methodInvocation.getArguments());
59  
60          if (result == null) {
61              threadLocalCache.put(cacheKey, nullResult);
62          }
63          else {
64              threadLocalCache.put(cacheKey, result);
65          }
66      }
67  
68      public Object before(MethodInvocation methodInvocation) throws Throwable {
69          MethodTargetClassKey methodTargetClassKey = buildMethodTargetClassKey(
70              methodInvocation);
71  
72          ThreadLocalCachable threadLocalCachable = findAnnotation(
73              methodTargetClassKey);
74  
75          if (threadLocalCachable == _nullThreadLocalCacheable) {
76              return null;
77          }
78  
79          ThreadLocalCache<?> threadLocalCache =
80              ThreadLocalCacheManager.getThreadLocalCache(
81                  threadLocalCachable.scope(), methodTargetClassKey.toString());
82  
83          String cacheKey = _buildCacheKey(methodInvocation.getArguments());
84  
85          Object value = threadLocalCache.get(cacheKey);
86  
87          if (value == nullResult) {
88              return null;
89          }
90  
91          return value;
92      }
93  
94      public ThreadLocalCachable getNullAnnotation() {
95          return _nullThreadLocalCacheable;
96      }
97  
98      private String _buildCacheKey(Object[] arguments) {
99          StringBundler sb = new StringBundler(arguments.length * 2 - 1);
100 
101         for (int i = 0; i < arguments.length; i++) {
102             sb.append(StringUtil.toHexString(arguments[i]));
103 
104             if ((i + 1) < arguments.length) {
105                 sb.append(StringPool.POUND);
106             }
107         }
108 
109         return sb.toString();
110     }
111 
112     private static ThreadLocalCachable _nullThreadLocalCacheable =
113         new ThreadLocalCachable() {
114 
115             public Class<? extends Annotation> annotationType() {
116                 return ThreadLocalCachable.class;
117             }
118 
119             public Lifecycle scope() {
120                 return null;
121             }
122 
123         };
124 
125 }