001 package org.springframework.cache.interceptor;
002
003 import org.aopalliance.aop.Advice;
004 import org.springframework.aop.Pointcut;
005 import org.springframework.aop.framework.ProxyFactory;
006 import org.springframework.aop.support.AbstractPointcutAdvisor;
007 import org.springframework.aop.support.AopUtils;
008 import org.springframework.cache.CacheManager;
009 import org.springframework.cache.annotation.AnnotationCacheOperationSource;
010
011 /**
012 * Methods for creating caching proxies.
013 */
014 public final class CacheProxy {
015 /*
016 WARNING! This class uses internal spring code and could be subject to breaking
017 changes between Spring releases.
018
019 This class is needed because Spring does not yet have a way to apply caching advise to
020 existing objects which is required for our remote service proxies.
021
022 Hopefully, Spring will provide this capability in the future and we can remove this class.
023 */
024
025
026 private CacheProxy() {
027 throw new IllegalArgumentException("do not call");
028 }
029
030 /**
031 * This creates a caching proxy around a existing object if the proxy can be applied.
032 *
033 * @param o the object to proxy. cannot be null.
034 * @param cacheManager the cacheManager to handle the caching operations. cannot be null.
035 * @return a proxy. will not return null.
036 * @throws IllegalArgumentException if the o or cacheManager is null
037 */
038 public static <T> T createCacheProxy(T o, CacheManager cacheManager) {
039 if (o == null) {
040 throw new IllegalArgumentException("o is null");
041 }
042
043 if (cacheManager == null) {
044 throw new IllegalArgumentException("cacheManager is null");
045 }
046
047 //this method is following the logic found in AnnotationDrivenCacheBeanDefinitionParser.AopAutoProxyConfigurer
048
049 final AnnotationCacheOperationSource source = new AnnotationCacheOperationSource();
050
051 final CacheInterceptor interceptor = new CacheInterceptor();
052 interceptor.setCacheManager(cacheManager);
053 interceptor.setCacheDefinitionSources(source);
054 //important! must call afterPropertiesSet or does not execute caching logic
055 interceptor.afterPropertiesSet();
056
057 final ProxyPointcut pointcut = new ProxyPointcut(source);
058 final ProxyPointCutAdvisor advisor = new ProxyPointCutAdvisor(pointcut, interceptor);
059
060 if (AopUtils.canApply(advisor, o.getClass())) {
061 final ProxyFactory proxyFactory = new ProxyFactory(o);
062 proxyFactory.addAdvisor(advisor);
063 return (T) proxyFactory.getProxy();
064 }
065 return o;
066 }
067
068 private static class ProxyPointcut extends CacheOperationSourcePointcut {
069 private static final long serialVersionUID = 6050508570006106939L;
070
071 private final AnnotationCacheOperationSource source;
072
073 private ProxyPointcut(AnnotationCacheOperationSource source) {
074 this.source = source;
075 }
076
077 @Override
078 protected CacheOperationSource getCacheOperationSource() {
079 return source;
080 }
081 }
082
083 private static class ProxyPointCutAdvisor extends AbstractPointcutAdvisor {
084
085 private static final long serialVersionUID = 6050508570006106939L;
086
087 private final CacheOperationSourcePointcut pointcut;
088 private final CacheInterceptor interceptor;
089
090 private ProxyPointCutAdvisor(CacheOperationSourcePointcut pointcut, CacheInterceptor interceptor) {
091 this.pointcut = pointcut;
092 this.interceptor = interceptor;
093 }
094
095 @Override
096 public Pointcut getPointcut() {
097 return pointcut;
098 }
099
100 @Override
101 public Advice getAdvice() {
102 return interceptor;
103 }
104 }
105 }