Revised SingleConnectionFactory for individual proxies with ExceptionListener and start/stop state

Issue: SPR-10397
This commit is contained in:
Juergen Hoeller
2014-10-29 22:43:48 +01:00
parent 38ef6dec50
commit 4927c9054f
2 changed files with 323 additions and 154 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -46,16 +46,16 @@ public class SingleConnectionFactoryTests {
SingleConnectionFactory scf = new SingleConnectionFactory(con);
Connection con1 = scf.createConnection();
con1.start();
con1.stop(); // should be ignored
con1.close(); // should be ignored
con1.stop();
con1.close();
Connection con2 = scf.createConnection();
con2.start(); // should be ignored
con2.stop(); // should be ignored
con2.close(); // should be ignored
con2.start();
con2.stop();
con2.close();
scf.destroy(); // should trigger actual close
verify(con).start();
verify(con).stop();
verify(con, times(2)).start();
verify(con, times(2)).stop();
verify(con).close();
verifyNoMoreInteractions(con);
}
@@ -67,16 +67,16 @@ public class SingleConnectionFactoryTests {
SingleConnectionFactory scf = new SingleConnectionFactory(con);
QueueConnection con1 = scf.createQueueConnection();
con1.start();
con1.stop(); // should be ignored
con1.close(); // should be ignored
con1.stop();
con1.close();
QueueConnection con2 = scf.createQueueConnection();
con2.start();
con2.stop(); // should be ignored
con2.close(); // should be ignored
con2.stop();
con2.close();
scf.destroy(); // should trigger actual close
verify(con).start();
verify(con).stop();
verify(con, times(2)).start();
verify(con, times(2)).stop();
verify(con).close();
verifyNoMoreInteractions(con);
}
@@ -88,16 +88,16 @@ public class SingleConnectionFactoryTests {
SingleConnectionFactory scf = new SingleConnectionFactory(con);
TopicConnection con1 = scf.createTopicConnection();
con1.start();
con1.stop(); // should be ignored
con1.close(); // should be ignored
con1.stop();
con1.close();
TopicConnection con2 = scf.createTopicConnection();
con2.start();
con2.stop(); // should be ignored
con2.close(); // should be ignored
con2.stop();
con2.close();
scf.destroy(); // should trigger actual close
verify(con).start();
verify(con).stop();
verify(con, times(2)).start();
verify(con, times(2)).stop();
verify(con).close();
verifyNoMoreInteractions(con);
}
@@ -111,11 +111,11 @@ public class SingleConnectionFactoryTests {
SingleConnectionFactory scf = new SingleConnectionFactory(cf);
Connection con1 = scf.createConnection();
con1.start();
con1.close(); // should be ignored
Connection con2 = scf.createConnection();
con1.start();
con2.start();
con2.close(); // should be ignored
con1.close();
con2.close();
scf.destroy(); // should trigger actual close
verify(con).start();
@@ -133,11 +133,11 @@ public class SingleConnectionFactoryTests {
SingleConnectionFactory scf = new SingleConnectionFactory(cf);
Connection con1 = scf.createConnection();
con1.start();
con1.close(); // should be ignored
Connection con2 = scf.createConnection();
con1.start();
con2.start();
con2.close(); // should be ignored
con1.close();
con2.close();
scf.destroy(); // should trigger actual close
verify(con).start();
@@ -155,11 +155,11 @@ public class SingleConnectionFactoryTests {
SingleConnectionFactory scf = new SingleConnectionFactory(cf);
Connection con1 = scf.createQueueConnection();
con1.start();
con1.close(); // should be ignored
Connection con2 = scf.createQueueConnection();
con1.start();
con2.start();
con2.close(); // should be ignored
con1.close();
con2.close();
scf.destroy(); // should trigger actual close
verify(con).start();
@@ -177,11 +177,11 @@ public class SingleConnectionFactoryTests {
SingleConnectionFactory scf = new SingleConnectionFactory(cf);
Connection con1 = scf.createConnection();
con1.start();
con1.close(); // should be ignored
Connection con2 = scf.createConnection();
con1.start();
con2.start();
con2.close(); // should be ignored
con1.close();
con2.close();
scf.destroy(); // should trigger actual close
verify(con).start();
@@ -199,11 +199,11 @@ public class SingleConnectionFactoryTests {
SingleConnectionFactory scf = new SingleConnectionFactory(cf);
Connection con1 = scf.createTopicConnection();
con1.start();
con1.close(); // should be ignored
Connection con2 = scf.createTopicConnection();
con1.start();
con2.start();
con2.close(); // should be ignored
con1.close();
con2.close();
scf.destroy(); // should trigger actual close
verify(con).start();
@@ -212,21 +212,52 @@ public class SingleConnectionFactoryTests {
verifyNoMoreInteractions(con);
}
@Test
public void testWithConnectionAggregatedStartStop() throws JMSException {
Connection con = mock(Connection.class);
SingleConnectionFactory scf = new SingleConnectionFactory(con);
Connection con1 = scf.createConnection();
con1.start();
verify(con).start();
con1.stop();
verify(con).stop();
Connection con2 = scf.createConnection();
con2.start();
verify(con, times(2)).start();
con2.stop();
verify(con, times(2)).stop();
con2.start();
verify(con, times(3)).start();
con1.start();
con2.stop();
con1.stop();
verify(con, times(3)).stop();
con1.start();
verify(con, times(4)).start();
con1.close();
verify(con, times(4)).stop();
con2.close();
scf.destroy();
verify(con).close();
verifyNoMoreInteractions(con);
}
@Test
public void testWithConnectionFactoryAndClientId() throws JMSException {
ConnectionFactory cf = mock(ConnectionFactory.class);
Connection con = mock(Connection.class);
given(cf.createConnection()).willReturn(con);
SingleConnectionFactory scf = new SingleConnectionFactory(cf);
scf.setClientId("myId");
Connection con1 = scf.createConnection();
con1.start();
con1.close(); // should be ignored
Connection con2 = scf.createConnection();
con1.start();
con2.start();
con2.close(); // should be ignored
con1.close();
con2.close();
scf.destroy(); // should trigger actual close
verify(con).setClientID("myId");
@@ -250,17 +281,17 @@ public class SingleConnectionFactoryTests {
Connection con1 = scf.createConnection();
assertEquals(listener, con1.getExceptionListener());
con1.start();
con1.stop(); // should be ignored
con1.close(); // should be ignored
con1.stop();
con1.close();
Connection con2 = scf.createConnection();
con2.start();
con2.stop(); // should be ignored
con2.close(); // should be ignored
con2.stop();
con2.close();
scf.destroy(); // should trigger actual close
verify(con).setExceptionListener(listener);
verify(con).start();
verify(con).stop();
verify(con, times(2)).start();
verify(con, times(2)).stop();
verify(con).close();
}
@@ -268,7 +299,6 @@ public class SingleConnectionFactoryTests {
public void testWithConnectionFactoryAndReconnectOnException() throws JMSException {
ConnectionFactory cf = mock(ConnectionFactory.class);
TestConnection con = new TestConnection();
given(cf.createConnection()).willReturn(con);
SingleConnectionFactory scf = new SingleConnectionFactory(cf);
@@ -289,7 +319,6 @@ public class SingleConnectionFactoryTests {
public void testWithConnectionFactoryAndExceptionListenerAndReconnectOnException() throws JMSException {
ConnectionFactory cf = mock(ConnectionFactory.class);
TestConnection con = new TestConnection();
given(cf.createConnection()).willReturn(con);
TestExceptionListener listener = new TestExceptionListener();
@@ -309,6 +338,78 @@ public class SingleConnectionFactoryTests {
assertEquals(1, listener.getCount());
}
@Test
public void testWithConnectionFactoryAndLocalExceptionListenerWithCleanup() throws JMSException {
ConnectionFactory cf = mock(ConnectionFactory.class);
TestConnection con = new TestConnection();
given(cf.createConnection()).willReturn(con);
TestExceptionListener listener0 = new TestExceptionListener();
TestExceptionListener listener1 = new TestExceptionListener();
TestExceptionListener listener2 = new TestExceptionListener();
SingleConnectionFactory scf = new SingleConnectionFactory(cf) {
@Override
public void onException(JMSException ex) {
// no-op
}
};
scf.setReconnectOnException(true);
scf.setExceptionListener(listener0);
Connection con1 = scf.createConnection();
con1.setExceptionListener(listener1);
assertSame(listener1, con1.getExceptionListener());
Connection con2 = scf.createConnection();
con2.setExceptionListener(listener2);
assertSame(listener2, con2.getExceptionListener());
con.getExceptionListener().onException(new JMSException(""));
con2.close();
con.getExceptionListener().onException(new JMSException(""));
con1.close();
con.getExceptionListener().onException(new JMSException(""));
scf.destroy(); // should trigger actual close
assertEquals(0, con.getStartCount());
assertEquals(1, con.getCloseCount());
assertEquals(3, listener0.getCount());
assertEquals(2, listener1.getCount());
assertEquals(1, listener2.getCount());
}
@Test
public void testWithConnectionFactoryAndLocalExceptionListenerWithReconnect() throws JMSException {
ConnectionFactory cf = mock(ConnectionFactory.class);
TestConnection con = new TestConnection();
given(cf.createConnection()).willReturn(con);
TestExceptionListener listener0 = new TestExceptionListener();
TestExceptionListener listener1 = new TestExceptionListener();
TestExceptionListener listener2 = new TestExceptionListener();
SingleConnectionFactory scf = new SingleConnectionFactory(cf);
scf.setReconnectOnException(true);
scf.setExceptionListener(listener0);
Connection con1 = scf.createConnection();
con1.setExceptionListener(listener1);
assertSame(listener1, con1.getExceptionListener());
con1.start();
Connection con2 = scf.createConnection();
con2.setExceptionListener(listener2);
assertSame(listener2, con2.getExceptionListener());
con.getExceptionListener().onException(new JMSException(""));
con2.close();
con1.getMetaData();
con.getExceptionListener().onException(new JMSException(""));
con1.close();
scf.destroy(); // should trigger actual close
assertEquals(2, con.getStartCount());
assertEquals(2, con.getCloseCount());
assertEquals(2, listener0.getCount());
assertEquals(2, listener1.getCount());
assertEquals(1, listener2.getCount());
}
@Test
public void testCachingConnectionFactory() throws JMSException {
ConnectionFactory cf = mock(ConnectionFactory.class);
@@ -328,17 +429,17 @@ public class SingleConnectionFactoryTests {
session1.getTransacted();
session1.close(); // should lead to rollback
session1 = con1.createSession(false, Session.CLIENT_ACKNOWLEDGE);
session1.close(); // should be ignored
session1.close();
con1.start();
con1.close(); // should be ignored
Connection con2 = scf.createConnection();
Session session2 = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
session2.close(); // should be ignored
session2.close();
session2 = con2.createSession(true, Session.AUTO_ACKNOWLEDGE);
session2.commit();
session2.close(); // should be ignored
session2.close();
con2.start();
con2.close(); // should be ignored
con1.close();
con2.close();
scf.destroy(); // should trigger actual close
verify(txSession).commit();
@@ -366,19 +467,19 @@ public class SingleConnectionFactoryTests {
Connection con1 = scf.createQueueConnection();
Session session1 = con1.createSession(true, Session.AUTO_ACKNOWLEDGE);
session1.rollback();
session1.close(); // should be ignored
session1.close();
session1 = con1.createSession(false, Session.CLIENT_ACKNOWLEDGE);
session1.close(); // should be ignored
session1.close();
con1.start();
con1.close(); // should be ignored
QueueConnection con2 = scf.createQueueConnection();
Session session2 = con2.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
session2.close(); // should be ignored
session2.close();
session2 = con2.createSession(true, Session.AUTO_ACKNOWLEDGE);
session2.getTransacted();
session2.close(); // should lead to rollback
con2.start();
con2.close(); // should be ignored
con1.close();
con2.close();
scf.destroy(); // should trigger actual close
verify(txSession).rollback();
@@ -408,17 +509,17 @@ public class SingleConnectionFactoryTests {
session1.getTransacted();
session1.close(); // should lead to rollback
session1 = con1.createSession(false, Session.CLIENT_ACKNOWLEDGE);
session1.close(); // should be ignored
session1.close();
con1.start();
con1.close(); // should be ignored
TopicConnection con2 = scf.createTopicConnection();
Session session2 = con2.createTopicSession(false, Session.CLIENT_ACKNOWLEDGE);
session2.close(); // should be ignored
session2.close();
session2 = con2.createSession(true, Session.AUTO_ACKNOWLEDGE);
session2.getTransacted();
session2.close(); // should be ignored
session2.close();
con2.start();
con2.close(); // should be ignored
con1.close();
con2.close();
scf.destroy(); // should trigger actual close
verify(txSession).close();