001    /**
002     * Copyright 2005-2011 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.springframework.cache.interceptor;
017    
018    import org.aopalliance.aop.Advice;
019    import org.springframework.aop.Pointcut;
020    import org.springframework.aop.framework.ProxyFactory;
021    import org.springframework.aop.support.AbstractPointcutAdvisor;
022    import org.springframework.aop.support.AopUtils;
023    import org.springframework.cache.CacheManager;
024    import org.springframework.cache.annotation.AnnotationCacheOperationSource;
025    
026    /**
027     * Methods for creating caching proxies.
028     */
029    public final class CacheProxy {
030        /*
031            WARNING!  This class uses internal spring code and could be subject to breaking
032            changes between Spring releases.
033    
034            This class is needed because Spring does not yet have a way to apply caching advise to
035            existing objects which is required for our remote service proxies.
036    
037            Hopefully, Spring will provide this capability in the future and we can remove this class.
038        */
039    
040    
041        private CacheProxy() {
042            throw new IllegalArgumentException("do not call");
043        }
044    
045        /**
046         * This creates a caching proxy around a existing object if the proxy can be applied.
047         *
048         * @param o the object to proxy.  cannot be null.
049         * @param cacheManager the cacheManager to handle the caching operations.  cannot be null.
050         * @return a proxy.  will not return null.
051         * @throws IllegalArgumentException if the o or cacheManager is null
052         */
053        public static <T> T createCacheProxy(T o, CacheManager cacheManager) {
054            if (o == null) {
055                throw new IllegalArgumentException("o is null");
056            }
057    
058            if (cacheManager == null) {
059                throw new IllegalArgumentException("cacheManager is null");
060            }
061    
062            //this method is following the logic found in AnnotationDrivenCacheBeanDefinitionParser.AopAutoProxyConfigurer
063    
064            final AnnotationCacheOperationSource source = new AnnotationCacheOperationSource();
065    
066            final CacheInterceptor interceptor = new CacheInterceptor();
067            interceptor.setCacheManager(cacheManager);
068            interceptor.setCacheOperationSources(source);
069            //important!  must call afterPropertiesSet or does not execute caching logic
070            interceptor.afterPropertiesSet();
071    
072            final ProxyPointcut pointcut = new ProxyPointcut(source);
073            final ProxyPointCutAdvisor advisor = new ProxyPointCutAdvisor(pointcut, interceptor);
074    
075            if (AopUtils.canApply(advisor, o.getClass())) {
076                final ProxyFactory proxyFactory = new ProxyFactory(o);
077                proxyFactory.addAdvisor(advisor);
078                return (T) proxyFactory.getProxy();
079            }
080            return o;
081        }
082    
083        private static class ProxyPointcut extends CacheOperationSourcePointcut {
084            private static final long serialVersionUID = 6050508570006106939L;
085    
086            private final AnnotationCacheOperationSource source;
087    
088            private ProxyPointcut(AnnotationCacheOperationSource source) {
089                this.source = source;
090            }
091    
092            @Override
093            protected CacheOperationSource getCacheOperationSource() {
094                return source;
095            }
096        }
097    
098        private static class ProxyPointCutAdvisor extends AbstractPointcutAdvisor {
099    
100            private static final long serialVersionUID = 6050508570006106939L;
101    
102            private final CacheOperationSourcePointcut pointcut;
103            private final CacheInterceptor interceptor;
104    
105            private ProxyPointCutAdvisor(CacheOperationSourcePointcut pointcut, CacheInterceptor interceptor) {
106                this.pointcut = pointcut;
107                this.interceptor = interceptor;
108            }
109    
110            @Override
111            public Pointcut getPointcut() {
112                return pointcut;
113            }
114    
115            @Override
116            public Advice getAdvice() {
117                return interceptor;
118            }
119        }
120    }