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    }