Skip to content

Commit

Permalink
Per ApplicationContext @transactional configuration
Browse files Browse the repository at this point in the history
Spring's AspectJ @transactional implementation is limited to a singleton that
only allows one ApplicationContext to configure the aspect, thus only
supporting a single transaction manager for the entire ClassLoader.

This patch introduces a modified version of Spring's
AnnotationTransactionAspect, which instantiates the aspect for each
transactional bean. A BeanPostProcesser is used to inject the appropriate
transaction manager into the aspect instances.

With this patch we can begin to use @transactional outside pin manager (and
have multiple pin manager services in the same dCache domain).

Target: trunk
Require-notes: no
Require-book: no
Acked-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
Patch: http://rb.dcache.org/r/6382/
  • Loading branch information
gbehrmann committed Jan 20, 2014
1 parent 46c37f2 commit c7b6aa3
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 8 deletions.
6 changes: 6 additions & 0 deletions modules/dcache/pom.xml
Expand Up @@ -220,6 +220,7 @@
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
Expand Down Expand Up @@ -303,6 +304,11 @@
</dependencies>
</plugin>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-maven-plugin</artifactId>
Expand Down
@@ -0,0 +1,86 @@
/* This class incorporates code from
*
* org.springframework.transaction.aspectj.AnnotationTransactionAspect
*
* which is subject to the following license:
*
* Copyright 2002-2013 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.dcache.util.aspects;

import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.aspectj.AbstractTransactionAspect;

/**
* Advice @Transactional classes and methods with transaction manager
* controlled transactions.
*
* Similar to AnnotationTransactionAspect, but in contrast to AnnotationTransactionAspect
* this class is not a singleton. Thus it can be used in the presence of multiple
* Spring ApplicationContext instances.
*
* @see org.dcache.util.aspects.PerInstanceAnnotationTransactionBeanPostProcessor
*/
public aspect PerInstanceAnnotationTransactionAspect extends AbstractTransactionAspect perthis(instantiationOfTransactionalClass())
{
public PerInstanceAnnotationTransactionAspect() {
super(new AnnotationTransactionAttributeSource(false));
}

/**
* Matches the execution of any public method in a type with the Transactional
* annotation, or any subtype of a type with the Transactional annotation.
*/
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);

/**
* Matches the execution of any method with the Transactional annotation.
*/
private pointcut executionOfTransactionalMethod() :
execution(@Transactional * *(..));

/**
* Definition of pointcut from super aspect - matched join points
* will have Spring transaction management applied.
*/
protected pointcut transactionalMethodExecution(Object txObject) :
(executionOfAnyPublicMethodInAtTransactionalType()
|| executionOfTransactionalMethod() )
&& this(txObject);

/**
* Marker interface to tag classes that have methods subject to transaction demarcation.
*
* The marker is needed so we can bind the perthis Aspect instantiation to the constructor
* invocation. This in turn is needed to let PerInstanceAnnotationTransactionBeanPostProcessor
* inject the transaction manager during the Spring configuration phase.
*/
public interface HasTransactional {} // marker

/**
* Matches any constructor of classes implementing the HasTransactional marker.
*/
pointcut instantiationOfTransactionalClass() :
execution(HasTransactional+.new(..));

/**
* Make any class that has transactional methods implement HasTransactional.
*/
declare parents : hasmethod(@Transactional * *(..)) implements HasTransactional;
declare parents : @Transactional * implements HasTransactional;
}
@@ -0,0 +1,61 @@
/* dCache - http://www.dcache.org/
*
* Copyright (C) 2014 Deutsches Elektronen-Synchrotron
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.dcache.util.aspects;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.transaction.PlatformTransactionManager;

/**
* BeanPostProcessor to configure PerInstanceAnnotationTransactionAspect instances.
*/
public class PerInstanceAnnotationTransactionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware
{
private PlatformTransactionManager txManager;
private BeanFactory beanFactory;

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
if (bean instanceof PerInstanceAnnotationTransactionAspect.HasTransactional) {
PerInstanceAnnotationTransactionAspect aspect = PerInstanceAnnotationTransactionAspect.aspectOf(bean);
aspect.setTransactionManager(txManager);
aspect.setBeanFactory(beanFactory);
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
return bean;
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException
{
this.beanFactory = beanFactory;
}

public void setTransactionManager(PlatformTransactionManager txManager)
{
this.txManager = txManager;
}
}
4 changes: 3 additions & 1 deletion modules/dcache/src/main/resources/META-INF/aop.xml
Expand Up @@ -3,9 +3,11 @@
<aspectj>
<weaver>
<include within="org.dcache.pinmanager.*"/>
<include within="org.dcache.util.aspects.*"/>
</weaver>

<aspects>
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
<exclude within="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
<aspect name="org.dcache.util.aspects.PerInstanceAnnotationTransactionAspect"/>
</aspects>
</aspectj>
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<context:annotation-config/>
Expand Down Expand Up @@ -191,5 +189,7 @@
<property name="persistenceManagerFactory" ref="pmf-proxy"/>
</bean>

<tx:annotation-driven transaction-manager="tx-manager" mode="aspectj"/>
<bean class="org.dcache.util.aspects.PerInstanceAnnotationTransactionBeanPostProcessor">
<property name="transactionManager" ref="tx-manager"/>
</bean>
</beans>
@@ -1,3 +1,20 @@
/* dCache - http://www.dcache.org/
*
* Copyright (C) 2014 Deutsches Elektronen-Synchrotron
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.dcache.srm.aspects;

import java.io.EOFException;
Expand Down
8 changes: 4 additions & 4 deletions packages/pom.xml
Expand Up @@ -149,10 +149,10 @@
<scope>runtime</scope>
</dependency>

<!-- Dependencies of a WAR artifact are not automatically
included, so we have to repeat them here. There is a plugin
(org.appfuse:maven-warpath-plugin) to solve
that (REVISIT). -->
<!-- Dependencies of a WAR artifact are not automatically
included, so we have to repeat them here. There is a plugin
(org.appfuse:maven-warpath-plugin) to solve
that (REVISIT). -->
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-core</artifactId>
Expand Down
6 changes: 6 additions & 0 deletions pom.xml
Expand Up @@ -895,6 +895,12 @@
<source>${source.version}</source>
<target>${target.version}</target>
<complianceLevel>${source.version}</complianceLevel>
<XhasMember>true</XhasMember>
<sources>
<source>
<basedir>${project.basedir}/src/main/aspect</basedir>
</source>
</sources>
</configuration>
<executions>
<execution>
Expand Down

0 comments on commit c7b6aa3

Please sign in to comment.