001: /*
002: * Copyright 2002-2006 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.interceptor;
018:
019: import java.util.Properties;
020:
021: import org.springframework.aop.Pointcut;
022: import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean;
023: import org.springframework.aop.support.DefaultPointcutAdvisor;
024: import org.springframework.beans.factory.BeanFactory;
025: import org.springframework.beans.factory.BeanFactoryAware;
026: import org.springframework.beans.factory.BeanFactoryUtils;
027: import org.springframework.beans.factory.FactoryBean;
028: import org.springframework.beans.factory.ListableBeanFactory;
029: import org.springframework.transaction.PlatformTransactionManager;
030:
031: /**
032: * Proxy factory bean for simplified declarative transaction handling.
033: * This is a convenient alternative to a standard AOP
034: * {@link org.springframework.aop.framework.ProxyFactoryBean}
035: * with a separate {@link TransactionInterceptor} definition.
036: *
037: * <p>This class is intended to cover the <i>typical</i> case of declarative
038: * transaction demarcation: namely, wrapping a singleton target object with a
039: * transactional proxy, proxying all the interfaces that the target implements.
040: *
041: * <p>There are three main properties that need to be specified:
042: * <ul>
043: * <li>"transactionManager": the {@link PlatformTransactionManager} implementation to use
044: * (for example, a {@link org.springframework.transaction.jta.JtaTransactionManager} instance)
045: * <li>"target": the target object that a transactional proxy should be created for
046: * <li>"transactionAttributes": the transaction attributes (for example, propagation
047: * behavior and "readOnly" flag) per target method name (or method name pattern)
048: * </ul>
049: *
050: * <p>If the "transactionManager" property is not set explicitly and this {@link FactoryBean}
051: * is running in a {@link ListableBeanFactory}, a single matching bean of type
052: * {@link PlatformTransactionManager} will be fetched from the {@link BeanFactory}.
053: *
054: * <p>In contrast to {@link TransactionInterceptor}, the transaction attributes are
055: * specified as properties, with method names as keys and transaction attribute
056: * descriptors as values. Method names are always applied to the target class.
057: *
058: * <p>Internally, a {@link TransactionInterceptor} instance is used, but the user of this
059: * class does not have to care. Optionally, a method pointcut can be specified
060: * to cause conditional invocation of the underlying {@link TransactionInterceptor}.
061: *
062: * <p>The "preInterceptors" and "postInterceptors" properties can be set to add
063: * additional interceptors to the mix, like
064: * {@link org.springframework.aop.interceptor.PerformanceMonitorInterceptor} or
065: * {@link org.springframework.orm.hibernate3.HibernateInterceptor} /
066: * {@link org.springframework.orm.jdo.JdoInterceptor}.
067: *
068: * <p><b>HINT:</b> This class is often used with parent / child bean definitions.
069: * Typically, you will define the transaction manager and default transaction
070: * attributes (for method name patterns) in an abstract parent bean definition,
071: * deriving concrete child bean definitions for specific target objects.
072: * This reduces the per-bean definition effort to a minimum.
073: *
074: * <pre code="class">
075: * <bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
076: * abstract="true">
077: * <property name="transactionManager" ref="transactionManager"/>
078: * <property name="transactionAttributes">
079: * <props>
080: * <prop key="insert*">PROPAGATION_REQUIRED</prop>
081: * <prop key="update*">PROPAGATION_REQUIRED</prop>
082: * <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
083: * </props>
084: * </property>
085: * </bean>
086: *
087: * <bean id="myProxy" parent="baseTransactionProxy">
088: * <property name="target" ref="myTarget"/>
089: * </bean>
090: *
091: * <bean id="yourProxy" parent="baseTransactionProxy">
092: * <property name="target" ref="yourTarget"/>
093: * </bean></pre>
094: *
095: * @author Juergen Hoeller
096: * @author Dmitriy Kopylenko
097: * @author Rod Johnson
098: * @since 21.08.2003
099: * @see #setTransactionManager
100: * @see #setTarget
101: * @see #setTransactionAttributes
102: * @see TransactionInterceptor
103: * @see org.springframework.aop.framework.ProxyFactoryBean
104: */
105: public class TransactionProxyFactoryBean extends
106: AbstractSingletonProxyFactoryBean implements FactoryBean,
107: BeanFactoryAware {
108:
109: private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
110:
111: private Pointcut pointcut;
112:
113: /**
114: * Set the transaction manager. This will perform actual
115: * transaction management: This class is just a way of invoking it.
116: * @see TransactionInterceptor#setTransactionManager
117: */
118: public void setTransactionManager(
119: PlatformTransactionManager transactionManager) {
120: this .transactionInterceptor
121: .setTransactionManager(transactionManager);
122: }
123:
124: /**
125: * Set properties with method names as keys and transaction attribute
126: * descriptors (parsed via TransactionAttributeEditor) as values:
127: * e.g. key = "myMethod", value = "PROPAGATION_REQUIRED,readOnly".
128: * <p>Note: Method names are always applied to the target class,
129: * no matter if defined in an interface or the class itself.
130: * <p>Internally, a NameMatchTransactionAttributeSource will be
131: * created from the given properties.
132: * @see #setTransactionAttributeSource
133: * @see TransactionInterceptor#setTransactionAttributes
134: * @see TransactionAttributeEditor
135: * @see NameMatchTransactionAttributeSource
136: */
137: public void setTransactionAttributes(
138: Properties transactionAttributes) {
139: this .transactionInterceptor
140: .setTransactionAttributes(transactionAttributes);
141: }
142:
143: /**
144: * Set the transaction attribute source which is used to find transaction
145: * attributes. If specifying a String property value, a PropertyEditor
146: * will create a MethodMapTransactionAttributeSource from the value.
147: * @see #setTransactionAttributes
148: * @see TransactionInterceptor#setTransactionAttributeSource
149: * @see TransactionAttributeSourceEditor
150: * @see MethodMapTransactionAttributeSource
151: * @see NameMatchTransactionAttributeSource
152: * @see AttributesTransactionAttributeSource
153: * @see org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
154: */
155: public void setTransactionAttributeSource(
156: TransactionAttributeSource transactionAttributeSource) {
157: this .transactionInterceptor
158: .setTransactionAttributeSource(transactionAttributeSource);
159: }
160:
161: /**
162: * Set a pointcut, i.e a bean that can cause conditional invocation
163: * of the TransactionInterceptor depending on method and attributes passed.
164: * Note: Additional interceptors are always invoked.
165: * @see #setPreInterceptors
166: * @see #setPostInterceptors
167: */
168: public void setPointcut(Pointcut pointcut) {
169: this .pointcut = pointcut;
170: }
171:
172: /**
173: * This callback is optional: If running in a BeanFactory and no transaction
174: * manager has been set explicitly, a single matching bean of type
175: * PlatformTransactionManager will be fetched from the BeanFactory.
176: * @see org.springframework.beans.factory.BeanFactoryUtils#beanOfTypeIncludingAncestors
177: * @see org.springframework.transaction.PlatformTransactionManager
178: */
179: public void setBeanFactory(BeanFactory beanFactory) {
180: if (this .transactionInterceptor.getTransactionManager() == null
181: && beanFactory instanceof ListableBeanFactory) {
182: ListableBeanFactory lbf = (ListableBeanFactory) beanFactory;
183: PlatformTransactionManager ptm = (PlatformTransactionManager) BeanFactoryUtils
184: .beanOfTypeIncludingAncestors(lbf,
185: PlatformTransactionManager.class);
186: this .transactionInterceptor.setTransactionManager(ptm);
187: }
188: }
189:
190: /**
191: * Creates an advisor for this FactoryBean's TransactionInterceptor.
192: */
193: protected Object createMainInterceptor() {
194: this .transactionInterceptor.afterPropertiesSet();
195: if (this .pointcut != null) {
196: return new DefaultPointcutAdvisor(this .pointcut,
197: this .transactionInterceptor);
198: } else {
199: // Rely on default pointcut.
200: return new TransactionAttributeSourceAdvisor(
201: this.transactionInterceptor);
202: }
203: }
204:
205: }
|