Issue #1642: Fix QPID Deadlock scenario

- Address peer review comments

Change-Id: I3c52fd57f762a762d54fdce3651c7f17a8fc6462

Former-commit-id: 2071d4f3cc54a3da43443bc71cecf038736194d8
This commit is contained in:
Richard Peter 2013-02-25 17:44:18 -06:00
parent 9cf3ca07b7
commit 9a0177861f
10 changed files with 307 additions and 331 deletions

View file

@ -35,7 +35,16 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.status.UFStatus.Priority;
/** /**
* TODO Add Description * Jms Pooled Connection. Tracks references to the connection to know when the
* connection can be released to the pool. Any exception will close pooled
* session instead of returning to the pool. The sessions are tracked in both
* active and available states. An available session can be reused by the next
* client.
*
* Synchronization Principle To prevent deadlocks: Chained sync blocks can only
* happen in a downward direction. A manager has a synchronized lock can make a
* call down to a wrapper, but not nice versa. Also a session inside a sync
* block can make a call down to a producer but not vice versa.
* *
* <pre> * <pre>
* *
@ -45,7 +54,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Apr 15, 2011 rjpeter Initial creation * Apr 15, 2011 rjpeter Initial creation
* Mar 08, 2012 194 njensen Improved safety of close() * Mar 08, 2012 194 njensen Improved safety of close()
* * Feb 21, 2013 1642 rjpeter Fix deadlock scenario
* </pre> * </pre>
* *
* @author rjpeter * @author rjpeter
@ -57,35 +66,33 @@ public class JmsPooledConnection implements ExceptionListener {
private final IUFStatusHandler statusHandler = UFStatus private final IUFStatusHandler statusHandler = UFStatus
.getHandler(JmsPooledConnection.class); .getHandler(JmsPooledConnection.class);
private JmsPooledConnectionFactory connFactory = null; private final JmsPooledConnectionFactory connFactory;
private Connection conn = null; private volatile Connection conn = null;
// keeps track of number of creates vs. closes to know when it can be // keeps track of number of creates vs. closes to know when it can be
// returned to the pool // returned to the pool
List<JmsConnectionWrapper> references = new ArrayList<JmsConnectionWrapper>( private final List<JmsConnectionWrapper> references = new ArrayList<JmsConnectionWrapper>(
1); 1);
private Object stateLock = new Object(); private final Object stateLock = new Object();
private State state = State.InUse; private volatile State state = State.InUse;
// technically can have multiple sessions to one connection and sessions can // technically can have multiple sessions to one connection and sessions can
// differ by transaction mode and acknowledgement mode, currently not // differ by transaction mode and acknowledgement mode, currently not
// supported // supported
private JmsPooledSession session = null; private volatile JmsPooledSession session = null;
private AvailableJmsPooledObject<JmsPooledSession> availableSession = null; private volatile AvailableJmsPooledObject<JmsPooledSession> availableSession = null;
private String key = null; private volatile String key = null;
private String clientId = null; private final String clientId;
private long connectionStartTime = 0; private volatile long connectionStartTime = 0;
private boolean exceptionOccurred = false; private volatile boolean exceptionOccurred = false;
private Throwable trappedExc;
public JmsPooledConnection(JmsPooledConnectionFactory connFactory) { public JmsPooledConnection(JmsPooledConnectionFactory connFactory) {
this.connFactory = connFactory; this.connFactory = connFactory;
@ -101,7 +108,7 @@ public class JmsPooledConnection implements ExceptionListener {
throw new IllegalStateException("Connection is closed"); throw new IllegalStateException("Connection is closed");
} }
synchronized (this) { synchronized (stateLock) {
// TODO: Add multiple session support // TODO: Add multiple session support
if (session != null) { if (session != null) {
JmsSessionWrapper ref = session.createReference(); JmsSessionWrapper ref = session.createReference();
@ -112,6 +119,7 @@ public class JmsPooledConnection implements ExceptionListener {
this.session = null; this.session = null;
} }
} }
if (availableSession != null) { if (availableSession != null) {
JmsPooledSession availSess = availableSession.getPooledObject(); JmsPooledSession availSess = availableSession.getPooledObject();
synchronized (availSess.getStateLock()) { synchronized (availSess.getStateLock()) {
@ -130,6 +138,7 @@ public class JmsPooledConnection implements ExceptionListener {
transacted, acknowledgeMode)); transacted, acknowledgeMode));
} }
} }
return session.createReference(); return session.createReference();
} }
@ -160,29 +169,22 @@ public class JmsPooledConnection implements ExceptionListener {
public void onException(JMSException jmsExc) { public void onException(JMSException jmsExc) {
// need to worry about multiple exceptions causing repeated // need to worry about multiple exceptions causing repeated
// disconnect/reconnect // disconnect/reconnect
statusHandler.handle(Priority.INFO, "Caught Exception on " statusHandler.handle(Priority.WARN, "Caught Exception on "
+ connFactory.getProvider() + connFactory.getProvider()
+ " connection. Closing connection", jmsExc); + " connection. Closing connection", jmsExc);
close(); close();
} }
public void close() { public void close() {
// synchronize on the connection to avoid deadlock conditions in qpid
boolean canClose = false; boolean canClose = false;
synchronized (stateLock) { synchronized (stateLock) {
if (!State.Closed.equals(state)) { if (!State.Closed.equals(state)) {
canClose = true; canClose = true;
state = State.Closed; state = State.Closed;
if (trappedExc != null) {
statusHandler.handle(Priority.INFO,
"Trapped internal exception", trappedExc);
}
} }
} }
if (canClose) { if (canClose) {
synchronized (this) {
// njensen: I moved removing the connection from the pool to be // njensen: I moved removing the connection from the pool to be
// the first thing in this block instead of last thing so // the first thing in this block instead of last thing so
// there's no chance it could be closed and then retrieved from // there's no chance it could be closed and then retrieved from
@ -192,14 +194,14 @@ public class JmsPooledConnection implements ExceptionListener {
try { try {
conn.stop(); conn.stop();
} catch (Exception e) { } catch (Exception e) {
statusHandler.handle(Priority.INFO, statusHandler.handle(Priority.WARN,
"Failed to stop connection", e); "Failed to stop connection", e);
} }
} }
synchronized (references) { synchronized (references) {
for (JmsConnectionWrapper wrapper : references) { for (JmsConnectionWrapper wrapper : references) {
wrapper.closeInternal(); wrapper.closeWrapper();
} }
references.clear(); references.clear();
} }
@ -209,16 +211,20 @@ public class JmsPooledConnection implements ExceptionListener {
session = null; session = null;
} }
if (availableSession != null) {
availableSession.getPooledObject().close();
availableSession = null;
}
try { try {
conn.close(); conn.close();
} catch (Exception e) { } catch (Exception e) {
statusHandler.handle(Priority.INFO, statusHandler.handle(Priority.WARN,
"Failed to close connection " + conn, e); "Failed to close connection " + conn, e);
} }
} }
conn = null; conn = null;
} }
}
/** /**
* Closing all resources that have been idle in the pool for more than * Closing all resources that have been idle in the pool for more than
@ -228,8 +234,13 @@ public class JmsPooledConnection implements ExceptionListener {
* @return * @return
*/ */
public int closeOldPooledResources(int resourceRetention) { public int closeOldPooledResources(int resourceRetention) {
if (!isValid()) {
return 0;
}
int count = 0; int count = 0;
JmsPooledSession sessionToCheck = null; JmsPooledSession sessionToCheck = null;
synchronized (stateLock) { synchronized (stateLock) {
if (session != null) { if (session != null) {
sessionToCheck = session; sessionToCheck = session;
@ -265,8 +276,12 @@ public class JmsPooledConnection implements ExceptionListener {
} }
public Connection getConnection() { public Connection getConnection() {
// lazy initialized so that we can handle reconnect and logging since
// spring reconnect doesn't give any status information and appears to
// the user that the process is hung
if (conn == null) { if (conn == null) {
synchronized (this) { // safe since conn is volatile
synchronized (stateLock) {
if (conn == null) { if (conn == null) {
long exceptionLastHandled = 0; long exceptionLastHandled = 0;
boolean connected = false; boolean connected = false;
@ -345,12 +360,12 @@ public class JmsPooledConnection implements ExceptionListener {
if (!valid) { if (!valid) {
removeSession(sess); removeSession(sess);
} else { } else {
synchronized (this) { synchronized (stateLock) {
// should only be able to have 1 session // should only be able to have 1 session
if (availableSession != null) { if (availableSession != null) {
availableSession.getPooledObject().close();
statusHandler statusHandler
.warn("Pooled session already existed for this connection, closing previous session"); .warn("Pooled session already existed for this connection, closing previous session");
availableSession.getPooledObject().close();
} }
availableSession = new AvailableJmsPooledObject<JmsPooledSession>( availableSession = new AvailableJmsPooledObject<JmsPooledSession>(
session); session);
@ -361,13 +376,19 @@ public class JmsPooledConnection implements ExceptionListener {
return valid; return valid;
} }
/**
* Removes this pooled session from the pooled connection. Does NOT close
* the session, this should be handled independently.
*
* @param sess
*/
public void removeSession(JmsPooledSession sess) { public void removeSession(JmsPooledSession sess) {
synchronized (this) { synchronized (stateLock) {
if (sess != null) { if (sess != null) {
if (this.session == sess) { if (this.session == sess) {
this.session = null; this.session = null;
} else if (availableSession != null } else if ((availableSession != null)
&& availableSession.getPooledObject() == sess) { && (availableSession.getPooledObject() == sess)) {
this.availableSession = null; this.availableSession = null;
} }
} }
@ -378,7 +399,11 @@ public class JmsPooledConnection implements ExceptionListener {
synchronized (stateLock) { synchronized (stateLock) {
if (isValid(State.InUse, true)) { if (isValid(State.InUse, true)) {
JmsConnectionWrapper wrapper = new JmsConnectionWrapper(this); JmsConnectionWrapper wrapper = new JmsConnectionWrapper(this);
synchronized (references) {
references.add(wrapper); references.add(wrapper);
}
return wrapper; return wrapper;
} }
} }
@ -433,6 +458,7 @@ public class JmsPooledConnection implements ExceptionListener {
public void removeReference(JmsConnectionWrapper wrapper) { public void removeReference(JmsConnectionWrapper wrapper) {
boolean returnToPool = false; boolean returnToPool = false;
synchronized (stateLock) { synchronized (stateLock) {
synchronized (references) {
if (references.remove(wrapper) && references.isEmpty() if (references.remove(wrapper) && references.isEmpty()
&& State.InUse.equals(state)) { && State.InUse.equals(state)) {
state = State.Available; state = State.Available;
@ -450,8 +476,10 @@ public class JmsPooledConnection implements ExceptionListener {
if (availableSession != null) { if (availableSession != null) {
JmsPooledSession availSess = availableSession JmsPooledSession availSess = availableSession
.getPooledObject(); .getPooledObject();
if (availSess != null synchronized (availSess.getStateLock()) {
&& !State.Available.equals(availSess.getState())) { if ((availSess != null)
&& !State.Available.equals(availSess
.getState())) {
statusHandler statusHandler
.warn("Connection marked available, but Session not Available. Sessions state is: " .warn("Connection marked available, but Session not Available. Sessions state is: "
+ availSess.getState()); + availSess.getState());
@ -461,6 +489,8 @@ public class JmsPooledConnection implements ExceptionListener {
} }
} }
} }
}
}
boolean valid = isValid(); boolean valid = isValid();
if (valid && returnToPool) { if (valid && returnToPool) {

View file

@ -1,6 +1,7 @@
package com.raytheon.uf.common.jms; package com.raytheon.uf.common.jms;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
@ -63,16 +64,16 @@ public class JmsPooledConnectionFactory implements ConnectionFactory {
private String provider = "QPID"; private String provider = "QPID";
// connections in use, key is "threadId-threadName" // connections in use, key is "threadId-threadName"
private Map<String, JmsPooledConnection> inUseConnections = new HashMap<String, JmsPooledConnection>(); private final Map<String, JmsPooledConnection> inUseConnections = new HashMap<String, JmsPooledConnection>();
// connections that were recently returned, key is "threadId-threadName" // connections that were recently returned, key is "threadId-threadName"
private Map<String, AvailableJmsPooledObject<JmsPooledConnection>> pendingConnections = new HashMap<String, AvailableJmsPooledObject<JmsPooledConnection>>(); private final Map<String, AvailableJmsPooledObject<JmsPooledConnection>> pendingConnections = new HashMap<String, AvailableJmsPooledObject<JmsPooledConnection>>();
// connections that have been released from pendingConnections and are // connections that have been released from pendingConnections and are
// awaiting being closed. // awaiting being closed.
private LinkedList<AvailableJmsPooledObject<JmsPooledConnection>> availableConnections = new LinkedList<AvailableJmsPooledObject<JmsPooledConnection>>(); private final Deque<AvailableJmsPooledObject<JmsPooledConnection>> availableConnections = new LinkedList<AvailableJmsPooledObject<JmsPooledConnection>>();
private ConcurrentLinkedQueue<JmsPooledConnection> deadConnections = new ConcurrentLinkedQueue<JmsPooledConnection>(); private final ConcurrentLinkedQueue<JmsPooledConnection> deadConnections = new ConcurrentLinkedQueue<JmsPooledConnection>();
private int reconnectInterval = 30000; private int reconnectInterval = 30000;
@ -350,13 +351,13 @@ public class JmsPooledConnectionFactory implements ConnectionFactory {
} }
} }
synchronized (availableConnections) {
for (AvailableJmsPooledObject<JmsPooledConnection> wrapper : connectionsToProcess) { for (AvailableJmsPooledObject<JmsPooledConnection> wrapper : connectionsToProcess) {
wrapper.reset(); wrapper.reset();
// putting to available pool // putting to available pool
JmsPooledConnection conn = wrapper.getPooledObject(); JmsPooledConnection conn = wrapper.getPooledObject();
conn.setKey(null); conn.setKey(null);
synchronized (availableConnections) {
availableConnections.add(wrapper); availableConnections.add(wrapper);
} }
} }
@ -372,10 +373,9 @@ public class JmsPooledConnectionFactory implements ConnectionFactory {
// available sessions added based on time, so oldest is front of // available sessions added based on time, so oldest is front of
// queue // queue
if (wrapper.expired(curTime, connectionHoldTime) if (wrapper.expired(curTime, connectionHoldTime)
|| availableConnections.size() > maxSpareConnections) { || (availableConnections.size() > maxSpareConnections)) {
// not immediately closing connection so that we minimize // not immediately closing connection so that we minimize
// time // time in sync block
// in sync block
deadConnections.add(wrapper.getPooledObject()); deadConnections.add(wrapper.getPooledObject());
iter.remove(); iter.remove();
} else { } else {
@ -409,15 +409,17 @@ public class JmsPooledConnectionFactory implements ConnectionFactory {
connectionsToProcess = new ArrayList<AvailableJmsPooledObject<JmsPooledConnection>>( connectionsToProcess = new ArrayList<AvailableJmsPooledObject<JmsPooledConnection>>(
pendingConnections.values()); pendingConnections.values());
} }
synchronized (availableConnections) { synchronized (availableConnections) {
connectionsToProcess.addAll(availableConnections); connectionsToProcess.addAll(availableConnections);
} }
for (AvailableJmsPooledObject<JmsPooledConnection> wrapper : connectionsToProcess) { for (AvailableJmsPooledObject<JmsPooledConnection> wrapper : connectionsToProcess) {
resourcesClosed += wrapper.getPooledObject() resourcesClosed += wrapper.getPooledObject()
.closeOldPooledResources(resourceRetention); .closeOldPooledResources(resourceRetention);
} }
if (connectionsClosed > 0 || resourcesClosed > 0) { if ((connectionsClosed > 0) || (resourcesClosed > 0)) {
statusHandler.handle( statusHandler.handle(
Priority.INFO, Priority.INFO,
"Closed unused jms pooled resources: connections closed: " "Closed unused jms pooled resources: connections closed: "

View file

@ -32,7 +32,14 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.status.UFStatus.Priority;
/** /**
* TODO Add Description * Jms Pooled Consumer. Tracks references to the consumers to know when consumer
* can be released to pool. Any exception will close pooled consumer instead of
* returning to pool.
*
* Synchronization Principle To prevent deadlocks: Chained sync blocks can only
* happen in a downward direction. A manager has a synchronized lock can make a
* call down to a wrapper, but not nice versa. Also a session inside a sync
* block can make a call down to a producer but not vice versa.
* *
* <pre> * <pre>
* *
@ -42,7 +49,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Apr 18, 2011 rjpeter Initial creation * Apr 18, 2011 rjpeter Initial creation
* Mar 08, 2012 194 njensen Improved logging * Mar 08, 2012 194 njensen Improved logging
* * Feb 26, 2013 1642 rjpeter Removed lazy initialization
* </pre> * </pre>
* *
* @author rjpeter * @author rjpeter
@ -55,34 +62,31 @@ public class JmsPooledConsumer {
private final JmsPooledSession sess; private final JmsPooledSession sess;
private final Destination destination; private final MessageConsumer consumer;
private final String messageSelector;
private MessageConsumer consumer;
private final String destKey; private final String destKey;
private boolean exceptionOccurred = false; private volatile boolean exceptionOccurred = false;
private Object stateLock = new Object(); private final Object stateLock = new Object();
private State state = State.InUse; private volatile State state = State.InUse;
/** /**
* Technically a pooled consumer should only have 1 reference at a time. * Technically a pooled consumer should only have 1 reference at a time.
* Bullet proofing in case 3rd party ever tries to get multiple consumers to * Bullet proofing in case 3rd party ever tries to get multiple consumers to
* the same destination. * the same destination.
*/ */
private List<JmsConsumerWrapper> references = new ArrayList<JmsConsumerWrapper>( private final List<JmsConsumerWrapper> references = new ArrayList<JmsConsumerWrapper>(
1); 1);
public JmsPooledConsumer(JmsPooledSession sess, String destKey, public JmsPooledConsumer(JmsPooledSession sess, String destKey,
Destination destination, String messageSelector) { Destination destination, String messageSelector)
throws JMSException {
this.sess = sess; this.sess = sess;
this.destKey = destKey; this.destKey = destKey;
this.destination = destination; consumer = sess.getSession().createConsumer(destination,
this.messageSelector = messageSelector; messageSelector);
} }
public String getDestKey() { public String getDestKey() {
@ -151,7 +155,7 @@ public class JmsPooledConsumer {
close = true; close = true;
for (JmsConsumerWrapper wrapper : references) { for (JmsConsumerWrapper wrapper : references) {
wrapper.closeInternal(); wrapper.closeWrapper();
} }
references.clear(); references.clear();
@ -159,15 +163,12 @@ public class JmsPooledConsumer {
} }
if (close) { if (close) {
if (consumer != null) {
try { try {
statusHandler.info("Closing consumer " + consumer); // njensen statusHandler.info("Closing consumer " + consumer); // njensen
consumer.close(); consumer.close();
} catch (Throwable e) { } catch (Throwable e) {
statusHandler.handle(Priority.INFO, statusHandler.handle(Priority.WARN, "Failed to close consumer "
"Failed to close consumer " + consumer, e); + consumer, e);
}
consumer = null;
} }
sess.removeConsumerFromPool(this); sess.removeConsumerFromPool(this);
@ -206,18 +207,6 @@ public class JmsPooledConsumer {
} }
public MessageConsumer getConsumer() throws JMSException { public MessageConsumer getConsumer() throws JMSException {
// TODO: allow this to automatically grab a new consumer if the current
// one fails, try up to 3 times so that we don't always drop messages on
// a single failure
if (consumer == null) {
synchronized (this) {
if (consumer == null) {
consumer = sess.getSession().createConsumer(destination,
messageSelector);
}
}
}
return consumer; return consumer;
} }

View file

@ -22,7 +22,6 @@ package com.raytheon.uf.common.jms;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.jms.Destination;
import javax.jms.JMSException; import javax.jms.JMSException;
import javax.jms.MessageProducer; import javax.jms.MessageProducer;
@ -32,8 +31,12 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.status.UFStatus.Priority;
/** /**
* Jms Pooled Producer. Tracks references to the producers to know when the
* producer can be released to the pool. Any exception will close pooled
* producer instead of returning to the pool.
*
* Synchronization Principle To prevent deadlocks: Chained sync blocks can only * Synchronization Principle To prevent deadlocks: Chained sync blocks can only
* happen in a doward direction. A manager has a synchonized lock can make a * happen in a downward direction. A manager has a synchronized lock can make a
* call down to a wrapper, but not nice versa. Also a session inside a sync * call down to a wrapper, but not nice versa. Also a session inside a sync
* block can make a call down to a producer but not vice versa. * block can make a call down to a producer but not vice versa.
* *
@ -45,7 +48,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Apr 18, 2011 rjpeter Initial creation * Apr 18, 2011 rjpeter Initial creation
* Mar 08, 2012 194 njensen Improved logging * Mar 08, 2012 194 njensen Improved logging
* * Feb 26, 2013 1642 rjpeter Removed lazy initialization
* </pre> * </pre>
* *
* @author rjpeter * @author rjpeter
@ -58,31 +61,29 @@ public class JmsPooledProducer {
private final JmsPooledSession sess; private final JmsPooledSession sess;
private final Destination destination; private final MessageProducer producer;
private MessageProducer producer;
private final String destKey; private final String destKey;
private boolean exceptionOccurred = false; private volatile boolean exceptionOccurred = false;
private Object stateLock = new Object(); private final Object stateLock = new Object();
private State state = State.InUse; private volatile State state = State.InUse;
/** /**
* Technically a pooled producer should only have 1 reference at a time. * Technically a pooled producer should only have 1 reference at a time.
* Bullet proofing in case 3rd party ever tries to get multiple producers to * Bullet proofing in case 3rd party ever tries to get multiple producers to
* the same destination. * the same destination.
*/ */
private List<JmsProducerWrapper> references = new ArrayList<JmsProducerWrapper>( private final List<JmsProducerWrapper> references = new ArrayList<JmsProducerWrapper>(
1); 1);
public JmsPooledProducer(JmsPooledSession sess, String destKey, public JmsPooledProducer(JmsPooledSession sess, String destKey,
Destination destination) { MessageProducer producer) {
this.sess = sess; this.sess = sess;
this.destKey = destKey; this.destKey = destKey;
this.destination = destination; this.producer = producer;
} }
public String getDestKey() { public String getDestKey() {
@ -151,7 +152,7 @@ public class JmsPooledProducer {
close = true; close = true;
for (JmsProducerWrapper wrapper : references) { for (JmsProducerWrapper wrapper : references) {
wrapper.closeInternal(); wrapper.closeWrapper();
} }
references.clear(); references.clear();
@ -159,15 +160,12 @@ public class JmsPooledProducer {
} }
if (close) { if (close) {
if (producer != null) {
try { try {
statusHandler.info("Closing producer " + producer); // njensen statusHandler.info("Closing producer " + producer); // njensen
producer.close(); producer.close();
} catch (Throwable e) { } catch (Throwable e) {
statusHandler.handle(Priority.INFO, statusHandler.handle(Priority.WARN, "Failed to close producer",
"Failed to close producer", e); e);
}
producer = null;
} }
sess.removeProducerFromPool(this); sess.removeProducerFromPool(this);
@ -207,17 +205,6 @@ public class JmsPooledProducer {
} }
public MessageProducer getProducer() throws JMSException { public MessageProducer getProducer() throws JMSException {
// TODO: allow this to automatically grab a new producer if the current
// one fails, try up to 3 times so that we don't always drop messages on
// a single failure
if (producer == null) {
synchronized (this) {
if (producer == null) {
producer = sess.getSession().createProducer(destination);
}
}
}
return producer; return producer;
} }

View file

@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.jms.Destination; import javax.jms.Destination;
import javax.jms.JMSException; import javax.jms.JMSException;
@ -39,7 +40,16 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.status.UFStatus.Priority;
/** /**
* TODO Add Description * Jms Pooled Session. Tracks references to the session to know when the session
* can be released to the pool. Any exception will close pooled session instead
* of returning to the pool. The consumers/producers are tracked in both active
* and available states. An available consumer/producer can be reused by the
* next client.
*
* Synchronization Principle To prevent deadlocks: Chained sync blocks can only
* happen in a downward direction. A manager has a synchronized lock can make a
* call down to a wrapper, but not nice versa. Also a session inside a sync
* block can make a call down to a producer but not vice versa.
* *
* <pre> * <pre>
* *
@ -49,7 +59,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Apr 15, 2011 rjpeter Initial creation * Apr 15, 2011 rjpeter Initial creation
* Mar 08, 2012 194 njensen Improved logging * Mar 08, 2012 194 njensen Improved logging
* * Feb 21, 2013 1642 rjpeter Fix deadlock scenario
* </pre> * </pre>
* *
* @author rjpeter * @author rjpeter
@ -65,27 +75,28 @@ public class JmsPooledSession {
private final Session sess; private final Session sess;
// The thread this session was most recently used by for tracking a pending
// session that is being reserved for a given thread.
private String threadKey; private String threadKey;
private boolean exceptionOccurred = false; private volatile boolean exceptionOccurred = false;
private Throwable trappedExc = null; private final Object stateLock = new Object();
private Object stateLock = new Object(); private volatile State state = State.InUse;
private State state = State.InUse;
// keeps track of number of creates vs. closes to know when it can be // keeps track of number of creates vs. closes to know when it can be
// returned to the pool // returned to the pool
List<JmsSessionWrapper> references = new ArrayList<JmsSessionWrapper>(1); private final List<JmsSessionWrapper> references = new ArrayList<JmsSessionWrapper>(
1);
private HashMap<String, AvailableJmsPooledObject<JmsPooledConsumer>> availableConsumers = new HashMap<String, AvailableJmsPooledObject<JmsPooledConsumer>>(); private final Map<String, AvailableJmsPooledObject<JmsPooledConsumer>> availableConsumers = new HashMap<String, AvailableJmsPooledObject<JmsPooledConsumer>>();
private HashMap<String, AvailableJmsPooledObject<JmsPooledProducer>> availableProducers = new HashMap<String, AvailableJmsPooledObject<JmsPooledProducer>>(); private final Map<String, AvailableJmsPooledObject<JmsPooledProducer>> availableProducers = new HashMap<String, AvailableJmsPooledObject<JmsPooledProducer>>();
private HashMap<String, JmsPooledConsumer> inUseConsumers = new HashMap<String, JmsPooledConsumer>(); private final Map<String, JmsPooledConsumer> inUseConsumers = new HashMap<String, JmsPooledConsumer>();
private HashMap<String, JmsPooledProducer> inUseProducers = new HashMap<String, JmsPooledProducer>(); private final Map<String, JmsPooledProducer> inUseProducers = new HashMap<String, JmsPooledProducer>();
public JmsPooledSession(JmsPooledConnection conn, Session sess) { public JmsPooledSession(JmsPooledConnection conn, Session sess) {
this.conn = conn; this.conn = conn;
@ -250,10 +261,12 @@ public class JmsPooledSession {
List<JmsPooledConsumer> consumersToClose = new ArrayList<JmsPooledConsumer>( List<JmsPooledConsumer> consumersToClose = new ArrayList<JmsPooledConsumer>(
inUseConsumers.size() + availableConsumers.size()); inUseConsumers.size() + availableConsumers.size());
synchronized (inUseConsumers) { synchronized (inUseConsumers) {
consumersToClose.addAll(inUseConsumers.values()); consumersToClose.addAll(inUseConsumers.values());
inUseConsumers.clear(); inUseConsumers.clear();
} }
synchronized (availableConsumers) { synchronized (availableConsumers) {
for (AvailableJmsPooledObject<JmsPooledConsumer> wrapper : availableConsumers for (AvailableJmsPooledObject<JmsPooledConsumer> wrapper : availableConsumers
.values()) { .values()) {
@ -288,7 +301,7 @@ public class JmsPooledSession {
// of time this is correct // of time this is correct
success = inUse == producer; success = inUse == producer;
if (!success && inUse != null) { if (!success && (inUse != null)) {
// put the bad removal back in. Done this way instead of // put the bad removal back in. Done this way instead of
// get/remove as 99% of time remove is correct, this // get/remove as 99% of time remove is correct, this
// really only here for bullet proofing code against bad // really only here for bullet proofing code against bad
@ -340,7 +353,7 @@ public class JmsPooledSession {
JmsPooledProducer inUse = inUseProducers.remove(destKey); JmsPooledProducer inUse = inUseProducers.remove(destKey);
removed = inUse == producer; removed = inUse == producer;
if (!removed && inUse != null) { if (!removed && (inUse != null)) {
// put the bad removal back in. Done this way instead of // put the bad removal back in. Done this way instead of
// get/remove as 95% of time remove is correct, this // get/remove as 95% of time remove is correct, this
// really only here for bullet proofing code against bad // really only here for bullet proofing code against bad
@ -427,7 +440,7 @@ public class JmsPooledSession {
JmsPooledConsumer inUse = inUseConsumers.remove(destKey); JmsPooledConsumer inUse = inUseConsumers.remove(destKey);
removed = inUse == consumer; removed = inUse == consumer;
if (!removed && inUse != null) { if (!removed && (inUse != null)) {
// put the bad removal back in. Done this way instead of // put the bad removal back in. Done this way instead of
// get/remove as 95% of time remove is correct, this // get/remove as 95% of time remove is correct, this
// really only here for bullet proofing code against bad // really only here for bullet proofing code against bad
@ -449,31 +462,22 @@ public class JmsPooledSession {
} }
if (canClose) { if (canClose) {
if (trappedExc != null) {
statusHandler.handle(Priority.INFO,
"Trapped internal exception", trappedExc);
}
closePooledConsumersProducers(); closePooledConsumersProducers();
// need to close down all wrappers // need to close down all wrappers
for (JmsSessionWrapper wrapper : references) { for (JmsSessionWrapper wrapper : references) {
wrapper.closeInternal(); wrapper.closeWrapper();
} }
references.clear(); references.clear();
conn.removeSession(this); conn.removeSession(this);
// synchronize on the connection to avoid deadlock conditions in
// qpid
synchronized (conn) {
try { try {
sess.close(); sess.close();
} catch (Exception e) { } catch (Exception e) {
statusHandler.handle(Priority.INFO, statusHandler.handle(Priority.WARN, "Failed to close session "
"Failed to close session " + sess, e); + sess, e);
}
} }
} }
} }
@ -603,7 +607,8 @@ public class JmsPooledSession {
} }
if (producer == null) { if (producer == null) {
producer = new JmsPooledProducer(this, destKey, destination); producer = new JmsPooledProducer(this, destKey,
sess.createProducer(destination));
} }
inUseProducers.put(destKey, producer); inUseProducers.put(destKey, producer);

View file

@ -20,7 +20,7 @@
package com.raytheon.uf.common.jms; package com.raytheon.uf.common.jms;
/** /**
* TODO Add Description * State of Jms Pooled object.
* *
* <pre> * <pre>
* *

View file

@ -36,7 +36,9 @@ import javax.jms.Topic;
import com.raytheon.uf.common.jms.JmsPooledConnection; import com.raytheon.uf.common.jms.JmsPooledConnection;
/** /**
* TODO Add Description * Wrapper class for jms connection pooling. Tracks wrapped sessions created
* from this wrapped connection to know when the connection can be returned to
* the pool.
* *
* <pre> * <pre>
* *
@ -45,7 +47,7 @@ import com.raytheon.uf.common.jms.JmsPooledConnection;
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Apr 15, 2011 rjpeter Initial creation * Apr 15, 2011 rjpeter Initial creation
* * Feb 21, 2013 1642 rjpeter Added volatile references for better concurrency handling.
* </pre> * </pre>
* *
* @author rjpeter * @author rjpeter
@ -53,18 +55,16 @@ import com.raytheon.uf.common.jms.JmsPooledConnection;
*/ */
public class JmsConnectionWrapper implements Connection { public class JmsConnectionWrapper implements Connection {
private JmsPooledConnection mgr = null; private final JmsPooledConnection mgr;
private boolean closed = false; private volatile boolean closed = false;
private boolean exceptionOccurred = false; private volatile boolean exceptionOccurred = false;
private Throwable trappedExc = null; private final List<JmsSessionWrapper> sessions = new ArrayList<JmsSessionWrapper>(
private List<JmsSessionWrapper> sessions = new ArrayList<JmsSessionWrapper>(
1); 1);
private String clientId = null; private final String clientId = null;
public JmsConnectionWrapper(JmsPooledConnection mgr) { public JmsConnectionWrapper(JmsPooledConnection mgr) {
this.mgr = mgr; this.mgr = mgr;
@ -76,22 +76,18 @@ public class JmsConnectionWrapper implements Connection {
* *
* @return True if this wrapper hasn't been closed before, false otherwise. * @return True if this wrapper hasn't been closed before, false otherwise.
*/ */
public boolean closeInternal() { public boolean closeWrapper() {
synchronized (this) { synchronized (this) {
if (!closed) { if (!closed) {
closed = true; closed = true;
if (sessions != null) {
for (JmsSessionWrapper session : sessions) { for (JmsSessionWrapper session : sessions) {
try { try {
session.close(); session.close();
} catch (JMSException e) { } catch (JMSException e) {
// closing of wrapper doesn't throw an exception
} }
} }
sessions = null;
}
if (exceptionOccurred) { if (exceptionOccurred) {
mgr.setExceptionOccurred(true); mgr.setExceptionOccurred(true);
} }
@ -109,7 +105,7 @@ public class JmsConnectionWrapper implements Connection {
*/ */
@Override @Override
public void close() throws JMSException { public void close() throws JMSException {
if (closeInternal()) { if (closeWrapper()) {
// remove this wrapper from the manager // remove this wrapper from the manager
mgr.removeReference(this); mgr.removeReference(this);
@ -169,9 +165,6 @@ public class JmsConnectionWrapper implements Connection {
JmsSessionWrapper session = mgr.getSession(transacted, JmsSessionWrapper session = mgr.getSession(transacted,
acknowledgeMode); acknowledgeMode);
if (session != null) { if (session != null) {
if (sessions == null) {
sessions = new ArrayList<JmsSessionWrapper>(1);
}
sessions.add(session); sessions.add(session);
} else { } else {
throw new IllegalStateException("Underlying session is closed"); throw new IllegalStateException("Underlying session is closed");
@ -179,7 +172,6 @@ public class JmsConnectionWrapper implements Connection {
return session; return session;
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled connection"); "Exception occurred on pooled connection");
exc.initCause(e); exc.initCause(e);
@ -220,7 +212,6 @@ public class JmsConnectionWrapper implements Connection {
return conn.getMetaData(); return conn.getMetaData();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled connection"); "Exception occurred on pooled connection");
exc.initCause(e); exc.initCause(e);

View file

@ -28,7 +28,8 @@ import javax.jms.MessageListener;
import com.raytheon.uf.common.jms.JmsPooledConsumer; import com.raytheon.uf.common.jms.JmsPooledConsumer;
/** /**
* TODO Add Description * Wrapper class for jms consumer pooling. Helps track references to the pooled
* consumer to know when the consumer can be closed.
* *
* <pre> * <pre>
* *
@ -37,7 +38,7 @@ import com.raytheon.uf.common.jms.JmsPooledConsumer;
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Apr 18, 2011 rjpeter Initial creation * Apr 18, 2011 rjpeter Initial creation
* * Feb 26, 2013 1642 rjpeter Added volatile references for better concurrency handling.
* </pre> * </pre>
* *
* @author rjpeter * @author rjpeter
@ -45,11 +46,11 @@ import com.raytheon.uf.common.jms.JmsPooledConsumer;
*/ */
public class JmsConsumerWrapper implements MessageConsumer { public class JmsConsumerWrapper implements MessageConsumer {
private JmsPooledConsumer mgr = null; private final JmsPooledConsumer mgr;
private boolean exceptionOccurred = false; private volatile boolean exceptionOccurred = false;
private boolean closed = false; private volatile boolean closed = false;
public JmsConsumerWrapper(JmsPooledConsumer mgr) { public JmsConsumerWrapper(JmsPooledConsumer mgr) {
this.mgr = mgr; this.mgr = mgr;
@ -74,21 +75,20 @@ public class JmsConsumerWrapper implements MessageConsumer {
* *
* @return True if this wrapper hasn't been closed before, false otherwise. * @return True if this wrapper hasn't been closed before, false otherwise.
*/ */
public boolean closeInternal() { public boolean closeWrapper() {
boolean close = false;
synchronized (this) { synchronized (this) {
if (!closed) { if (!closed) {
closed = true; closed = true;
close = true;
}
}
if (close && exceptionOccurred) { if (exceptionOccurred) {
mgr.setExceptionOccurred(true); mgr.setExceptionOccurred(true);
} }
return close; return true;
}
}
return false;
} }
/* /*
@ -101,7 +101,7 @@ public class JmsConsumerWrapper implements MessageConsumer {
*/ */
@Override @Override
public void close() throws JMSException { public void close() throws JMSException {
if (closeInternal()) { if (closeWrapper()) {
mgr.removeReference(this); mgr.removeReference(this);
if (exceptionOccurred) { if (exceptionOccurred) {

View file

@ -28,7 +28,8 @@ import javax.jms.MessageProducer;
import com.raytheon.uf.common.jms.JmsPooledProducer; import com.raytheon.uf.common.jms.JmsPooledProducer;
/** /**
* TODO Add Description * Wrapper class for jms producer pooling. Helps track references to the pooled
* producer to know when the producer can be closed.
* *
* <pre> * <pre>
* *
@ -36,8 +37,8 @@ import com.raytheon.uf.common.jms.JmsPooledProducer;
* *
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Dec 8, 2011 rjpeter Initial creation * Dec fi8, 2011 rjpeter Initial creation
* * Feb 26, 2013 1642 rjpeter Added volatile references for better concurrency handling.
* </pre> * </pre>
* *
* @author rjpeter * @author rjpeter
@ -45,11 +46,11 @@ import com.raytheon.uf.common.jms.JmsPooledProducer;
*/ */
public class JmsProducerWrapper implements MessageProducer { public class JmsProducerWrapper implements MessageProducer {
private JmsPooledProducer mgr = null; private final JmsPooledProducer mgr;
private boolean exceptionOccurred = false; private volatile boolean exceptionOccurred = false;
private boolean closed = false; private volatile boolean closed = false;
public JmsProducerWrapper(JmsPooledProducer mgr) { public JmsProducerWrapper(JmsPooledProducer mgr) {
this.mgr = mgr; this.mgr = mgr;
@ -61,21 +62,18 @@ public class JmsProducerWrapper implements MessageProducer {
* *
* @return True if this wrapper hasn't been closed before, false otherwise. * @return True if this wrapper hasn't been closed before, false otherwise.
*/ */
public boolean closeInternal() { public boolean closeWrapper() {
boolean close = false;
synchronized (this) { synchronized (this) {
if (!closed) { if (!closed) {
closed = true; closed = true;
close = true;
}
}
if (close && exceptionOccurred) { if (exceptionOccurred) {
mgr.setExceptionOccurred(true); mgr.setExceptionOccurred(true);
} }
}
}
return close; return false;
} }
/* /*
@ -88,7 +86,7 @@ public class JmsProducerWrapper implements MessageProducer {
*/ */
@Override @Override
public void close() throws JMSException { public void close() throws JMSException {
if (closeInternal()) { if (closeWrapper()) {
mgr.removeReference(this); mgr.removeReference(this);
if (exceptionOccurred) { if (exceptionOccurred) {

View file

@ -46,7 +46,9 @@ import javax.jms.TopicSubscriber;
import com.raytheon.uf.common.jms.JmsPooledSession; import com.raytheon.uf.common.jms.JmsPooledSession;
/** /**
* TODO Add Description * Wrapper class for jms session pooling. Tracks wrapped consumers/producers
* created from this wrapped session to know when the session can be returned to
* the pool.
* *
* <pre> * <pre>
* *
@ -55,7 +57,7 @@ import com.raytheon.uf.common.jms.JmsPooledSession;
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Nov 30, 2011 rjpeter Initial creation * Nov 30, 2011 rjpeter Initial creation
* * Feb 26, 2013 1642 rjpeter Added volatile references for better concurrency handling.
* </pre> * </pre>
* *
* @author rjpeter * @author rjpeter
@ -63,20 +65,18 @@ import com.raytheon.uf.common.jms.JmsPooledSession;
*/ */
public class JmsSessionWrapper implements Session { public class JmsSessionWrapper implements Session {
private JmsPooledSession mgr = null; private final JmsPooledSession mgr;
private boolean closed = false; private volatile boolean closed = false;
private boolean exceptionOccurred = false; private volatile boolean exceptionOccurred = false;
private Throwable trappedExc = null; private final List<JmsProducerWrapper> producers = new ArrayList<JmsProducerWrapper>(
1);;
private List<JmsProducerWrapper> producers = null; private final List<JmsConsumerWrapper> consumers = new ArrayList<JmsConsumerWrapper>(
1);
private List<JmsConsumerWrapper> consumers = null;
// TODO: needs to track the wrappers opened by this wrapped session so when
// wrapped session is closed, all underlying wrappers are closed.
public JmsSessionWrapper(JmsPooledSession mgr) { public JmsSessionWrapper(JmsPooledSession mgr) {
this.mgr = mgr; this.mgr = mgr;
} }
@ -87,11 +87,10 @@ public class JmsSessionWrapper implements Session {
* *
* @return True if this wrapper hasn't been closed before, false otherwise. * @return True if this wrapper hasn't been closed before, false otherwise.
*/ */
public boolean closeInternal() { public boolean closeWrapper() {
synchronized (this) { synchronized (this) {
if (!closed) { if (!closed) {
closed = true; closed = true;
if (consumers != null) {
for (JmsConsumerWrapper consumer : consumers) { for (JmsConsumerWrapper consumer : consumers) {
try { try {
consumer.close(); consumer.close();
@ -100,10 +99,6 @@ public class JmsSessionWrapper implements Session {
} }
} }
consumers = null;
}
if (producers != null) {
for (JmsProducerWrapper producer : producers) { for (JmsProducerWrapper producer : producers) {
try { try {
producer.close(); producer.close();
@ -112,9 +107,6 @@ public class JmsSessionWrapper implements Session {
} }
} }
producers = null;
}
if (exceptionOccurred) { if (exceptionOccurred) {
mgr.setExceptionOccurred(true); mgr.setExceptionOccurred(true);
} }
@ -132,7 +124,7 @@ public class JmsSessionWrapper implements Session {
*/ */
@Override @Override
public void close() throws JMSException { public void close() throws JMSException {
if (closeInternal()) { if (closeWrapper()) {
// remove this wrapper from the manager // remove this wrapper from the manager
mgr.removeReference(this); mgr.removeReference(this);
@ -164,7 +156,6 @@ public class JmsSessionWrapper implements Session {
sess.commit(); sess.commit();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -185,7 +176,6 @@ public class JmsSessionWrapper implements Session {
return sess.createBrowser(queue); return sess.createBrowser(queue);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -207,7 +197,6 @@ public class JmsSessionWrapper implements Session {
return sess.createBrowser(queue, messageSelector); return sess.createBrowser(queue, messageSelector);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -228,7 +217,6 @@ public class JmsSessionWrapper implements Session {
return sess.createBytesMessage(); return sess.createBytesMessage();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -256,20 +244,24 @@ public class JmsSessionWrapper implements Session {
@Override @Override
public MessageConsumer createConsumer(Destination destination, public MessageConsumer createConsumer(Destination destination,
String messageSelector) throws JMSException { String messageSelector) throws JMSException {
try {
JmsConsumerWrapper consumer = mgr.getConsumer(destination, JmsConsumerWrapper consumer = mgr.getConsumer(destination,
messageSelector); messageSelector);
if (consumer != null) { if (consumer != null) {
if (consumers == null) {
consumers = new ArrayList<JmsConsumerWrapper>(1);
}
consumers.add(consumer); consumers.add(consumer);
} else { } else {
throw new IllegalStateException("Underlying consumer is closed"); throw new IllegalStateException("Underlying consumer is closed");
} }
return consumer; return consumer;
} catch (Throwable e) {
exceptionOccurred = true;
JMSException exc = new JMSException(
"Exception occurred on pooled session");
exc.initCause(e);
throw exc;
}
} }
/* /*
@ -290,7 +282,6 @@ public class JmsSessionWrapper implements Session {
noLocal); noLocal);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -317,7 +308,6 @@ public class JmsSessionWrapper implements Session {
return sess.createDurableSubscriber(topic, name); return sess.createDurableSubscriber(topic, name);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -342,7 +332,6 @@ public class JmsSessionWrapper implements Session {
noLocal); noLocal);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -363,7 +352,6 @@ public class JmsSessionWrapper implements Session {
return sess.createMapMessage(); return sess.createMapMessage();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -384,7 +372,6 @@ public class JmsSessionWrapper implements Session {
return sess.createMessage(); return sess.createMessage();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -405,7 +392,6 @@ public class JmsSessionWrapper implements Session {
return sess.createObjectMessage(); return sess.createObjectMessage();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -427,7 +413,6 @@ public class JmsSessionWrapper implements Session {
return sess.createObjectMessage(obj); return sess.createObjectMessage(obj);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -443,19 +428,23 @@ public class JmsSessionWrapper implements Session {
@Override @Override
public MessageProducer createProducer(Destination destination) public MessageProducer createProducer(Destination destination)
throws JMSException { throws JMSException {
try {
JmsProducerWrapper producer = mgr.getProducer(destination); JmsProducerWrapper producer = mgr.getProducer(destination);
if (producer != null) { if (producer != null) {
if (producers == null) {
producers = new ArrayList<JmsProducerWrapper>(1);
}
producers.add(producer); producers.add(producer);
} else { } else {
throw new IllegalStateException("Underlying producer is closed"); throw new IllegalStateException("Underlying producer is closed");
} }
return producer; return producer;
} catch (Throwable e) {
exceptionOccurred = true;
JMSException exc = new JMSException(
"Exception occurred on pooled session");
exc.initCause(e);
throw exc;
}
} }
/* /*
@ -471,7 +460,6 @@ public class JmsSessionWrapper implements Session {
return sess.createQueue(queueName); return sess.createQueue(queueName);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -492,7 +480,6 @@ public class JmsSessionWrapper implements Session {
return sess.createStreamMessage(); return sess.createStreamMessage();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -513,7 +500,6 @@ public class JmsSessionWrapper implements Session {
return sess.createTemporaryQueue(); return sess.createTemporaryQueue();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -534,7 +520,6 @@ public class JmsSessionWrapper implements Session {
return sess.createTemporaryTopic(); return sess.createTemporaryTopic();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -555,7 +540,6 @@ public class JmsSessionWrapper implements Session {
return sess.createTextMessage(); return sess.createTextMessage();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -576,7 +560,6 @@ public class JmsSessionWrapper implements Session {
return sess.createTextMessage(text); return sess.createTextMessage(text);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -597,7 +580,6 @@ public class JmsSessionWrapper implements Session {
return sess.createTopic(topicName); return sess.createTopic(topicName);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -618,7 +600,6 @@ public class JmsSessionWrapper implements Session {
return sess.getAcknowledgeMode(); return sess.getAcknowledgeMode();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -639,7 +620,6 @@ public class JmsSessionWrapper implements Session {
return sess.getMessageListener(); return sess.getMessageListener();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -660,7 +640,6 @@ public class JmsSessionWrapper implements Session {
return sess.getTransacted(); return sess.getTransacted();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -681,7 +660,6 @@ public class JmsSessionWrapper implements Session {
sess.recover(); sess.recover();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -702,7 +680,6 @@ public class JmsSessionWrapper implements Session {
sess.rollback(); sess.rollback();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -722,7 +699,6 @@ public class JmsSessionWrapper implements Session {
sess.run(); sess.run();
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
RuntimeException exc = new RuntimeException( RuntimeException exc = new RuntimeException(
"Exception occurred on pooled session", e); "Exception occurred on pooled session", e);
throw exc; throw exc;
@ -743,7 +719,6 @@ public class JmsSessionWrapper implements Session {
sess.setMessageListener(listener); sess.setMessageListener(listener);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);
@ -764,7 +739,6 @@ public class JmsSessionWrapper implements Session {
sess.unsubscribe(name); sess.unsubscribe(name);
} catch (Throwable e) { } catch (Throwable e) {
exceptionOccurred = true; exceptionOccurred = true;
trappedExc = e;
JMSException exc = new JMSException( JMSException exc = new JMSException(
"Exception occurred on pooled session"); "Exception occurred on pooled session");
exc.initCause(e); exc.initCause(e);