001/*
002 * Copyright 2002-2016 the original author or authors.
003 *
004 * Licensed under the Apache 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 *      https://www.apache.org/licenses/LICENSE-2.0
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
017package org.springframework.aop.config;
018
019import java.util.List;
020
021import org.w3c.dom.Node;
022
023import org.springframework.aop.framework.ProxyFactoryBean;
024import org.springframework.beans.factory.config.BeanDefinition;
025import org.springframework.beans.factory.config.BeanDefinitionHolder;
026import org.springframework.beans.factory.support.AbstractBeanDefinition;
027import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
028import org.springframework.beans.factory.support.BeanDefinitionRegistry;
029import org.springframework.beans.factory.support.ManagedList;
030import org.springframework.beans.factory.support.RootBeanDefinition;
031import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
032import org.springframework.beans.factory.xml.ParserContext;
033import org.springframework.util.ClassUtils;
034import org.springframework.util.StringUtils;
035
036/**
037 * Base implementation for
038 * {@link org.springframework.beans.factory.xml.BeanDefinitionDecorator BeanDefinitionDecorators}
039 * wishing to add an {@link org.aopalliance.intercept.MethodInterceptor interceptor}
040 * to the resulting bean.
041 *
042 * <p>This base class controls the creation of the {@link ProxyFactoryBean} bean definition
043 * and wraps the original as an inner-bean definition for the {@code target} property
044 * of {@link ProxyFactoryBean}.
045 *
046 * <p>Chaining is correctly handled, ensuring that only one {@link ProxyFactoryBean} definition
047 * is created. If a previous {@link org.springframework.beans.factory.xml.BeanDefinitionDecorator}
048 * already created the {@link org.springframework.aop.framework.ProxyFactoryBean} then the
049 * interceptor is simply added to the existing definition.
050 *
051 * <p>Subclasses have only to create the {@code BeanDefinition} to the interceptor that
052 * they wish to add.
053 *
054 * @author Rob Harrop
055 * @author Juergen Hoeller
056 * @since 2.0
057 * @see org.aopalliance.intercept.MethodInterceptor
058 */
059public abstract class AbstractInterceptorDrivenBeanDefinitionDecorator implements BeanDefinitionDecorator {
060
061        @Override
062        public final BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definitionHolder, ParserContext parserContext) {
063                BeanDefinitionRegistry registry = parserContext.getRegistry();
064
065                // get the root bean name - will be the name of the generated proxy factory bean
066                String existingBeanName = definitionHolder.getBeanName();
067                BeanDefinition targetDefinition = definitionHolder.getBeanDefinition();
068                BeanDefinitionHolder targetHolder = new BeanDefinitionHolder(targetDefinition, existingBeanName + ".TARGET");
069
070                // delegate to subclass for interceptor definition
071                BeanDefinition interceptorDefinition = createInterceptorDefinition(node);
072
073                // generate name and register the interceptor
074                String interceptorName = existingBeanName + '.' + getInterceptorNameSuffix(interceptorDefinition);
075                BeanDefinitionReaderUtils.registerBeanDefinition(
076                                new BeanDefinitionHolder(interceptorDefinition, interceptorName), registry);
077
078                BeanDefinitionHolder result = definitionHolder;
079
080                if (!isProxyFactoryBeanDefinition(targetDefinition)) {
081                        // create the proxy definition
082                        RootBeanDefinition proxyDefinition = new RootBeanDefinition();
083                        // create proxy factory bean definition
084                        proxyDefinition.setBeanClass(ProxyFactoryBean.class);
085                        proxyDefinition.setScope(targetDefinition.getScope());
086                        proxyDefinition.setLazyInit(targetDefinition.isLazyInit());
087                        // set the target
088                        proxyDefinition.setDecoratedDefinition(targetHolder);
089                        proxyDefinition.getPropertyValues().add("target", targetHolder);
090                        // create the interceptor names list
091                        proxyDefinition.getPropertyValues().add("interceptorNames", new ManagedList<String>());
092                        // copy autowire settings from original bean definition.
093                        proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
094                        proxyDefinition.setPrimary(targetDefinition.isPrimary());
095                        if (targetDefinition instanceof AbstractBeanDefinition) {
096                                proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
097                        }
098                        // wrap it in a BeanDefinitionHolder with bean name
099                        result = new BeanDefinitionHolder(proxyDefinition, existingBeanName);
100                }
101
102                addInterceptorNameToList(interceptorName, result.getBeanDefinition());
103                return result;
104        }
105
106        @SuppressWarnings("unchecked")
107        private void addInterceptorNameToList(String interceptorName, BeanDefinition beanDefinition) {
108                List<String> list = (List<String>)
109                                beanDefinition.getPropertyValues().getPropertyValue("interceptorNames").getValue();
110                list.add(interceptorName);
111        }
112
113        private boolean isProxyFactoryBeanDefinition(BeanDefinition existingDefinition) {
114                return ProxyFactoryBean.class.getName().equals(existingDefinition.getBeanClassName());
115        }
116
117        protected String getInterceptorNameSuffix(BeanDefinition interceptorDefinition) {
118                return StringUtils.uncapitalize(ClassUtils.getShortName(interceptorDefinition.getBeanClassName()));
119        }
120
121        /**
122         * Subclasses should implement this method to return the {@code BeanDefinition}
123         * for the interceptor they wish to apply to the bean being decorated.
124         */
125        protected abstract BeanDefinition createInterceptorDefinition(Node node);
126
127}