/*
* 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.ConvergedContextConfig;
import com.ericsson.ssa.dd.ServletMappingCriteria;
import com.ericsson.ssa.sip.PathNode.Type;
import com.ericsson.ssa.sip.dns.TargetTuple;
import com.ericsson.ssa.utils.ParserHelper;
import com.ericsson.ssa.utils.StringDataSource;
import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import javax.servlet.sip.Address;
import javax.servlet.sip.Parameterable;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipSession;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jvnet.glassfish.comms.util.LogUtil;
/**
* @author ekrigro TODO To change the template for this generated type comment
* go to Window - Preferences - Java - Code Style - Code Templates
*/
public abstract class SipServletMessageImpl
implements SipServletMessageInterface, ServletMappingCriteria,
Externalizable {
// NOTE! If you ADD | REMOVE check cloneShallowHelper() and update it!
protected static final EnumerationConverter<String> empty = new EnumerationConverter<String>();
private static boolean _NoJSR289isCommitted = Boolean.getBoolean(
"org.glassfish.comms.nojsr289iscommitted");
private static final ConcurrentHashMap<Long, Boolean> sentMap = new ConcurrentHashMap<Long, Boolean>();
protected static DialogManager dialogManager = DialogManager.getInstance();
private static final Logger _logger = LogUtil.SIP_LOGGER.getLogger();
// protected String protocol;
protected SipFactoryImpl _sf = SipFactoryImpl.getInstance();
protected SipSessionBase _session = null;
protected String _method = "";
protected String _protocol;
protected String _default_enc = "UTF8";
protected String _content_enc = _default_enc;
protected byte[] _content_byte = null;
protected Object _content_obj = null;
protected Map<String, Object> attrib = null;
// Currently no systemAttrib exist today (only be set by container). See SSA.
protected Map<String, Object> systemAttrib = null;
protected HashMap<String, Header> headerMap = new HashMap<String, Header>();
protected List<Dispatcher> _transactionStack = new ArrayList<Dispatcher>();
protected List<Dispatcher> _applicationStack = new ArrayList<Dispatcher>();
protected List<String> _roles = new ArrayList<String>(2);
protected int _content_byte_offset = 0;
protected TargetTuple _remote;
protected volatile OutboundInterface oi;
protected TargetTuple _initialRemote; //Initial Remote Address.
protected TargetTuple _remoteHop; //Remote Address of the current hop.
protected InetSocketAddress _local;
protected Type _Type = Type.Undefined;
protected boolean _IsContactIndicated = false;
protected boolean _headersComplete = false;
protected boolean _messageComplete = false;
protected DialogFragment _dialog = null;
protected String _fragmentId = DialogFragment.DEFAULT_FRAGMENT_ID;
private Principal _principal = null;
private String _user = null;
private X509Certificate[] _clientCert = null;
protected SipMessageType _messageType;
// Cached values for ByteBuffer concatenated write
private byte[] toBufferContent = null;
private int toBufferContentOffset = -1;
private int toBufferHeaderOffset = 0;
protected String _beKey;
protected HeaderForm headerForm = HeaderForm.DEFAULT;
/** Flag indicating that the remote has already been resolved. */
private boolean remoteResolved = false;
protected final Object byteBufferLock = new Object();
/** Used in conjuction with setRemoteResovled() */
public enum RetryPolicy {
/** Dont retry. Could be used by the OutBound connections where no retry is needed. */
DONT_RETRY,
/** Retry without resolving message */
RETRY,
/** Resolve and retry */
RESOLVE_AND_RETRY;
}
/** Used in conjuction with setRemoteResovled() */
private RetryPolicy retryPolicy = RetryPolicy.RETRY;
public SipServletMessageImpl() {
}
public SipServletMessageImpl(String protocol) {
_protocol = protocol;
}
public SipServletMessageImpl(String method, String protocol) {
_protocol = protocol;
_method = method;
}
public SipMessageType getMessageType() {
return _messageType;
}
/**
* TODO: This implementation is out of date.
* This should be updated if/when message are serialized/deserialized.
*/
public void writeExternal(ObjectOutput output) throws IOException {
try {
// _method, _protocol, _content_byte, headerMap,
// _remote, _initialRemote, _remoteHop, _local
output.writeUTF(_method); // TODO change to writeInt + writeBytes and
// check performance
output.writeUTF(_protocol);
if (_content_byte != null) {
output.writeInt(_content_byte.length);
output.write(_content_byte);
} else {
output.writeInt(0);
}
output.writeInt(headerMap.size());
Iterator<String> key = headerMap.keySet().iterator();
Iterator<Header> value = headerMap.values().iterator(); // TODO check
// the Header
// serialization
while (key.hasNext()) {
output.writeUTF(key.next());
output.writeObject(value.next());
}
output.writeObject(_remote); // TODO check the TargetTuple
// serialization
output.writeObject(_initialRemote); // TODO check the TargetTuple
// serialization
output.writeObject(_remoteHop); // TODO check the TargetTuple
// serialization
output.writeObject(_local); // Is the InetSocketAddress serialization
// fast!?
// TODO _IsContactIndicated, _headersComplete, _messageComplete
// output.writeBoolean(IsContactIndicated)
output.writeObject(oi);
} catch (Exception ignore) {
}
}
/**
* TODO: This implementation is out of date.
* This should be updated if/when message are serialized/deserialized.
*/
public void readExternal(ObjectInput input) throws IOException {
try {
// method, _protocol, _content_byte, headerMap, _remote, _local
_method = input.readUTF();
_protocol = input.readUTF();
int cbl = input.readInt();
_content_byte = new byte[cbl];
input.read(_content_byte);
int hml = input.readInt();
if (headerMap == null) {
headerMap = new HashMap<String, Header>(hml);
}
for (int i = 0; i < hml; i++) {
String key = input.readUTF();
Header value = (Header) input.readObject();
headerMap.put(key, value);
}
_remote = (TargetTuple) input.readObject();
_initialRemote = (TargetTuple) input.readObject();
_remoteHop = (TargetTuple) input.readObject();
_local = (InetSocketAddress) input.readObject();
oi = (OutboundInterface) input.readObject();
_transactionStack = new ArrayList<Dispatcher>();
_applicationStack = new ArrayList<Dispatcher>();
_sf = SipFactoryImpl.getInstance();
} catch (Exception ignore) {
}
}
/**
* The message coming from caller (Type.Caller) or callee (Type.Callee). If
* its not determined it could also be Type.Undefined
*
* @return the direction of the message. Coming from caller or callee.
*/
public Type isDirection() {
if ((_Type != Type.Caller) && (_Type != Type.Callee)) {
try {
if (getDialog() != null) {
if (getDialog().isMessageFromCaller(this)) {
_Type = Type.Caller;
} else {
_Type = Type.Callee;
}
} else {
return Type.Undefined;
}
} catch (NotEqualDialogException e) {
return Type.Undefined;
}
}
return _Type;
}
public void setDirection(Type direction) {
_Type = direction;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getFrom()
*/
public Address getFromImpl() {
try {
return headerMap.get(Header.FROM).getAddressValue();
} catch (ServletParseException e) {
throw new LazyParsingException(400, e.getMessage(), e);
}
}
public Address getFrom() {
try {
return getAddressHeader(Header.FROM);
//return headerMap.get(Header.FROM).getAddressValue();
} catch (ServletParseException e) {
throw new LazyParsingException(400, e.getMessage(), e);
}
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getTo()
*/
public Address getToImpl() {
try {
return headerMap.get(Header.TO).getAddressValue();
} catch (ServletParseException e) {
throw new LazyParsingException(400, e.getMessage(), e);
}
}
public Address getTo() {
try {
//return headerMap.get(Header.TO).getAddressValue();
return getAddressHeader(Header.TO);
} catch (ServletParseException e) {
throw new LazyParsingException(400, e.getMessage(), e);
}
}
public String createTag(String name) {
String tag = _sf.createTag();
try {
Address adr = headerMap.get(name).getAddressValue();
((AddressImpl) adr).setReadOnly(false);
adr.setParameter(AddressImpl.TAG_PARAM, tag);
((AddressImpl) adr).setReadOnly(true);
} catch (ServletParseException e) {
return null;
}
return tag;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getMethod()
*/
public String getMethod() {
return _method; // The req and response must set the method.
}
// Container internal when the message is parsed
public void setMethod(String method) {
_method = method;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getProtocol()
*/
public String getProtocol() {
return _protocol;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getHeader(java.lang.String)
*/
public String getHeader(String name) {
Header header = headerMap.get(Header.format(name));
if (header == null) {
return null;
}
return header.getValue();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getHeaders(java.lang.String)
*/
public ListIterator<String> getHeaders(String name) {
String pretty = Header.format(name);
if (headerMap.containsKey(pretty)) {
return headerMap.get(pretty).getValues();
}
return Collections.EMPTY_LIST.listIterator();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getHeaderNames()
*/
public Iterator<String> getHeaderNames() {
if ((headerForm == HeaderForm.DEFAULT) ||
(headerForm == HeaderForm.LONG)) {
return headerMap.keySet().iterator();
} else { // COMPACT
HashSet<String> headerNames = new HashSet<String>();
headerNames.addAll(headerMap.keySet());
for (String s : Header.LONG_TO_SHORT_MAP.keySet()) {
if (headerNames.contains(s)) {
headerNames.remove(s);
headerNames.add(Header.LONG_TO_SHORT_MAP.get(s));
}
}
return headerNames.iterator();
}
}
/*
* (non-Javadoc) Overwrites
*
* @see javax.servlet.sip.SipServletMessage#setHeader(java.lang.String,
* java.lang.String)
*/
public void setHeader(String name, String value) {
String pretty = Header.format(name);
boolean system = Header.isSystemHeader(pretty, this);
String crap = "\r\n\t";
if ((value.indexOf(crap)) > 0) {
value = value.replaceAll(crap, "");
}
if (system) {
throw new IllegalArgumentException(Header.ILLEGAL_ACCESS);
}
validateMessageCommitted();
setPrettyHeader(pretty, value);
}
public void setPrettyHeader(String pretty, String value) {
Header header = null;
if (headerMap.containsKey(pretty)) {
header = headerMap.get(pretty);
header.removeValues();
header.setValue(value, true);
} else {
header = Header.createFormatted(pretty, this);
header.setValue(value, true);
headerMap.put(pretty, header);
}
}
/*
* (non-Javadoc) adds
*
* @see javax.servlet.sip.SipServletMessage#addHeader(java.lang.String,
* java.lang.String)
*/
public void addHeader(String name, String value) {
Header header = null;
String pretty = Header.format(name);
boolean system = Header.isSystemHeader(pretty, this);
if (system) {
throw new IllegalArgumentException(Header.ILLEGAL_ACCESS);
}
validateMessageCommitted();
if (headerMap.containsKey(pretty)) {
header = headerMap.get(pretty);
header.setValue(value, false);
} else {
header = Header.createFormatted(pretty, this);
header.setValue(value, false);
headerMap.put(pretty, header);
}
}
public void addHeader(Header header) {
Header in = headerMap.get(header.getName());
if (in != null) {
in.merge(header);
} else {
headerMap.put(header.getName(), header);
}
}
public void setHeader(Header header) {
headerMap.put(header.getName(), header);
}
/*
* public String getHeader(Header header) { Header in =
* headerMap.get(header.getName()); if (in != null) return in.toString();
* return null; }
*/
public Header getRawHeader(String header) {
return headerMap.get(header);
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#removeHeader(java.lang.String)
*/
public void removeHeader(String name) {
String pretty = Header.format(name);
if (Header.isSystemHeader(pretty, this)) {
throw new IllegalArgumentException(Header.ILLEGAL_ACCESS);
}
validateMessageCommitted();
headerMap.remove(pretty);
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getAddressHeader(java.lang.String)
*/
public Address getAddressHeader(String name) throws ServletParseException {
if (allowFromToChange(name)) {
AddressImpl impl = getAddressHeaderImpl(name);
return new AddressPolicyProxy(name, impl, getSessionImpl(), getDialog());
} else {
return getAddressHeaderImpl(name);
}
}
private boolean allowFromToChange(String name) {
return ConvergedContextConfig.ALLOW_FROM_CHANGE &&
(Header.FROM.equals(name) || Header.TO.equals(name));
}
/*
*
*/
public AddressImpl getAddressHeaderImpl(String name)
throws ServletParseException {
Header address = headerMap.get(Header.format(name));
if (address == null) {
return null;
}
AddressImpl addressHeaderImpl = (AddressImpl) address.getAddressValue();
if (addressHeaderImpl != null) {
addressHeaderImpl.setModifiable(_isCommitted());
}
if (name.equals(Header.CONTACT) ) {
if (addressHeaderImpl != null) {
addressHeaderImpl.setReadOnly(false);
}
}
return addressHeaderImpl;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getAddressHeaders(java.lang.String)
*/
public ListIterator<Address> getAddressHeaders(String name)
throws ServletParseException {
String pretty = Header.format(name);
boolean systemHeader = Header.isSystemHeader(pretty, this);
if (headerMap.containsKey(pretty)) {
return new SipListIterator<Address>(headerMap.get(pretty)
.getAddressValues(),
systemHeader);
} else {
return Collections.EMPTY_LIST.listIterator();
/*
Header header = Header.createFormated(pretty, this);
headerMap.put(pretty, header);
return new SipListIterator<Address>(headerMap.get(pretty)
.getAddressValues(),
systemHeader);
*/
}
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#setAddressHeader(java.lang.String,
* javax.servlet.sip.Address)
*/
public void setAddressHeader(String name, Address value) {
Header header = null;
String pretty = Header.format(name);
boolean system = Header.isSystemHeader(pretty, this);
if (system) {
throw new IllegalArgumentException(Header.ILLEGAL_ACCESS);
}
if (!(value instanceof AddressImpl)) {
value = (AddressImpl) ((AddressImplInstance) value).getAddressImpl();
}
validateMessageCommitted();
if (headerMap.containsKey(pretty)) {
header = headerMap.get(pretty);
header.removeValues();
header.setAddressValue(value, false);
} else {
header = Header.createFormatted(pretty, this);
header.setAddressValue(value, false);
headerMap.put(pretty, header);
}
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#addAddressHeader(java.lang.String,
* javax.servlet.sip.Address, boolean)
*/
public void addAddressHeader(String name, Address value, boolean first) {
Header header = null;
String pretty = Header.format(name);
boolean system = Header.isSystemHeader(pretty, this);
if (system) {
throw new IllegalArgumentException(Header.ILLEGAL_ACCESS);
}
if (headerMap.containsKey(pretty)) {
header = headerMap.get(pretty);
header.setAddressValue(value, first);
} else {
// already formated using createFormated
header = Header.createFormatted(pretty, this);
header.setAddressValue(value, first);
headerMap.put(pretty, header);
}
}
public void addParameterableHeader(String name, Parameterable param,
boolean first) {
Header header = null;
String pretty = Header.format(name);
boolean system = Header.isSystemHeader(pretty, this);
if (system) {
throw new IllegalArgumentException(Header.ILLEGAL_ACCESS);
}
if (!ParameterableImpl.isParameterableHeader(pretty, param))
throw new IllegalArgumentException("Specified header isn't defined to hold Parameterable value");
if (headerMap.containsKey(pretty)) {
header = headerMap.get(pretty);
header.setParameterableValue(param, first);
} else {
// already formated using createFormated
header = Header.createFormatted(pretty, this);
header.setParameterableValue(param, first);
headerMap.put(pretty, header);
}
}
public Parameterable getParameterableHeader(String name)
throws ServletParseException {
if (name == null)
throw new NullPointerException("Argument name is null");
String pretty = Header.format(name);
if (!ParameterableImpl.isParameterableHeader(pretty,null))
throw new ServletParseException(" Header can not be parsed as Parameterable");
Header parameterable = headerMap.get(pretty);
if (parameterable == null) {
return null;
}
ParameterableImpl pi = (ParameterableImpl) parameterable.getParameterableValue();
if (pi != null) {
pi.setModifiable(_isCommitted());
}
return pi;
}
public ListIterator<?extends Parameterable> getParameterableHeaders(
String name) throws ServletParseException {
if (name == null)
throw new NullPointerException("Argument name is null");
String pretty = Header.format(name);
if (!ParameterableImpl.isParameterableHeader(pretty,null))
throw new ServletParseException(" Header can not be parsed as Parameterable");
boolean systemHeader = Header.isSystemHeader(pretty, this);
if (headerMap.containsKey(pretty)) {
return new SipListIterator<Parameterable>(headerMap.get(pretty)
.getParameterableValues(),
systemHeader);
} else {
return Collections.EMPTY_LIST.listIterator();
}
}
public void setParameterableHeader(String name, Parameterable param) {
Header header = null;
String pretty = Header.format(name);
boolean system = Header.isSystemHeader(pretty, this);
if (system) {
throw new IllegalArgumentException(Header.ILLEGAL_ACCESS);
}
if (!ParameterableImpl.isParameterableHeader(pretty, param))
throw new IllegalArgumentException("Specified header isn't defined to hold Parameterable value");
validateMessageCommitted();
if (headerMap.containsKey(pretty)) {
header = headerMap.get(pretty);
header.removeValues();
header.setParameterableValue(param, false);
} else {
header = Header.createFormatted(pretty, this);
header.setParameterableValue(param, false);
headerMap.put(pretty, header);
}
}
/* To be implemented */
public HeaderForm getHeaderForm() {
return headerForm;
}
public void setHeaderForm(HeaderForm form) {
validateMessageCommitted();
headerForm = form;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getCallId()
*/
public String getCallId() {
return headerMap.get(Header.CALL_ID).getValue();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getExpires()
*/
public int getExpires() {
Header header = headerMap.get(Header.EXPIRES);
if (header == null) {
return -1;
}
String exp = header.getValue();
if (exp == null) {
return -1;
}
return Integer.parseInt(exp);
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#setExpires(int)
*/
public void setExpires(int seconds) {
// TODO Could be optimized since no pretty print is required in this
// case
setPrettyHeader(Header.EXPIRES, String.valueOf(seconds));
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getCharacterEncoding()
*/
public String getCharacterEncoding() {
Header h = headerMap.get(Header.CONTENT_ENCODING);
if (h != null) {
return h.getValue();
}
// This method should return null if the message does not specify
// a character encoding. The service will use UTF-8 as default, SSA1.0.
Header sh = headerMap.get(Header.CONTENT_TYPE);
if (sh != null) {
String value = sh.getValue();
if (value != null) {
_content_enc = ParserHelper.getValue(value, "charset", ";");
}
if (_content_enc != null) {
return _content_enc;
}
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#setCharacterEncoding(java.lang.String)
*/
public void setCharacterEncoding(String enc)
throws UnsupportedEncodingException {
if (!Charset.isSupported(enc)) {
throw new UnsupportedEncodingException("CharSet: " + enc);
}
_setCharacterEncoding(enc);
}
protected void _setCharacterEncoding(String enc) {
validateMessageCommitted();
Header ceh = headerMap.get(Header.CONTENT_ENCODING);
if (ceh == null) {
ceh = new MultiLineHeader(Header.CONTENT_ENCODING, false);
headerMap.put(Header.CONTENT_ENCODING,ceh);
} else {
ceh.removeValues();
}
ceh.setValue(enc,false);
// TODO see what encodings we should support
// Perfect thing to write in a SAD
Header h = headerMap.get(Header.CONTENT_TYPE);
if (h != null) {
String newEnc = ParserHelper.replaceParam(h.getValue(), "charset",
enc, ";", true);
setPrettyHeader(Header.CONTENT_TYPE, newEnc);
_content_enc = enc;
}
}
public int getContentLengthHeader() {
if (headerMap.get(Header.CONTENT_LENGTH) == null) {
// fix so that SipParser notices when no contentLength is set
return -1;
}
return getContentLength();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getContentLength()
*/
public int getContentLength() {
Header header = headerMap.get(Header.CONTENT_LENGTH);
if (header == null) {
return 0;
}
String len = header.getValue();
if (len == null) {
return 0;
}
return Integer.parseInt(len);
}
public int getMessageSize() {
/*
if ((_content_byte == null) && (_content_obj == null)) {
return 0;
} else if (_content_byte != null) {
return _content_byte.length;
} else if (_content_obj != null) {
return _content_obj.toString().length();
}
return 0;
*/
return getContentLength();
// TODO - Add the header size + requri
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getContentType()
*/
public String getContentType() {
if ((_content_obj == null) && (_content_byte == null)) {
return null;
}
if ((_content_byte != null) && (_content_byte.length == 0)) {
return null;
}
Header h = headerMap.get(Header.CONTENT_TYPE);
if (h != null) {
return h.getValue();
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getRawContent()
*/
public byte[] getRawContent() throws IOException {
byte[] bytes = null;
if ((_content_byte != null) || (_content_obj != null)) {
Header sh = headerMap.get(Header.CONTENT_TYPE);
if (sh != null) {
String newEnc = ParserHelper.getValue(sh.getValue(), "charset",
";");
if (newEnc != null) {
_content_enc = newEnc;
}
if (_content_obj != null) {
if (_content_obj instanceof Multipart) {
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
((Multipart) _content_obj).writeTo(stream);
bytes = stream.toByteArray();
stream.close();
} catch (MessagingException e) {
throw new IOException(e.getMessage());
}
} else {
String msg = _content_obj.toString();
bytes = msg.getBytes(_content_enc);
}
} else if (_content_byte != null) {
return _content_byte;
}
}
}
return bytes;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getContent()
*/
public Object getContent() throws IOException, UnsupportedEncodingException {
Object body = null;
Header h = headerMap.get(Header.CONTENT_TYPE);
if (h != null) {
String mediaType = ParserHelper.getFirstToken(h.getValue(), "/");
String charset = ParserHelper.getValue(h.getValue(), "charset", ";");
if (_content_byte != null) {
if (charset == null) {
charset = _content_enc;
if (charset == null) {
charset = _default_enc;
}
}
if (!Charset.isSupported(charset)) {
throw new UnsupportedEncodingException("CharSet: " + charset);
}
// Return a string if it is text
if ("text".equalsIgnoreCase(mediaType)) {
body = getContentAsString(charset);
}
// Return a MimeMultipart if we have one
else if ((_content_obj != null) &&
"multipart".equalsIgnoreCase(mediaType) &&
(_content_obj instanceof Multipart)) {
body = _content_obj;
}
// Unknown content, return a byte array
else {
body = getRawContent();
}
} else if (_content_obj != null) {
if ("multipart".equalsIgnoreCase(mediaType) &&
(_content_obj instanceof Multipart)) {
body = _content_obj;
}
}
}
return body;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#setContent(java.lang.Object,
* java.lang.String)
*/
public void setContent(Object content, String contentType)
throws UnsupportedEncodingException {
validateMessageCommitted();
if ((content == null) || (contentType == null)) {
throw new NullPointerException("null content");
}
int contentLength = -1;
_content_byte = null;
_content_obj = null;
setContentType(contentType);
String mediatype = ParserHelper.getFirstToken(contentType, "/");
if (mediatype == null) {
throw new UnsupportedEncodingException(
"media type not known or null");
}
if (mediatype.equalsIgnoreCase("text")) {
if (content instanceof byte[]) {
_content_byte = (byte[]) content;
contentLength = _content_byte.length;
} else if (content instanceof String) {
String encoding = getCharacterEncoding();
if (encoding == null) {
encoding = _default_enc;
}
if (!Charset.isSupported(encoding)) {
throw new UnsupportedEncodingException("CharSet: " + encoding);
}
_content_byte = ((String) content).getBytes(encoding);
contentLength = _content_byte.length;
} else {
_content_obj = content.toString();
contentLength = _content_obj.toString().length();
}
} else if (mediatype.equalsIgnoreCase("multipart")) {
if (content instanceof Multipart) {
_content_obj = content;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
((Multipart) _content_obj).writeTo(stream);
contentLength = stream.toByteArray().length;
} catch (IOException e) {
throw new IllegalStateException(e.toString());
} catch (MessagingException e) {
throw new IllegalStateException(e.toString());
} finally {
try {
stream.close();
} catch (IOException e) {
// ignore
}
}
} else {
try {
// getCharacterEncoding can return null.
String encoding = getCharacterEncoding();
if (encoding == null) {
encoding = _default_enc;
}
if (!Charset.isSupported(encoding)) {
throw new UnsupportedEncodingException("CharSet: " + encoding);
}
contentLength = parseMultipart(content, contentType,
encoding);
} catch (MessagingException e) {
throw new IllegalStateException(e.getMessage());
}
}
} else if (content instanceof byte[]) {
_content_byte = (byte[]) content;
contentLength = _content_byte.length;
} else if (content instanceof String) {
String encoding = getCharacterEncoding();
if (encoding == null) {
encoding = _default_enc;
}
_content_byte = ((String) content).getBytes(encoding);
contentLength = _content_byte.length;
} else {
throw new IllegalArgumentException(
"Content object is not supported for this MIME type");
}
if (contentLength > -1) {
setPrettyHeader(Header.CONTENT_LENGTH, String.valueOf(contentLength));
}
}
/* Internal container function called by the Parser */
public void setContent(byte[] content) {
_content_byte = content;
try {
String ctype = getContentType();
if (ctype != null) {
setContent(content, ctype);
}
} catch (UnsupportedEncodingException e) {
}
}
public int getContentMaxLength() {
// TODO read value from jmx config
// TODO define constant if no jmx config
return 500000;
}
public void addContent(byte[] srcBytes, int pos, int length) {
if (_content_byte == null) {
// allocate array to hold the hole content (possibly several deltas)
int content_len = getContentLengthHeader();
if (content_len > getContentMaxLength()) {
throw new RuntimeException(
"Content-length exceeds defined max value:" +
getContentLengthHeader() + "(" + getContentMaxLength() +
")");
}
_content_byte = new byte[getContentLengthHeader()];
}
System.arraycopy(srcBytes, pos, _content_byte, _content_byte_offset,
length);
_content_byte_offset += length;
}
/**
* Internal container function which returns the currrent parsing offset of
* content data (used for internal debugging purpose)
*/
public int getContentOffset() {
return _content_byte_offset;
}
/*
* Internal container function to set "Content-Length" header after
*/
public void internalSetContentLength(int len) {
setPrettyHeader(Header.CONTENT_LENGTH, new Integer(len).toString());
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#setContentLength(int)
*/
public void setContentLength(int len) {
if (isDirection() == Type.Callee || hasSentOnThread())
throw new IllegalStateException("Incoming Message or Message has been sent!");
setPrettyHeader(Header.CONTENT_LENGTH, new Integer(len).toString());
// new IllegalStateException("Instead use the setContent method please!");
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#setContentType(java.lang.String)
*/
public void setContentType(String type) {
setPrettyHeader(Header.CONTENT_TYPE, type); // TODO enc
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getAttribute(java.lang.String)
*/
public Object getAttribute(String name) {
if (attrib != null) {
Object returnValue = attrib.get(name);
if (returnValue != null) return returnValue;
}
if (systemAttrib != null) {
return systemAttrib.get(name);
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getAttributeNames()
*/
public Enumeration<String> getAttributeNames() {
Collection<String> names = null;
if (attrib != null) {
names = new ArrayList<String>(attrib.keySet());
}
if (systemAttrib != null) {
if (names == null) {
names = new ArrayList<String>(systemAttrib.keySet());
} else {
names.addAll(systemAttrib.keySet());
}
}
if (names == null) {
return empty;
} else {
return new EnumerationConverter<String>(names);
}
}
/*
* (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( " Argument name is null ");
}
if (o == null) {
throw new NullPointerException( " Argument object is null ");
}
validateMessageCommitted();
if (attrib == null) {
attrib = new HashMap<String, Object>(1, 1);
}
attrib.put(name, o);
}
public void removeAttribute(String name) {
if (name == null) {
throw new NullPointerException(" name is null ");
}
attrib.remove(name);
}
public void setSystemAttribute(String name, Object o) {
if (name == null) {
throw new NullPointerException( " Argument name is null ");
}
if (o == null) {
throw new NullPointerException( " Argument object is null ");
}
if (systemAttrib == null) {
systemAttrib = new HashMap<String, Object>(1,1);
}
systemAttrib.put(name, o);
}
/*
* (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) {
return getSessionImpl();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getApplicationSession()
*/
public SipApplicationSession getApplicationSession() {
return getApplicationSession(true);
}
public SipSessionBase getSessionImpl() {
return _session;
}
public void setSession(SipSessionBase sessionImpl) {
_session = sessionImpl;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getApplicationSession(boolean)
*/
public SipApplicationSession getApplicationSession(boolean create) {
return getApplicationSessionImpl();
}
public SipApplicationSessionImpl getApplicationSessionImpl() {
return getSessionImpl().getApplicationSessionImpl();
}
private Locale _getAcceptLanguage(String language) {
StringTokenizer st = new StringTokenizer(language, "-");
String localeLang = null;
String localeCountry = null;
String localeVariant = null;
if (st.hasMoreTokens())
localeLang = st.nextToken();
if (st.hasMoreTokens())
localeCountry = st.nextToken();
if (st.hasMoreTokens())
localeVariant = st.nextToken();
if (localeLang != null) {
if (localeCountry != null) {
if (localeVariant != null) {
return new Locale(localeLang, localeCountry, localeVariant);
} else {
return new Locale(localeLang, localeCountry);
}
} else {
return new Locale(localeLang);
}
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getAcceptLanguage()
*/
public Locale getAcceptLanguage() {
Header al = headerMap.get(Header.ACCEPT_LANGUAGE);
if (al != null) {
Iterator<String> i = al.getValues();
String language = null;
float q = 0.0f;
while (i.hasNext()) {
String acceptLanguage = i.next();
ParameterableImpl p = ParameterableImpl.parse(acceptLanguage);
String qParam = p.getParameter("q");
if ( qParam == null) { // default is 1.0 and reurn the Locale
language = p.getValue();
break;
}
float q1 = 0.0f;
try {
q1 = Float.parseFloat(qParam);
} catch (NumberFormatException e) {
continue;
}
if (q1 > q) {
language = p.getValue();
q = q1;
} else if (language == null) {
language = p.getValue();
}
}
return _getAcceptLanguage(language);
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getAcceptLanguages()
*/
public Iterator<Locale> getAcceptLanguages() {
ArrayList<Locale> locales = new ArrayList<Locale>(3);
Header al = headerMap.get(Header.ACCEPT_LANGUAGE);
if (al != null) {
Iterator<String> i = al.getValues();
while (i.hasNext()) {
StringTokenizer st = new StringTokenizer(i.next(), ";");
if (st.hasMoreTokens())
locales.add(_getAcceptLanguage(st.nextToken()));
}
}
return locales.iterator();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#setAcceptLanguage(java.util.Locale)
*/
public void setAcceptLanguage(Locale locale) {
validateMessageCommitted();
if (locale == null) {
headerMap.remove(Header.ACCEPT_LANGUAGE);
} else {
Header al = headerMap.get(Header.ACCEPT_LANGUAGE);
if (al == null) {
al = new MultiLineHeader(Header.ACCEPT_LANGUAGE, false);
headerMap.put(Header.ACCEPT_LANGUAGE, al);
} else {
al.removeValues();
}
al.setValue(locale.getLanguage(), false);
}
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#addAcceptLanguage(java.util.Locale)
*/
public void addAcceptLanguage(Locale locale) {
validateMessageCommitted();
Header al = headerMap.get(Header.ACCEPT_LANGUAGE);
if (al == null) {
al = new MultiLineHeader(Header.ACCEPT_LANGUAGE, false);
headerMap.put(Header.ACCEPT_LANGUAGE, al);
}
al.setValue(locale.getLanguage(), false);
// TODO - should be sorted with the other based on q value
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#setContentLanguage(java.util.Locale)
*/
public void setContentLanguage(Locale locale) {
setPrettyHeader(Header.CONTENT_LANGUAGE, locale.getLanguage());
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getContentLanguage()
*/
public Locale getContentLanguage() {
String cl = getHeader(Header.CONTENT_LANGUAGE);
if (cl != null) {
return new Locale(cl);
} else {
} // TODO locale identified by the charset parameter of the
// Content-Type
// header
return Locale.getDefault();
}
public abstract void send() throws IOException;
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#isSecure()
*/
public boolean isSecure() {
return "TLS".equals(getTransport());
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#isCommitted()
*/
public boolean isCommitted() {
return false;
}
private boolean _isCommitted() {
return !_NoJSR289isCommitted && isCommitted();
}
protected void validateMessageCommitted() {
if (_isCommitted()) {
throw new IllegalStateException("Message is already committed");
}
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getRemoteUser()
*/
public String getRemoteUser() {
return _user;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#isUserInRole(java.lang.String)
*/
public boolean isUserInRole(String role) {
AuthModule authModule = getApplicationSessionImpl().getServletDispatcher().getAuthModule();
if (authModule == null) {
return false;
}
String servletName = getApplicationSessionImpl().getCurrentServlet();
return authModule.isUserInRole(servletName, role,getUserPrincipal());
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#isUserInRole(java.lang.String)
*/
public void setRoles(List<String> roles) {
_roles = roles;
}
public List<String> getRoles() {
return _roles;
}
public void setRole(String role) {
_roles = new ArrayList<String>();
_roles.add(role);
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#isUserInRole(java.lang.String)
*/
public String popRole() {
if (_roles != null) {
int size = _roles.size();
if (size > 0) {
return _roles.remove(size - 1);
}
}
return null;
}
public String peekRole() {
int size = _roles.size();
if (size > 0) {
return _roles.get(size - 1);
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getUserPrincipal()
*/
public Principal getUserPrincipal() {
return _principal;
}
public void setCertificate(X509Certificate[] cert) {
_clientCert = cert;
}
public X509Certificate[] getCertificate() {
return _clientCert;
}
/**
* _initialRemote is the original remote address from where
* container received the request (or a response). This will
* be set in the Network Manager. CLB would set this too, if
* it decodes the address from the special header it received
* from the frontend.
*/
public void setInitialRemote(TargetTuple initialRemote) {
_initialRemote = initialRemote;
_remote = initialRemote;
_remoteHop = initialRemote;
}
public TargetTuple getInitialRemote() {
return _initialRemote;
}
/**
* _remote is the target-tuple that is used by the container to
* the other party it is communicating with. This will be set
* by different places in the container.
*/
public void setRemote(TargetTuple remote) {
_remote = remote;
}
public TargetTuple getRemote() {
return _remote;
}
/**
* oi is the target-tuple that is used by the container to
* determine the Network interface that will be used to send the message
* out.
*/
public void setOutboundInterface(OutboundInterface outboundinterface) {
oi = outboundinterface;
}
public OutboundInterface getOutboundInterface() {
return oi;
}
/**
* Address of the last hop from where the container received
* this incoming message. This could be localhost, if App
* router has internally routed the request.
*/
public void setRemoteHop(TargetTuple remoteHop) {
_remoteHop = remoteHop;
}
public TargetTuple getRemoteHop() {
return _remoteHop;
}
public void setLocal(InetSocketAddress local) {
_local = local;
}
public InetSocketAddress getLocal() {
return _local;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getLocalAddr()
*/
public String getLocalAddr() {
if (_local != null) {
return _local.getAddress().getHostAddress();
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getLocalPort()
*/
public int getLocalPort() {
if (_local != null) {
return _local.getPort();
}
return -1;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getRemoteAddr()
*/
public String getRemoteAddr() {
if (_remoteHop != null) {
return _remoteHop.getIP();
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getInitialRemoteAddr()
*/
public String getInitialRemoteAddr() {
if (_initialRemote != null) {
return _initialRemote.getIP();
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getRemotePort()
*/
public int getRemotePort() {
if (_remoteHop != null) {
return _remoteHop.getPort();
}
return -1;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getInitialRemotePort()
*/
public int getInitialRemotePort() {
if (_initialRemote != null) {
return _initialRemote.getPort();
}
return -1;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getTransport()
*/
public String getTransport() {
if (_remote != null) {
return _remote.getProtocol().name().toUpperCase();
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.sip.SipServletMessage#getInitialTransport()
*/
public String getInitialTransport() {
if (_initialRemote != null) {
return _initialRemote.getProtocol().name().toUpperCase();
}
return null;
}
/****************************************************************************
* Checks the To,From,Cseq,Call-Id
*
* @return
*/
/**
* Return true if no to tag has been set in the message otherwise false.
*
* @return true if no to tag has been set in the message otherwise false.
*/
public boolean hasToTag() {
return getToImpl().getParameter(AddressImpl.TAG_PARAM) != null;
}
public boolean isValidMessage() {
// TODO implement
return false;
}
public void pushTransactionDispatcher(Dispatcher disp) {
_transactionStack.add(disp);
}
public void pushApplicationDispatcher(Dispatcher disp) {
_applicationStack.add(disp);
}
public void clearTransactionDispatchers() {
_transactionStack.clear();
}
public void clearApplicationDispatchers() {
_applicationStack.clear();
}
public abstract Dispatcher popDispatcher();
public abstract Dispatcher peekDispatcher();
String toDebugString() {
StringBuilder sb = new StringBuilder("Call-ID: ");
sb.append(headerMap.get(Header.CALL_ID).getValue());
sb.append(" To-tag: ");
try {
sb.append(headerMap.get(Header.TO).getAddressValue()
.getParameter(AddressImpl.TAG_PARAM));
} catch (Exception e) {
sb.append("undefined");
}
sb.append(" From-tag: ");
try {
sb.append(headerMap.get(Header.FROM).getAddressValue()
.getParameter(AddressImpl.TAG_PARAM));
} catch (Exception e) {
sb.append("undefined");
}
sb.append(" CSeq: ");
sb.append(headerMap.get(Header.CSEQ).getValue());
return sb.toString();
}
/**
* The method called when a service called send method. This is checked in
* the ApplicationDispatcher whether to continue executing other services or
* stopping. Has to be set to false first to activate the function for the
* current thread, this is in order not to loose memory in non Sip container
* threads like from EJB,Timers and Http container.
*
* @param hasSent
* A boolean.
*/
public void setSentOnThread(boolean hasSent) {
long tid = Thread.currentThread().getId();
if (hasSent) {
if (sentMap.containsKey(tid)) {
sentMap.put(tid, Boolean.TRUE);
}
} else { //Init function for thread
sentMap.put(tid, Boolean.FALSE);
}
}
/**
* The method return a boolean indicating if a service has sent a response or
* generate a request to break the execution of other services.
* Return null if not initialized in thread by : setSentOnThread(false)
*
* @return
*/
public boolean hasSentOnThread() {
Boolean b = sentMap.get(Thread.currentThread().getId());
if (b == null) {
return false;
} else {
return b.booleanValue();
}
}
/**
* Helper function, if not activated setSentOnThread(true) will not be saved.
* This is in order that threads sending SIP messages that does not need
* to se this status will not consume memory.
*
*/
public void activateSentOnThread() {
setSentOnThread(false);
}
/**
* Clear should be called in a finally statemnt to always clean up.
* If not done each thread in the system may consume memory in the map.
* This should be avoided by proper clean up!
*/
public void clearSentOnThread() {
sentMap.remove(Thread.currentThread().getId());
}
/**
* States that a Contact header should be added to this message
*/
public void indicateContact() {
_IsContactIndicated = true;
}
/**
* Returns that a Contact header should be added to this message
*
* @return whether a Contact header should be added to this message or not
*/
public boolean isContactIndicated() {
return _IsContactIndicated;
}
/**
* This method returns the content-length for a multipart message.
*
* @param content -
* the content
* @param contentType -
* the content type
* @param charSet -
* encoding
* @return content-length.
* @throws UnsupportedEncodingException
* @throws MessagingException
*/
private int parseMultipart(Object content, String contentType,
String charSet) throws UnsupportedEncodingException, MessagingException {
if (content instanceof byte[]) {
ByteArrayDataSource bds = new ByteArrayDataSource((byte[])content,
contentType);
_content_obj = new MimeMultipart(bds);
return ((byte[])content).length;
}
if (content instanceof String) {
String multipart = (String) content;
_content_obj = new MimeMultipart(new StringDataSource(multipart,
contentType, charSet));
return multipart.length();
}
throw new IllegalArgumentException(
"Content object needs to be a Multipart object, byte[], " +
"or a String for MIME multipart type");
}
/**
* Used with getContent().
*
* @param charSet -
* the encoding to be used
* @return - the content as a String encoded with charSet or null if the
* content is null.
*/
private String getContentAsString(String charSet) {
// If an object, return its toString()
if (_content_obj != null) {
return _content_obj.toString();
} else if (_content_byte != null) {
try {
// Encode it
return new String(_content_byte, charSet);
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Unsupported encoding " + e);
}
}
return null;
}
public boolean isHeadersComplete() {
return _headersComplete;
}
public void setHeadersComplete(boolean complete) {
_headersComplete = complete;
}
public boolean isMessageComplete() {
return _messageComplete;
}
public void setMessageComplete(boolean complete) {
_messageComplete = complete;
String ctype = getContentType();
if (ctype != null) {
try {
setContent(_content_byte, ctype);
} catch (UnsupportedEncodingException e) {
}
}
}
public DialogFragment getDialog() {
return _dialog;
}
public void setDialog(DialogFragment dialog) {
_dialog = dialog;
}
public String getFragmentId() {
return _fragmentId;
}
public void addInternalHeader(String name, String value) {
Header header = null;
String pretty = Header.format(name);
if (headerMap.containsKey(pretty)) {
header = headerMap.get(pretty);
header.removeValues();
header.setValue(value, true);
} else {
header = Header.createFormatted(pretty, this);
header.setValue(value, true);
headerMap.put(pretty, header);
}
}
/**
* Returns true if the message has a body. This method was added for the
* solution of HF73291, which says that a message with a body but missing a
* Content-Type header should be rejected with a 400 response.
*
* @return
*/
public boolean hasBody() {
return (_content_byte != null) || (_content_obj != null);
}
/**
* Extracts the Cseq number from the message.
*
* @param m
* the messge holding the Cseq value
* @return the CSeq number
*/
public int getCSeqNumber() throws NumberFormatException {
String CSeq = getHeader("CSeq");
if (CSeq == null) {
throw new NumberFormatException(
"Could not extract CSeq number from message.");
}
int posStart = 0;
// trim
while ((CSeq.charAt(posStart) == ' ') && (posStart < CSeq.length())) {
++posStart;
}
int posStop = posStart;
// find end of integer, CSeq number
while (Character.isDigit(CSeq.charAt(posStop)) &&
(posStop < CSeq.length())) {
++posStop;
}
if (posStop >= CSeq.length()) {
// the CSeq is corrupt
throw new NumberFormatException(
"Could not extract CSeq number from message.");
}
return Integer.parseInt(CSeq.substring(posStart, posStop));
}
public void setUser(String user) {
_user = user;
}
public void setUserPrincipal(Principal value) {
_principal = value;
}
/**
* Translate the <code>SipServletMessageImpl</code> bytes into
* a <code>ByteBuffer</code>.
*
* @param byteBuffer The byteBuffer to store the bytes.
* @return byteBuffer The byteBuffer to store the bytes.
*/
/*abstract public ByteBuffer toBuffer(ByteBuffer byteBuffer)
throws UnsupportedEncodingException;*/
abstract ByteBuffer toBufferFirstline(ByteBuffer byteBuffer)
throws UnsupportedEncodingException;
/**
* returns true if there is data in this request which should be copied to
* the writebuffer and sent via the link (e.g. tcp)
*
* @return
*/
public boolean toBufferHasRemaining() {
synchronized (byteBufferLock){
return toBufferContentOffset != ((toBufferContent == null) ? 0
: toBufferContent.length);
}
}
/**
* resets some variables used to hold state during transmission for the case
* when msgsize > buffersize
*/
public void toBufferInit() {
synchronized (byteBufferLock) {
toBufferContent = null;
toBufferContentOffset = -1;
toBufferHeaderOffset = 0;
}
}
/**
* puts the data in this message to the supplied ByteBuffer. The invocation
* of this method has to be repeated until toBufferHasRemaining() return
* false.
*
* @param bb
* @return
* @throws UnsupportedEncodingException
* Thrown when SipFactoryImpl.SIP_CHARSET encoding is not supported.
*/
public ByteBuffer toBuffer(ByteBuffer bb)
throws UnsupportedEncodingException {
/*
* This "bigmessage fix" is based on the assumption that the headers will
* fit into the provided writeBuffer (typical size 8K)
*/
synchronized (byteBufferLock) {
if (toBufferContentOffset == -1) {
toBufferContentOffset = 0;
toBufferFirstline(bb);
int len = 0;
// byte[] content = null;
try {
toBufferContent = getRawContent();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (toBufferContent != null) {
len = toBufferContent.length;
}
Header cl = headerMap.get(Header.CONTENT_LENGTH);
if (cl == null) {
cl = new SingleLineHeader(Header.CONTENT_LENGTH, false);
cl.setValue(new StringBuilder().append(len).toString(), false);
headerMap.put(Header.CONTENT_LENGTH, cl);
} else {
cl.setValue(new StringBuilder().append(len).toString(), false);
}
HashMap<String, Header> clonedHeaders = headerMap;
if (headerForm == HeaderForm.COMPACT) {
clonedHeaders = new HashMap<String, Header>(headerMap);
for (String s : Header.LONG_TO_SHORT_MAP.keySet()) {
if (clonedHeaders.containsKey(s)) {
Header h = clonedHeaders.remove(s);
h.setName(Header.LONG_TO_SHORT_MAP.get(s));
clonedHeaders.put(Header.LONG_TO_SHORT_MAP.get(s), h);
}
}
}
Object[] headers = clonedHeaders.values().toArray();
while (toBufferHeaderOffset < headers.length) {
byte[] h = headers[toBufferHeaderOffset].toString()
.getBytes(SipFactoryImpl.SIP_CHARSET);
if (bb.remaining() < h.length) {
return bb; // There is no more space in this buffer
}
bb.put(h);
toBufferHeaderOffset++;
}
bb.put(SipFactoryImpl.NEW_LINE.getBytes());
}
if ((toBufferContent != null) && (toBufferContent.length > 0)) {
int remainingContent = (toBufferContent.length -
toBufferContentOffset);
int remainingBufferLength = bb.remaining();
int bytesToCopy = (remainingContent < remainingBufferLength)
? remainingContent : remainingBufferLength;
bb.put(toBufferContent, toBufferContentOffset, bytesToCopy);
toBufferContentOffset += bytesToCopy;
}
}
return bb;
}
/**
* Sets the hash key used by the Converged Load Balance to route on.
* @param beKey the back-end hash key
*/
public void setBeKey(String beKey) {
this._beKey = beKey;
}
/**
* Gets the hash key used by the Converged Load Balance to route on.
* @return the hash key used by the Converged Load Balance to route on
*/
public String getBeKey() {
return _beKey;
}
//Optimazation in order not have to do instanceof
public enum SipMessageType {SipRequest,
SipResponse;
}
/**
* Sets the remote that is already resolved.
*/
public void setResolvedRemote(TargetTuple remote) {
_remote = remote;
remoteResolved = true;
}
/**
* Checks if the remote is already resolved
* @return true if the remote has been already been resolved
*/
public boolean isRemoteResolved() {
return remoteResolved;
}
/**
* Gets the retry policy that shall be considered when message has failed on the IO level
* @return the retry policy for this message.
*/
public RetryPolicy getRetryPolicy() {
return retryPolicy;
}
/**
* Sets the message sending error policy.
* @param retryPolicy the policy to apply when the message has failed on the IO level
*/
public void setRetryPolicy(RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
}
/**
* Returns the bekey for request. If bekey is already set on
* request/response, then that value is returned. Else it is retrieved from
* SipApplicationSession associated with request/response.
*
* @return bekey associated with request/response
*/
public String getBeKeyFromSession() {
if(_beKey != null){
return _beKey;
}
if (_session != null) {
SipApplicationSessionImpl sas = _session.getApplicationSessionImpl();
if (sas != null) {
String key = sas.getBeKey();
if(key == null){
_logger.log(Level.WARNING,
"sip.stack.message.cannot_retrieve_bekey_from_sas_id",
new Object[]{sas.getId()});
}
return key;
} else {
_logger.log(Level.WARNING,
"sip.stack.message.cannot_retrieve_bekey_sas_is_null");
}
} else {
_logger.log(Level.WARNING,
"sip.stack.message.cannot_retrieve_bekey_session_is_null");
}
return null;
}
}