View Javadoc
1   /*
2    * Copyright 2002-2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.transaction.interceptor;
18  
19  import java.io.Serializable;
20  import java.util.Properties;
21  
22  import org.junit.Rule;
23  import org.junit.Test;
24  import org.junit.rules.ExpectedException;
25  
26  import org.springframework.aop.framework.ProxyFactory;
27  import org.springframework.beans.factory.BeanFactory;
28  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
29  import org.springframework.transaction.PlatformTransactionManager;
30  import org.springframework.transaction.TransactionDefinition;
31  import org.springframework.transaction.TransactionException;
32  import org.springframework.transaction.TransactionStatus;
33  import org.springframework.util.SerializationTestUtils;
34  
35  import static org.junit.Assert.*;
36  import static org.mockito.BDDMockito.*;
37  import static org.mockito.Mockito.mock;
38  import static org.mockito.Mockito.times;
39  import static org.mockito.Mockito.verify;
40  
41  /**
42   * Mock object based tests for TransactionInterceptor.
43   *
44   * @author Rod Johnson
45   * @since 16.03.2003
46   */
47  public class TransactionInterceptorTests extends AbstractTransactionAspectTests {
48  
49  	@Rule
50  	public final ExpectedException thrown = ExpectedException.none();
51  
52  	@Override
53  	protected Object advised(Object target, PlatformTransactionManager ptm, TransactionAttributeSource[] tas) throws Exception {
54  		TransactionInterceptor ti = new TransactionInterceptor();
55  		ti.setTransactionManager(ptm);
56  		ti.setTransactionAttributeSources(tas);
57  
58  		ProxyFactory pf = new ProxyFactory(target);
59  		pf.addAdvice(0, ti);
60  		return pf.getProxy();
61  	}
62  
63  	/**
64  	 * Template method to create an advised object given the
65  	 * target object and transaction setup.
66  	 * Creates a TransactionInterceptor and applies it.
67  	 */
68  	@Override
69  	protected Object advised(Object target, PlatformTransactionManager ptm, TransactionAttributeSource tas) {
70  		TransactionInterceptor ti = new TransactionInterceptor();
71  		ti.setTransactionManager(ptm);
72  		assertEquals(ptm, ti.getTransactionManager());
73  		ti.setTransactionAttributeSource(tas);
74  		assertEquals(tas, ti.getTransactionAttributeSource());
75  
76  		ProxyFactory pf = new ProxyFactory(target);
77  		pf.addAdvice(0, ti);
78  		return pf.getProxy();
79  	}
80  
81  	/**
82  	 * A TransactionInterceptor should be serializable if its
83  	 * PlatformTransactionManager is.
84  	 */
85  	@Test
86  	public void serializableWithAttributeProperties() throws Exception {
87  		TransactionInterceptor ti = new TransactionInterceptor();
88  		Properties props = new Properties();
89  		props.setProperty("methodName", "PROPAGATION_REQUIRED");
90  		ti.setTransactionAttributes(props);
91  		PlatformTransactionManager ptm = new SerializableTransactionManager();
92  		ti.setTransactionManager(ptm);
93  		ti = (TransactionInterceptor) SerializationTestUtils.serializeAndDeserialize(ti);
94  
95  		// Check that logger survived deserialization
96  		assertNotNull(ti.logger);
97  		assertTrue(ti.getTransactionManager() instanceof SerializableTransactionManager);
98  		assertNotNull(ti.getTransactionAttributeSource());
99  	}
100 
101 	@Test
102 	public void serializableWithCompositeSource() throws Exception {
103 		NameMatchTransactionAttributeSource tas1 = new NameMatchTransactionAttributeSource();
104 		Properties props = new Properties();
105 		props.setProperty("methodName", "PROPAGATION_REQUIRED");
106 		tas1.setProperties(props);
107 
108 		NameMatchTransactionAttributeSource tas2 = new NameMatchTransactionAttributeSource();
109 		props = new Properties();
110 		props.setProperty("otherMethodName", "PROPAGATION_REQUIRES_NEW");
111 		tas2.setProperties(props);
112 
113 		TransactionInterceptor ti = new TransactionInterceptor();
114 		ti.setTransactionAttributeSources(new TransactionAttributeSource[] {tas1, tas2});
115 		PlatformTransactionManager ptm = new SerializableTransactionManager();
116 		ti.setTransactionManager(ptm);
117 		ti = (TransactionInterceptor) SerializationTestUtils.serializeAndDeserialize(ti);
118 
119 		assertTrue(ti.getTransactionManager() instanceof SerializableTransactionManager);
120 		assertTrue(ti.getTransactionAttributeSource() instanceof CompositeTransactionAttributeSource);
121 		CompositeTransactionAttributeSource ctas = (CompositeTransactionAttributeSource) ti.getTransactionAttributeSource();
122 		assertTrue(ctas.getTransactionAttributeSources()[0] instanceof NameMatchTransactionAttributeSource);
123 		assertTrue(ctas.getTransactionAttributeSources()[1] instanceof NameMatchTransactionAttributeSource);
124 	}
125 
126 	@Test
127 	public void determineTransactionManagerWithNoBeanFactory() {
128 		PlatformTransactionManager transactionManager = mock(PlatformTransactionManager.class);
129 		TransactionInterceptor ti = transactionInterceptorWithTransactionManager(transactionManager, null);
130 
131 		assertSame(transactionManager, ti.determineTransactionManager(new DefaultTransactionAttribute()));
132 	}
133 
134 	@Test
135 	public void determineTransactionManagerWithNoBeanFactoryAndNoTransactionAttribute() {
136 		PlatformTransactionManager transactionManager = mock(PlatformTransactionManager.class);
137 		TransactionInterceptor ti = transactionInterceptorWithTransactionManager(transactionManager, null);
138 
139 		assertSame(transactionManager, ti.determineTransactionManager(null));
140 	}
141 
142 	@Test
143 	public void determineTransactionManagerWithNoTransactionAttribute() {
144 		BeanFactory beanFactory = mock(BeanFactory.class);
145 		TransactionInterceptor ti = simpleTransactionInterceptor(beanFactory);
146 
147 		assertNull(ti.determineTransactionManager(null));
148 	}
149 
150 	@Test
151 	public void determineTransactionManagerWithQualifierUnknown() {
152 		BeanFactory beanFactory = mock(BeanFactory.class);
153 		TransactionInterceptor ti = simpleTransactionInterceptor(beanFactory);
154 		DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
155 		attribute.setQualifier("fooTransactionManager");
156 
157 		thrown.expect(NoSuchBeanDefinitionException.class);
158 		thrown.expectMessage("'fooTransactionManager'");
159 		ti.determineTransactionManager(attribute);
160 	}
161 
162 	@Test
163 	public void determineTransactionManagerWithQualifierAndDefault() {
164 		BeanFactory beanFactory = mock(BeanFactory.class);
165 		PlatformTransactionManager transactionManager = mock(PlatformTransactionManager.class);
166 		TransactionInterceptor ti = transactionInterceptorWithTransactionManager(transactionManager, beanFactory);
167 		PlatformTransactionManager fooTransactionManager =
168 				associateTransactionManager(beanFactory, "fooTransactionManager");
169 
170 		DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
171 		attribute.setQualifier("fooTransactionManager");
172 
173 		assertSame(fooTransactionManager, ti.determineTransactionManager(attribute));
174 	}
175 
176 	@Test
177 	public void determineTransactionManagerWithQualifierAndDefaultName() {
178 		BeanFactory beanFactory = mock(BeanFactory.class);
179 		associateTransactionManager(beanFactory, "defaultTransactionManager");
180 		TransactionInterceptor ti = transactionInterceptorWithTransactionManagerName(
181 				"defaultTransactionManager", beanFactory);
182 
183 		PlatformTransactionManager fooTransactionManager =
184 				associateTransactionManager(beanFactory, "fooTransactionManager");
185 		DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
186 		attribute.setQualifier("fooTransactionManager");
187 
188 		assertSame(fooTransactionManager, ti.determineTransactionManager(attribute));
189 	}
190 
191 	@Test
192 	public void determineTransactionManagerWithEmptyQualifierAndDefaultName() {
193 		BeanFactory beanFactory = mock(BeanFactory.class);
194 		PlatformTransactionManager defaultTransactionManager
195 				= associateTransactionManager(beanFactory, "defaultTransactionManager");
196 		TransactionInterceptor ti = transactionInterceptorWithTransactionManagerName(
197 				"defaultTransactionManager", beanFactory);
198 
199 		DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
200 		attribute.setQualifier("");
201 
202 		assertSame(defaultTransactionManager, ti.determineTransactionManager(attribute));
203 	}
204 
205 	@Test
206 	public void determineTransactionManagerWithQualifierSeveralTimes() {
207 		BeanFactory beanFactory = mock(BeanFactory.class);
208 		TransactionInterceptor ti = simpleTransactionInterceptor(beanFactory);
209 
210 		PlatformTransactionManager txManager = associateTransactionManager(beanFactory, "fooTransactionManager");
211 
212 		DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
213 		attribute.setQualifier("fooTransactionManager");
214 		PlatformTransactionManager actual = ti.determineTransactionManager(attribute);
215 		assertSame(txManager, actual);
216 
217 		// Call again, should be cached
218 		PlatformTransactionManager actual2 = ti.determineTransactionManager(attribute);
219 		assertSame(txManager, actual2);
220 		verify(beanFactory, times(1)).containsBean("fooTransactionManager");
221 		verify(beanFactory, times(1)).getBean("fooTransactionManager", PlatformTransactionManager.class);
222 	}
223 
224 	@Test
225 	public void determineTransactionManagerWithBeanNameSeveralTimes() {
226 		BeanFactory beanFactory = mock(BeanFactory.class);
227 		TransactionInterceptor ti = transactionInterceptorWithTransactionManagerName(
228 				"fooTransactionManager", beanFactory);
229 
230 		PlatformTransactionManager txManager = 	associateTransactionManager(beanFactory, "fooTransactionManager");
231 
232 		DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
233 		PlatformTransactionManager actual = ti.determineTransactionManager(attribute);
234 		assertSame(txManager, actual);
235 
236 		// Call again, should be cached
237 		PlatformTransactionManager actual2 = ti.determineTransactionManager(attribute);
238 		assertSame(txManager, actual2);
239 		verify(beanFactory, times(1)).getBean("fooTransactionManager", PlatformTransactionManager.class);
240 	}
241 
242 	@Test
243 	public void determineTransactionManagerDefaultSeveralTimes() {
244 		BeanFactory beanFactory = mock(BeanFactory.class);
245 		TransactionInterceptor ti = simpleTransactionInterceptor(beanFactory);
246 
247 		PlatformTransactionManager txManager = mock(PlatformTransactionManager.class);
248 		given(beanFactory.getBean(PlatformTransactionManager.class)).willReturn(txManager);
249 
250 		DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
251 		PlatformTransactionManager actual = ti.determineTransactionManager(attribute);
252 		assertSame(txManager, actual);
253 
254 		// Call again, should be cached
255 		PlatformTransactionManager actual2 = ti.determineTransactionManager(attribute);
256 		assertSame(txManager, actual2);
257 		verify(beanFactory, times(1)).getBean(PlatformTransactionManager.class);
258 	}
259 
260 	private TransactionInterceptor createTransactionInterceptor(BeanFactory beanFactory,
261 			String transactionManagerName, PlatformTransactionManager transactionManager) {
262 		TransactionInterceptor ti = new TransactionInterceptor();
263 		if (beanFactory != null) {
264 			ti.setBeanFactory(beanFactory);
265 		}
266 		if (transactionManagerName != null) {
267 			ti.setTransactionManagerBeanName(transactionManagerName);
268 
269 		}
270 		if (transactionManager != null) {
271 			ti.setTransactionManager(transactionManager);
272 		}
273 		ti.setTransactionAttributeSource(new NameMatchTransactionAttributeSource());
274 		ti.afterPropertiesSet();
275 		return ti;
276 	}
277 
278 	private TransactionInterceptor transactionInterceptorWithTransactionManager(
279 			PlatformTransactionManager transactionManager, BeanFactory beanFactory) {
280 
281 		return createTransactionInterceptor(beanFactory, null, transactionManager);
282 	}
283 
284 	private TransactionInterceptor transactionInterceptorWithTransactionManagerName(
285 			String transactionManagerName, BeanFactory beanFactory) {
286 
287 		return createTransactionInterceptor(beanFactory, transactionManagerName, null);
288 	}
289 
290 	private TransactionInterceptor simpleTransactionInterceptor(BeanFactory beanFactory) {
291 		return createTransactionInterceptor(beanFactory, null, null);
292 	}
293 
294 	private PlatformTransactionManager associateTransactionManager(BeanFactory beanFactory, String name) {
295 		PlatformTransactionManager transactionManager = mock(PlatformTransactionManager.class);
296 		given(beanFactory.containsBean(name)).willReturn(true);
297 		given(beanFactory.getBean(name, PlatformTransactionManager.class)).willReturn(transactionManager);
298 		return transactionManager;
299 	}
300 
301 
302 	/**
303 	 * We won't use this: we just want to know it's serializable.
304 	 */
305 	@SuppressWarnings("serial")
306 	public static class SerializableTransactionManager implements PlatformTransactionManager, Serializable {
307 
308 		@Override
309 		public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
310 			throw new UnsupportedOperationException();
311 		}
312 
313 		@Override
314 		public void commit(TransactionStatus status) throws TransactionException {
315 			throw new UnsupportedOperationException();
316 		}
317 
318 		@Override
319 		public void rollback(TransactionStatus status) throws TransactionException {
320 			throw new UnsupportedOperationException();
321 		}
322 
323 	}
324 }