Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Conditions Of Use
    *
    * This software was developed by employees of the National Institute of
    * Standards and Technology (NIST), an agency of the Federal Government.
    * Pursuant to title 15 Untied States Code Section 105, works of NIST
    * employees are not subject to copyright protection in the United States
    * and are considered to be in the public domain.  As a result, a formal
    * license is not needed to use the software.
   *
   * This software is provided by NIST as a service and is expressly
   * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
   * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
   * AND DATA ACCURACY.  NIST does not warrant or make any representations
   * regarding the use of the software or the results thereof, including but
   * not limited to the correctness, accuracy, reliability or usefulness of
   * the software.
   *
   * Permission to use this software is contingent upon your acceptance
   * of the terms of this agreement
   *
   * .
   *
   */
Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * /
  
  package gov.nist.javax.sip.message;
  
  
  import java.util.List;
  
 
 /*
  * Acknowledgements: Yanick Belanger sent in a patch for the right content length when the content
  * is a String. Bill Mccormick from Nortel Networks sent in a bug fix for setContent.
  * 
  */
This is the main SIP Message structure.

Author(s):
M. Ranganathan
Version:
1.2 $Revision: 1.55 $ $Date: 2010-03-15 17:01:23 $
Since:
1.1
See also:
gov.nist.javax.sip.parser.StringMsgParser
gov.nist.javax.sip.parser.PipelinedMsgParser
 
 public abstract class SIPMessage extends MessageObject implements javax.sip.message.Message,
         MessageExt {
 
 	// JvB: use static here?
     private String contentEncodingCharset = MessageFactoryImpl.getDefaultContentEncodingCharset();
     
     /*
      * True if this is a null request.
      */
     protected boolean nullRequest;
    
    
unparsed headers
 
     protected LinkedList<StringunrecognizedHeaders;

    
List of parsed headers (in the order they were added)
 
     protected ConcurrentLinkedQueue<SIPHeaderheaders;

    
Direct accessors for frequently accessed headers
 
     protected From fromHeader;
 
     protected To toHeader;
 
     protected CSeq cSeqHeader;
 
     protected CallID callIdHeader;
 
     protected ContentLength contentLengthHeader;
 
     protected MaxForwards maxForwardsHeader;
 
     // Cumulative size of all the headers.
     protected int size;
 
     // Payload
     protected String messageContent;
 
     protected byte[] messageContentBytes;
 
     protected Object messageContentObject;
 
     // Table of headers indexed by name.
     private Hashtable<StringSIPHeadernameTable;

    
The application data pointer. This is un-interpreted by the stack. This is provided as a convenient way of keeping book-keeping data for applications.
 
     protected Object applicationData;
 
     private String forkId;

    
Return true if the header belongs only in a Request.

Parameters:
sipHeader is the header to test.
 
     public static boolean isRequestHeader(SIPHeader sipHeader) {
         return sipHeader instanceof AlertInfo || sipHeader instanceof InReplyTo
                 || sipHeader instanceof Authorization || sipHeader instanceof MaxForwards
                 || sipHeader instanceof UserAgent || sipHeader instanceof Priority
                 || sipHeader instanceof ProxyAuthorization || sipHeader instanceof ProxyRequire
                 || sipHeader instanceof ProxyRequireList || sipHeader instanceof Route
                 || sipHeader instanceof RouteList || sipHeader instanceof Subject
                 || sipHeader instanceof SIPIfMatch;
     }

    
Return true if the header belongs only in a response.

Parameters:
sipHeader is the header to test.
 
     public static boolean isResponseHeader(SIPHeader sipHeader) {
         return sipHeader instanceof ErrorInfo || sipHeader instanceof ProxyAuthenticate
                 || sipHeader instanceof Server || sipHeader instanceof Unsupported
                 || sipHeader instanceof RetryAfter || sipHeader instanceof Warning
                 || sipHeader instanceof WWWAuthenticate || sipHeader instanceof SIPETag
                 || sipHeader instanceof RSeq;
 
     }

    
Get the headers as a linked list of encoded Strings

Returns:
a linked list with each element of the list containing a string encoded header in canonical form.
 
         LinkedList<Stringretval = new LinkedList<String>();
         Iterator<SIPHeaderli = .iterator();
         while (li.hasNext()) {
             SIPHeader sipHeader = (SIPHeaderli.next();
             if (sipHeader instanceof SIPHeaderList) {
                 SIPHeaderList< ? > shl = (SIPHeaderList< ? >) sipHeader;
                 retval.addAll(shl.getHeadersAsEncodedStrings());
             } else {
                 retval.add(sipHeader.encode());
             }
         }
 
         return retval;
     }

    
Encode only the message and exclude the contents (for debugging);

Returns:
a string with all the headers encoded.
 
     protected String encodeSIPHeaders() {
         StringBuffer encoding = new StringBuffer();
         Iterator<SIPHeaderit = this..iterator();
 
         while (it.hasNext()) {
             SIPHeader siphdr = (SIPHeaderit.next();
             if (!(siphdr instanceof ContentLength))
                 siphdr.encode(encoding);
         }
 
         return .encode(encoding).append().toString();
     }

    
Encode all the headers except the contents. For debug logging.
 
     public abstract String encodeMessage();

    
Get A dialog identifier constructed from this messsage. This is an id that can be used to identify dialogs.

Parameters:
isServerTransaction is a flag that indicates whether this is a server transaction.
 
     public abstract String getDialogId(boolean isServerTransaction);

    
Template match for SIP messages. The matchObj is a SIPMessage template to match against. This method allows you to do pattern matching with incoming SIP messages. Null matches wild card.

Parameters:
other is the match template to match against.
Returns:
true if a match occured and false otherwise.
 
     public boolean match(Object other) {
         if (other == null)
             return true;
         if (!other.getClass().equals(this.getClass()))
             return false;
         SIPMessage matchObj = (SIPMessageother;
         Iterator<SIPHeaderli = matchObj.getHeaders();
         while (li.hasNext()) {
             SIPHeader hisHeaders = (SIPHeaderli.next();
             List<SIPHeadermyHeaders = this.getHeaderList(hisHeaders.getHeaderName());
 
             // Could not find a header to match his header.
             if (myHeaders == null || myHeaders.size() == 0)
                 return false;
 
             if (hisHeaders instanceof SIPHeaderList) {
                 ListIterator< ? > outerIterator = ((SIPHeaderList< ? >) hisHeaders)
                         .listIterator();
                 while (outerIterator.hasNext()) {
                     SIPHeader hisHeader = (SIPHeaderouterIterator.next();
                     if (hisHeader instanceof ContentLength)
                         continue;
                     ListIterator< ? > innerIterator = myHeaders.listIterator();
                     boolean found = false;
                     while (innerIterator.hasNext()) {
                         SIPHeader myHeader = (SIPHeaderinnerIterator.next();
                         if (myHeader.match(hisHeader)) {
                             found = true;
                             break;
                         }
                     }
                     if (!found)
                         return false;
                 }
             } else {
                 SIPHeader hisHeader = hisHeaders;
                 ListIterator<SIPHeaderinnerIterator = myHeaders.listIterator();
                 boolean found = false;
                 while (innerIterator.hasNext()) {
                     SIPHeader myHeader = (SIPHeaderinnerIterator.next();
                     if (myHeader.match(hisHeader)) {
                         found = true;
                         break;
                     }
                 }
                 if (!found)
                     return false;
             }
         }
         return true;
 
     }

    
Merge a request with a template

Parameters:
template -- template to merge with.
 
     public void merge(Object template) {
         if (!template.getClass().equals(this.getClass()))
             throw new IllegalArgumentException("Bad class " + template.getClass());
         SIPMessage templateMessage = (SIPMessagetemplate;
         Object[] templateHeaders = templateMessage.headers.toArray();
         for (int i = 0; i < templateHeaders.lengthi++) {
             SIPHeader hdr = (SIPHeadertemplateHeaders[i];
             String hdrName = hdr.getHeaderName();
             List<SIPHeadermyHdrs = this.getHeaderList(hdrName);
             if (myHdrs == null) {
                 this.attachHeader(hdr);
             } else {
                 ListIterator<SIPHeaderit = myHdrs.listIterator();
                 while (it.hasNext()) {
                     SIPHeader sipHdr = (SIPHeaderit.next();
                     sipHdr.merge(hdr);
                 }
             }
         }
 
     }

    
Encode this message as a string. This is more efficient when the payload is a string (rather than a binary array of bytes). If the payload cannot be encoded as a UTF-8 string then it is simply ignored (will not appear in the encoded message).

Returns:
The Canonical String representation of the message (including the canonical string representation of the SDP payload if it exists).
 
     public String encode() {
         StringBuffer encoding = new StringBuffer();
         Iterator<SIPHeaderit = this..iterator();
 
         while (it.hasNext()) {
             SIPHeader siphdr = (SIPHeaderit.next();
             if (!(siphdr instanceof ContentLength))
                 encoding.append(siphdr.encode());
         }
         // Append the unrecognized headers. Headers that are not
         // recognized are passed through unchanged.
         for (String unrecognized : this.) {
             encoding.append(unrecognized).append();
         }
 
         encoding.append(.encode()).append();
 
         if (this. != null) {
             String mbody = this.getContent().toString();
 
             encoding.append(mbody);
         } else if (this. != null || this. != null) {
 
             String content = null;
             try {
                 if ( != null)
                     content = ;
                 else {
                 	// JvB: Check for 'charset' parameter which overrides the default UTF-8
                     content = new String(getCharset() );
                 }
             } catch (UnsupportedEncodingException ex) {
             	InternalErrorHandler.handleException(ex);
             }
 
             encoding.append(content);
         }
         return encoding.toString();
     }

    
Encode the message as a byte array. Use this when the message payload is a binary byte array.

Returns:
The Canonical byte array representation of the message (including the canonical byte array representation of the SDP payload if it exists all in one contiguous byte array).
 
     public byte[] encodeAsBytes(String transport) {
         if (this instanceof SIPRequest && ((SIPRequestthis).isNullRequest()) {
             return "\r\n\r\n".getBytes();
         }
         // JvB: added to fix case where application provides the wrong transport
         // in the topmost Via header
         ViaHeader topVia = (ViaHeaderthis.getHeader(.);
         try {
             topVia.setTransport(transport);
         } catch (ParseException e) {
             InternalErrorHandler.handleException(e);
         }
 
         StringBuffer encoding = new StringBuffer();
         synchronized (this.) {
             Iterator<SIPHeaderit = this..iterator();
 
             while (it.hasNext()) {
                 SIPHeader siphdr = (SIPHeaderit.next();
                 if (!(siphdr instanceof ContentLength))
                     siphdr.encode(encoding);
 
             }
         }
         .encode(encoding);
         encoding.append();
 
         byte[] retval = null;
         byte[] content = this.getRawContent();
         if (content != null) {
             // Append the content
 
             byte[] msgarray = null;
             try {
                 msgarray = encoding.toString().getBytesgetCharset() );
             } catch (UnsupportedEncodingException ex) {
                 InternalErrorHandler.handleException(ex);
             }
 
             retval = new byte[msgarray.length + content.length];
             System.arraycopy(msgarray, 0, retval, 0, msgarray.length);
             System.arraycopy(content, 0, retvalmsgarray.lengthcontent.length);
         } else {
             // Message content does not exist.
 
             try {
                 retval = encoding.toString().getBytesgetCharset() );
             } catch (UnsupportedEncodingException ex) {
                 InternalErrorHandler.handleException(ex);
             }
         }
         return retval;
     }

    
clone this message (create a new deep physical copy). All headers in the message are cloned. You can modify the cloned copy without affecting the original. The content is handled as follows: If the content is a String, or a byte array, a new copy of the content is allocated and copied over. If the content is an Object that supports the clone method, then the clone method is invoked and the cloned content is the new content. Otherwise, the content of the new message is set equal to the old one.

Returns:
A cloned copy of this object.
 
     public Object clone() {
         SIPMessage retval = (SIPMessagesuper.clone();
         retval.nameTable = new Hashtable<StringSIPHeader>();
         retval.fromHeader = null;
         retval.toHeader = null;
         retval.cSeqHeader = null;
         retval.callIdHeader = null;
         retval.contentLengthHeader = null;
         retval.maxForwardsHeader = null;
         if (this. != null) {
             retval.headers = new ConcurrentLinkedQueue<SIPHeader>();
             for (Iterator<SIPHeaderiter = .iterator(); iter.hasNext();) {
                 SIPHeader hdr = (SIPHeaderiter.next();
                 retval.attachHeader((SIPHeaderhdr.clone());
             }
 
         }
         if (this. != null)
             retval.messageContentBytes = (byte[]) this..clone();
         if (this. != null)
             retval.messageContentObject = makeClone();
         retval.unrecognizedHeaders = this.;
         return retval;
     }

    
Get the string representation of this header (for pretty printing the generated structure).

Returns:
Formatted string representation of the object. Note that this is NOT the same as encode(). This is used mainly for debugging purposes.
 
     public String debugDump() {
          = "";
         sprint("SIPMessage:");
         sprint("{");
         try {
 
             Field[] fields = this.getClass().getDeclaredFields();
             for (int i = 0; i < fields.lengthi++) {
                 Field f = fields[i];
                 Class< ? > fieldType = f.getType();
                 String fieldName = f.getName();
                 if (f.get(this) != null && SIPHeader.class.isAssignableFrom(fieldType)
                         && fieldName.compareTo("headers") != 0) {
                     sprint(fieldName + "=");
                     sprint(((SIPHeaderf.get(this)).debugDump());
                 }
             }
         } catch (Exception ex) {
             InternalErrorHandler.handleException(ex);
         }
 
         sprint("List of headers : ");
         sprint(.toString());
         sprint("messageContent = ");
         sprint("{");
         sprint();
         sprint("}");
         if (this.getContent() != null) {
             sprint(this.getContent().toString());
         }
         sprint("}");
         return ;
     }

    
Constructor: Initializes lists and list headers. All the headers for which there can be multiple occurances in a message are derived from the SIPHeaderListClass. All singleton headers are derived from SIPHeader class.
 
     public SIPMessage() {
         this. = new LinkedList<String>();
         this. = new ConcurrentLinkedQueue<SIPHeader>();
          = new Hashtable<StringSIPHeader>();
         try {
             this.attachHeader(new ContentLength(0), false);
         } catch (Exception ex) {
         }
     }

    
Attach a header and die if you get a duplicate header exception.

Parameters:
h SIPHeader to attach.
 
     private void attachHeader(SIPHeader h) {
         if (h == null)
             throw new IllegalArgumentException("null header!");
         try {
             if (h instanceof SIPHeaderList) {
                 SIPHeaderList< ? > hl = (SIPHeaderList< ? >) h;
                 if (hl.isEmpty()) {
                     return;
                 }
             }
             attachHeader(hfalsefalse);
         } catch (SIPDuplicateHeaderException ex) {
             // InternalErrorHandler.handleException(ex);
         }
     }

    
Attach a header (replacing the original header).

Parameters:
sipHeader SIPHeader that replaces a header of the same type.
 
     public void setHeader(Header sipHeader) {
         SIPHeader header = (SIPHeadersipHeader;
         if (header == null)
             throw new IllegalArgumentException("null header!");
         try {
             if (header instanceof SIPHeaderList) {
                 SIPHeaderList< ? > hl = (SIPHeaderList< ? >) header;
                 // Ignore empty lists.
                 if (hl.isEmpty())
                     return;
             }
             this.removeHeader(header.getHeaderName());
             attachHeader(headertruefalse);
         } catch (SIPDuplicateHeaderException ex) {
             InternalErrorHandler.handleException(ex);
         }
     }

    
Set a header from a linked list of headers.

Parameters:
headers -- a list of headers to set.
 
     public void setHeaders(java.util.List<SIPHeaderheaders) {
         ListIterator<SIPHeaderlistIterator = headers.listIterator();
         while (listIterator.hasNext()) {
             SIPHeader sipHeader = (SIPHeaderlistIterator.next();
             try {
                 this.attachHeader(sipHeaderfalse);
             } catch (SIPDuplicateHeaderException ex) {
             }
         }
     }

    
Attach a header to the end of the existing headers in this SIPMessage structure. This is equivalent to the attachHeader(SIPHeader,replaceflag,false); which is the normal way in which headers are attached. This was added in support of JAIN-SIP.

Parameters:
h header to attach.
replaceflag if true then replace a header if it exists.
Throws:
SIPDuplicateHeaderException If replaceFlag is false and only a singleton header is allowed (fpr example CSeq).
 
     public void attachHeader(SIPHeader hboolean replaceflagthrows SIPDuplicateHeaderException {
         this.attachHeader(hreplaceflagfalse);
     }

    
Attach the header to the SIP Message structure at a specified position in its list of headers.

Parameters:
header Header to attach.
replaceFlag If true then replace the existing header.
top Location in the header list to insert the header.
Throws:
SIPDuplicateHeaderException if the header is of a type that cannot tolerate duplicates and one of this type already exists (e.g. CSeq header).
java.lang.IndexOutOfBoundsException If the index specified is greater than the number of headers that are in this message.
 
 
     public void attachHeader(SIPHeader headerboolean replaceFlagboolean top)
             throws SIPDuplicateHeaderException {
         if (header == null) {
             throw new NullPointerException("null header");
         }
 
         SIPHeader h;
 
         if (ListMap.hasList(header) && !SIPHeaderList.class.isAssignableFrom(header.getClass())) {
             SIPHeaderList<SIPHeaderhdrList = ListMap.getList(header);
             hdrList.add(header);
             h = hdrList;
         } else {
             h = header;
         }
 
         String headerNameLowerCase = SIPHeaderNamesCache.toLowerCase(h.getName());
         if (replaceFlag) {
             .remove(headerNameLowerCase);
         } else if (.containsKey(headerNameLowerCase) && !(h instanceof SIPHeaderList)) {
             if (h instanceof ContentLength) {
                 try {
                     ContentLength cl = (ContentLengthh;
                     .setContentLength(cl.getContentLength());
                 } catch (InvalidArgumentException e) {
                 }
             }
             // Just ignore duplicate header.
             return;
         }
 
         SIPHeader originalHeader = (SIPHeadergetHeader(header.getName());
 
         // Delete the original header from our list structure.
         if (originalHeader != null) {
             Iterator<SIPHeaderli = .iterator();
             while (li.hasNext()) {
                 SIPHeader next = (SIPHeaderli.next();
                 if (next.equals(originalHeader)) {
                     li.remove();
                 }
             }
         }
 
         if (!.containsKey(headerNameLowerCase)) {
             .put(headerNameLowerCaseh);
             .add(h);
         } else {
             if (h instanceof SIPHeaderList) {
                 SIPHeaderList< ? > hdrlist = (SIPHeaderList< ? >) 
                         .get(headerNameLowerCase);
                 if (hdrlist != null)
                     hdrlist.concatenate((SIPHeaderListhtop);
                 else
                     .put(headerNameLowerCaseh);
             } else {
                 .put(headerNameLowerCaseh);
             }
         }
 
         // Direct accessor fields for frequently accessed headers.
         if (h instanceof From) {
             this. = (Fromh;
         } else if (h instanceof ContentLength) {
             this. = (ContentLengthh;
         } else if (h instanceof To) {
             this. = (Toh;
         } else if (h instanceof CSeq) {
             this. = (CSeqh;
         } else if (h instanceof CallID) {
             this. = (CallIDh;
         } else if (h instanceof MaxForwards) {
             this. = (MaxForwardsh;
         }
 
     }

    
Remove a header given its name. If multiple headers of a given name are present then the top flag determines which end to remove headers from.

Parameters:
headerName is the name of the header to remove.
top -- flag that indicates which end of header list to process.
 
     public void removeHeader(String headerNameboolean top) {
 
         String headerNameLowerCase = SIPHeaderNamesCache.toLowerCase(headerName);
         SIPHeader toRemove = (SIPHeader.get(headerNameLowerCase);
         // nothing to do then we are done.
         if (toRemove == null)
             return;
         if (toRemove instanceof SIPHeaderList) {
             SIPHeaderList< ? > hdrList = (SIPHeaderList< ? >) toRemove;
             if (top)
                 hdrList.removeFirst();
             else
                 hdrList.removeLast();
             // Clean up empty list
             if (hdrList.isEmpty()) {
                 Iterator<SIPHeaderli = this..iterator();
                 while (li.hasNext()) {
                     SIPHeader sipHeader = (SIPHeaderli.next();
                     if (sipHeader.getName().equalsIgnoreCase(headerNameLowerCase))
                         li.remove();
                 }
 
                 // JvB: also remove it from the nameTable! Else NPE in
                 // DefaultRouter
                 .remove(headerNameLowerCase);
             }
         } else {
             this..remove(headerNameLowerCase);
             if (toRemove instanceof From) {
                 this. = null;
             } else if (toRemove instanceof To) {
                 this. = null;
             } else if (toRemove instanceof CSeq) {
                 this. = null;
             } else if (toRemove instanceof CallID) {
                 this. = null;
             } else if (toRemove instanceof MaxForwards) {
                 this. = null;
             } else if (toRemove instanceof ContentLength) {
                 this. = null;
             }
             Iterator<SIPHeaderli = this..iterator();
             while (li.hasNext()) {
                 SIPHeader sipHeader = (SIPHeaderli.next();
                 if (sipHeader.getName().equalsIgnoreCase(headerName))
                     li.remove();
             }
         }
 
     }

    
Remove all headers given its name.

Parameters:
headerName is the name of the header to remove.
 
     public void removeHeader(String headerName) {
 
         if (headerName == null)
             throw new NullPointerException("null arg");
         String headerNameLowerCase = SIPHeaderNamesCache.toLowerCase(headerName);
         SIPHeader removed = (SIPHeader.remove(headerNameLowerCase);
         // nothing to do then we are done.
         if (removed == null)
             return;
 
         // Remove the fast accessor fields.
         if (removed instanceof From) {
             this. = null;
         } else if (removed instanceof To) {
             this. = null;
         } else if (removed instanceof CSeq) {
             this. = null;
         } else if (removed instanceof CallID) {
             this. = null;
         } else if (removed instanceof MaxForwards) {
             this. = null;
         } else if (removed instanceof ContentLength) {
             this. = null;
         }
 
         Iterator<SIPHeaderli = this..iterator();
         while (li.hasNext()) {
             SIPHeader sipHeader = (SIPHeaderli.next();
             if (sipHeader.getName().equalsIgnoreCase(headerNameLowerCase))
                 li.remove();
 
         }
     }

    
Generate (compute) a transaction ID for this SIP message.

Returns:
a string that can be used as a transaction identifier for this message. This can be used for matching responses and requests (i.e. an outgoing request and its matching response have the same computed transaction identifier).
 
     public String getTransactionId() {
         Via topVia = null;
         if (!this.getViaHeaders().isEmpty()) {
             topVia = (Viathis.getViaHeaders().getFirst();
         }
         // Have specified a branch Identifier so we can use it to identify
         // the transaction. BranchId is not case sensitive.
         // Branch Id prefix is not case sensitive.
         if (topVia != null
                 && topVia.getBranch() != null
                 && topVia.getBranch().toUpperCase().startsWith(
                         .)) {
             // Bis 09 compatible branch assignment algorithm.
             // implies that the branch id can be used as a transaction
             // identifier.
             if (this.getCSeq().getMethod().equals(.))
                 return (topVia.getBranch() + ":" + this.getCSeq().getMethod()).toLowerCase();
             else
                 return topVia.getBranch().toLowerCase();
         } else {
             // Old style client so construct the transaction identifier
             // from various fields of the request.
             StringBuffer retval = new StringBuffer();
             From from = (Fromthis.getFrom();
             To to = (Tothis.getTo();
             // String hpFrom = from.getUserAtHostPort();
             // retval.append(hpFrom).append(":");
             if (from.hasTag())
                 retval.append(from.getTag()).append("-");
             // String hpTo = to.getUserAtHostPort();
             // retval.append(hpTo).append(":");
             String cid = this..getCallId();
             retval.append(cid).append("-");
             retval.append(this..getSequenceNumber()).append("-").append(
                     this..getMethod());
             if (topVia != null) {
                 retval.append("-").append(topVia.getSentBy().encode());
                 if (!topVia.getSentBy().hasPort()) {
                     retval.append("-").append(5060);
                 }
             }
             if (this.getCSeq().getMethod().equals(.)) {
                 retval.append(.);
             }
             return retval.toString().toLowerCase().replace(":""-").replace("@""-")
                     + Utils.getSignature();
         }
     }

    
Override the hashcode method ( see issue # 55 ) Note that if you try to use this method before you assemble a valid request, you will get a constant ( -1 ). Beware of placing any half formed requests in a table.
 
     public int hashCode() {
         if (this. == null)
             throw new RuntimeException(
                     "Invalid message! Cannot compute hashcode! call-id header is missing !");
         else
             return this..getCallId().hashCode();
     }

    
Return true if this message has a body.
 
     public boolean hasContent() {
         return  != null ||  != null;
     }

    
Return an iterator for the list of headers in this message.

Returns:
an Iterator for the headers of this message.
 
     public Iterator<SIPHeadergetHeaders() {
         return .iterator();
     }

    
Get the first header of the given name.

Returns:
header -- the first header of the given name.
 
     public Header getHeader(String headerName) {
         return getHeaderLowerCase(SIPHeaderNamesCache.toLowerCase(headerName));
     }
 
     private Header getHeaderLowerCase(String lowerCaseHeaderName) {
         if (lowerCaseHeaderName == null)
             throw new NullPointerException("bad name");
         SIPHeader sipHeader = (SIPHeader.get(lowerCaseHeaderName);
         if (sipHeader instanceof SIPHeaderList)
             return (Header) ((SIPHeaderListsipHeader).getFirst();
         else
             return (HeadersipHeader;
     }

    
Get the contentType header (null if one does not exist).

Returns:
contentType header
 
     
     public ContentType getContentTypeHeader() {
     }
     
     private static final String CONTENT_TYPE_LOWERCASE = SIPHeaderNamesCache
     .toLowerCase(.);

    
    
Get the contentLength header.
 
         return this.getContentLength();
     }

  
    
Get the from header.

Returns:
-- the from header.
 
     public FromHeader getFrom() {
         return (FromHeader;
     }

    
Get the ErrorInfo list of headers (null if one does not exist).

Returns:
List containing ErrorInfo headers.
 
     public ErrorInfoList getErrorInfoHeaders() {
     }
 
     private static final String ERROR_LOWERCASE = SIPHeaderNamesCache.toLowerCase(.);

    
Get the Contact list of headers (null if one does not exist).

Returns:
List containing Contact headers.
 
     public ContactList getContactHeaders() {
         return (ContactListthis.getSIPHeaderListLowerCase();
     }
 
     private static final String CONTACT_LOWERCASE = SIPHeaderNamesCache
             .toLowerCase(.);

    
Get the contact header ( the first contact header) which is all we need for the most part.
 
     public Contact getContactHeader() {
         ContactList clist = this.getContactHeaders();
         if (clist != null) {
             return (Contactclist.getFirst();
 
         } else {
             return null;
         }
     }

    
Get the Via list of headers (null if one does not exist).

Returns:
List containing Via headers.
    public ViaList getViaHeaders() {
    }
    private static final String VIA_LOWERCASE = SIPHeaderNamesCache.toLowerCase(.);

    
Set A list of via headers.

Parameters:
viaList a list of via headers to add.
    public void setVia(java.util.List viaList) {
        ViaList vList = new ViaList();
        ListIterator it = viaList.listIterator();
        while (it.hasNext()) {
            Via via = (Viait.next();
            vList.add(via);
        }
        this.setHeader(vList);
    }

    
Set the header given a list of headers.

Parameters:
sipHeaderList a headerList to set
    public void setHeader(SIPHeaderList<ViasipHeaderList) {
        this.setHeader((HeadersipHeaderList);
    }

    
Get the topmost via header.

Returns:
the top most via header if one exists or null if none exists.
    public Via getTopmostVia() {
        if (this.getViaHeaders() == null)
            return null;
        else
            return (Via) (getViaHeaders().getFirst());
    }

    
Get the CSeq list of header (null if one does not exist).

Returns:
CSeq header
    public CSeqHeader getCSeq() {
        return (CSeqHeader;
    }

    
Get the Authorization header (null if one does not exist).

Returns:
Authorization header.
    public Authorization getAuthorization() {
    }
    private static final String AUTHORIZATION_LOWERCASE = SIPHeaderNamesCache
            .toLowerCase(.);

    
Get the MaxForwards header (null if one does not exist).

Returns:
Max-Forwards header
        return ;
    }

    
Set the max forwards header.

Parameters:
maxForwards is the MaxForwardsHeader to set.
    public void setMaxForwards(MaxForwardsHeader maxForwards) {
        this.setHeader(maxForwards);
    }

    
Get the Route List of headers (null if one does not exist).

Returns:
List containing Route headers
    public RouteList getRouteHeaders() {
    }
    private static final String ROUTE_LOWERCASE = SIPHeaderNamesCache
            .toLowerCase(.);

    
Get the CallID header (null if one does not exist)

Returns:
Call-ID header .
    public CallIdHeader getCallId() {
        return ;
    }

    
Set the call id header.

Parameters:
callId call idHeader (what else could it be?)
    public void setCallId(CallIdHeader callId) {
        this.setHeader(callId);
    }

    
Get the CallID header (null if one does not exist)

Parameters:
callId -- the call identifier to be assigned to the call id header
    public void setCallId(String callIdthrows java.text.ParseException {
        if ( == null) {
            this.setHeader(new CallID());
        }
        .setCallId(callId);
    }

    
Get the RecordRoute header list (null if one does not exist).

Returns:
Record-Route header
    }
    private static final String RECORDROUTE_LOWERCASE = SIPHeaderNamesCache
            .toLowerCase(.);

    
Get the To header (null if one does not exist).

Returns:
To header
    public ToHeader getTo() {
        return (ToHeader;
    }
    public void setTo(ToHeader to) {
        this.setHeader(to);
    }
    public void setFrom(FromHeader from) {
        this.setHeader(from);
    }

    
Get the ContentLength header (null if one does not exist).

Returns:
content-length header.
        return this.;
    }

    
Get the message body as a string. If the message contains a content type header with a specified charset, and if the payload has been read as a byte array, then it is returned encoded into this charset.

Returns:
Message body (as a string)
Throws:
java.io.UnsupportedEncodingException if the platform does not support the charset specified in the content type header.
        if (this. == null && this. == null)
            return null;
        else if (this. == null) {
            this. = new String(getCharset() );
        }
        return this.;
    }

    
Get the message content as an array of bytes. If the payload has been read as a String then it is decoded using the charset specified in the content type header if it exists. Otherwise, it is encoded using the default encoding which is UTF-8.

Returns:
an array of bytes that is the message payload.
    public byte[] getRawContent() {
        try {
            if ( this. != null ) {
                // return messageContentBytes;
            } else if (this. != null) {
                String messageContent = this..toString();
                this. = messageContent.getBytesgetCharset() );
            } else if (this. != null) {
            	this. = .getBytesgetCharset() );                
            }
            return this.;
        } catch (UnsupportedEncodingException ex) {
            InternalErrorHandler.handleException(ex);
            return null;
        }
    }

    
Set the message content given type and subtype.

Parameters:
type is the message type (eg. application)
subType is the message sybtype (eg. sdp)
messageContent is the messge content as a string.
    public void setMessageContent(String typeString subTypeString messageContent) {
        if (messageContent == null)
            throw new IllegalArgumentException("messgeContent is null");
        ContentType ct = new ContentType(typesubType);
        this.setHeader(ct);
        this. = messageContent;
        this. = null;
        this. = null;
        // Could be double byte so we need to compute length
        // after converting to byte[]
        computeContentLength(messageContent);
    }

    
Set the message content after converting the given object to a String.

Parameters:
content -- content to set.
contentTypeHeader -- content type header corresponding to content.
    public void setContent(Object contentContentTypeHeader contentTypeHeader)
            throws ParseException {
        if (content == null)
            throw new NullPointerException("null content");
        this.setHeader(contentTypeHeader);
        this. = null;
        this. = null;
        this. = null;
        if (content instanceof String) {
            this. = (Stringcontent;
        } else if (content instanceof byte[]) {
            this. = (byte[]) content;
        } else
            this. = content;
        computeContentLength(content);
    }

    
Get the content (body) of the message.

Returns:
the content of the sip message.
    public Object getContent() {
        if (this. != null)
            return ;
        else if (this. != null)
            return this.;
        else if (this. != null)
            return this.;
        else
            return null;
    }

    
Set the message content for a given type and subtype.

Parameters:
type is the messge type.
subType is the message subType.
messageContent is the message content as a byte array.
    public void setMessageContent(String typeString subTypebyte[] messageContent) {
        ContentType ct = new ContentType(typesubType);
        this.setHeader(ct);
        this.setMessageContent(messageContent);
        computeContentLength(messageContent);
    }

    
Set the message content for this message.

Parameters:
content Message body as a string.
    public void setMessageContent(String contentboolean strictboolean computeContentLengthint givenLength)
            throws ParseException {
        // Note that that this could be a double byte character
        // set - bug report by Masafumi Watanabe
        computeContentLength(content);
        if ((!computeContentLength)) {
            if ( (!strict && this..getContentLength() != givenLength
                    || this..getContentLength() < givenLength) {
                throw new ParseException("Invalid content length "
                        + this..getContentLength() + " / " + givenLength, 0);
            }
        }
         = content;
         = null;
         = null;
    }

    
Set the message content as an array of bytes.

Parameters:
content is the content of the message as an array of bytes.
    public void setMessageContent(byte[] content) {
        computeContentLength(content);
         = content;
         = null;
         = null;
    }

    
Method to set the content - called by the parser

Parameters:
content
Throws:
java.text.ParseException
    public void setMessageContent(byte[] contentboolean computeContentLengthint givenLength)
            throws ParseException {
        computeContentLength(content);
        if ((!computeContentLength) && this..getContentLength() < givenLength) {
            // System.out.println("!!!!!!!!!!! MISMATCH !!!!!!!!!!!");
            throw new ParseException("Invalid content length "