- /*
- * Copyright 2002-2004 the original author or authors.
- *
- * 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.springframework.transaction.interceptor;
- import java.util.Properties;
- import org.springframework.aop.Advisor;
- import org.springframework.aop.Pointcut;
- import org.springframework.aop.TargetSource;
- import org.springframework.aop.framework.AopConfigException;
- import org.springframework.aop.framework.ProxyConfig;
- import org.springframework.aop.framework.ProxyFactory;
- import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
- import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
- import org.springframework.aop.support.AopUtils;
- import org.springframework.aop.support.DefaultPointcutAdvisor;
- import org.springframework.aop.target.SingletonTargetSource;
- import org.springframework.beans.factory.FactoryBean;
- import org.springframework.beans.factory.InitializingBean;
- import org.springframework.transaction.PlatformTransactionManager;
- /**
- * Proxy factory bean for simplified declarative transaction handling.
- * Alternative to the standard AOP ProxyFactoryBean with a TransactionInterceptor.
- *
- * <p>This class is intended to cover the <i>typical</i> case of declarative
- * transaction demarcation: namely, wrapping a (singleton) target object with a
- * transactional proxy, proxying all the interfaces that the target implements.
- *
- * <p>In contrast to TransactionInterceptor, the transaction attributes are
- * specified as properties, with method names as keys and transaction attribute
- * descriptors as values. Method names are always applied to the target class.
- *
- * <p>Internally, a TransactionInterceptor instance is used, but the user of this
- * class does not have to care. Optionally, a MethodPointcut can be specified
- * to cause conditional invocation of the underlying TransactionInterceptor.
- *
- * <p>The preInterceptors and postInterceptors properties can be set to add
- * additional interceptors to the mix, like PerformanceMonitorInterceptor or
- * HibernateInterceptor/JdoInterceptor.
- *
- * @author Juergen Hoeller
- * @author Dmitriy Kopylenko
- * @author Rod Johnson
- * @since 21.08.2003
- * @see org.springframework.aop.framework.ProxyFactoryBean
- * @see TransactionInterceptor
- * @see #setTransactionAttributes
- * @version $Id: TransactionProxyFactoryBean.java,v 1.29 2004/05/23 20:13:33 jhoeller Exp $
- */
- public class TransactionProxyFactoryBean extends ProxyConfig implements FactoryBean, InitializingBean {
- private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
- private Object target;
- private Class[] proxyInterfaces;
- private Pointcut pointcut;
- private Object[] preInterceptors;
- private Object[] postInterceptors;
- /** Default is global AdvisorAdapterRegistry */
- private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
- private Object proxy;
- /**
- * Set the transaction manager. This will perform actual
- * transaction management: This class is just a way of invoking it.
- * @see TransactionInterceptor#setTransactionManager
- */
- public void setTransactionManager(PlatformTransactionManager transactionManager) {
- this.transactionInterceptor.setTransactionManager( transactionManager);
- }
- /**
- * Set the target object, i.e. the bean to be wrapped with a transactional proxy.
- * <p>The target may be any object, in which case a SingletonTargetSource will
- * be created. If it is a TargetSource, no wrapper TargetSource is created:
- * This enables the use of a pooling or prototype TargetSource etc.
- * @see org.springframework.aop.TargetSource
- * @see org.springframework.aop.target.SingletonTargetSource
- */
- public void setTarget(Object target) {
- this.target = target;
- }
- /**
- * Specify the set of interfaces being proxied.
- * <p>If left null (the default), the AOP infrastructure works
- * out which interfaces need proxying by analyzing the target,
- * proxying all the interfaces that the target object implements.
- */
- public void setProxyInterfaces(String[] interfaceNames) throws ClassNotFoundException {
- this.proxyInterfaces = AopUtils.toInterfaceArray(interfaceNames);
- }
- /**
- * Set properties with method names as keys and transaction attribute
- * descriptors (parsed via TransactionAttributeEditor) as values:
- * e.g. key = "myMethod", value = "PROPAGATION_REQUIRED,readOnly".
- * <p>Note: Method names are always applied to the target class,
- * no matter if defined in an interface or the class itself.
- * <p>Internally, a NameMatchTransactionAttributeSource will be
- * created from the given properties.
- * @see #setTransactionAttributeSource
- * @see TransactionInterceptor#setTransactionAttributes
- * @see TransactionAttributeEditor
- * @see NameMatchTransactionAttributeSource
- */
- public void setTransactionAttributes(Properties transactionAttributes) {
- this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
- }
- /**
- * Set the transaction attribute source which is used to find transaction
- * attributes. If specifying a String property value, a PropertyEditor
- * will create a MethodMapTransactionAttributeSource from the value.
- * @see #setTransactionAttributes
- * @see TransactionInterceptor#setTransactionAttributeSource
- * @see TransactionAttributeSourceEditor
- * @see MethodMapTransactionAttributeSource
- * @see NameMatchTransactionAttributeSource
- */
- public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
- this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);
- }
- /**
- * Set a pointcut, i.e a bean that can cause conditional invocation
- * of the TransactionInterceptor depending on method and attributes passed.
- * Note: Additional interceptors are always invoked.
- * @see #setPreInterceptors
- * @see #setPostInterceptors
- */
- public void setPointcut(Pointcut pointcut) {
- this.pointcut = pointcut;
- }
- /**
- * Set additional interceptors (or advisors) to be applied before the
- * implicit transaction interceptor, e.g. PerformanceMonitorInterceptor.
- * @see org.springframework.aop.interceptor.PerformanceMonitorInterceptor
- */
- public void setPreInterceptors(Object[] preInterceptors) {
- this.preInterceptors = preInterceptors;
- }
- /**
- * Set additional interceptors (or advisors) to be applied after the
- * implicit transaction interceptor, e.g. HibernateInterceptors for
- * eagerly binding Sessions to the current thread when using JTA.
- * <p>Note that this is just necessary if you rely on those interceptors in general:
- * HibernateTemplate and JdoTemplate work nicely with JtaTransactionManager through
- * implicit on-demand thread binding.
- * @see org.springframework.orm.hibernate.HibernateInterceptor
- * @see org.springframework.orm.jdo.JdoInterceptor
- */
- public void setPostInterceptors(Object[] preInterceptors) {
- this.postInterceptors = preInterceptors;
- }
- /**
- * Specify the AdvisorAdapterRegistry to use.
- * Default is the global AdvisorAdapterRegistry.
- * @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
- */
- public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
- this.advisorAdapterRegistry = advisorAdapterRegistry;
- }
- public void afterPropertiesSet() throws AopConfigException {
- this.transactionInterceptor.afterPropertiesSet();
- if (this.target == null) {
- throw new IllegalArgumentException("'target' is required");
- }
- ProxyFactory proxyFactory = new ProxyFactory();
- if (this.preInterceptors != null) {
- for (int i = 0; i < this.preInterceptors.length; i++) {
- proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.preInterceptors[i]));
- }
- }
- if (this.pointcut != null) {
- Advisor advice = new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
- proxyFactory.addAdvisor(advice);
- }
- else {
- // rely on default pointcut
- proxyFactory.addAdvisor(new TransactionAttributeSourceAdvisor(this.transactionInterceptor));
- // could just do the following, but it's usually less efficient because of AOP advice chain caching
- // proxyFactory.addInterceptor(transactionInterceptor);
- }
- if (this.postInterceptors != null) {
- for (int i = 0; i < this.postInterceptors.length; i++) {
- proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.postInterceptors[i]));
- }
- }
- proxyFactory.copyFrom(this);
- proxyFactory.setTargetSource(createTargetSource(this.target));
- if (this.proxyInterfaces != null) {
- proxyFactory.setInterfaces(this.proxyInterfaces);
- }
- else if (!getProxyTargetClass()) {
- if (this.target instanceof TargetSource) {
- throw new AopConfigException("Either 'proxyInterfaces' or 'proxyTargetClass' is required " +
- "when using a TargetSource as 'target");
- }
- // rely on AOP infrastructure to tell us what interfaces to proxy
- proxyFactory.setInterfaces(AopUtils.getAllInterfaces(this.target));
- }
- this.proxy = proxyFactory.getProxy();
- }
- /**
- * Set the target or TargetSource.
- * @param target target. If this is an implementation of TargetSource it is
- * used as our TargetSource; otherwise it is wrapped in a SingletonTargetSource.
- * @return a TargetSource for this object
- */
- protected TargetSource createTargetSource(Object target) {
- if (target instanceof TargetSource) {
- return (TargetSource) target;
- }
- else {
- return new SingletonTargetSource(target);
- }
- }
- public Object getObject() {
- return this.proxy;
- }
- public Class getObjectType() {
- if (this.proxy != null) {
- return this.proxy.getClass();
- }
- else if (this.target != null && this.target instanceof TargetSource) {
- return this.target.getClass();
- }
- else {
- return null;
- }
- }
- public boolean isSingleton() {
- return true;
- }
- }