001
014
015 package com.liferay.portal.cache;
016
017 import com.liferay.portal.kernel.cache.Lifecycle;
018 import com.liferay.portal.kernel.cache.ThreadLocalCachable;
019 import com.liferay.portal.kernel.cache.ThreadLocalCache;
020 import com.liferay.portal.kernel.cache.ThreadLocalCacheManager;
021 import com.liferay.portal.kernel.util.StringBundler;
022 import com.liferay.portal.kernel.util.StringPool;
023 import com.liferay.portal.kernel.util.StringUtil;
024 import com.liferay.portal.spring.aop.AnnotationChainableMethodAdvice;
025 import com.liferay.portal.spring.aop.ServiceBeanMethodInvocation;
026
027 import java.io.Serializable;
028
029 import java.lang.annotation.Annotation;
030
031 import org.aopalliance.intercept.MethodInvocation;
032
033
037 public class ThreadLocalCacheAdvice
038 extends AnnotationChainableMethodAdvice<ThreadLocalCachable> {
039
040 @Override
041 public void afterReturning(
042 MethodInvocation methodInvocation, Object result)
043 throws Throwable {
044
045 ThreadLocalCachable threadLocalCachable = findAnnotation(
046 methodInvocation);
047
048 if (threadLocalCachable == _nullThreadLocalCacheable) {
049 return;
050 }
051
052 Serializable cacheName = _getCacheName(methodInvocation);
053
054 ThreadLocalCache<Object> threadLocalCache =
055 ThreadLocalCacheManager.getThreadLocalCache(
056 threadLocalCachable.scope(), cacheName);
057
058 String cacheKey = _getCacheKey(methodInvocation.getArguments());
059
060 if (result == null) {
061 threadLocalCache.put(cacheKey, nullResult);
062 }
063 else {
064 threadLocalCache.put(cacheKey, result);
065 }
066 }
067
068 @Override
069 public Object before(MethodInvocation methodInvocation) throws Throwable {
070 ThreadLocalCachable threadLocalCachable = findAnnotation(
071 methodInvocation);
072
073 if (threadLocalCachable == _nullThreadLocalCacheable) {
074 return null;
075 }
076
077 Serializable cacheName = _getCacheName(methodInvocation);
078
079 ThreadLocalCache<?> threadLocalCache =
080 ThreadLocalCacheManager.getThreadLocalCache(
081 threadLocalCachable.scope(), cacheName);
082
083 String cacheKey = _getCacheKey(methodInvocation.getArguments());
084
085 Object value = threadLocalCache.get(cacheKey);
086
087 if (value == nullResult) {
088 return null;
089 }
090
091 return value;
092 }
093
094 @Override
095 public ThreadLocalCachable getNullAnnotation() {
096 return _nullThreadLocalCacheable;
097 }
098
099 private String _getCacheKey(Object[] arguments) {
100 StringBundler sb = new StringBundler(arguments.length * 2 - 1);
101
102 for (int i = 0; i < arguments.length; i++) {
103 sb.append(StringUtil.toHexString(arguments[i]));
104
105 if ((i + 1) < arguments.length) {
106 sb.append(StringPool.POUND);
107 }
108 }
109
110 return sb.toString();
111 }
112
113 private Serializable _getCacheName(MethodInvocation methodInvocation) {
114 if (methodInvocation instanceof ServiceBeanMethodInvocation) {
115 ServiceBeanMethodInvocation serviceBeanMethodInvocation =
116 (ServiceBeanMethodInvocation)methodInvocation;
117
118 return serviceBeanMethodInvocation.toCacheKeyModel();
119 }
120 else {
121 return methodInvocation.toString();
122 }
123 }
124
125 private static ThreadLocalCachable _nullThreadLocalCacheable =
126 new ThreadLocalCachable() {
127
128 public Class<? extends Annotation> annotationType() {
129 return ThreadLocalCachable.class;
130 }
131
132 public Lifecycle scope() {
133 return null;
134 }
135
136 };
137
138 }