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 ThreadLocalCachable getNullAnnotation() {
042 return _nullThreadLocalCacheable;
043 }
044
045 @Override
046 public Object invoke(MethodInvocation methodInvocation) throws Throwable {
047 ThreadLocalCachable threadLocalCachable = findAnnotation(
048 methodInvocation);
049
050 if (threadLocalCachable == _nullThreadLocalCacheable) {
051 return methodInvocation.proceed();
052 }
053
054 Serializable cacheName = _getCacheName(methodInvocation);
055
056 ThreadLocalCache<Object> threadLocalCache =
057 ThreadLocalCacheManager.getThreadLocalCache(
058 threadLocalCachable.scope(), cacheName);
059
060 String cacheKey = _getCacheKey(methodInvocation.getArguments());
061
062 Object value = threadLocalCache.get(cacheKey);
063
064 if (value != null) {
065 if (value == nullResult) {
066 return null;
067 }
068
069 return value;
070 }
071
072 Object result = methodInvocation.proceed();
073
074 if (result == null) {
075 threadLocalCache.put(cacheKey, nullResult);
076 }
077 else {
078 threadLocalCache.put(cacheKey, result);
079 }
080
081 return result;
082 }
083
084 private String _getCacheKey(Object[] arguments) {
085 if (arguments.length == 1) {
086 return StringUtil.toHexString(arguments[0]);
087 }
088
089 StringBundler sb = new StringBundler(arguments.length * 2 - 1);
090
091 for (int i = 0; i < arguments.length; i++) {
092 sb.append(StringUtil.toHexString(arguments[i]));
093
094 if ((i + 1) < arguments.length) {
095 sb.append(StringPool.POUND);
096 }
097 }
098
099 return sb.toString();
100 }
101
102 private Serializable _getCacheName(MethodInvocation methodInvocation) {
103 if (methodInvocation instanceof ServiceBeanMethodInvocation) {
104 ServiceBeanMethodInvocation serviceBeanMethodInvocation =
105 (ServiceBeanMethodInvocation)methodInvocation;
106
107 return serviceBeanMethodInvocation.toCacheKeyModel();
108 }
109 else {
110 return methodInvocation.toString();
111 }
112 }
113
114 private static final ThreadLocalCachable _nullThreadLocalCacheable =
115 new ThreadLocalCachable() {
116
117 @Override
118 public Class<? extends Annotation> annotationType() {
119 return ThreadLocalCachable.class;
120 }
121
122 @Override
123 public Lifecycle scope() {
124 return null;
125 }
126
127 };
128
129 }