/* * Copyright 2002-2005 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.springmodules.resource.interceptor; import org.springframework.aop.Advisor; import org.springframework.aop.Pointcut; import org.springframework.aop.TargetSource; 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.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ListableBeanFactory; import org.springmodules.resource.ResourceManager; /** * 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>There are three main properties to be specified: * * <ul> * <li>"transactionManager": the PlatformTransactionManager implementation to use * (for example, a JtaTransactionManager instance) * <li>"target": the target object that a transactional proxy shouls be created for * <li>"transactionAttributes": the transaction attributes (for example, propagation * behavior and "readOnly" flag) per target method name (or method name pattern) * </ul> * * <p>If the "transactionManager" property is not set explicitly and this FactoryBean * is running in a ListableBeanFactory, a single matching bean of type * PlatformTransactionManager will be fetched from the BeanFactory. * * <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 #setTransactionManager * @see #setTarget * @see #setTransactionAttributes * @see TransactionInterceptor * @see org.springframework.aop.framework.ProxyFactoryBean */ public class ResourceProxyFactoryBean extends ProxyConfig implements FactoryBean, BeanFactoryAware, InitializingBean { private final ResourceInterceptor resourceInterceptor = new ResourceInterceptor(); 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 resource manager. This will perform actual * resource management: This class is just a way of invoking it. * @see ResourceInterceptor#setresourceManager */ public void setResourceManager(ResourceManager resourceManager) { this.resourceInterceptor.setResourceManager(resourceManager); } /** * Set the target object, i.e. the bean to be wrapped with a resource 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 * @see org.springframework.aop.target.LazyInitTargetSource * @see org.springframework.aop.target.PrototypeTargetSource * @see org.springframework.aop.target.CommonsPoolTargetSource */ 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 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[] postInterceptors) { this.postInterceptors = postInterceptors; } /** * 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; } /** * This callback is optional: If running in a BeanFactory and no transaction * manager has been set explicitly, a single matching bean of type * PlatformTransactionManager will be fetched from the BeanFactory. * @see org.springframework.beans.factory.BeanFactoryUtils#beanOfTypeIncludingAncestors * @see org.springframework.transaction.PlatformTransactionManager */ public void setBeanFactory(BeanFactory beanFactory) { if (this.resourceInterceptor.getResourceManager() == null && beanFactory instanceof ListableBeanFactory) { ListableBeanFactory lbf = (ListableBeanFactory) beanFactory; ResourceManager rm = (ResourceManager) BeanFactoryUtils.beanOfTypeIncludingAncestors(lbf, ResourceManager.class); this.resourceInterceptor.setResourceManager(rm); } } public void afterPropertiesSet() { this.resourceInterceptor.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.resourceInterceptor); proxyFactory.addAdvisor(advice); } else { // rely on default pointcut proxyFactory.addAdvisor(new ResourceAdvisor(this.resourceInterceptor)); // 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); TargetSource targetSource = createTargetSource(this.target); proxyFactory.setTargetSource(targetSource); if (this.proxyInterfaces != null) { proxyFactory.setInterfaces(this.proxyInterfaces); } else if (!isProxyTargetClass()) { // Rely on AOP infrastructure to tell us what interfaces to proxy. proxyFactory.setInterfaces(AopUtils.getAllInterfacesForClass(targetSource.getTargetClass())); } 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.proxyInterfaces != null && this.proxyInterfaces.length == 1) { return this.proxyInterfaces[0]; } else if (this.target instanceof TargetSource) { return ((TargetSource) this.target).getTargetClass(); } else if (this.target != null) { return this.target.getClass(); } else { return null; } } public boolean isSingleton() { return true; } }