/*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.mobicents.servlet.sip.message;
import gov.nist.javax.sip.header.SIPHeader;
import gov.nist.javax.sip.stack.SIPTransaction;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.security.Principal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.sip.Address;
import javax.servlet.sip.Parameterable;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipServletMessage;
import javax.servlet.sip.SipSession;
import javax.sip.Dialog;
import javax.sip.InvalidArgumentException;
import javax.sip.SipFactory;
import javax.sip.Transaction;
import javax.sip.header.AcceptLanguageHeader;
import javax.sip.header.CSeqHeader;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ContentLanguageHeader;
import javax.sip.header.ContentLengthHeader;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.Header;
import javax.sip.header.HeaderAddress;
import javax.sip.header.HeaderFactory;
import javax.sip.header.Parameters;
import javax.sip.header.ToHeader;
import javax.sip.message.Message;
import javax.sip.message.Request;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.log4j.Logger;
import org.mobicents.servlet.sip.JainSipUtils;
import org.mobicents.servlet.sip.SipFactories;
import org.mobicents.servlet.sip.address.AddressImpl;
import org.mobicents.servlet.sip.address.ParameterableHeaderImpl;
import org.mobicents.servlet.sip.core.ExtendedListeningPoint;
import org.mobicents.servlet.sip.core.session.MobicentsSipApplicationSession;
import org.mobicents.servlet.sip.core.session.MobicentsSipSession;
import org.mobicents.servlet.sip.core.session.SessionManagerUtil;
import org.mobicents.servlet.sip.core.session.SipApplicationSessionKey;
import org.mobicents.servlet.sip.core.session.SipManager;
import org.mobicents.servlet.sip.core.session.SipSessionKey;
import org.mobicents.servlet.sip.startup.SipContext;
/**
* Implementation of SipServletMessage
*
* @author mranga
*
*/
public abstract class SipServletMessageImpl implements SipServletMessage, Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(SipServletMessageImpl.class
.getCanonicalName());
private static final String CONTENT_TYPE_TEXT = "text";
// private static final String HCOLON = " : ";
private static final HeaderFactory headerFactory = SipFactories.headerFactory;
protected final Message message;
protected final SipFactoryImpl sipFactoryImpl;
protected SipSessionKey sessionKey;
//lazy loaded and not serialized
protected transient MobicentsSipSession sipSession;
protected final Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();
private Transaction transaction;
protected TransactionApplicationData transactionApplicationData;
protected transient HeaderForm headerForm = HeaderForm.DEFAULT;
// IP address of the next upstream/downstream hop from which this message
// was received. Applications can determine the actual IP address of the UA
// that originated the message from the message Via header fields.
// But for upstream - thats a proxy stuff, fun with ReqURI, RouteHeader
protected transient InetAddress remoteAddr = null;
protected transient int remotePort = -1;
protected transient String transport = null;
protected String currentApplicationName = null;
protected transient Principal userPrincipal;
protected boolean isMessageSent;
protected final Dialog dialog;
protected transient String method;
protected SipServletMessageImpl(Message message,
SipFactoryImpl sipFactoryImpl, Transaction transaction,
MobicentsSipSession sipSession, Dialog dialog) {
if (sipFactoryImpl == null)
throw new NullPointerException("Null factory");
if (message == null)
throw new NullPointerException("Null message");
// if (sipSession == null)
// throw new NullPointerException("Null session");
this.sipFactoryImpl = sipFactoryImpl;
this.message = message;
this.transaction = transaction;
if(sipSession != null) {
this.sessionKey = sipSession.getKey();
}
this.transactionApplicationData = new TransactionApplicationData(this);
isMessageSent = false;
this.dialog = dialog;
if(sipSession != null && dialog != null) {
sipSession.setSessionCreatingDialog(dialog);
if(dialog.getApplicationData() == null) {
dialog.setApplicationData(transactionApplicationData);
}
}
// good behaviour, lets make some default
//seems like bad behavior finally
//check http://forums.java.net/jive/thread.jspa?messageID=260944
// => commented out
// if (this.message.getContentEncoding() == null)
// try {
// this.message.addHeader(this.headerFactory
// .createContentEncodingHeader(this.defaultEncoding));
// } catch (ParseException e) {
// logger.debug("Couldnt add deafualt enconding...");
// e.printStackTrace();
// }
if (transaction != null && transaction.getApplicationData() == null) {
transaction.setApplicationData(transactionApplicationData);
}
}
private void checkCommitted() {
if(this.isCommitted()) {
throw new IllegalStateException("This message is in committed state. You can not modify it");
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#addAcceptLanguage(java.util.Locale)
*/
public void addAcceptLanguage(Locale locale) {
checkCommitted();
AcceptLanguageHeader ach = headerFactory
.createAcceptLanguageHeader(locale);
message.addHeader(ach);
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#addAddressHeader(java.lang.String, javax.servlet.sip.Address, boolean)
*/
public void addAddressHeader(String name, Address addr, boolean first)
throws IllegalArgumentException {
checkCommitted();
String hName = getFullHeaderName(name);
if (logger.isDebugEnabled()) {
logger.debug("Adding address header [" + hName + "] as first ["
+ first + "] value [" + addr + "]");
}
//we should test for
//This method can be used with headers which are defined to contain one
//or more entries matching (name-addr | addr-spec) *(SEMI generic-param) as defined in RFC 3261
// if (!isAddressTypeHeader(hName)) {
// logger.error("Header [" + hName + "] is not address type header");
// throw new IllegalArgumentException("Header[" + hName
// + "] is not of an address type");
// }
if (isSystemHeader(hName)) {
logger.error("Error, can't add system header [" + hName + "]");
throw new IllegalArgumentException("Header[" + hName
+ "] is system header, cant add, modify it!!!");
}
try {
String nameToAdd = getCorrectHeaderName(hName);
Header h = headerFactory.createHeader(nameToAdd, addr.toString());
if (first) {
this.message.addFirst(h);
} else {
this.message.addLast(h);
}
} catch (Exception e) {
throw new IllegalArgumentException("Error adding header", e);
}
}
public void addHeaderInternal(String name, String value, boolean bypassSystemHeaderCheck) {
String hName = getFullHeaderName(name);
if (logger.isDebugEnabled())
logger.debug("Adding header under name [" + hName + "]");
if (!bypassSystemHeaderCheck && isSystemHeader(hName)) {
logger.error("Cant add system header [" + hName + "]");
throw new IllegalArgumentException("Header[" + hName
+ "] is system header, cant add,cant modify it!!!");
}
String nameToAdd = getCorrectHeaderName(hName);
try {
if(JainSipUtils.multiValueHeaders.contains(name)) {
List<Header> headers = SipFactory.getInstance().createHeaderFactory().createHeaders(nameToAdd + ":" +
value);
for (Header header : headers) {
this.message.addLast(header);
}
} else {
Header header = SipFactory.getInstance().createHeaderFactory()
.createHeader(nameToAdd, value);
this.message.addLast(header);
}
} catch (Exception ex) {
throw new IllegalArgumentException("Illegal args supplied ", ex);
}
}
//check if the submitted value is of the form header-value *(COMMA header-value)
// private boolean isMultipleValue(String value) {
// StringTokenizer tokenizer = new StringTokenizer(value, ",");
// tokenizer.nextToken();
// return tokenizer.hasMoreTokens();
// }
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#addHeader(java.lang.String, java.lang.String)
*/
public void addHeader(String name, String value) {
checkCommitted();
addHeaderInternal(name, value, false);
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#addParameterableHeader(java.lang.String, javax.servlet.sip.Parameterable, boolean)
*/
public void addParameterableHeader(String name, Parameterable param,
boolean first) {
checkCommitted();
try {
String hName = getFullHeaderName(name);
if (logger.isDebugEnabled())
logger.debug("Adding parametrable header under name [" + hName
+ "] as first [" + first + "] value [" + param + "]");
String body = param.toString();
String nameToAdd = getCorrectHeaderName(hName);
Header header = SipFactories.headerFactory.createHeader(nameToAdd,
body);
if (first)
this.message.addFirst(header);
else
this.message.addLast(header);
} catch (Exception ex) {
throw new IllegalArgumentException("Illegal args supplied", ex);
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getAcceptLanguage()
*/
public Locale getAcceptLanguage() {
// See section 14.4 of RFC 2616 (HTTP/1.1) for more information about how the Accept-Language header
// must interpreted to determine the preferred language of the client.
Locale preferredLocale = null;
float q = 0;
Iterator<Header> it = (Iterator<Header>) this.message
.getHeaders(AcceptLanguageHeader.NAME);
while (it.hasNext()) {
AcceptLanguageHeader alh = (AcceptLanguageHeader) it.next();
if(preferredLocale == null) {
preferredLocale = alh.getAcceptLanguage();
q = alh.getQValue();
} else {
if(alh.getQValue() > q) {
preferredLocale = alh.getAcceptLanguage();
q = alh.getQValue();
}
}
}
return preferredLocale;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getAcceptLanguages()
*/
public Iterator<Locale> getAcceptLanguages() {
LinkedList<Locale> ll = new LinkedList<Locale>();
Iterator<Header> it = (Iterator<Header>) this.message
.getHeaders(AcceptLanguageHeader.NAME);
while (it.hasNext()) {
AcceptLanguageHeader alh = (AcceptLanguageHeader) it.next();
ll.add(alh.getAcceptLanguage());
}
return ll.iterator();
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getAddressHeader(java.lang.String)
*/
@SuppressWarnings("unchecked")
public Address getAddressHeader(String name) throws ServletParseException {
if (name == null)
throw new NullPointerException();
String hName = getFullHeaderName(name);
if (logger.isDebugEnabled())
logger.debug("Fetching address header for name [" + hName + "]");
// if (!isAddressTypeHeader(hName)) {
// logger.error("Header of name [" + hName
// + "] is not address type header!!!");
// throw new ServletParseException("Header of type [" + hName
// + "] cant be parsed to address, wrong content type!!!");
// }
String nameToSearch = getCorrectHeaderName(hName);
ListIterator<Header> headers = (ListIterator<Header>) this.message
.getHeaders(nameToSearch);
ListIterator<Header> lit = headers;
if (lit != null && lit.hasNext()) {
Header first = lit.next();
if (first instanceof HeaderAddress) {
try {
if(this.isCommitted()) {
return new AddressImpl((HeaderAddress) first, false);
} else {
return new AddressImpl((HeaderAddress) first, true);
}
} catch (ParseException e) {
throw new ServletParseException("Bad address " + first);
}
} else {
Parameterable parametrable = createParameterable(first, first.getName());
try {
if(this.isCommitted()) {
return new AddressImpl(SipFactories.addressFactory.createAddress(parametrable.getValue()), ((ParameterableHeaderImpl)parametrable).getInternalParameters(), false);
} else {
return new AddressImpl(SipFactories.addressFactory.createAddress(parametrable.getValue()), ((ParameterableHeaderImpl)parametrable).getInternalParameters(), false);
}
} catch (ParseException e) {
throw new ServletParseException("Impossible to parse the following header " + name + " as an address.", e);
}
}
}
return null;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getAddressHeaders(java.lang.String)
*/
@SuppressWarnings("unchecked")
public ListIterator<Address> getAddressHeaders(String name)
throws ServletParseException {
String hName = getFullHeaderName(name);
// Fix from Thomas Leseney from Nexcom systems
// if (!isAddressTypeHeader(hName)) {
// throw new ServletParseException(
// "Header [" + hName + "] is not address type header");
// }
LinkedList<Address> retval = new LinkedList<Address>();
String nameToSearch = getCorrectHeaderName(hName);
for (Iterator<Header> it = this.message.getHeaders(nameToSearch); it
.hasNext();) {
Header header = (Header) it.next();
if (header instanceof HeaderAddress) {
HeaderAddress aph = (HeaderAddress) header;
try {
AddressImpl addressImpl = new AddressImpl(
aph, true);
retval.add(addressImpl);
} catch (ParseException ex) {
throw new ServletParseException("Bad header", ex);
}
} else {
Parameterable parametrable = createParameterable(header, header.getName());
try {
AddressImpl addressImpl = new AddressImpl(SipFactories.addressFactory.createAddress(parametrable.getValue()), ((ParameterableHeaderImpl)parametrable).getInternalParameters(), false);
retval.add(addressImpl);
} catch (ParseException e) {
throw new ServletParseException("Impossible to parse the following header " + name + " as an address.", e);
}
}
}
return retval.listIterator();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getApplicationSession()
*/
public SipApplicationSession getApplicationSession() {
return getApplicationSession(true);
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getApplicationSession(boolean)
*/
public SipApplicationSession getApplicationSession(boolean create) {
String applicationName = null;
if(sessionKey != null) {
applicationName = sessionKey.getApplicationName();
}
if(applicationName != null) {
final SipContext sipContext = sipFactoryImpl.getSipApplicationDispatcher().findSipApplication(applicationName);
//call id not needed anymore since the sipappsessionkey is not a callid anymore but a random uuid
final SipApplicationSessionKey sipApplicationSessionKey = SessionManagerUtil.getSipApplicationSessionKey(
applicationName,
sessionKey.getApplicationSessionId());
MobicentsSipApplicationSession applicationSession = sipContext.getSipManager().getSipApplicationSession(sipApplicationSessionKey, create);
return applicationSession;
}
return null;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getAttribute(java.lang.String)
*/
public Object getAttribute(String name) {
if (name == null)
throw new NullPointerException("Attribute name can not be null.");
return this.attributes.get(name);
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getAttributeNames()
*/
public Enumeration<String> getAttributeNames() {
Vector<String> names = new Vector<String>(this.attributes.keySet());
return names.elements();
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getCallId()
*/
public String getCallId() {
CallIdHeader id = (CallIdHeader) this.message
.getHeader(getCorrectHeaderName(CallIdHeader.NAME));
if (id != null)
return id.getCallId();
else
return null;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getCharacterEncoding()
*/
public String getCharacterEncoding() {
if (this.message.getContentEncoding() != null) {
return this.message.getContentEncoding().getEncoding();
} else {
ContentTypeHeader cth = (ContentTypeHeader)
this.message.getHeader(ContentTypeHeader.NAME);
if(cth == null) return null;
return cth.getParameter("charset");
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getContent()
*/
public Object getContent() throws IOException, UnsupportedEncodingException {
ContentTypeHeader contentTypeHeader = (ContentTypeHeader)
this.message.getHeader(ContentTypeHeader.NAME);
if(contentTypeHeader!= null && CONTENT_TYPE_TEXT.equals(contentTypeHeader.getContentType())) {
String content = null;
if(message.getRawContent() != null) {
String charset = this.getCharacterEncoding();
if(charset == null) {
content = new String(message.getRawContent());
} else {
content = new String(message.getRawContent(), charset);
}
} else {
content = "";
}
return content;
} else {
return this.message.getRawContent();
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getContentLanguage()
*/
public Locale getContentLanguage() {
if (this.message.getContentLanguage() != null)
return this.message.getContentLanguage().getContentLanguage();
else
return null;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getContentLength()
*/
public int getContentLength() {
if (this.message.getContentLength() != null) {
return this.message.getContentLength().getContentLength();
} else {
return 0;
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getContentType()
*/
public String getContentType() {
ContentTypeHeader cth = (ContentTypeHeader) this.message
.getHeader(getCorrectHeaderName(ContentTypeHeader.NAME));
if (cth != null)
{
String contentType = cth.getContentType();
String contentSubType = cth.getContentSubType();
if(contentSubType != null)
return contentType + "/" + contentSubType;
return contentType;
}
else
return null;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getExpires()
*/
public int getExpires() {
if (this.message.getExpires() != null)
return this.message.getExpires().getExpires();
else
return -1;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getFrom()
*/
public Address getFrom() {
// AddressImpl enforces immutability!!
FromHeader from = (FromHeader) this.message
.getHeader(getCorrectHeaderName(FromHeader.NAME));
AddressImpl address = new AddressImpl(from.getAddress(), AddressImpl.getParameters((Parameters)from), transaction == null ? true : false);
return address;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getHeader(java.lang.String)
*/
public String getHeader(String name) {
String nameToSearch = getCorrectHeaderName(name);
String value = null;
if (this.message.getHeader(nameToSearch) != null) {
value = ((SIPHeader) this.message.getHeader(nameToSearch))
.getValue();
}
// if(logger.isDebugEnabled()) {
// logger.debug("getHeader "+ name+ ", value="+ value );
// }
return value;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getHeaderForm()
*/
public HeaderForm getHeaderForm() {
return this.headerForm;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getHeaderNames()
*/
public Iterator<String> getHeaderNames() {
return this.message.getHeaderNames();
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getHeaders(java.lang.String)
*/
public ListIterator<String> getHeaders(String name) {
String nameToSearch = getCorrectHeaderName(name);
ArrayList<String> result = new ArrayList<String>();
try {
ListIterator<Header> list = this.message.getHeaders(nameToSearch);
while (list != null && list.hasNext()) {
Header h = list.next();
result.add(((SIPHeader)h).getHeaderValue());
}
} catch (Exception e) {
logger.fatal("Couldnt fetch headers, original name[" + name
+ "], name searched[" + nameToSearch + "]", e);
return result.listIterator();
}
return result.listIterator();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getMethod()
*/
public final String getMethod() {
if(method == null) {
method = message instanceof Request ? ((Request) message).getMethod()
: ((CSeqHeader) message.getHeader(CSeqHeader.NAME)).getMethod();
}
return method;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getParameterableHeader(java.lang.String)
*/
public Parameterable getParameterableHeader(String name)
throws ServletParseException {
if (name == null)
throw new NullPointerException(
"Parametrable header name cant be null!!!");
String nameToSearch = getCorrectHeaderName(name);
Header h = this.message.getHeader(nameToSearch);
if(!isParameterable(name)) {
throw new ServletParseException(name + " header is not parameterable !");
}
if(h == null) {
return null;
}
return createParameterable(h, getFullHeaderName(name));
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getParameterableHeaders(java.lang.String)
*/
public ListIterator<Parameterable> getParameterableHeaders(String name)
throws ServletParseException {
ListIterator<Header> headers = this.message
.getHeaders(getCorrectHeaderName(name));
ArrayList<Parameterable> result = new ArrayList<Parameterable>();
while (headers != null && headers.hasNext())
result.add(createParameterable(headers.next(),
getFullHeaderName(name)));
if(!isParameterable(name)) {
throw new ServletParseException(name + " header is not parameterable !");
}
return result.listIterator();
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getProtocol()
*/
public String getProtocol() {
// For this version of the SIP Servlet API this is always "SIP/2.0"
return "SIP/2.0";
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getRawContent()
*/
public byte[] getRawContent() throws IOException {
if (message != null)
return message.getRawContent();
else
return null;
}
/**
* {@inheritDoc}
*/
public String getInitialRemoteAddr() {
return transactionApplicationData.getInitialRemoteHostAddress();
}
/**
* {@inheritDoc}
*/
public int getInitialRemotePort() {
return transactionApplicationData.getInitialRemotePort();
}
/**
* {@inheritDoc}
*/
public String getInitialTransport() {
return transactionApplicationData.getInitialRemoteTransport();
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getRemoteAddr()
*/
public String getRemoteAddr() {
if(getTransaction() != null) {
if(((SIPTransaction)getTransaction()).getPeerPacketSourceAddress() != null) {
return ((SIPTransaction)getTransaction()).getPeerPacketSourceAddress().getHostAddress();
} else {
return ((SIPTransaction)getTransaction()).getPeerAddress();
}
} else {
return null;
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getRemotePort()
*/
public int getRemotePort() {
if(getTransaction() != null) {
if(((SIPTransaction)getTransaction()).getPeerPacketSourceAddress() != null) {
return ((SIPTransaction)getTransaction()).getPeerPacketSourcePort();
} else {
return ((SIPTransaction)getTransaction()).getPeerPort();
}
} else {
return -1;
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getTransport()
*/
public String getTransport() {
if(getTransaction() != null) {
return ((SIPTransaction)getTransaction()).getTransport();
} else {
return null;
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getRemoteUser()
*/
public String getRemoteUser() {
// This method returns non-null only if the user is authenticated
if(this.userPrincipal != null)
return this.userPrincipal.getName();
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getSession()
*/
public SipSession getSession() {
return getSession(true);
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getSession(boolean)
*/
public SipSession getSession(boolean create) {
MobicentsSipSession session = getSipSession();
if (session == null && create) {
MobicentsSipApplicationSession sipApplicationSessionImpl = (MobicentsSipApplicationSession)getApplicationSession(create);
SipSessionKey sessionKey = SessionManagerUtil.getSipSessionKey(sipApplicationSessionImpl.getKey().getId(), currentApplicationName, message, false);
session = ((SipManager)sipApplicationSessionImpl.getSipContext().getManager()).getSipSession(sessionKey, create,
sipFactoryImpl, sipApplicationSessionImpl);
session.setSessionCreatingTransaction(transaction);
sessionKey = session.getKey();
}
if(session != null) {
return session.getSession();
}
return null;
}
/**
* Retrieve the sip session implementation
* @return the sip session implementation
*/
public final MobicentsSipSession getSipSession() {
if(sipSession == null && sessionKey != null) {
final String applicationName = sessionKey.getApplicationName();
final SipContext sipContext = sipFactoryImpl.getSipApplicationDispatcher().findSipApplication(applicationName);
sipSession = sipContext.getSipManager().getSipSession(sessionKey, false, sipFactoryImpl, null);
}
return sipSession;
}
/**
* @param session the session to set
*/
public void setSipSessionKey(SipSessionKey sessionKey) {
this.sessionKey = sessionKey;
}
/**
* @param session the session to set
*/
public SipSessionKey getSipSessionKey() {
return this.sessionKey;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getTo()
*/
public Address getTo() {
ToHeader to = (ToHeader) this.message
.getHeader(getCorrectHeaderName(ToHeader.NAME));
return new AddressImpl(to.getAddress(), AddressImpl.getParameters((Parameters)to), transaction == null ? true : false);
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getUserPrincipal()
*/
public Principal getUserPrincipal() {
if(this.userPrincipal == null) {
if(this.getSipSession() != null) {
this.userPrincipal = this.getSipSession().getUserPrincipal();
}
}
return this.userPrincipal;
}
public void setUserPrincipal(Principal principal) {
this.userPrincipal = principal;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#isSecure()
*/
public boolean isSecure() {
// TODO Auto-generated method stub
return false;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#isUserInRole(java.lang.String)
*/
public boolean isUserInRole(String role) {
if(this.userPrincipal != null) {
return ((GenericPrincipal)this.userPrincipal).hasRole(role);
}
return false;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#removeAttribute(java.lang.String)
*/
public void removeAttribute(String name) {
this.attributes.remove(name);
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#removeHeader(java.lang.String)
*/
public void removeHeader(String name) {
checkCommitted();
String hName = getFullHeaderName(name);
if (isSystemHeader(hName)) {
throw new IllegalArgumentException("Cant remove system header["
+ hName + "]");
}
String nameToSearch = getCorrectHeaderName(hName);
this.message.removeHeader(nameToSearch);
}
public void removeHeaderInternal(String name, boolean bypassSystemHeaderCheck) {
String hName = getFullHeaderName(name);
if (logger.isDebugEnabled())
logger.debug("Removing header under name [" + hName + "]");
if (!bypassSystemHeaderCheck && isSystemHeader(hName)) {
logger.error("Cant remove system header [" + hName + "]");
throw new IllegalArgumentException("Header[" + hName
+ "] is system header, can't remove it!!!");
}
String nameToRemove = getCorrectHeaderName(hName);
try {
message.removeHeader(nameToRemove);
} catch (Exception ex) {
throw new IllegalArgumentException("Illegal args supplied ", ex);
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#send()
*/
public abstract void send();
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setAcceptLanguage(java.util.Locale)
*/
public void setAcceptLanguage(Locale locale) {
checkCommitted();
AcceptLanguageHeader alh = headerFactory
.createAcceptLanguageHeader(locale);
this.message.setHeader(alh);
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setAddressHeader(java.lang.String, javax.servlet.sip.Address)
*/
public void setAddressHeader(String name, Address addr) {
checkCommitted();
String hName = getFullHeaderName(name);
if (logger.isDebugEnabled())
logger.debug("Setting address header [" + name + "] to value ["
+ addr + "]");
if (isSystemHeader(hName)) {
logger.error("Error, cant remove system header [" + hName + "]");
throw new IllegalArgumentException(
"Cant set system header, it is maintained by container!!");
}
// if (!isAddressTypeHeader(hName)) {
// logger.error("Error, set header, its not address type header ["
// + hName + "]!!");
// throw new IllegalArgumentException(
// "This header is not address type header");
// }
Header h;
String headerNameToAdd = getCorrectHeaderName(hName);
try {
h = SipFactories.headerFactory.createHeader(headerNameToAdd, addr
.toString());
this.message.setHeader(h);
} catch (ParseException e) {
logger.error("Parsing problem while setting address header with name "
+ name + " and address "+ addr, e);
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setAttribute(java.lang.String, java.lang.Object)
*/
public void setAttribute(String name, Object o) {
if (name == null)
throw new NullPointerException("Attribute name can not be null.");
this.attributes.put(name, o);
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setCharacterEncoding(java.lang.String)
*/
public void setCharacterEncoding(String enc) throws UnsupportedEncodingException {
new String("testEncoding".getBytes(),enc);
checkCommitted();
try {
this.message.setContentEncoding(SipFactories.headerFactory
.createContentEncodingHeader(enc));
} catch (Exception ex) {
throw new UnsupportedEncodingException(enc);
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setContent(java.lang.Object, java.lang.String)
*/
public void setContent(Object content, String contentType)
throws UnsupportedEncodingException {
checkMessageState();
checkContentType(contentType);
checkCommitted();
if(contentType != null && contentType.length() > 0) {
this.addHeader(ContentTypeHeader.NAME, contentType);
String charset = this.getCharacterEncoding();
try {
if(content instanceof String && charset != null) {
//test for unsupportedencoding exception
new String("testEncoding".getBytes(charset));
content = new String(((String)content).getBytes());
}
ContentTypeHeader contentTypeHeader = (ContentTypeHeader)this.message.getHeader(ContentTypeHeader.NAME);
this.message.setContent(content, contentTypeHeader);
} catch (ParseException e) {
throw new IllegalArgumentException("Parse error reading content type", e);
}
}
}
protected abstract void checkMessageState();
/**
* Check the content type against the list defined by the iana
* http://www.iana.org/assignments/media-types/
* @param contentType
*/
private void checkContentType(String contentType) {
if(contentType == null) {
throw new IllegalArgumentException("the content type cannot be null");
}
int indexOfSlash = contentType.indexOf("/");
if(indexOfSlash != -1) {
if(!JainSipUtils.ianaAllowedContentTypes.contains(contentType.substring(0, indexOfSlash))) {
throw new IllegalArgumentException("the given content type " + contentType + " is not allowed");
}
} else if(!JainSipUtils.ianaAllowedContentTypes.contains(contentType.toLowerCase())) {
throw new IllegalArgumentException("the given content type " + contentType + " is not allowed");
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setContentLanguage(java.util.Locale)
*/
public void setContentLanguage(Locale locale) {
checkCommitted();
ContentLanguageHeader contentLanguageHeader =
SipFactories.headerFactory.createContentLanguageHeader(locale);
this.message.setContentLanguage(contentLanguageHeader);
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setContentLength(int)
*/
public void setContentLength(int len) {
checkMessageState();
checkCommitted();
try {
ContentLengthHeader h = headerFactory.createContentLengthHeader(len);
this.message.setHeader(h);
} catch (InvalidArgumentException e) {
throw new IllegalStateException("Impossible to set a content length lower than 0", e);
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setContentType(java.lang.String)
*/
public void setContentType(String type) {
checkContentType(type);
checkCommitted();
String name = getCorrectHeaderName(ContentTypeHeader.NAME);
try {
Header h = headerFactory.createHeader(name, type);
this.message
.removeHeader(getCorrectHeaderName(ContentTypeHeader.NAME));
this.message.addHeader(h);
} catch (ParseException e) {
logger.error("Error while setting content type header !!!", e);
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setExpires(int)
*/
public void setExpires(int seconds) {
try {
ExpiresHeader expiresHeader =
SipFactories.headerFactory.createExpiresHeader(seconds);
expiresHeader.setExpires(seconds);
this.message.setExpires(expiresHeader);
} catch (Exception e) {
throw new RuntimeException("Error setting expiration header!", e);
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setHeader(java.lang.String, java.lang.String)
*/
public void setHeader(String name, String value) {
if(name == null) {
throw new NullPointerException ("name parameter is null");
}
if(value == null) {
throw new NullPointerException ("value parameter is null");
}
if(isSystemHeader(name)) {
throw new IllegalArgumentException(name + " is a system header !");
}
checkCommitted();
try {
if(JainSipUtils.multiValueHeaders.contains(name)) {
List<Header> headers = SipFactory.getInstance().createHeaderFactory().createHeaders(name + ":" +
value);
for (Header header : headers) {
this.message.addLast(header);
}
} else {
Header header = SipFactory.getInstance().createHeaderFactory()
.createHeader(name, value);
this.message.setHeader(header);
}
} catch (Exception e) {
throw new RuntimeException("Error creating header!", e);
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setHeaderForm(javax.servlet.sip.SipServletMessage.HeaderForm)
*/
public void setHeaderForm(HeaderForm form) {
this.headerForm = form;
// When form changes to HeaderForm.COMPACT or HeaderForm.LONG - all
// names must transition, if it is changed to HeaderForm.DEFAULT, no
// action is performed
if(form == HeaderForm.DEFAULT)
return;
// if(form == HeaderForm.COMPACT) {
// for(String fullName : headerFull2CompactNamesMappings.keySet()) {
// if(message.getHeader(fullName) != null) {
// try {
//Handle the case where mutliple headers for the same header name
// Header header = SipFactories.headerFactory.createHeader(headerCompact2FullNamesMappings.get(fullName), ((SIPHeader)message.getHeader(fullName)).getHeaderValue());
// message.removeHeader(fullName);
// message.addHeader(header);
// } catch (ParseException e) {
// logger.error("Impossible to parse the header " + fullName + " to its compact form");
// }
// }
// }
// }
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#setParameterableHeader(java.lang.String, javax.servlet.sip.Parameterable)
*/
public void setParameterableHeader(String name, Parameterable param) {
checkCommitted();
if(isSystemHeader(name)) {
throw new IllegalArgumentException(name + " is a system header !");
}
try {
this.message.setHeader(SipFactories.headerFactory.createHeader(name, param.toString()));
} catch (ParseException e) {
throw new IllegalArgumentException("Impossible to set this parameterable header", e);
}
}
/**
* Applications must not add, delete, or modify so-called "system" headers.
* These are header fields that the servlet container manages: From, To,
* Call-ID, CSeq, Via, Route (except through pushRoute), Record-Route.
* Contact is a system header field in messages other than REGISTER requests
* and responses, 3xx and 485 responses, and 200/OPTIONS responses.
* Additionally, for containers implementing the reliable provisional
* responses extension, RAck and RSeq are considered system headers also.
*
* This method should return true if passed name - full or compact is name
* of system header in context of this message. Each subclass has to
* implement it in the manner that it conforms to semantics of wrapping
* class
*
* @param headerName -
* either long or compact header name
* @return
*/
public abstract boolean isSystemHeader(String headerName);
/**
* This method checks if passed name is name of address type header -
* according to rfc 3261
*
* @param headerName -
* name of header - either full or compact
* @return
*/
public static boolean isAddressTypeHeader(String headerName) {
return JainSipUtils.addressHeadersNames.contains(getFullHeaderName(headerName));
}
/**
* This method tries to resolve header name - meaning if it is compact - it
* returns full name, if its not, it returns passed value.
*
* @param headerName
* @return
*/
protected static String getFullHeaderName(String headerName) {
String fullName = null;
if (JainSipUtils.headerCompact2FullNamesMappings.containsKey(headerName)) {
fullName = JainSipUtils.headerCompact2FullNamesMappings.get(headerName);
} else {
fullName = headerName;
}
if (logger.isDebugEnabled())
logger.debug("Fetching full header name for [" + headerName
+ "] returning [" + fullName + "]");
return fullName;
}
/**
* This method tries to determine compact header name - if passed value is
* compact form it is returned, otherwise method tries to find compact name -
* if it is found, string rpresenting compact name is returned, otherwise
* null!!!
*
* @param headerName
* @return
*/
public static String getCompactName(String headerName) {
String compactName = null;
if (JainSipUtils.headerCompact2FullNamesMappings.containsKey(headerName)) {
compactName = JainSipUtils.headerCompact2FullNamesMappings.get(headerName);
} else {
// This can be null if there is no mapping!!!
compactName = JainSipUtils.headerFull2CompactNamesMappings.get(headerName);
}
if (logger.isDebugEnabled())
logger.debug("Fetching compact header name for [" + headerName
+ "] returning [" + compactName + "]");
return compactName;
}
public String getCorrectHeaderName(String name) {
return getCorrectHeaderName(name, this.headerForm);
}
protected static String getCorrectHeaderName(String name, HeaderForm form) {
if (form == HeaderForm.DEFAULT) {
return name;
} else if (form == HeaderForm.COMPACT) {
String compact = getCompactName(name);
if (compact != null)
return compact;
else
return name;
} else if (form == HeaderForm.LONG) {
return getFullHeaderName(name);
} else {
// ERROR ? - this shouldnt happen
throw new IllegalStateException(
"No default form of a header set!!!");
}
}
public Transaction getTransaction() {
return this.transaction;
}
/*
* (non-Javadoc)
* @see java.lang.Object#clone()
*/
@Override
protected Object clone() throws CloneNotSupportedException {
// FIXME
return super.clone();
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return this.message.toString();
}
protected void setTransactionApplicationData(
TransactionApplicationData applicationData) {
this.transactionApplicationData = applicationData;
}
public TransactionApplicationData getTransactionApplicationData() {
return this.transactionApplicationData;
}
public Message getMessage() {
return message;
}
public Dialog getDialog() {
if (this.dialog != null) return dialog;
if (this.transaction != null)
return this.transaction.getDialog();
else
return null;
}
/**
* @param transaction
* the transaction to set
*/
public void setTransaction(Transaction transaction) {
this.transaction = transaction;
}
public void setTransport(String transport) {
this.transport = transport;
}
protected static Parameterable createParameterable(Header header, String hName)
throws ServletParseException {
String whole = header.toString();
if (logger.isDebugEnabled())
logger.debug("Creating parametrable for [" + hName + "] from ["
+ whole + "]");
// Remove name
String stringHeader = whole.substring(whole.indexOf(":") + 1).trim();
// if (!stringHeader.contains("<") || !stringHeader.contains(">")
// || !isParameterable(getFullHeaderName(hName))) {
Map<String, String> paramMap = new HashMap<String, String>();
String value = stringHeader;
if(stringHeader.trim().indexOf("<") == 0) {
stringHeader = stringHeader.substring(1);
String[] split = stringHeader.split(">");
value = split[0];
if (split.length > 1 && split[1].contains(";")) {
// repleace first ";" with ""
split[1] = split[1].replaceFirst(";", "");
split = split[1].split(";");
for (String pair : split) {
String[] vals = pair.split("=");
if (vals.length != 2) {
logger
.error("Wrong parameter format, expected value and name, got ["
+ pair + "]");
throw new ServletParseException(
"Wrong parameter format, expected value or name["
+ pair + "]");
}
paramMap.put(vals[0], vals[1]);
}
}
} else {
if (value.length() > 1 && value.contains(";")) {
// repleace first ";" with ""
String parameters = value.substring(value.indexOf(";") + 1);
value = value.substring(0, value.indexOf(";"));
String[] split = parameters.split(";");
for (String pair : split) {
String[] vals = pair.split("=");
if (vals.length != 2) {
logger
.error("Wrong parameter format, expected value and name, got ["
+ pair + "]");
throw new ServletParseException(
"Wrong parameter format, expected value or name["
+ pair + "]");
}
paramMap.put(vals[0], vals[1]);
}
}
}
boolean isNotModifiable = JainSipUtils.systemHeaders.contains(header.getName());
ParameterableHeaderImpl parameterable = new ParameterableHeaderImpl(
header, value, paramMap, isNotModifiable);
return parameterable;
}
public static boolean isParameterable(String header) {
if(JainSipUtils.parameterableHeadersNames.contains(header)) {
return true;
}
return false;
}
/**
* @return the currentApplicationName
*/
public String getCurrentApplicationName() {
return currentApplicationName;
}
/**
* @param currentApplicationName the currentApplicationName to set
*/
public void setCurrentApplicationName(String currentApplicationName) {
this.currentApplicationName = currentApplicationName;
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getLocalAddr()
*/
public String getLocalAddr() {
final SIPTransaction sipTransaction = (SIPTransaction)getTransaction();
if(sipTransaction != null) {
return sipTransaction.getHostPort().getHost().getIpAddress();
} else {
final String transport = JainSipUtils.findTransport(message);
final ExtendedListeningPoint listeningPoint = sipFactoryImpl.getSipNetworkInterfaceManager().findMatchingListeningPoint(transport, false);
return listeningPoint.getHost(true);
}
}
/*
* (non-Javadoc)
* @see javax.servlet.sip.SipServletMessage#getLocalPort()
*/
public int getLocalPort() {
final SIPTransaction sipTransaction = (SIPTransaction)getTransaction();
if(sipTransaction != null) {
return sipTransaction.getPort();
} else {
final String transport = JainSipUtils.findTransport(message);
final ExtendedListeningPoint listeningPoint = sipFactoryImpl.getSipNetworkInterfaceManager().findMatchingListeningPoint(transport, false);
return listeningPoint.getPort();
}
}
}