/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the license at
* https://glassfish.dev.java.net/public/CDDLv1.0.html or
* glassfish/bootstrap/legal/CDDLv1.0.txt.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at glassfish/bootstrap/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* you own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*/
package com.ericsson.ssa.sip;
import com.ericsson.ssa.container.SipContainerThreadPool;
import com.ericsson.ssa.container.reporter.Reporter;
import com.ericsson.ssa.container.sim.ApplicationDispatcher;
import com.ericsson.ssa.sip.persistence.ReplicationUnitOfWork;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jvnet.glassfish.comms.util.LogUtil;
/**
* re-INVITE requests are sent in an existing dialogs, i.e. where the end points with to-tags has been
* established. For a proxy to be able to handle CANCELS of re-INVITE requests information in the the
* original reinvite request and matching provisional responses must be saved. This class handles saving
* such information and gives the client code the ability to create a proper CANCEL request.
*
*
*
* @author Magnus Hessel, HiQ Stockholm AB
* @since 2008 apr 30
*
*/
public class ReinviteProxyTracer {
/**
* reINVITE request object to create cancel request from.
*/
SipServletRequestImpl reinviteRequest;
private static final Logger _log = LogUtil.SIP_LOGGER.getLogger();
/**
* last registered provisional response to take CANCEL Via from.
*/
SipServletResponseImpl lastProvisionalResponse;
/**
* Whether there is a pending CANCEL waiting to be sent.
* CANCEL is not allowed to be send until the first provisional
* response is received.
*/
private boolean pendingCancel = false;
/**
* Creation. Is typically called when receiving a reINVITE.
*
*
* @param reinviteRequest
*/
public ReinviteProxyTracer(SipServletRequestImpl reinviteRequest) {
this.reinviteRequest = reinviteRequest;
}
/**
* Registration of a received provisional response for a reINVITE.
*
* @param response
*/
public void registerProvisionalResponse(SipServletResponseImpl response) {
// Only interested in the last one.
this.lastProvisionalResponse = response;
if (pendingCancel) {
final SipServletRequestImpl cancel = createCancel();
cancel.pushTransactionDispatcher(lastProvisionalResponse.getRequestImpl().getProxyContext());
Reporter reporter = ApplicationDispatcher.getInstance().getServletReporters();
if (reporter != null) {
String interceptedAt = cancel.getApplicationSessionImpl().getApplicationName() + "/" + cancel.getSessionImpl().getHandler();
reporter.logOutgoingRequest(Reporter.InterceptionType.SERVLET, cancel, interceptedAt);
}
SipContainerThreadPool.getInstance().execute(new Callable() {
// execute in another thread...
public Object call() throws Exception {
DialogFragment dialog = cancel.getDialog();
if (dialog != null) {
dialog.getDialogLifeCycle().setThreadLocalUnitOfWork();
try {
cancel.popDispatcher().dispatch(cancel);
} finally {
ReplicationUnitOfWork.clearThreadLocal();
}
} else {
if (_log.isLoggable(Level.INFO)) {
_log.log(Level.INFO, "can not send message {0} since the dialog is null", new Object[]{cancel});
}
}
return null;
}
});
}
// Ensurte the cancel is only sent once.
pendingCancel = false;
}
/**
* Creation of a cancel based on information in this object.
*
* @return
*/
private SipServletRequestImpl createCancel() {
SipServletRequestImpl cancel = reinviteRequest.createCancelImpl();
// add saved top via from provisional response...
if (lastProvisionalResponse != null) {
if (lastProvisionalResponse.getCancelVia() != null) {
cancel.setHeader(lastProvisionalResponse.getCancelVia());
}
} else {
// Haven't received any provisional responses
// Since this is re-INVITE there is no need to wait
// for a provisional response. We already have a established
// dialog
// Use the Via from the INVITE request
cancel.setHeader(reinviteRequest.getRawHeader(Header.VIA));
}
return cancel;
}
/**
* Instruction to cancel the reINVITE.
*
* If no provisional response has been received yet, the sending of a CANCEL
* is postponed.
*
* @param incomingCancel
*/
public void cancel(SipServletRequestImpl incomingCancel) {
if (lastProvisionalResponse != null) {
SipServletRequestImpl cancel = createCancel();
cancel._transactionStack.addAll(incomingCancel._transactionStack);
cancel.popDispatcher().dispatch(cancel);
} else {
pendingCancel = true;
}
}
}