/*
* Copyright 2002-2015 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.annotation;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.tests.transaction.CallCountingTransactionManager;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import static org.junit.Assert.*;
/**
* @author Rob Harrop
* @author Juergen Hoeller
*/
public class AnnotationTransactionInterceptorTests {
private final CallCountingTransactionManager ptm = new CallCountingTransactionManager();
private final AnnotationTransactionAttributeSource source = new AnnotationTransactionAttributeSource();
private final TransactionInterceptor ti = new TransactionInterceptor(this.ptm, this.source);
@Test
public void classLevelOnly() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestClassLevelOnly());
proxyFactory.addAdvice(this.ti);
TestClassLevelOnly proxy = (TestClassLevelOnly) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(2);
proxy.doSomething();
assertGetTransactionAndCommitCount(3);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(4);
}
@Test
public void withSingleMethodOverride() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithSingleMethodOverride());
proxyFactory.addAdvice(this.ti);
TestWithSingleMethodOverride proxy = (TestWithSingleMethodOverride) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(2);
proxy.doSomethingCompletelyElse();
assertGetTransactionAndCommitCount(3);
proxy.doSomething();
assertGetTransactionAndCommitCount(4);
}
@Test
public void withSingleMethodOverrideInverted() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithSingleMethodOverrideInverted());
proxyFactory.addAdvice(this.ti);
TestWithSingleMethodOverrideInverted proxy = (TestWithSingleMethodOverrideInverted) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(2);
proxy.doSomethingCompletelyElse();
assertGetTransactionAndCommitCount(3);
proxy.doSomething();
assertGetTransactionAndCommitCount(4);
}
@Test
public void withMultiMethodOverride() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithMultiMethodOverride());
proxyFactory.addAdvice(this.ti);
TestWithMultiMethodOverride proxy = (TestWithMultiMethodOverride) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(2);
proxy.doSomethingCompletelyElse();
assertGetTransactionAndCommitCount(3);
proxy.doSomething();
assertGetTransactionAndCommitCount(4);
}
@Test
public void withRollback() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithRollback());
proxyFactory.addAdvice(this.ti);
TestWithRollback proxy = (TestWithRollback) proxyFactory.getProxy();
try {
proxy.doSomethingErroneous();
fail("Should throw IllegalStateException");
}
catch (IllegalStateException ex) {
assertGetTransactionAndRollbackCount(1);
}
try {
proxy.doSomethingElseErroneous();
fail("Should throw IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
assertGetTransactionAndRollbackCount(2);
}
}
@Test
public void withInterface() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithInterfaceImpl());
proxyFactory.addInterface(TestWithInterface.class);
proxyFactory.addAdvice(this.ti);
TestWithInterface proxy = (TestWithInterface) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(2);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(3);
proxy.doSomething();
assertGetTransactionAndCommitCount(4);
}
@Test
public void crossClassInterfaceMethodLevelOnJdkProxy() throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new SomeServiceImpl());
proxyFactory.addInterface(SomeService.class);
proxyFactory.addAdvice(this.ti);
SomeService someService = (SomeService) proxyFactory.getProxy();
someService.bar();
assertGetTransactionAndCommitCount(1);
someService.foo();
assertGetTransactionAndCommitCount(2);
someService.fooBar();
assertGetTransactionAndCommitCount(3);
}
@Test
public void crossClassInterfaceOnJdkProxy() throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new OtherServiceImpl());
proxyFactory.addInterface(OtherService.class);
proxyFactory.addAdvice(this.ti);
OtherService otherService = (OtherService) proxyFactory.getProxy();
otherService.foo();
assertGetTransactionAndCommitCount(1);
}
private void assertGetTransactionAndCommitCount(int expectedCount) {
assertEquals(expectedCount, this.ptm.begun);
assertEquals(expectedCount, this.ptm.commits);
}
private void assertGetTransactionAndRollbackCount(int expectedCount) {
assertEquals(expectedCount, this.ptm.begun);
assertEquals(expectedCount, this.ptm.rollbacks);
}
@Transactional
public static class TestClassLevelOnly {
public void doSomething() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
}
@Transactional
public static class TestWithSingleMethodOverride {
public void doSomething() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
@Transactional(readOnly = true)
public void doSomethingElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingCompletelyElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
}
@Transactional(readOnly = true)
public static class TestWithSingleMethodOverrideInverted {
@Transactional
public void doSomething() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingCompletelyElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
}
@Transactional
public static class TestWithMultiMethodOverride {
@Transactional(readOnly = true)
public void doSomething() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
@Transactional(readOnly = true)
public void doSomethingElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingCompletelyElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
}
@Transactional(rollbackFor = IllegalStateException.class)
public static class TestWithRollback {
public void doSomethingErroneous() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
throw new IllegalStateException();
}
@Transactional(rollbackFor = IllegalArgumentException.class)
public void doSomethingElseErroneous() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
throw new IllegalArgumentException();
}
}
@Transactional
public static interface TestWithInterface {
public void doSomething();
@Transactional(readOnly = true)
public void doSomethingElse();
}
public static class TestWithInterfaceImpl implements TestWithInterface {
@Override
public void doSomething() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
@Override
public void doSomethingElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
}
public static interface SomeService {
void foo();
@Transactional
void bar();
@Transactional(readOnly = true)
void fooBar();
}
public static class SomeServiceImpl implements SomeService {
@Override
public void bar() {
}
@Override
@Transactional
public void foo() {
}
@Override
@Transactional(readOnly = false)
public void fooBar() {
}
}
public interface OtherService {
void foo();
}
@Transactional
public static class OtherServiceImpl implements OtherService {
@Override
public void foo() {
}
}
}