public void timeout(GeneralTimer timer) {
TransactionTimer tt = (TransactionTimer) timer.getInfo();
Dispatcher d = null;
SipServletResponseImpl resp = null;
SipServletRequestImpl req = null;
switch (tt) {
case TimerA:
synchronized (this) {
if (_state == CALLING) {
// Have to dirty cast in order not to reimplement hole
// structure
long delay = ((GeneralTimerBase) timer).getDelay();
// calculate next timer*2
delay *= 2;
// schedule new timer
_timerA = _timerService.createTimer(this, delay, TimerA);
// resend the request
getRequest().restoreRetransmissionApplicationStack();
req = (SipServletRequestImpl) getRequest().clone();
}
}
if (req != null) {
// dispatch after synch block...
d = req.popDispatcher();
if (d != null) {
d.dispatch(req);
}
if (SipMonitoring.isEnabled(SipMonitoring.TRANSACTION_MANAGER)) {
updateLastAccessTimestamp();
}
}
break;
case TimerB:
if (_log.isLoggable(Level.FINE)) {
_log.log(Level.FINE, "Timer B fired - terminating()");
}
synchronized (this) {
resp = getRequest().createTerminatingResponse(408);
popVia(resp);
resp.setInternalTransportFailure(true);
terminate(false);
}
// NEW: act as if received from the network (but skip the transaction manager layer)
// better to start a new thread???
final SipServletResponseImpl respToSend = resp;
SipContainerThreadPool.getInstance().execute(new Callable() {
public Object call() throws Exception {
try {
// UOW will be set by the Replication manager
TransactionManager.getInstance().invokeNextLayer(respToSend);
} finally {
ReplicationUnitOfWork.clearThreadLocal();
}
return null;
}
});
cleanup();
break; // Time to do some GC
case TimerC:
if (_log.isLoggable(Level.FINE)) {
_log.log(Level.FINE, "Timer C fired - terminating()");
}
boolean isRequestProxied = !getRequest()
.isContactIndicated();
synchronized (this) {
if ((_state == CALLING) || (_state == PROCEEDING)) {
if (_has101To199Response && isRequestProxied && !getRequest().isNoCancel()) {
req = sendCancel();
} else {
resp = sendRequestTimeout();
terminate(false);
}
}
}
// dispatch after synch block...Only send CANCEL if proxy
// lets CANCEL this branch...
if (req != null) {
//Pending state handles the case when no final response is recived even after the CANCEL is sent.
toPending();
d = req.popDispatcher();
if (d != null) {
dispatchInUOW(d, req);
}
} else if (resp != null) {