public Object handleClosing(Invocation invocation) throws Throwable
{
MethodInvocation mi = (MethodInvocation)invocation;
SessionState state = getState(invocation);
SessionDelegate del = (SessionDelegate)mi.getTargetObject();
if (trace) { log.trace("handleClosing()"); }
//Sanity check
if (state.isXA())
{
if (trace) { log.trace("Session is XA"); }
ConnectionState connState = (ConnectionState)state.getParent();
ResourceManager rm = connState.getResourceManager();
// An XASession should never be closed if there is prepared ack work that has not yet been
// committed or rolled back. Imagine if messages had been consumed in the session, and
// prepared but not committed. Then the connection was explicitly closed causing the
// session to close. Closing the session causes any outstanding delivered but unacked
// messages to be cancelled to the server which means they would be available for other
// consumers to consume. If another consumer then consumes them, then recover() is called
// and the original transaction is committed, then this means the same message has been
// delivered twice which breaks the once and only once delivery guarantee.
if (rm.checkForAcksInSession(state.getSessionID()))
{
throw new IllegalStateException(
"Attempt to close an XASession when there are still uncommitted acknowledgements!");
}
}
int ackMode = state.getAcknowledgeMode();
//We need to either ack (for auto_ack) or cancel (for client_ack)
//any deliveries - this is because the message listener might have closed
//before on message had finished executing
if (ackMode == Session.AUTO_ACKNOWLEDGE)
{
//Acknowledge or cancel any outstanding auto ack
DeliveryInfo remainingAutoAck = state.getAutoAckInfo();
if (remainingAutoAck != null)
{
if (trace) { log.trace(this + " handleClosing(). Found remaining auto ack. Will ack " + remainingAutoAck); }
try
{
ackDelivery(del, remainingAutoAck);
if (trace) { log.trace(this + " acked it"); }
}
finally
{
state.setAutoAckInfo(null);
}
}
}
else if (ackMode == Session.DUPS_OK_ACKNOWLEDGE)
{
//Ack any remaining deliveries
if (!state.getClientAckList().isEmpty())
{
try
{
del.acknowledgeDeliveries(state.getClientAckList());
}
finally
{
state.getClientAckList().clear();