ConnectionState connState = (ConnectionState)getParent();
ResourceManager rm = connState.getResourceManager();
List ackInfos = Collections.EMPTY_LIST;
ClientSessionDelegate newDelegate = (ClientSessionDelegate)newState.getDelegate();
rm.failoverLock.lock();
try
{
//this guard aginst new ack info coming in the list. it should be before the ClientConsumer.synchronizedWith()
//otherwise the message can be added to buffer after buffer cleared and added to acklist.
//JBMESSAGING-1878
synchronized (ackLock)
{
ackSource = ((ConnectionState)newState.getParent()).getRemotingConnection().getCallbackManager();
}
for (Iterator i = getChildren().iterator(); i.hasNext(); )
{
HierarchicalState child = (HierarchicalState)i.next();
if (child instanceof ConsumerState)
{
ConsumerState consState = (ConsumerState)child;
ClientConsumerDelegate consDelegate = (ClientConsumerDelegate)consState.getDelegate();
// create a new consumer over the new session for each consumer on the old session
ClientConsumerDelegate newConsDelegate = (ClientConsumerDelegate)newDelegate.
createConsumerDelegate((JBossDestination)consState.getDestination(),
consState.getSelector(),
consState.isNoLocal(),
consState.getSubscriptionName(),
consState.isConnectionConsumer(), true);
log.trace(this + " created new consumer " + newConsDelegate);
consDelegate.synchronizeWith(newConsDelegate);
log.trace(this + " synchronized failover consumer " + consDelegate);
}
else if (child instanceof ProducerState)
{
ProducerState prodState = (ProducerState)child;
ClientProducerDelegate prodDelegate = (ClientProducerDelegate)prodState.getDelegate();
// create a new producer over the new session for each producer on the old session
ClientProducerDelegate newProdDelegate = (ClientProducerDelegate)newDelegate.
createProducerDelegate((JBossDestination)prodState.getDestination());
log.trace(this + " created new producer " + newProdDelegate);
prodDelegate.synchronizeWith(newProdDelegate);
log.trace(this + " synchronized failover producer " + prodDelegate);
}
else if (child instanceof BrowserState)
{
BrowserState browserState = (BrowserState)child;
ClientBrowserDelegate browserDelegate =
(ClientBrowserDelegate)browserState.getDelegate();
// create a new browser over the new session for each browser on the old session
ClientBrowserDelegate newBrowserDelegate = (ClientBrowserDelegate)newDelegate.
createBrowserDelegate(browserState.getJmsDestination(),
browserState.getMessageSelector());
log.trace(this + " created new browser " + newBrowserDelegate);
browserDelegate.synchronizeWith(newBrowserDelegate);
log.trace(this + " synchronized failover browser " + browserDelegate);
}
}
// We need to failover from one session ID to another in the resource manager
rm.handleFailover(connState.getServerID(), oldSessionID, newState.sessionID);
if (isCC)
{
log.trace(this + " is a connection consumer. Load ack info from rm first.");
//https://issues.jboss.org/browse/JBMESSAGING-1889
//for a connection consumer session, we need to treat the ackInfos specially.
ackInfos = rm.getDeliveriesForSession(getSessionID());
}
if (ackInfos.size() == 0)
{
if (!isTransacted() || (isXA() && getCurrentTxId() == null))
{
// TODO - the check "(isXA() && getCurrentTxId() == null)" shouldn't be necessary any more
// since xa sessions no longer fall back to non transacted
// Non transacted session or an XA session with no transaction set (it falls back
// to AUTO_ACKNOWLEDGE)
log.trace(this + " is not transacted (or XA with no transaction set), " +
"retrieving deliveries from session state");
// We remove any unacked non-persistent messages - this is because we don't want to ack
// them since the server won't know about them and will get confused
if (acknowledgeMode == Session.CLIENT_ACKNOWLEDGE)
{
for (Iterator i = getClientAckList().iterator(); i.hasNext();)
{
DeliveryInfo info = (DeliveryInfo)i.next();
if (!info.getMessageProxy().getMessage().isReliable())
{
i.remove();
ackMap.remove(info.getMessageProxy().getMessage().getMessageID());
log.trace("removed non persistent delivery " + info);
}
}
ackInfos = getClientAckList();
}
else
{
DeliveryInfo autoAck = getAutoAckInfo();
if (autoAck != null)
{
if (!autoAck.getMessageProxy().getMessage().isReliable())
{
// unreliable, discard
setAutoAckInfo(null);
}
else
{
// reliable
ackInfos = new ArrayList();
ackInfos.add(autoAck);
}
}
}
log.trace(this + " retrieved " + ackInfos.size() + " deliveries");
}
else
{
// Transacted session - we need to get the acks from the resource manager. BTW we have
// kept the old resource manager.
ackInfos = rm.getDeliveriesForSession(getSessionID());
}
}
}
finally
{
while (rm.failoverLock.isHeldByCurrentThread())
{
rm.failoverLock.unlock();
}
}
List recoveryInfos = new ArrayList();
if (!ackInfos.isEmpty())
{
for (Iterator i = ackInfos.iterator(); i.hasNext(); )
{
DeliveryInfo del = (DeliveryInfo)i.next();
DeliveryRecovery recInfo =
new DeliveryRecovery(del.getMessageProxy().getDeliveryId(),
del.getMessageProxy().getMessage().getMessageID(),
del.getQueueName());
recoveryInfos.add(recInfo);
}
}
log.trace(this + " sending delivery recovery " + recoveryInfos + " on failover");
//Note we only recover sessions that are transacted or client ack
if (transacted || xa || acknowledgeMode == Session.CLIENT_ACKNOWLEDGE)
{
//Note! We ALWAYS call recoverDeliveries even if there are no deliveries since it also does other stuff
//like remove from recovery Area refs corresponding to messages in client consumer buffers
newDelegate.recoverDeliveries(recoveryInfos, oldSessionID);
}
}