/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, 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/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.ericsson.ssa.sip;
import com.ericsson.ssa.config.SipFactoryFacade;
import com.ericsson.ssa.sip.PathNode.Type;
import com.sun.enterprise.util.LocalStringManagerImpl;
import org.jvnet.glassfish.comms.util.LogUtil;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.sip.Address;
import javax.servlet.sip.B2buaHelper;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipFactory;
import javax.servlet.sip.SipServletMessage;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipSession;
import javax.servlet.sip.TooManyHopsException;
import javax.servlet.sip.UAMode;
import javax.servlet.sip.URI;
import javax.servlet.sip.ar.SipApplicationRoutingDirective;
import javax.servlet.sip.ar.SipApplicationRoutingRegion;
/**
* Implementation of jsr289 B2buaHelper interface.
*
* @author ehsroha
*/
public class B2buaHelperImpl implements B2buaHelper {
private static final Logger _log = LogUtil.SIP_LOGGER.getLogger();
protected static final LocalStringManagerImpl localStrings = new LocalStringManagerImpl(SipSessionImplBase.class);
private SipServletRequestImpl _originalRequest = null;
private final SipFactory _sf;
public B2buaHelperImpl(SipServletRequestImpl req) {
_sf = req.getApplicationSessionImpl().getServletDispatcher()
.getSipFactory();
if (req.isInitial()) {
_originalRequest = req;
}
}
public synchronized SipServletRequest createRequest(
SipServletRequest origRequest, boolean linkedSessions,
Map<String, List<String>> headerMap)
throws IllegalArgumentException, TooManyHopsException {
if (origRequest == null) {
throw new NullPointerException();
}
if (!origRequest.isInitial()) {
throw new IllegalStateException();
}
if (origRequest.getMaxForwards() == 0) {
throw new TooManyHopsException();
}
Map<String, List<String>> clonedHeaderMap = null;
if (headerMap != null) {
clonedHeaderMap = new HashMap<String, List<String>>(headerMap);
} else {
clonedHeaderMap = new HashMap<String, List<String>>();
}
List<String> from = null;
List<String> to = null;
List<String> contact = null;
List<String> route = null;
if (clonedHeaderMap != null) {
from = clonedHeaderMap.remove("From");
to = clonedHeaderMap.remove("To");
contact = clonedHeaderMap.remove("Contact");
route = clonedHeaderMap.remove("Route");
}
SipServletRequestImpl origRequestImpl = (SipServletRequestImpl) origRequest;
if ((clonedHeaderMap != null) && !clonedHeaderMap.isEmpty()) {
// are there any illegal system headers to add?
if (isSystemHeader(clonedHeaderMap.keySet(), origRequestImpl, true)) {
// not allowed to add system headers...
throw new IllegalArgumentException();
}
}
// time to give birth to a new request...
SipServletRequest copiedReq = null;
// need special treatment for from and to headers
// Set<String> from = headerMap != null ? headerMap.remove("From") : null;
// Set<String> to = headerMap != null ? headerMap.remove("To") : null;
SipFactoryFacade sfImpl = (SipFactoryFacade) _sf;
SipApplicationSessionImpl sappSessImpl = (SipApplicationSessionImpl) origRequest.getApplicationSession();
try {
if ((from != null) && (to != null)) {
copiedReq = sfImpl.createRequestImpl(sappSessImpl,
origRequest.getMethod(),
sfImpl.createAddress(from.iterator().next()),
sfImpl.createAddress(to.iterator().next()), false,
origRequestImpl);
} else if (from != null) {
copiedReq = sfImpl.createRequestImpl(sappSessImpl,
origRequest.getMethod(),
sfImpl.createAddress(from.iterator().next()),
origRequestImpl.getToImpl(), false, origRequestImpl);
} else if (to != null) {
copiedReq = sfImpl.createRequestImpl(sappSessImpl,
origRequest.getMethod(), origRequestImpl.getFromImpl(),
sfImpl.createAddress(to.iterator().next()), false,
origRequestImpl);
} else {
copiedReq = sfImpl.createRequestImpl(sappSessImpl,
origRequest.getMethod(), origRequestImpl.getFromImpl(),
origRequestImpl.getToImpl(), false, origRequestImpl);
}
} catch (ServletParseException e) {
throw new IllegalArgumentException(e);
}
SipServletRequestImpl copiedReqImpl = (SipServletRequestImpl) copiedReq;
// lets add non system headers
if ((clonedHeaderMap != null) && !clonedHeaderMap.isEmpty()) {
Iterator<String> names = clonedHeaderMap.keySet().iterator();
Iterator<List<String>> values = clonedHeaderMap.values().iterator();
while (names.hasNext()) {
setHeader(names.next(), values.next(), copiedReqImpl);
}
}
if (route != null) {
MultiLineHeader rHdr = new MultiLineHeader(Header.ROUTE, true);
for (String s: route) {
rHdr.setValue(s, false);
}
copiedReqImpl.setHeader(rHdr);
} else {
Header rt = origRequestImpl.getRawHeader(Header.ROUTE);
if (rt != null) {
copiedReqImpl.setHeader((Header) rt.clone());
}
}
if (contact != null) {
if (origRequest.getMethod().equals("REGISTER")) {
copiedReqImpl.setHeader("Contact", contact.iterator().next());
} else { // change only parameters and user part of the URI
try {
Address cnctAddr = new AddressImpl(contact.iterator().next());
Address contactAddr = copiedReqImpl.getAddressHeaderImpl(
"Contact");
if (contactAddr != null && !contactAddr.isWildcard()) {
((AddressImpl) contactAddr).modifyContactParameters(cnctAddr);
}
} catch (ServletParseException ex) {
if (_log.isLoggable(Level.FINE)) {
_log.log(Level.FINE,
" Exception while parsing Contact address ", ex);
}
}
}
}
if (linkedSessions) {
SipSession session1 = origRequest.getSession();
SipSession session2 = copiedReq.getSession();
if ((session1 == null) || (session2 == null)) {
throw new NullPointerException();
}
// are sessions consistent?
if ((isValidSessions((SipSessionBase) session1,
(SipSessionBase) session2) &&
(origRequest.getApplicationSession(false) != null) &&
session1.getApplicationSession()
.equals(origRequest.getApplicationSession())) == false) {
throw new IllegalArgumentException();
}
// always link requests...
if (isAlreadyLinked(origRequestImpl)) {
throw new IllegalArgumentException();
}
if (!isAlreadyLinkedToEachOther((SipSessionBase) session1,
(SipSessionBase) session2)) {
// sessions are not linked to each other...
if (!isNotLinkedToAnyone((SipSessionBase) session1,
(SipSessionBase) session2)) {
// ...but one session is linked somewhere else.
throw new IllegalArgumentException();
}
// lets link sessions.
linkSipSessions((SipSessionBase) session1,
(SipSessionBase) session2);
}
// requests are not linked, lets link them...
linkRequests(origRequestImpl, copiedReqImpl);
}
copiedReqImpl.setB2buaHelper(this);
return copiedReq;
}
public synchronized SipServletRequest createRequest(SipSession session2,
SipServletRequest origRequest, Map<String, List<String>> headerMap)
throws IllegalArgumentException {
if ((origRequest == null)) {
throw new NullPointerException();
}
if (isAlreadyLinked((SipServletRequestImpl) origRequest)) {
throw new IllegalArgumentException();
}
SipSession session1 = origRequest.getSession();
if ((session1 == null) || (session2 == null)) {
throw new NullPointerException();
}
// are sessions consistent?
if (isValidSessions((SipSessionBase) session1, (SipSessionBase) session2) &&
(origRequest.getApplicationSession(false) != null) &&
(session1.getApplicationSession()
.equals(origRequest.getApplicationSession()) == false)) {
throw new IllegalArgumentException();
}
// headerMap can only contain TO, FROM or CONTACT system headers.
if ((headerMap != null) && !headerMap.isEmpty()) {
Map<String, List<String>> clonedHeaderMap = new HashMap<String, List<String>>(headerMap);
clonedHeaderMap.remove(Header.FROM);
clonedHeaderMap.remove(Header.TO);
clonedHeaderMap.remove(Header.CONTACT);
if (!clonedHeaderMap.isEmpty()) {
// are there any illegal system headers to add?
if (isSystemHeader(clonedHeaderMap.keySet(),
(SipServletRequestImpl) origRequest, false)) {
// not allowed to add system headers other than from, to and contact...
throw new IllegalArgumentException();
}
}
}
boolean shouldLinkSessions = false;
if (!isAlreadyLinkedToEachOther((SipSessionBase) session1,
(SipSessionBase) session2)) {
// sessions are not linked to each other...
if (!isNotLinkedToAnyone((SipSessionBase) session1,
(SipSessionBase) session2)) {
// ...but one session is linked somewhere else.
throw new IllegalArgumentException();
}
// ...lets link them later.
shouldLinkSessions = true;
}
SipServletRequest newRequest = session2.createRequest(origRequest.getMethod());
// set Routing directive to CONTINUE (will also copy the stateInfo)
// only in case of initial requests (JSR289)
if (origRequest.isInitial()) {
// set implicit routing directive (will be overridden by app if it feels like it
((SipServletRequestImpl) newRequest).setInternalRoutingDirective(SipApplicationRoutingDirective.CONTINUE,
origRequest);
((SipServletRequestImpl) newRequest).setRegion(origRequest.getRegion());
}
// lets add non system headers
if ((headerMap != null) && !headerMap.isEmpty()) {
Iterator<String> names = headerMap.keySet().iterator();
Iterator<List<String>> values = headerMap.values().iterator();
while (names.hasNext()) {
setHeader(names.next(), values.next(),
(SipServletRequestImpl) newRequest);
}
}
if (shouldLinkSessions) {
// lets link sessions.
linkSipSessions((SipSessionBase) session1, (SipSessionBase) session2);
}
// requests are not linked, lets link them...
linkRequests((SipServletRequestImpl) origRequest,
(SipServletRequestImpl) newRequest);
((SipServletRequestImpl) newRequest).setB2buaHelper(this);
return newRequest;
}
public SipServletRequest createRequest(SipServletRequest origRequest) {
if (origRequest == null) {
throw new NullPointerException();
}
if (!origRequest.isInitial()) {
throw new IllegalStateException();
}
SipServletRequestImpl origRequestImpl = (SipServletRequestImpl) origRequest;
SipFactoryFacade sfImpl = (SipFactoryFacade) _sf;
SipApplicationSessionImpl sappSessImpl = (SipApplicationSessionImpl) origRequest.getApplicationSession();
SipServletRequestImpl copiedReq = null;
copiedReq = sfImpl.createRequestImpl(sappSessImpl,
origRequestImpl.getMethod(), origRequestImpl.getFromImpl(),
origRequestImpl.getToImpl(), false, origRequestImpl);
if (origRequest.getMethod().equals("REGISTER")) {
Header cnct = origRequestImpl.getRawHeader(Header.CONTACT);
if (cnct != null) {
copiedReq.setHeader((Header) cnct.clone());
}
}
return copiedReq;
}
public SipServletRequest createCancel(SipSession session) {
if (session == null)
throw new NullPointerException("SipSession Argument is null");
DialogSet ds = ((SipSessionImplBase) session).getDS();
if (ds != null) {
DialogFragment df = ds.getInitialDialogFragment();
if (df != null) {
PathNode pn = df.getFirst();
if (pn instanceof UA) {
INVITESession inviteFSM = UA.class.cast(pn).getInviteFSM();
SipServletRequestImpl invite = inviteFSM.getOrigRequestImpl();
if (invite != null) {
return invite.createCancel();
}
}
}
}
throw new IllegalStateException(localStrings.getLocalString(
"cannot_create_cancel", "Cannot create CANCEL for this session"));
}
private void setHeader(String name, List<String> values,
SipServletRequestImpl req1) throws IllegalArgumentException {
if (Header.isSingleLineHeader(name) && (values.size() > 1)) {
throw new IllegalArgumentException("Header " + name +
" should be a singel line header.");
}
Header header = Header.createFormatted(name, req1);
boolean isFirst = true;
for (String value : values) {
header.setValue(value, isFirst);
isFirst = false;
}
// since the initial request can add new from and to header,
// and also modify Contact header,
// make sure they have proper address format...
if ((Header.FROM.equalsIgnoreCase(name) ||
Header.TO.equalsIgnoreCase(name)) ||
Header.CONTACT.equalsIgnoreCase(name)) {
try {
header.getAddressValue();
} catch (ServletParseException e) {
throw new IllegalArgumentException("Header " + name +
" is not valid.", e);
}
}
req1.setHeader(header);
}
private boolean isSystemHeader(Set<String> headers,
SipServletMessageImpl message, boolean isInitial) {
for (String name : headers) {
// it's allowed to change From and To header of initial request
if (!(isInitial &&
(Header.FROM.equalsIgnoreCase(name) ||
Header.TO.equalsIgnoreCase(name)))) {
if (Header.isSystemHeader(Header.format(name), message)) {
return true;
}
}
}
return false;
}
private boolean isAlreadyLinked(SipServletRequestImpl req1) {
return req1.getLinkedRequest() != null;
}
private void linkRequests(SipServletRequestImpl origReq,
SipServletRequestImpl linkedReq) {
origReq.setLinkedRequest(linkedReq);
linkedReq.setLinkedRequest(origReq);
}
private void updateTransactionStack(SipServletResponseImpl resp) {
// need to update transaction path since there are new nodes.
// lets start by cleaning the top of the stack...
PathNode p = null;
Iterator<PathNode> i = resp.getDialog().getCaller2CalleePath();
if (i.hasNext()) {
// skip this since it is the uas, which is not on the stack
i.next();
}
while (i.hasNext()) {
resp.popDispatcher();
}
// ...and replace it with the new nodes.
i = resp.getDialog().getCaller2CalleePath();
if (i.hasNext()) {
// skip this since it is the uas, which is not on the stack
i.next();
}
while (i.hasNext()) {
// add the rest of the nodes..
p = i.next();
resp.pushTransactionDispatcher(p);
}
}
public synchronized SipServletResponse createResponseToOriginalRequest(
SipSession session, int status, String reasonPhrase) {
return createResponseToOriginalRequest((SipSessionBase) session,
status, reasonPhrase);
}
private SipServletResponse createResponseToOriginalRequest(
SipSessionBase session2, int status, String reasonPhrase) {
// 1. create response with original request
// 2. verify that only final response 200OK has been created before
// otherwise throw IllegalStateException: included in createResponse
if (_originalRequest == null) {
throw new IllegalStateException(
"Only allowed to create response to original request.");
}
if (!session2.isValid())
throw new IllegalArgumentException("Session is invalid");
SipSessionBase session = null;
TempSession tempSession = null;
// some trix to make jsr289 12.5.1 Cloning and Linking working.
// see also getLinkedSession()
if (session2 instanceof TempSession) {
if (_log.isLoggable(Level.FINE)) {
_log.log(Level.FINE, "Convert FacadeSession -> session");
}
tempSession = (TempSession) session2;
session = tempSession.getDerivedUACSessionToLink();
} else {
session = session2;
}
SipServletResponseImpl resp = null;
if (session.isDerived()) {
// maybe it's a subsequent response or retransmission
// and hence sessions might already be linked
SipSessionBase linkedSession = (SipSessionBase) getLinkedSession(session,
false);
if (linkedSession != null) {
DialogFragment dialog = _originalRequest.getDialog()
.getDialogSet()
.searchForDialog(linkedSession.getToTag(),
linkedSession.getFragmentId());
if (dialog != null) {
// make a copy of the original request, can't change the original
SipServletRequestImpl clone = (SipServletRequestImpl) _originalRequest.clone();
// adjust the clone, needed because of new fragmentId,
// which changes contact
clone.setDialog(dialog);
resp = (SipServletResponseImpl) clone.createResponse(status,
reasonPhrase);
// point back again...
resp.setRequest(_originalRequest);
resp.setSession((SipSessionBase) linkedSession);
updateTransactionStack(resp);
if (_log.isLoggable(Level.FINE)) {
_log.log(Level.FINE,
"Session is derivied and linked, uac session = " +
session + ", uas session = " + linkedSession +
" , linked dialog =" + dialog + ", " + resp);
}
} else {
throw new IllegalStateException(
"Derived session is already linked but dialog is not established.");
}
} else {
// need to create a new structure (dialog, etc.)
// of the derived linked session
// fetch the original uas
PathNode uas = _originalRequest.getDialog().getLast();
// clone only until uas, i.e. exclude it
DialogFragment d = _originalRequest.getDialog()
.cloneFromCallerToCalleeUntil(uas,
true);
// create the new uas replacing the original
uas = new UA(_originalRequest.getApplicationSessionImpl(), false);
// lets add the current uas to the application & transaction path
d.addToPath(uas);
// make a copy of the original request, can't change the original
SipServletRequestImpl clone = (SipServletRequestImpl) _originalRequest.clone();
// adjust the clone, needed because of new fragmentId,
// which changes contact
clone.setDialog(d);
// create response
resp = (SipServletResponseImpl) clone.createResponse(status,
reasonPhrase);
// point back again...
resp.setRequest(_originalRequest);
// need to update transaction stack
updateTransactionStack(resp);
// save session in response.
// It will later be linked to new derived session.
//
// It is also used as signal of b2buaHelper usage.
if (tempSession != null) {
resp.setB2buaHelperTempSession(tempSession);
}
if (_log.isLoggable(Level.FINE)) {
_log.log(Level.FINE,
"Session is derivied but not linked, uac session = " +
session + ", uas session = " + linkedSession +
" , linked dialog =" + d + ", " + resp);
}
}
} else {
resp = (SipServletResponseImpl) _originalRequest.createResponse(status,
reasonPhrase);
if (!isAlreadyLinkedToEachOther(session,
_originalRequest.getSessionImpl())) {
// lets link the sessions...
linkSipSessions(session, _originalRequest.getSessionImpl());
if (_log.isLoggable(Level.FINE)) {
_log.log(Level.FINE,
"Session is original and was not linked, uac session = " +
session + ", uas session = " +
_originalRequest.getSessionImpl() +
" , linked dialog =" + _originalRequest.getDialog() +
", " + resp);
}
} else {
if (_log.isLoggable(Level.FINE)) {
_log.log(Level.FINE,
"Session is original and already linked, uac session = " +
session + ", uas session = " +
_originalRequest.getSessionImpl() +
" , linked dialog =" + _originalRequest.getDialog() +
", " + resp);
}
}
}
return resp;
}
public synchronized SipSession getLinkedSession(SipSession session) {
if (!session.isValid())
throw new IllegalArgumentException(" Session is not valid ");
return getLinkedSession((SipSessionBase) session, true);
}
/**
* Special handling to support jsr289 12.5.1 Cloning and Linking. Furnish the
* UAS-2 (a clone of UAS-1) when the getLinkedSipSession is invoked with
* UAC-2 according to jsr289. Since lazy creation of sessions are enabled
* only a wrapper session (FacadeSession) is returned. It will later be
* replaced by the correct one.
*
* @param session
* @param enableFacade -
* enables jsr289 12.5.1 Cloning and Linking
* @return
*/
private SipSession getLinkedSession(SipSessionBase session,
boolean enableFacade) {
SipApplicationSession app = session.getApplicationSession();
SipSessionBase sb = (SipSessionBase) session;
String id = sb.getLinkedSipSessionId();
if (enableFacade && (id == null) && sb.isDerived()) {
// jsr289 support 12.5.1 Cloning and Linking.
// lazy creation is enforced, lets return a dummy wrapper...
// NOTE: TempSession wrappes UAC session, not UAS session
return new TempSession(sb);
}
return (id != null)
? ((SipApplicationSessionImpl) app).getSipSession(id) : null;
}
public SipServletRequest getLinkedSipServletRequest(SipServletRequest req) {
return getLinkedSipServletRequest((SipServletRequestImpl) req);
}
private synchronized SipServletRequestImpl getLinkedSipServletRequest(
SipServletRequestImpl req1) {
SipServletRequestImpl req2 = req1.getLinkedRequest();
if (req2 != null) {
SipSession session1 = req1.getSession();
SipSession session2 = req2.getSession();
if (!isAlreadyLinkedToEachOther((SipSessionBase) session1,
(SipSessionBase) session2)) {
// since the sessions are not linked to each other,
// the request can't be linked either...
req2 = null;
}
}
return req2;
}
public List<SipServletMessage> getPendingMessages(SipSession session,
UAMode mode) {
if (!session.isValid())
throw new IllegalArgumentException("Session is not valid");
return ((SipSessionBase) session).getPendingMessages(mode);
}
private boolean isValidSessions(SipSessionBase session1,
SipSessionBase session2) {
return (session1.isValid() && session2.isValid()) &&
(session1.getApplicationSession().getId()
.equals(session2.getApplicationSession().getId()));
}
private boolean isNotLinkedToAnyone(SipSessionBase session1,
SipSessionBase session2) {
return (session1.getLinkedSipSessionId() == null) &&
(session2.getLinkedSipSessionId() == null);
}
private boolean isAlreadyLinkedToEachOther(SipSessionBase session1,
SipSessionBase session2) {
return session1.equals(session2) ||
(((session1.getLinkedSipSessionId() != null) &&
(session2.getLinkedSipSessionId() != null)) &&
((session1.getLinkedSipSessionId().equals(session2.getId())) &&
(session2.getLinkedSipSessionId().equals(session1.getId()))));
}
public synchronized void linkSipSessions(SipSession session1,
SipSession session2) {
if ((session1 == null) || (session2 == null)) {
throw new NullPointerException();
}
if (isTerminated(session1) || isTerminated(session2)) {
throw new IllegalArgumentException();
}
// silently ignore if already linked
if (!isAlreadyLinkedToEachOther((SipSessionBase) session1,
(SipSessionBase) session2)) {
if ((!isValidSessions((SipSessionBase) session1,
(SipSessionBase) session2)) ||
!isNotLinkedToAnyone((SipSessionBase) session1,
(SipSessionBase) session2)) {
throw new IllegalArgumentException();
}
linkSipSessions((SipSessionBase) session1, (SipSessionBase) session2);
}
}
private void linkSipSessions(SipSessionBase session1,
SipSessionBase session2) {
if (_log.isLoggable(Level.FINE)) {
_log.log(Level.FINE,
"linkSipSessions(" + session1.getId() + "," + session2.getId() +
")");
}
session1.setLinkedSipSessionId(session2.getId());
session2.setLinkedSipSessionId(session1.getId());
}
private boolean isTerminated(SipSession sess) {
return sess.getState() == SipSession.State.TERMINATED;
}
public synchronized void unlinkSipSessions(SipSession session1) {
SipSession session2 = getLinkedSession((SipSessionBase) session1, false);
if ((session2 == null) || isTerminated(session1) ) {
throw new IllegalArgumentException();
}
unlinkSipSessions((SipSessionBase) session1, (SipSessionBase) session2);
// Also unlink requests
if (this._originalRequest != null && this._originalRequest.getLinkedRequest() != null) {
this._originalRequest.getLinkedRequest().setLinkedRequest(null);
this._originalRequest.setLinkedRequest(null);
}
}
private void unlinkSipSessions(SipSessionBase session1,
SipSessionBase session2) {
session1.setLinkedSipSessionId(null);
session2.setLinkedSipSessionId(null);
}
/**
* Only a dummy wrapper for B2buaHelper support 12.5.1 Cloning and Linking
* Support saving attributes and will be replaced by a real sip session after
* send of message.
*
* @author ehsroha
* @since 2007-apr-01
*
*/
class TempSession implements SipSessionBase {
private static final long serialVersionUID = -5845365964095917542L;
private ConcurrentHashMap<String, Object> _sessionAttributeMap = new ConcurrentHashMap<String, Object>();
private final SipSessionBase _session;
private TempSession(SipSessionBase derivedUACSessionToLink) {
_session = derivedUACSessionToLink;
}
/**
* Method MUST be kept as is.
* Call this method when finally the derived UAC session should be
* linked with the derived UAS session (which is not jet created).
* @return
*/
SipSessionBase getDerivedUACSessionToLink() {
return _session;
}
public long getCreationTime() {
return 0;
}
public String getId() {
return "";
}
public long getLastAccessedTime() {
return 0;
}
public void invalidate() {
}
public boolean isReadyToInvalidate() {
return false;
}
public void setInvalidateWhenReady(boolean invalidateWhenReady) {
throw new RuntimeException(" Not yet implemented ");
}
public boolean getInvalidateWhenReady() {
return false;
}
public void setOutboundInterface(InetAddress address) {
}
public void setOutboundInterface(InetSocketAddress address) {
}
public void addPendingMessage(SipServletMessageImpl m, UAMode mode) {
}
public void createPendingMessageHelper() {
}
public SipSessionInterface.State getState() {
throw new RuntimeException(" Not yet implemented ");
}
public SipApplicationSession getApplicationSession() {
return null;
}
public String getCallId() {
return "";
}
public Address getLocalParty() {
return null;
}
public Address getRemoteParty() {
return null;
}
public SipServletRequest createRequest(String method) {
return null;
}
public void setHandler(String name) throws ServletException {
}
public Object getAttribute(String name) {
return _sessionAttributeMap.get(name);
}
public void access() {
}
public Enumeration<String> getAttributeNames() {
// Since Map doesn't have Enumeration as interface need to convert via
// private class EnumerationConverter.
synchronized (_sessionAttributeMap) {
return new EnumerationConverter<String>(_sessionAttributeMap.keySet());
}
}
public void setAttribute(String name, Object attribute) {
if (name.equals(SipFactoryImpl.REMOTE_TARGET)) {
throw new IllegalStateException("reserved key.");
}
_sessionAttributeMap.put(name, attribute);
}
public void removeAttribute(String name) {
_sessionAttributeMap.remove(name);
}
public SipApplicationRoutingRegion getRegion() {
return SipApplicationRoutingRegion.TERMINATING_REGION; // correct?
}
public URI getSubscriberURI() throws IllegalStateException {
return null;
}
public ServletContext getServletContext() {
return null;
}
public boolean isValid() {
return true;
}
public SipApplicationSessionImpl getApplicationSessionImpl() {
return null;
}
public String getFragmentId() {
return null;
}
public String getFromTag() {
return "";
}
public String getHandler() {
return "";
}
public String getLinkedSipSessionId() {
return "";
}
public SipSessionBase getOriginalOrDerivedSessionAndRegisterDialog(
SipServletRequestImpl req, DialogFragment d) {
return null;
}
public SipSessionBase getOriginalOrDerivedSessionAndRegisterDialog(
SipServletResponseImpl resp, DialogFragment d) {
return null;
}
public URI getRemoteTarget() {
return null;
}
public Address getTo() {
return null;
}
public String getToTag() {
return "";
}
public boolean hasNoToTag() {
return false;
}
public void invalidate(boolean hasTimedOut) {
}
public boolean is1xxReliableOngoing() {
return false;
}
public boolean is1xxReliableSDP() {
return false;
}
public boolean isDerived() {
return true;
}
public void reset1xxReliable() {
}
public void resetUpdateOngoing() {
}
public boolean set1xxReliableOngoing(boolean sdp) {
return false;
}
public void setLinkedSipSessionId(String id) {
}
public void setRegion(SipApplicationRoutingRegion region) {
}
public void setRemoteTarget(URI contact) {
}
public void setSubscriberURI(URI subscriberURI) {
}
public void setType(Type type) {
}
public boolean setUpdateOngoing() {
return false;
}
public boolean isReplicable() {
return false;
}
public List<SipServletMessage> getPendingMessages(UAMode mode) {
return null;
}
public void setShouldBePersisted() {
}
public void updateSipSessionState(SipServletRequest req, Type type) {
}
public void updateSipSessionState(SipServletResponse resp, Type type) {
}
public int getCSeq() {
return 1;
}
public boolean isB2buaHelper() {
return true;
}
}
}