/* * Copyright 2002-2007 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.lang.reflect.Method; import javax.servlet.ServletException; import junit.framework.TestCase; import org.springframework.beans.ITestBean; import org.springframework.beans.TestBean; import org.springframework.metadata.Attributes; import org.springframework.metadata.commons.CommonsAttributes; import org.springframework.metadata.support.MapAttributes; import org.springframework.transaction.TransactionDefinition; /** * @author Rod Johnson * @author Juergen Hoeller */ public class CommonsAttributesTransactionAttributeSourceTests extends TestCase { public void testNullOrEmpty() throws Exception { Method method = ITestBean.class.getMethod("getAge", (Class[]) null); MapAttributes mar = new MapAttributes(); mar.register(method, null); AttributesTransactionAttributeSource atas = new AttributesTransactionAttributeSource(mar); assertNull(atas.getTransactionAttribute(method, null)); mar.register(method, new Object[0]); assertNull(atas.getTransactionAttribute(method, null)); // Try again in case of caching assertNull(atas.getTransactionAttribute(method, null)); } public void testSingleTransactionAttribute() throws Exception { Method method = ITestBean.class.getMethod("getAge", (Class[]) null); TransactionAttribute txAtt = new DefaultTransactionAttribute(); MapAttributes ma = new MapAttributes(); ma.register(method, new Object[]{txAtt}); AttributesTransactionAttributeSource atas = new AttributesTransactionAttributeSource(ma); TransactionAttribute actual = atas.getTransactionAttribute(method, method.getDeclaringClass()); assertEquals(txAtt, actual); // Check that the same attribute comes back if we ask twice assertSame(txAtt, atas.getTransactionAttribute(method, method.getDeclaringClass())); } public void testTransactionAttributeAmongOthers() throws Exception { Method method = TestBean.class.getMethod("getAge", (Class[]) null); TransactionAttribute txAtt = new DefaultTransactionAttribute(); MapAttributes ma = new MapAttributes(); AttributesTransactionAttributeSource atas = new AttributesTransactionAttributeSource(ma); ma.register(method, new Object[]{new Object(), "", txAtt, "er"}); TransactionAttribute actual = atas.getTransactionAttribute(method, method.getDeclaringClass()); assertEquals(txAtt, actual); assertSame(txAtt, atas.getTransactionAttribute(method, method.getDeclaringClass())); } public void testOverloadedMethodsGetDistinctTransactionAttributes() throws Exception { Method method1 = TestBeanWithOverloadedMethod.class.getMethod("getAge", (Class[]) null); Method method2 = TestBeanWithOverloadedMethod.class.getMethod("getAge", new Class[]{int.class}); TransactionAttribute txAtt1 = new DefaultTransactionAttribute(); TransactionAttribute txAtt2 = new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_NEVER); MapAttributes ma = new MapAttributes(); AttributesTransactionAttributeSource atas = new AttributesTransactionAttributeSource(ma); ma.register(method1, new Object[]{new Object(), "", txAtt1, "er"}); ma.register(method2, new Object[]{txAtt2}); TransactionAttribute actual = atas.getTransactionAttribute(method1, TestBeanWithOverloadedMethod.class); assertEquals(txAtt1, actual); assertSame(txAtt1, atas.getTransactionAttribute(method1, method1.getDeclaringClass())); TransactionAttribute actual2 = atas.getTransactionAttribute(method2, TestBeanWithOverloadedMethod.class); assertEquals(txAtt2, actual2); assertSame(txAtt2, atas.getTransactionAttribute(method2, method2.getDeclaringClass())); } /** * Test the important case where the invocation is on a proxied interface method, but * the attribute is defined on the target class */ public void testTransactionAttributeDeclaredOnClassMethod() throws Exception { Method classMethod = TestBean.class.getMethod("getAge", (Class[]) null); Method interfaceMethod = ITestBean.class.getMethod("getAge", (Class[]) null); TransactionAttribute txAtt = new DefaultTransactionAttribute(); MapAttributes ma = new MapAttributes(); AttributesTransactionAttributeSource atas = new AttributesTransactionAttributeSource(ma); ma.register(classMethod, new Object[]{new Object(), "", txAtt, "er"}); // Target class implements ITestBean TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean.class); assertEquals(txAtt, actual); } public void testTransactionAttributeDeclaredOnInterfaceMethodOnly() throws Exception { Method interfaceMethod = ITestBean.class.getMethod("getAge", (Class[]) null); TransactionAttribute txAtt = new DefaultTransactionAttribute(); MapAttributes ma = new MapAttributes(); AttributesTransactionAttributeSource atas = new AttributesTransactionAttributeSource(ma); ma.register(interfaceMethod, new Object[]{new Object(), "", txAtt, "er"}); // Target class implements ITestBean TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean.class); assertEquals(txAtt, actual); } public void testTransactionAttributeDeclaredOnTargetClassMethodTakesPrecedenceOverAttributeDeclaredOnInterfaceMethod() throws Exception { Method classMethod = TestBean.class.getMethod("getAge", (Class[]) null); Method interfaceMethod = ITestBean.class.getMethod("getAge", (Class[]) null); TransactionAttribute interfaceAtt = new DefaultTransactionAttribute(); TransactionAttribute classAtt = new DefaultTransactionAttribute(); MapAttributes ma = new MapAttributes(); AttributesTransactionAttributeSource atas = new AttributesTransactionAttributeSource(ma); ma.register(interfaceMethod, new Object[]{new Object(), "", interfaceAtt, "er"}); ma.register(classMethod, new Object[]{new Object(), "", classAtt, "er"}); // Target class implements ITestBean TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean.class); assertEquals(classAtt, actual); } public void testRollbackRulesAreApplied() throws Exception { Method method = TestBean.class.getMethod("getAge", (Class[]) null); MapAttributes ma = new MapAttributes(); TransactionAttribute txAtt = new RuleBasedTransactionAttribute(); RollbackRuleAttribute rr = new RollbackRuleAttribute("java.lang.Exception"); RollbackRuleAttribute nrr = new NoRollbackRuleAttribute("ServletException"); AttributesTransactionAttributeSource atas = new AttributesTransactionAttributeSource(ma); ma.register(method, new Object[]{new Object(), "", txAtt, rr, nrr, "er"}); TransactionAttribute actual = atas.getTransactionAttribute(method, method.getDeclaringClass()); assertEquals(txAtt, actual); assertTrue(txAtt.rollbackOn(new Exception())); assertFalse(txAtt.rollbackOn(new ServletException())); assertSame(txAtt, atas.getTransactionAttribute(method, method.getDeclaringClass())); } /** * Test that transaction attribute is inherited from class * if not specified on method. */ public void testDefaultsToClassTransactionAttribute() throws Exception { Method method = TestBean.class.getMethod("getAge", (Class[]) null); TransactionAttribute txAtt = new DefaultTransactionAttribute(); MapAttributes ma = new MapAttributes(); AttributesTransactionAttributeSource atas = new AttributesTransactionAttributeSource(ma); ma.register(TestBean.class, new Object[]{new Object(), "", txAtt, "er"}); TransactionAttribute actual = atas.getTransactionAttribute(method, null); assertEquals(txAtt, actual); } public void testUnboundedCacheSizeGrowth() throws Exception { Attributes attributes = new CommonsAttributes(); AttributesTransactionAttributeSource attributeSource = new AttributesTransactionAttributeSource(attributes); for (int i = 0; i < 100; i++) { PrototypeBean bean = new PrototypeBean(); Method m = bean.getClass().getMethod("doNothing", new Class[0]); attributeSource.getTransactionAttribute(m, bean.getClass()); assertEquals("Cache size should not increase: i=" + i, 1, attributeSource.attributeCache.size()); } } public static class TestBeanWithOverloadedMethod extends TestBean { public int getAge(int i) { return i; } } private static class PrototypeBean { public void doNothing() { } } }