All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jsr107.ri.annotations.spring.config.AnnotationDrivenJCacheBeanDefinitionParser Maven / Gradle / Ivy

There is a newer version: 0.6
Show newest version
/**
 *  Copyright 2011-2013 Terracotta, Inc.
 *  Copyright 2011-2013 Oracle America Incorporated
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.jsr107.ri.annotations.spring.config;

import org.jsr107.ri.annotations.AbstractCacheInterceptor;
import org.jsr107.ri.annotations.DefaultCacheKeyGenerator;
import org.jsr107.ri.annotations.DefaultCacheResolverFactory;
import org.jsr107.ri.annotations.spring.CacheContextSourceImpl;
import org.jsr107.ri.annotations.spring.CachePutInterceptor;
import org.jsr107.ri.annotations.spring.CacheRemoveAllInterceptor;
import org.jsr107.ri.annotations.spring.CacheRemoveEntryInterceptor;
import org.jsr107.ri.annotations.spring.CacheResultInterceptor;
import org.springframework.aop.config.AopNamespaceUtils;
import org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

/**
 * Class that handles the parsing the custom jcache namespace elements in a spring bean definition file
 *
 * @author Eric Dalquist
 */
public class AnnotationDrivenJCacheBeanDefinitionParser implements BeanDefinitionParser {
  private static final String XSD_ATTR_CACHE_MANAGER = "cache-manager";

  private static final String JCACHE_CACHE_OPERATION_SOURCE_BEAN_NAME = AnnotationDrivenJCacheBeanDefinitionParser.class
      .getPackage().getName() + ".internalJCacheOperationSourceAdvisor";

  /* (non-Javadoc)
   * @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element,
   * org.springframework.beans.factory.xml.ParserContext)
   */
  @Override
  public BeanDefinition parse(Element element, ParserContext parserContext) {
    AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

    final BeanDefinitionRegistry registry = parserContext.getRegistry();
    if (!registry.containsBeanDefinition(JCACHE_CACHE_OPERATION_SOURCE_BEAN_NAME)) {
      final Object elementSource = parserContext.extractSource(element);

      final RuntimeBeanReference cacheOperationSourceReference = this.setupCacheOperationSource(element,
          parserContext,
          elementSource);


      this.setupPointcutAdvisor(CacheResultInterceptor.class,
          element, parserContext, elementSource, cacheOperationSourceReference);

      this.setupPointcutAdvisor(CachePutInterceptor.class,
          element, parserContext, elementSource, cacheOperationSourceReference);

      this.setupPointcutAdvisor(CacheRemoveEntryInterceptor.class,
          element, parserContext, elementSource, cacheOperationSourceReference);

      this.setupPointcutAdvisor(CacheRemoveAllInterceptor.class,
          element, parserContext, elementSource, cacheOperationSourceReference);

      return registry.getBeanDefinition(JCACHE_CACHE_OPERATION_SOURCE_BEAN_NAME);
    }

    return null;
  }

  /**
   * Create a {@link CacheContextSourceImpl} bean that will be used by the advisor and interceptor
   *
   * @return Reference to the {@link CacheContextSourceImpl}. Should never be null.
   */
  protected RuntimeBeanReference setupCacheOperationSource(Element element, ParserContext parserContext,
                                                           Object elementSource) {

    final RootBeanDefinition cacheAttributeSource = new RootBeanDefinition(CacheContextSourceImpl.class);
    cacheAttributeSource.setSource(elementSource);
    cacheAttributeSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

    final RootBeanDefinition defaultCacheResolverFactory = new RootBeanDefinition(DefaultCacheResolverFactory.class);
    cacheAttributeSource.setSource(elementSource);
    cacheAttributeSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    final String cacheManagerName = element.getAttribute(XSD_ATTR_CACHE_MANAGER);
    if (StringUtils.hasText(cacheManagerName)) {
      final RuntimeBeanReference cacheManagerReference = new RuntimeBeanReference(cacheManagerName);

      final ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
      constructorArgumentValues.addIndexedArgumentValue(0, cacheManagerReference);
      cacheAttributeSource.setConstructorArgumentValues(constructorArgumentValues);

    }

    final RootBeanDefinition defaultCacheKeyGenerator = new RootBeanDefinition(DefaultCacheKeyGenerator.class);
    cacheAttributeSource.setSource(elementSource);
    cacheAttributeSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

    final MutablePropertyValues propertyValues = cacheAttributeSource.getPropertyValues();
    propertyValues.addPropertyValue("defaultCacheKeyGenerator", defaultCacheKeyGenerator);
    propertyValues.addPropertyValue("defaultCacheResolverFactory", defaultCacheResolverFactory);

    final BeanDefinitionRegistry registry = parserContext.getRegistry();
    registry.registerBeanDefinition(JCACHE_CACHE_OPERATION_SOURCE_BEAN_NAME, cacheAttributeSource);

    return new RuntimeBeanReference(JCACHE_CACHE_OPERATION_SOURCE_BEAN_NAME);
  }

  /**
   * Create the {@link RuntimeBeanReference} used to apply the caching interceptor
   *
   * @return Reference to the {@link RuntimeBeanReference}. Should never be null.
   */
  protected RuntimeBeanReference setupPointcut(ParserContext parserContext, Object elementSource,
                                               RuntimeBeanReference cacheOperationSourceRuntimeReference,
                                               RuntimeBeanReference cacheInterceptorSourceRuntimeReference) {

    final RootBeanDefinition pointcut = new RootBeanDefinition(CacheStaticMethodMatcherPointcut.class);
    pointcut.setSource(elementSource);
    pointcut.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

    final ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
    constructorArgumentValues.addIndexedArgumentValue(0, cacheOperationSourceRuntimeReference);
    constructorArgumentValues.addIndexedArgumentValue(1, cacheInterceptorSourceRuntimeReference);
    pointcut.setConstructorArgumentValues(constructorArgumentValues);

    final String pointcutBeanName = pointcut.getBeanClassName() + "_" + cacheInterceptorSourceRuntimeReference.getBeanName();

    final BeanDefinitionRegistry registry = parserContext.getRegistry();
    registry.registerBeanDefinition(pointcutBeanName, pointcut);

    return new RuntimeBeanReference(pointcutBeanName);
  }

  /**
   * Create {@link org.aopalliance.intercept.MethodInterceptor} that is applies the caching logic to advised methods.
   *
   * @return Reference to the {@link org.aopalliance.intercept.MethodInterceptor}. Should never be null.
   */
  protected RuntimeBeanReference setupInterceptor(Class> interceptorClass,
                                                  ParserContext parserContext, Object elementSource,
                                                  RuntimeBeanReference cacheOperationSourceRuntimeReference) {

    final RootBeanDefinition interceptor = new RootBeanDefinition(interceptorClass);
    interceptor.setSource(elementSource);
    interceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

    final ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
    constructorArgumentValues.addIndexedArgumentValue(0, cacheOperationSourceRuntimeReference);
    interceptor.setConstructorArgumentValues(constructorArgumentValues);

    final XmlReaderContext readerContext = parserContext.getReaderContext();
    final String interceptorBeanName = readerContext.registerWithGeneratedName(interceptor);
    return new RuntimeBeanReference(interceptorBeanName);
  }

  /**
   * Create {@link org.springframework.aop.PointcutAdvisor} that puts the
   * {@link org.springframework.aop.Pointcut} and {@link AbstractCacheInterceptor} together.
   */
  protected void setupPointcutAdvisor(Class> interceptorClass,
                                      Element element, ParserContext parserContext,
                                      Object elementSource, RuntimeBeanReference cacheOperationSourceReference) {

    final RuntimeBeanReference interceptorReference =
        this.setupInterceptor(interceptorClass, parserContext, elementSource, cacheOperationSourceReference);

    final RuntimeBeanReference pointcutReference =
        this.setupPointcut(parserContext, elementSource, cacheOperationSourceReference, interceptorReference);


    final RootBeanDefinition pointcutAdvisor = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
    pointcutAdvisor.setSource(elementSource);
    pointcutAdvisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

    final MutablePropertyValues propertyValues = pointcutAdvisor.getPropertyValues();
    propertyValues.addPropertyValue("adviceBeanName", interceptorReference.getBeanName());
    propertyValues.addPropertyValue("pointcut", pointcutReference);
    if (element.hasAttribute("order")) {
      propertyValues.addPropertyValue("order", element.getAttribute("order"));
    }

    final XmlReaderContext readerContext = parserContext.getReaderContext();
    readerContext.registerWithGeneratedName(pointcutAdvisor);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy