log.debug("failure detected by " + source);
// generate a FAILURE_DETECTED event
broadcastFailoverEvent(new FailoverEvent(FailoverEvent.FAILURE_DETECTED, source));
CreateConnectionResult res = null;
boolean failoverSuccessful = false;
boolean valveOpened = false;
try
{
// block any other invocations ariving to any delegate from the hierarchy while we're
// doing failover
valve.close();
synchronized(this)
{
// testing for failed connection and setting the failed flag need to be done in one
// atomic operation, otherwise multiple threads can get to perform the client-side
// failover concurrently
if (remotingConnection.isFailed())
{
log.debug(this + " ignoring failure detection notification, as failover was " +
"already (or is in process of being) performed on this connection");
return;
}
remotingConnection.setFailed();
}
// Note - failover doesn't occur until _after_ the above check - so the next comment
// belongs here
log.debug(this + " starting client-side failover");
// generate a FAILOVER_STARTED event. The event must be broadcasted AFTER valve closure,
// to insure the client-side stack is in a deterministic state
broadcastFailoverEvent(new FailoverEvent(FailoverEvent.FAILOVER_STARTED, this));
int failedNodeID = state.getServerID();
ConnectionFactoryDelegate clusteredDelegate =
state.getClusteredConnectionFactoryDelegate();
// re-try creating the connection
res = clusteredDelegate.
createConnectionDelegate(state.getUsername(), state.getPassword(), failedNodeID);
if (res == null)
{
// No failover attempt was detected on the server side; this might happen if the
// client side network fails temporarily so the client connection breaks but the
// server cluster is still up and running - in this case we don't perform failover.
failoverSuccessful = false;
}
else
{
// recursively synchronize state
ClientConnectionDelegate newDelegate = (ClientConnectionDelegate)res.getDelegate();
state.getDelegate().synchronizeWith(newDelegate);
valve.open();
valveOpened = true;