001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.transaction.config;
018:
019: import org.w3c.dom.Element;
020:
021: import org.springframework.aop.config.AopNamespaceUtils;
022: import org.springframework.beans.factory.config.BeanDefinition;
023: import org.springframework.beans.factory.config.RuntimeBeanReference;
024: import org.springframework.beans.factory.parsing.BeanComponentDefinition;
025: import org.springframework.beans.factory.support.RootBeanDefinition;
026: import org.springframework.beans.factory.xml.BeanDefinitionParser;
027: import org.springframework.beans.factory.xml.ParserContext;
028: import org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor;
029: import org.springframework.transaction.interceptor.TransactionInterceptor;
030:
031: /**
032: * {@link org.springframework.beans.factory.xml.BeanDefinitionParser}
033: * implementation that allows users to easily configure all the infrastructure
034: * beans required to enable annotation-driven transaction demarcation.
035: *
036: * <p>By default, all proxies are created as JDK proxies. This may cause some
037: * problems if you are injecting objects as concrete classes rather than
038: * interfaces. To overcome this restriction you can set the
039: * '<code>proxy-target-class</code>' attribute to '<code>true</code>', which
040: * will result in class-based proxies being created.
041: *
042: * @author Juergen Hoeller
043: * @author Rob Harrop
044: * @since 2.0
045: */
046: class AnnotationDrivenBeanDefinitionParser implements
047: BeanDefinitionParser {
048:
049: public static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
050:
051: /**
052: * The bean name of the internally managed transaction advisor (mode="proxy").
053: */
054: public static final String TRANSACTION_ADVISOR_BEAN_NAME = "org.springframework.transaction.config.internalTransactionAdvisor";
055:
056: /**
057: * The bean name of the internally managed transaction aspect (mode="aspectj").
058: */
059: public static final String TRANSACTION_ASPECT_BEAN_NAME = "org.springframework.transaction.config.internalTransactionAspect";
060:
061: private static final String TRANSACTION_ASPECT_CLASS_NAME = "org.springframework.transaction.aspectj.AnnotationTransactionAspect";
062:
063: /**
064: * Parses the '<code><tx:annotation-driven/></code>' tag. Will
065: * {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
066: * with the container as necessary.
067: */
068: public BeanDefinition parse(Element element,
069: ParserContext parserContext) {
070: String mode = element.getAttribute("mode");
071: if ("aspectj".equals(mode)) {
072: // mode="aspectj"
073: registerTransactionAspect(element, parserContext);
074: } else {
075: // mode="proxy"
076: AopAutoProxyConfigurer.configureAutoProxyCreator(element,
077: parserContext);
078: }
079: return null;
080: }
081:
082: private void registerTransactionAspect(Element element,
083: ParserContext parserContext) {
084: if (!parserContext.getRegistry().containsBeanDefinition(
085: TRANSACTION_ASPECT_BEAN_NAME)) {
086: RootBeanDefinition def = new RootBeanDefinition();
087: def.setBeanClassName(TRANSACTION_ASPECT_CLASS_NAME);
088: def.setFactoryMethodName("aspectOf");
089: registerTransactionManager(element, def);
090: parserContext
091: .registerBeanComponent(new BeanComponentDefinition(
092: def, TRANSACTION_ASPECT_BEAN_NAME));
093: }
094: }
095:
096: private static void registerTransactionManager(Element element,
097: BeanDefinition def) {
098: String transactionManagerName = (element
099: .hasAttribute(TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE) ? element
100: .getAttribute(TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE)
101: : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
102: def.getPropertyValues().addPropertyValue(
103: TxNamespaceUtils.TRANSACTION_MANAGER_PROPERTY,
104: new RuntimeBeanReference(transactionManagerName));
105: }
106:
107: /**
108: * Inner class to just introduce an AOP framework dependency when actually in proxy mode.
109: */
110: private static class AopAutoProxyConfigurer {
111:
112: public static void configureAutoProxyCreator(Element element,
113: ParserContext parserContext) {
114: AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(
115: parserContext, element);
116:
117: if (!parserContext.getRegistry().containsBeanDefinition(
118: TRANSACTION_ADVISOR_BEAN_NAME)) {
119: // Create the TransactionInterceptor definition.
120: RootBeanDefinition interceptorDef = new RootBeanDefinition(
121: TransactionInterceptor.class);
122: interceptorDef.setSource(parserContext
123: .extractSource(element));
124: interceptorDef
125: .setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
126: registerTransactionManager(element, interceptorDef);
127:
128: Class sourceClass = TxNamespaceUtils
129: .getAnnotationTransactionAttributeSourceClass();
130: interceptorDef.getPropertyValues().addPropertyValue(
131: TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE,
132: new RootBeanDefinition(sourceClass));
133:
134: // Create the TransactionAttributeSourceAdvisor definition.
135: RootBeanDefinition advisorDef = new RootBeanDefinition(
136: TransactionAttributeSourceAdvisor.class);
137: advisorDef.setSource(parserContext
138: .extractSource(element));
139: advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
140: advisorDef.getPropertyValues().addPropertyValue(
141: "transactionInterceptor", interceptorDef);
142: if (element.hasAttribute("order")) {
143: advisorDef.getPropertyValues().addPropertyValue(
144: "order", element.getAttribute("order"));
145: }
146:
147: parserContext
148: .registerBeanComponent(new BeanComponentDefinition(
149: advisorDef,
150: TRANSACTION_ADVISOR_BEAN_NAME));
151: }
152: }
153: }
154:
155: }
|