View Javadoc
1   /*
2    * Copyright 2002-2014 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.jms.connection;
18  
19  import javax.jms.Connection;
20  import javax.jms.ConnectionFactory;
21  import javax.jms.ExceptionListener;
22  import javax.jms.JMSException;
23  import javax.jms.QueueConnection;
24  import javax.jms.QueueConnectionFactory;
25  import javax.jms.QueueSession;
26  import javax.jms.Session;
27  import javax.jms.TopicConnection;
28  import javax.jms.TopicConnectionFactory;
29  import javax.jms.TopicSession;
30  
31  import org.junit.Test;
32  
33  import static org.junit.Assert.*;
34  import static org.mockito.BDDMockito.*;
35  
36  /**
37   * @author Juergen Hoeller
38   * @since 26.07.2004
39   */
40  public class SingleConnectionFactoryTests {
41  
42  	@Test
43  	public void testWithConnection() throws JMSException {
44  		Connection con = mock(Connection.class);
45  
46  		SingleConnectionFactory scf = new SingleConnectionFactory(con);
47  		Connection con1 = scf.createConnection();
48  		con1.start();
49  		con1.stop();
50  		con1.close();
51  		Connection con2 = scf.createConnection();
52  		con2.start();
53  		con2.stop();
54  		con2.close();
55  		scf.destroy();  // should trigger actual close
56  
57  		verify(con, times(2)).start();
58  		verify(con, times(2)).stop();
59  		verify(con).close();
60  		verifyNoMoreInteractions(con);
61  	}
62  
63  	@Test
64  	public void testWithQueueConnection() throws JMSException {
65  		Connection con = mock(QueueConnection.class);
66  
67  		SingleConnectionFactory scf = new SingleConnectionFactory(con);
68  		QueueConnection con1 = scf.createQueueConnection();
69  		con1.start();
70  		con1.stop();
71  		con1.close();
72  		QueueConnection con2 = scf.createQueueConnection();
73  		con2.start();
74  		con2.stop();
75  		con2.close();
76  		scf.destroy();  // should trigger actual close
77  
78  		verify(con, times(2)).start();
79  		verify(con, times(2)).stop();
80  		verify(con).close();
81  		verifyNoMoreInteractions(con);
82  	}
83  
84  	@Test
85  	public void testWithTopicConnection() throws JMSException {
86  		Connection con = mock(TopicConnection.class);
87  
88  		SingleConnectionFactory scf = new SingleConnectionFactory(con);
89  		TopicConnection con1 = scf.createTopicConnection();
90  		con1.start();
91  		con1.stop();
92  		con1.close();
93  		TopicConnection con2 = scf.createTopicConnection();
94  		con2.start();
95  		con2.stop();
96  		con2.close();
97  		scf.destroy();  // should trigger actual close
98  
99  		verify(con, times(2)).start();
100 		verify(con, times(2)).stop();
101 		verify(con).close();
102 		verifyNoMoreInteractions(con);
103 	}
104 
105 	@Test
106 	public void testWithConnectionFactory() throws JMSException {
107 		ConnectionFactory cf = mock(ConnectionFactory.class);
108 		Connection con = mock(Connection.class);
109 
110 		given(cf.createConnection()).willReturn(con);
111 
112 		SingleConnectionFactory scf = new SingleConnectionFactory(cf);
113 		Connection con1 = scf.createConnection();
114 		Connection con2 = scf.createConnection();
115 		con1.start();
116 		con2.start();
117 		con1.close();
118 		con2.close();
119 		scf.destroy();  // should trigger actual close
120 
121 		verify(con).start();
122 		verify(con).stop();
123 		verify(con).close();
124 		verifyNoMoreInteractions(con);
125 	}
126 
127 	@Test
128 	public void testWithQueueConnectionFactoryAndJms11Usage() throws JMSException {
129 		QueueConnectionFactory cf = mock(QueueConnectionFactory.class);
130 		QueueConnection con = mock(QueueConnection.class);
131 
132 		given(cf.createConnection()).willReturn(con);
133 
134 		SingleConnectionFactory scf = new SingleConnectionFactory(cf);
135 		Connection con1 = scf.createConnection();
136 		Connection con2 = scf.createConnection();
137 		con1.start();
138 		con2.start();
139 		con1.close();
140 		con2.close();
141 		scf.destroy();  // should trigger actual close
142 
143 		verify(con).start();
144 		verify(con).stop();
145 		verify(con).close();
146 		verifyNoMoreInteractions(con);
147 	}
148 
149 	@Test
150 	public void testWithQueueConnectionFactoryAndJms102Usage() throws JMSException {
151 		QueueConnectionFactory cf = mock(QueueConnectionFactory.class);
152 		QueueConnection con = mock(QueueConnection.class);
153 
154 		given(cf.createQueueConnection()).willReturn(con);
155 
156 		SingleConnectionFactory scf = new SingleConnectionFactory(cf);
157 		Connection con1 = scf.createQueueConnection();
158 		Connection con2 = scf.createQueueConnection();
159 		con1.start();
160 		con2.start();
161 		con1.close();
162 		con2.close();
163 		scf.destroy();  // should trigger actual close
164 
165 		verify(con).start();
166 		verify(con).stop();
167 		verify(con).close();
168 		verifyNoMoreInteractions(con);
169 	}
170 
171 	@Test
172 	public void testWithTopicConnectionFactoryAndJms11Usage() throws JMSException {
173 		TopicConnectionFactory cf = mock(TopicConnectionFactory.class);
174 		TopicConnection con = mock(TopicConnection.class);
175 
176 		given(cf.createConnection()).willReturn(con);
177 
178 		SingleConnectionFactory scf = new SingleConnectionFactory(cf);
179 		Connection con1 = scf.createConnection();
180 		Connection con2 = scf.createConnection();
181 		con1.start();
182 		con2.start();
183 		con1.close();
184 		con2.close();
185 		scf.destroy();  // should trigger actual close
186 
187 		verify(con).start();
188 		verify(con).stop();
189 		verify(con).close();
190 		verifyNoMoreInteractions(con);
191 	}
192 
193 	@Test
194 	public void testWithTopicConnectionFactoryAndJms102Usage() throws JMSException {
195 		TopicConnectionFactory cf = mock(TopicConnectionFactory.class);
196 		TopicConnection con = mock(TopicConnection.class);
197 
198 		given(cf.createTopicConnection()).willReturn(con);
199 
200 		SingleConnectionFactory scf = new SingleConnectionFactory(cf);
201 		Connection con1 = scf.createTopicConnection();
202 		Connection con2 = scf.createTopicConnection();
203 		con1.start();
204 		con2.start();
205 		con1.close();
206 		con2.close();
207 		scf.destroy();  // should trigger actual close
208 
209 		verify(con).start();
210 		verify(con).stop();
211 		verify(con).close();
212 		verifyNoMoreInteractions(con);
213 	}
214 
215 	@Test
216 	public void testWithConnectionAggregatedStartStop() throws JMSException {
217 		Connection con = mock(Connection.class);
218 
219 		SingleConnectionFactory scf = new SingleConnectionFactory(con);
220 		Connection con1 = scf.createConnection();
221 		con1.start();
222 		verify(con).start();
223 		con1.stop();
224 		verify(con).stop();
225 		Connection con2 = scf.createConnection();
226 		con2.start();
227 		verify(con, times(2)).start();
228 		con2.stop();
229 		verify(con, times(2)).stop();
230 		con2.start();
231 		verify(con, times(3)).start();
232 		con1.start();
233 		con2.stop();
234 		con1.stop();
235 		verify(con, times(3)).stop();
236 		con1.start();
237 		verify(con, times(4)).start();
238 		con1.close();
239 		verify(con, times(4)).stop();
240 		con2.close();
241 		scf.destroy();
242 		verify(con).close();
243 
244 		verifyNoMoreInteractions(con);
245 	}
246 
247 	@Test
248 	public void testWithConnectionFactoryAndClientId() throws JMSException {
249 		ConnectionFactory cf = mock(ConnectionFactory.class);
250 		Connection con = mock(Connection.class);
251 		given(cf.createConnection()).willReturn(con);
252 
253 		SingleConnectionFactory scf = new SingleConnectionFactory(cf);
254 		scf.setClientId("myId");
255 		Connection con1 = scf.createConnection();
256 		Connection con2 = scf.createConnection();
257 		con1.start();
258 		con2.start();
259 		con1.close();
260 		con2.close();
261 		scf.destroy();  // should trigger actual close
262 
263 		verify(con).setClientID("myId");
264 		verify(con).start();
265 		verify(con).stop();
266 		verify(con).close();
267 		verifyNoMoreInteractions(con);
268 	}
269 
270 	@Test
271 	public void testWithConnectionFactoryAndExceptionListener() throws JMSException {
272 		ConnectionFactory cf = mock(ConnectionFactory.class);
273 		Connection con = mock(Connection.class);
274 
275 		ExceptionListener listener = new ChainedExceptionListener();
276 		given(cf.createConnection()).willReturn(con);
277 		given(con.getExceptionListener()).willReturn(listener);
278 
279 		SingleConnectionFactory scf = new SingleConnectionFactory(cf);
280 		scf.setExceptionListener(listener);
281 		Connection con1 = scf.createConnection();
282 		assertEquals(listener, con1.getExceptionListener());
283 		con1.start();
284 		con1.stop();
285 		con1.close();
286 		Connection con2 = scf.createConnection();
287 		con2.start();
288 		con2.stop();
289 		con2.close();
290 		scf.destroy();  // should trigger actual close
291 
292 		verify(con).setExceptionListener(listener);
293 		verify(con, times(2)).start();
294 		verify(con, times(2)).stop();
295 		verify(con).close();
296 	}
297 
298 	@Test
299 	public void testWithConnectionFactoryAndReconnectOnException() throws JMSException {
300 		ConnectionFactory cf = mock(ConnectionFactory.class);
301 		TestConnection con = new TestConnection();
302 		given(cf.createConnection()).willReturn(con);
303 
304 		SingleConnectionFactory scf = new SingleConnectionFactory(cf);
305 		scf.setReconnectOnException(true);
306 		Connection con1 = scf.createConnection();
307 		assertNull(con1.getExceptionListener());
308 		con1.start();
309 		con.getExceptionListener().onException(new JMSException(""));
310 		Connection con2 = scf.createConnection();
311 		con2.start();
312 		scf.destroy();  // should trigger actual close
313 
314 		assertEquals(2, con.getStartCount());
315 		assertEquals(2, con.getCloseCount());
316 	}
317 
318 	@Test
319 	public void testWithConnectionFactoryAndExceptionListenerAndReconnectOnException() throws JMSException {
320 		ConnectionFactory cf = mock(ConnectionFactory.class);
321 		TestConnection con = new TestConnection();
322 		given(cf.createConnection()).willReturn(con);
323 
324 		TestExceptionListener listener = new TestExceptionListener();
325 		SingleConnectionFactory scf = new SingleConnectionFactory(cf);
326 		scf.setExceptionListener(listener);
327 		scf.setReconnectOnException(true);
328 		Connection con1 = scf.createConnection();
329 		assertSame(listener, con1.getExceptionListener());
330 		con1.start();
331 		con.getExceptionListener().onException(new JMSException(""));
332 		Connection con2 = scf.createConnection();
333 		con2.start();
334 		scf.destroy();  // should trigger actual close
335 
336 		assertEquals(2, con.getStartCount());
337 		assertEquals(2, con.getCloseCount());
338 		assertEquals(1, listener.getCount());
339 	}
340 
341 	@Test
342 	public void testWithConnectionFactoryAndLocalExceptionListenerWithCleanup() throws JMSException {
343 		ConnectionFactory cf = mock(ConnectionFactory.class);
344 		TestConnection con = new TestConnection();
345 		given(cf.createConnection()).willReturn(con);
346 
347 		TestExceptionListener listener0 = new TestExceptionListener();
348 		TestExceptionListener listener1 = new TestExceptionListener();
349 		TestExceptionListener listener2 = new TestExceptionListener();
350 
351 		SingleConnectionFactory scf = new SingleConnectionFactory(cf) {
352 			@Override
353 			public void onException(JMSException ex) {
354 				// no-op
355 			}
356 		};
357 		scf.setReconnectOnException(true);
358 		scf.setExceptionListener(listener0);
359 		Connection con1 = scf.createConnection();
360 		con1.setExceptionListener(listener1);
361 		assertSame(listener1, con1.getExceptionListener());
362 		Connection con2 = scf.createConnection();
363 		con2.setExceptionListener(listener2);
364 		assertSame(listener2, con2.getExceptionListener());
365 		con.getExceptionListener().onException(new JMSException(""));
366 		con2.close();
367 		con.getExceptionListener().onException(new JMSException(""));
368 		con1.close();
369 		con.getExceptionListener().onException(new JMSException(""));
370 		scf.destroy();  // should trigger actual close
371 
372 		assertEquals(0, con.getStartCount());
373 		assertEquals(1, con.getCloseCount());
374 		assertEquals(3, listener0.getCount());
375 		assertEquals(2, listener1.getCount());
376 		assertEquals(1, listener2.getCount());
377 	}
378 
379 	@Test
380 	public void testWithConnectionFactoryAndLocalExceptionListenerWithReconnect() throws JMSException {
381 		ConnectionFactory cf = mock(ConnectionFactory.class);
382 		TestConnection con = new TestConnection();
383 		given(cf.createConnection()).willReturn(con);
384 
385 		TestExceptionListener listener0 = new TestExceptionListener();
386 		TestExceptionListener listener1 = new TestExceptionListener();
387 		TestExceptionListener listener2 = new TestExceptionListener();
388 
389 		SingleConnectionFactory scf = new SingleConnectionFactory(cf);
390 		scf.setReconnectOnException(true);
391 		scf.setExceptionListener(listener0);
392 		Connection con1 = scf.createConnection();
393 		con1.setExceptionListener(listener1);
394 		assertSame(listener1, con1.getExceptionListener());
395 		con1.start();
396 		Connection con2 = scf.createConnection();
397 		con2.setExceptionListener(listener2);
398 		assertSame(listener2, con2.getExceptionListener());
399 		con.getExceptionListener().onException(new JMSException(""));
400 		con2.close();
401 		con1.getMetaData();
402 		con.getExceptionListener().onException(new JMSException(""));
403 		con1.close();
404 		scf.destroy();  // should trigger actual close
405 
406 		assertEquals(2, con.getStartCount());
407 		assertEquals(2, con.getCloseCount());
408 		assertEquals(2, listener0.getCount());
409 		assertEquals(2, listener1.getCount());
410 		assertEquals(1, listener2.getCount());
411 	}
412 
413 	@Test
414 	public void testCachingConnectionFactory() throws JMSException {
415 		ConnectionFactory cf = mock(ConnectionFactory.class);
416 		Connection con = mock(Connection.class);
417 		Session txSession = mock(Session.class);
418 		Session nonTxSession = mock(Session.class);
419 
420 		given(cf.createConnection()).willReturn(con);
421 		given(con.createSession(true, Session.AUTO_ACKNOWLEDGE)).willReturn(txSession);
422 		given(txSession.getTransacted()).willReturn(true);
423 		given(con.createSession(false, Session.CLIENT_ACKNOWLEDGE)).willReturn(nonTxSession);
424 
425 		CachingConnectionFactory scf = new CachingConnectionFactory(cf);
426 		scf.setReconnectOnException(false);
427 		Connection con1 = scf.createConnection();
428 		Session session1 = con1.createSession(true, Session.AUTO_ACKNOWLEDGE);
429 		session1.getTransacted();
430 		session1.close();  // should lead to rollback
431 		session1 = con1.createSession(false, Session.CLIENT_ACKNOWLEDGE);
432 		session1.close();
433 		con1.start();
434 		Connection con2 = scf.createConnection();
435 		Session session2 = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
436 		session2.close();
437 		session2 = con2.createSession(true, Session.AUTO_ACKNOWLEDGE);
438 		session2.commit();
439 		session2.close();
440 		con2.start();
441 		con1.close();
442 		con2.close();
443 		scf.destroy();  // should trigger actual close
444 
445 		verify(txSession).commit();
446 		verify(txSession).close();
447 		verify(nonTxSession).close();
448 		verify(con).start();
449 		verify(con).stop();
450 		verify(con).close();
451 	}
452 
453 	@Test
454 	public void testCachingConnectionFactoryWithQueueConnectionFactoryAndJms102Usage() throws JMSException {
455 		QueueConnectionFactory cf = mock(QueueConnectionFactory.class);
456 		QueueConnection con = mock(QueueConnection.class);
457 		QueueSession txSession = mock(QueueSession.class);
458 		QueueSession nonTxSession = mock(QueueSession.class);
459 
460 		given(cf.createQueueConnection()).willReturn(con);
461 		given(con.createQueueSession(true, Session.AUTO_ACKNOWLEDGE)).willReturn(txSession);
462 		given(txSession.getTransacted()).willReturn(true);
463 		given(con.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE)).willReturn(nonTxSession);
464 
465 		CachingConnectionFactory scf = new CachingConnectionFactory(cf);
466 		scf.setReconnectOnException(false);
467 		Connection con1 = scf.createQueueConnection();
468 		Session session1 = con1.createSession(true, Session.AUTO_ACKNOWLEDGE);
469 		session1.rollback();
470 		session1.close();
471 		session1 = con1.createSession(false, Session.CLIENT_ACKNOWLEDGE);
472 		session1.close();
473 		con1.start();
474 		QueueConnection con2 = scf.createQueueConnection();
475 		Session session2 = con2.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
476 		session2.close();
477 		session2 = con2.createSession(true, Session.AUTO_ACKNOWLEDGE);
478 		session2.getTransacted();
479 		session2.close();  // should lead to rollback
480 		con2.start();
481 		con1.close();
482 		con2.close();
483 		scf.destroy();  // should trigger actual close
484 
485 		verify(txSession).rollback();
486 		verify(txSession).close();
487 		verify(nonTxSession).close();
488 		verify(con).start();
489 		verify(con).stop();
490 		verify(con).close();
491 	}
492 
493 	@Test
494 	public void testCachingConnectionFactoryWithTopicConnectionFactoryAndJms102Usage() throws JMSException {
495 		TopicConnectionFactory cf = mock(TopicConnectionFactory.class);
496 		TopicConnection con = mock(TopicConnection.class);
497 		TopicSession txSession = mock(TopicSession.class);
498 		TopicSession nonTxSession = mock(TopicSession.class);
499 
500 		given(cf.createTopicConnection()).willReturn(con);
501 		given(con.createTopicSession(true, Session.AUTO_ACKNOWLEDGE)).willReturn(txSession);
502 		given(txSession.getTransacted()).willReturn(true);
503 		given(con.createTopicSession(false, Session.CLIENT_ACKNOWLEDGE)).willReturn(nonTxSession);
504 
505 		CachingConnectionFactory scf = new CachingConnectionFactory(cf);
506 		scf.setReconnectOnException(false);
507 		Connection con1 = scf.createTopicConnection();
508 		Session session1 = con1.createSession(true, Session.AUTO_ACKNOWLEDGE);
509 		session1.getTransacted();
510 		session1.close();  // should lead to rollback
511 		session1 = con1.createSession(false, Session.CLIENT_ACKNOWLEDGE);
512 		session1.close();
513 		con1.start();
514 		TopicConnection con2 = scf.createTopicConnection();
515 		Session session2 = con2.createTopicSession(false, Session.CLIENT_ACKNOWLEDGE);
516 		session2.close();
517 		session2 = con2.createSession(true, Session.AUTO_ACKNOWLEDGE);
518 		session2.getTransacted();
519 		session2.close();
520 		con2.start();
521 		con1.close();
522 		con2.close();
523 		scf.destroy();  // should trigger actual close
524 
525 		verify(txSession).close();
526 		verify(nonTxSession).close();
527 		verify(con).start();
528 		verify(con).stop();
529 		verify(con).close();
530 	}
531 
532 }