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.HashSet;
  import java.util.Map;
  import java.util.Set;
  
  
  /*
   * Acknowledgements: Mark Bednarek made a few fixes to this code. Jeff Keyser added two methods
   * that create responses and generate cancel requests from incoming orignial requests without the
   * additional overhead of encoding and decoding messages. Bruno Konik noticed an extraneous
   * newline added to the end of the buffer when encoding it. Incorporates a bug report from Andreas
   * Bystrom. Szabo Barna noticed a contact in a cancel request - this is a pointless header for
   * cancel. Antonis Kyardis contributed bug fixes. Jeroen van Bemmel noted that method names are
   * case sensitive, should use equals() in getting CannonicalName
   * 
   */

The SIP Request structure.

Author(s):
M. Ranganathan
Version:
1.2 $Revision: 1.57 $ $Date: 2010-09-17 20:06:57 $
Since:
1.1
  
  
  public class SIPRequest extends SIPMessage implements javax.sip.message.RequestRequestExt {
  
      private static final long serialVersionUID = 3360720013577322927L;
  
     private static final String DEFAULT_USER = "ip";
 
     private static final String DEFAULT_TRANSPORT = "udp";
 
     private transient Object transactionPointer;
 
     protected RequestLine requestLine;
 
     private transient Object messageChannel;
     
     
 
     private transient Object inviteTransaction// The original invite request for a
     // given cancel request
 
    
Set of target refresh methods, currently: INVITE, UPDATE, SUBSCRIBE, NOTIFY, REFER A target refresh request and its response MUST have a Contact
 
     private static final Set<StringtargetRefreshMethods = new HashSet<String>();
 
     /*
      * A table that maps a name string to its cannonical constant. This is used to speed up
      * parsing of messages .equals reduces to == if we use the constant value.
      * 
      * jeand : Setting the capacity to save on memory since the capacity here will never change
      */
     private static final Map<StringStringnameTable = new ConcurrentHashMap<StringString>(15);
     
     protected static final Set<StringheadersToIncludeInResponse = new HashSet<String>(0);
 
     private static void putName(String name) {
         .put(namename);
     }
 
     static {
 
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
         putName(.);
 
         .add(..toLowerCase());        
     }

    

Returns:
true iff the method is a target refresh
 
     public static boolean isTargetRefresh(String ucaseMethod) {
         return .contains(ucaseMethod);
     }

    

Returns:
true iff the method is a dialog creating method
 
     public static boolean isDialogCreating(String ucaseMethod) {
         return SIPTransactionStack.isDialogCreated(ucaseMethod);
     }
    
    
Set to standard constants to speed up processing. this makes equals comparisons run much faster in the stack because then it is just identity comparision. Character by char comparison is not required. The method returns the String CONSTANT corresponding to the String name.
 
     public static String getCannonicalName(String method) {
 
         if (.containsKey(method))
             return (String.get(method);
         else
             return method;
     }

    
Get the Request Line of the SIPRequest.

Returns:
the request line of the SIP Request.
 
 
     public RequestLine getRequestLine() {
         return ;
     }

    
Set the request line of the SIP Request.

Parameters:
requestLine is the request line to set in the SIP Request.
 
 
     public void setRequestLine(RequestLine requestLine) {
         this. = requestLine;
     }

    
Constructor.
 
     public SIPRequest() {
         super();
     }

    
Convert to a formatted string for pretty printing. Note that the encode method converts this into a sip message that is suitable for transmission. Note hack here if you want to convert the nice curly brackets into some grotesque XML tag.

Returns:
a string which can be used to examine the message contents.
 
     public String debugDump() {
         String superstring = super.debugDump();
          = "";
         sprint(SIPRequest.class.getName());
         sprint("{");
         if ( != null)
             sprint(.debugDump());
         sprint(superstring);
         sprint("}");
         return ;
     }

    
Check header for constraints. (1) Invite options and bye requests can only have SIP URIs in the contact headers. (2) Request must have cseq, to and from and via headers. (3) Method in request URI must match that in CSEQ.
 
     public void checkHeaders() throws ParseException {
         String prefix = "Missing a required header : ";
 
         /* Check for required headers */
 
         if (getCSeq() == null) {
             throw new ParseException(prefix + ., 0);
         }
         if (getTo() == null) {
             throw new ParseException(prefix + ., 0);
         }
 
         if (this. == null || this..getCallId() == null
                 || .getCallId().equals("")) {
             throw new ParseException(prefix + ., 0);
         }
         if (getFrom() == null) {
             throw new ParseException(prefix + ., 0);
         }
         if (getViaHeaders() == null) {
             throw new ParseException(prefix + ., 0);
         }
         if (getMaxForwards() == null) {
             throw new ParseException(prefix + ., 0);
         }
 
         if (getTopmostVia() == null)
             throw new ParseException("No via header in request! ", 0);
 
         if (getMethod().equals(.)) {
             if (getHeader(.) == null)
                 throw new ParseException(prefix + ., 0);
 
             if (getHeader(.) == null)
                 throw new ParseException(prefix + ., 0);
 
         } else if (getMethod().equals(.)) {
             /*
              * For determining the type of the published event state, the EPA MUST include a
              * single Event header field in PUBLISH requests. The value of this header field
              * indicates the event package for which this request is publishing event state.
              */
             if (getHeader(.) == null)
                 throw new ParseException(prefix + ., 0);
         }
 
         /*
          * RFC 3261 8.1.1.8 The Contact header field MUST be present and contain exactly one SIP
          * or SIPS URI in any request that can result in the establishment of a dialog. For the
          * methods defined in this specification, that includes only the INVITE request. For these
          * requests, the scope of the Contact is global. That is, the Contact header field value
          * contains the URI at which the UA would like to receive requests, and this URI MUST be
          * valid even if used in subsequent requests outside of any dialogs.
          * 
          * If the Request-URI or top Route header field value contains a SIPS URI, the Contact
          * header field MUST contain a SIPS URI as well.
          */
         final String method = .getMethod();
         if (SIPTransactionStack.isDialogCreated(method)) {
             if (this.getContactHeader() == null) {
                 // Make sure this is not a target refresh. If this is a target
                 // refresh its ok not to have a contact header. Otherwise
                 // contact header is mandatory.
                 if (this.getToTag() == null)
                     throw new ParseException(prefix + ., 0);
             }
 
             if (.getUri() instanceof SipUri) {
                 String scheme = ((SipUri.getUri()).getScheme();
                 if ("sips".equalsIgnoreCase(scheme)) {
                     SipUri sipUri = (SipUrithis.getContactHeader().getAddress().getURI();
                     if (!sipUri.getScheme().equals("sips")) {
                         throw new ParseException("Scheme for contact should be sips:" + sipUri, 0);
                     }
                 }
             }
         }
 
         /*
          * Contact header is mandatory for a SIP INVITE request.
          */
         /* emmartins: dupe logic, see above
          if (this.getContactHeader() == null
                 && SIPTransactionStack.isDialogCreated(method)) {
             throw new ParseException("Contact Header is Mandatory for a SIP INVITE", 0);
         }*/
 
         if ( != null && method != null
                 && getCSeq().getMethod() != null
                 && method.compareTo(getCSeq().getMethod()) != 0) {
             throw new ParseException("CSEQ method mismatch with  Request-Line ", 0);
 
         }
 
     }

    
Set the default values in the request URI if necessary.
 
     protected void setDefaults() {
         // The request line may be unparseable (set to null by the
         // exception handler.
         if ( == null)
             return;
         String method = .getMethod();
         // The requestLine may be malformed!
         if (method == null)
             return;
         GenericURI u = .getUri();
         if (u == null)
             return;
         if (method.compareTo(.) == 0 || method.compareTo(.) == 0) {
             if (u instanceof SipUri) {
                 SipUri sipUri = (SipUriu;
                 sipUri.setUserParam();
                 try {
                     sipUri.setTransportParam();
                 } catch (ParseException ex) {
                 }
             }
         }
     }

    
Patch up the request line as necessary.
 
     protected void setRequestLineDefaults() {
         String method = .getMethod();
         if (method == null) {
             CSeq cseq = (CSeqthis.getCSeq();
             if (cseq != null) {
                 method = getCannonicalName(cseq.getMethod());
                 .setMethod(method);
             }
         }
     }

    
A conveniance function to access the Request URI.

Returns:
the requestURI if it exists.
 
     public javax.sip.address.URI getRequestURI() {
         if (this. == null)
             return null;
         else
             return (javax.sip.address.URIthis..getUri();
     }

    
Sets the RequestURI of Request. The Request-URI is a SIP or SIPS URI or a general URI. It indicates the user or service to which this request is being addressed. SIP elements MAY support Request-URIs with schemes other than "sip" and "sips", for example the "tel" URI scheme. SIP elements MAY translate non-SIP URIs using any mechanism at their disposal, resulting in SIP URI, SIPS URI, or some other scheme.

Parameters:
uri the new Request URI of this request message
 
     public void setRequestURI(URI uri) {
         if ( uri == null ) {
             throw new NullPointerException("Null request URI");
         }
         if (this. == null) {
             this. = new RequestLine();
         }
         this..setUri((GenericURIuri);
         this. = false;
     }

    
Set the method.

Parameters:
method is the method to set.
Throws:
java.lang.IllegalArgumentException if the method is null
 
     public void setMethod(String method) {
         if (method == null)
             throw new IllegalArgumentException("null method");
         if (this. == null) {
             this. = new RequestLine();
         }
 
         // Set to standard constants to speed up processing.
         // this makes equals compares run much faster in the
         // stack because then it is just identity comparision
 
         String meth = getCannonicalName(method);
         this..setMethod(meth);
 
         if (this. != null) {
             try {
                 this..setMethod(meth);
             } catch (ParseException e) {
             }
         }
     }

    
Get the method from the request line.

Returns:
the method from the request line if the method exits and null if the request line or the method does not exist.
 
     public String getMethod() {
         if ( == null)
             return null;
         else
             return .getMethod();
     }

    
Encode the SIP Request as a string.

Returns:
an encoded String containing the encoded SIP Message.
 
 
     public String encode() {
         String retval;
         if ( != null) {
             this.setRequestLineDefaults();
             retval = .encode() + super.encode();
         } else if (this.isNullRequest()) {
             retval = "\r\n\r\n";
         } else {       
             retval = super.encode();
         }
         return retval;
     }

    
Encode only the headers and not the content.
 
     public StringBuilder encodeMessage(StringBuilder retval) {    	       
         if ( != null) {
             this.setRequestLineDefaults();
             .encode(retval);
             encodeSIPHeaders(retval);
         } else if (this.isNullRequest()) {
             retval.append("\r\n\r\n");
         } else
             retval = encodeSIPHeaders(retval);
         return retval;
 
     }

    
ALias for encode above.
 
     public String toString() {
         return this.encode();
     }

    
Make a clone (deep copy) of this object. You can use this if you want to modify a request while preserving the original

Returns:
a deep copy of this object.
 
 
     public Object clone() {
         SIPRequest retval = (SIPRequestsuper.clone();
         // Do not copy over the tx pointer -- this is only for internal
         // tracking.
         retval.transactionPointer = null;
         if (this. != null)
             retval.requestLine = (RequestLinethis..clone();
 
         return retval;
     }

    
Compare for equality.

Parameters:
other object to compare ourselves with.
 
     public boolean equals(Object other) {
         if (!this.getClass().equals(other.getClass()))
             return false;
         SIPRequest that = (SIPRequestother;
 
         return .equals(that.requestLine) && super.equals(other);
     }

    
Get the message as a linked list of strings. Use this if you want to iterate through the message.

Returns:
a linked list containing the request line and headers encoded as strings.
 
         LinkedList retval = super.getMessageAsEncodedStrings();
         if ( != null) {
             this.setRequestLineDefaults();
             retval.addFirst(.encode());
         }
         return retval;
 
     }

    
Match with a template. You can use this if you want to match incoming messages with a pattern and do something when you find a match. This is useful for building filters/pattern matching responders etc.

Parameters:
matchObj object to match ourselves with (null matches wildcard)
 
     public boolean match(Object matchObj) {
         if (matchObj == null)
             return true;
         else if (!matchObj.getClass().equals(this.getClass()))
             return false;
         else if (matchObj == this)
             return true;
         SIPRequest that = (SIPRequestmatchObj;
         RequestLine rline = that.requestLine;
         if (this. == null && rline != null)
             return false;
         else if (this. == rline)
             return super.match(matchObj);
         return .match(that.requestLine) && super.match(matchObj);
 
     }

    
Encode this into a byte array. This is used when the body has been set as a binary array and you want to encode the body as a byte array for transmission.

Returns:
a byte array containing the SIPRequest encoded as a byte array.
 
 
     public byte[] encodeAsBytes(String transport) {
         if (this.isNullRequest()) {
             // Encoding a null message for keepalive.
             return "\r\n\r\n".getBytes();
         } else if ( this. == null ) {
             return new byte[0];
         }
 
         byte[] rlbytes = null;
         if ( != null) {
             try {
                 rlbytes = .encode().getBytes("UTF-8");
             } catch (UnsupportedEncodingException ex) {
                 InternalErrorHandler.handleException(ex);
             }
         }
         byte[] superbytes = super.encodeAsBytes(transport);
         byte[] retval = new byte[rlbytes.length + superbytes.length];
         System.arraycopy(rlbytes, 0, retval, 0, rlbytes.length);
         System.arraycopy(superbytes, 0, retvalrlbytes.lengthsuperbytes.length);
         return retval;
     }

    
Creates a default SIPResponse message for this request. Note You must add the necessary tags to outgoing responses if need be. For efficiency, this method does not clone the incoming request. If you want to modify the outgoing response, be sure to clone the incoming request as the headers are shared and any modification to the headers of the outgoing response will result in a modification of the incoming request. Tag fields are just copied from the incoming request. Contact headers are removed from the incoming request. Added by Jeff Keyser.

Parameters:
statusCode Status code for the response. Reason phrase is generated.
Returns:
A SIPResponse with the status and reason supplied, and a copy of all the original headers from this request.
 
 
     public SIPResponse createResponse(int statusCode) {
 
         String reasonPhrase = SIPResponse.getReasonPhrase(statusCode);
         return this.createResponse(statusCodereasonPhrase);
 
     }

    
Creates a default SIPResponse message for this request. Note You must add the necessary tags to outgoing responses if need be. For efficiency, this method does not clone the incoming request. If you want to modify the outgoing response, be sure to clone the incoming request as the headers are shared and any modification to the headers of the outgoing response will result in a modification of the incoming request. Tag fields are just copied from the incoming request. Contact headers are removed from the incoming request. Added by Jeff Keyser. Route headers are not added to the response.

Parameters:
statusCode Status code for the response.
reasonPhrase Reason phrase for this response.
Returns:
A SIPResponse with the status and reason supplied, and a copy of all the original headers from this request except the ones that are not supposed to be part of the response .
 
 
     public SIPResponse createResponse(int statusCodeString reasonPhrase) {
         SIPResponse newResponse;
 //        Iterator headerIterator;
 //        SIPHeader nextHeader;
 
         newResponse = new SIPResponse();
         try {
             newResponse.setStatusCode(statusCode);
         } catch (ParseException ex) {
             throw new IllegalArgumentException("Bad code " + statusCode);
         }
         if (reasonPhrase != null)
             newResponse.setReasonPhrase(reasonPhrase);
         else
             newResponse.setReasonPhrase(SIPResponse.getReasonPhrase(statusCode));
         
 //        headerIterator = getHeaders();
 //        while (headerIterator.hasNext()) {
 //            nextHeader = (SIPHeader) headerIterator.next();
 //            if (nextHeader instanceof From
 //                    || nextHeader instanceof To
 //                    || nextHeader instanceof ViaList
 //                    || nextHeader instanceof CallID
 //                    || (nextHeader instanceof RecordRouteList && mustCopyRR(statusCode))
 //                    || nextHeader instanceof CSeq
 //                    // We just copy TimeStamp for all headers (not just 100).
 //                    || nextHeader instanceof TimeStamp) {
 //
 //                try {
 //
 //                    newResponse.attachHeader((SIPHeader) nextHeader.clone(), false);
 //                } catch (SIPDuplicateHeaderException e) {
 //                    e.printStackTrace();
 //                }
 //            }
 //        }
         
         // no need to iterate through all headers to create the response since we know which headers
         // we only want to keep and helps the lazy parsing to avoid going through all headers
         for(String headerName : ) {                	
         	SIPHeader nextHeader = .get(headerName);
         	if(nextHeader != null) {
         		if(!(nextHeader instanceof RecordRouteList) || (nextHeader instanceof RecordRouteList && mustCopyRR(statusCode))) {
         			try {
         				newResponse.attachHeader((SIPHeadernextHeader.clone(), false);
         			} catch (SIPDuplicateHeaderException e) {
                       e.printStackTrace();
                   }
         		}
         	}
         }
         
         if (MessageFactoryImpl.getDefaultServerHeader() != null) {
             newResponse.setHeader(MessageFactoryImpl.getDefaultServerHeader());
 
         }
         // Commented out for Issue 305 : 
         // tag parameter in the To header in 100 Trying response for re-INVITE 
         // is needed
         // Fix by Tomasz Zieleniewski
 //        if (newResponse.getStatusCode() == 100) {
 //            // Trying is never supposed to have the tag parameter set.
 //            newResponse.getTo().removeParameter("tag");
 //        }
         ServerHeader server = MessageFactoryImpl.getDefaultServerHeader();
         if (server != null) {
             newResponse.setHeader(server);
         }
         return newResponse;
     }
 
     // Helper method for createResponse, to avoid copying Record-Route unless needed
     protected final boolean mustCopyRRint code ) {
     	// Only for 1xx-2xx, not for 100 or errors
     	if ( code>100 && code<300 ) {
     		return isDialogCreatingthis.getMethod() ) && getToTag() == null;
     	} else return false;
     }
    
    
Creates a default SIPResquest message that would cancel this request. Note that tag assignment and removal of is left to the caller (we use whatever tags are present in the original request).

Returns:
A CANCEL SIPRequest constructed according to RFC3261 section 9.1
Throws:
javax.sip.SipException
java.text.ParseException
 
     public SIPRequest createCancelRequest() throws SipException {
 
         // see RFC3261 9.1
 
         // A CANCEL request SHOULD NOT be sent to cancel a request other than
         // INVITE
 
         if (!this.getMethod().equals(.))
             throw new SipException("Attempt to create CANCEL for " + this.getMethod());
 
         /*
          * The following procedures are used to construct a CANCEL request. The Request-URI,
          * Call-ID, To, the numeric part of CSeq, and From header fields in the CANCEL request
          * MUST be identical to those in the request being cancelled, including tags. A CANCEL
          * constructed by a client MUST have only a single Via header field value matching the top
          * Via value in the request being cancelled. Using the same values for these header fields
          * allows the CANCEL to be matched with the request it cancels (Section 9.2 indicates how
          * such matching occurs). However, the method part of the CSeq header field MUST have a
          * value of CANCEL. This allows it to be identified and processed as a transaction in its
          * own right (See Section 17).
          */
         SIPRequest cancel = new SIPRequest();
         cancel.setRequestLine((RequestLinethis..clone());
         cancel.setMethod(.);
         cancel.setHeader((Headerthis..clone());
         cancel.setHeader((Headerthis..clone());
         cancel.setHeader((Header.clone());
         try {
             cancel.getCSeq().setMethod(.);
         } catch (ParseException e) {
             e.printStackTrace(); // should not happen
         }
         cancel.setHeader((Headerthis..clone());
 
         cancel.addFirst((Headerthis.getTopmostVia().clone());
         cancel.setHeader((Headerthis..clone());
 
         /*
          * If the request being cancelled contains a Route header field, the CANCEL request MUST
          * include that Route header field's values.
          */
         if (this.getRouteHeaders() != null) {
             cancel.setHeader((SIPHeaderList< ? >) this.getRouteHeaders().clone());
         }
         if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
             cancel.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
 
         }
         return cancel;
     }

    
Creates a default ACK SIPRequest message for this original request. Note that the defaultACK SIPRequest does not include the content of the original SIPRequest. If responseToHeader is null then the toHeader of this request is used to construct the ACK. Note that tag fields are just copied from the original SIP Request. Added by Jeff Keyser.

Parameters:
responseToHeader To header to use for this request.
Returns:
A SIPRequest with an ACK method.
 
     public SIPRequest createAckRequest(To responseToHeader) {
 //    	SIPRequest newRequest;
 //        Iterator headerIterator;
 //        SIPHeader nextHeader;
 
     	// cloning instead of iterating through headers so that lazy parsers don't have to parse the messages fully
     	// to create ACK requests
         SIPRequest newRequest = (SIPRequestthis.clone();
 //        newRequest = new SIPRequest();
 //        newRequest.setRequestLine((RequestLine) this.requestLine.clone());
         newRequest.setMethod(.);
         // Ack and cancel do not get ROUTE headers.
         // Route header for ACK is assigned by the
         // Dialog if necessary.
         newRequest.removeHeader(.);
         // Remove proxy auth header.
         // Assigned by the Dialog if necessary.
         newRequest.removeHeader(.);
         // Adding content is responsibility of user.
         newRequest.removeContent();
         // Content type header is removed since
         // content length is 0.
         newRequest.removeHeader(.);
         // The CSeq header field in the
         // ACK MUST contain the same value for the
         // sequence number as was present in the
         // original request, but the method parameter
         // MUST be equal to "ACK".
         try{
         	newRequest.getCSeq().setMethod(.);
         } catch (ParseException e) {
         }
         if (responseToHeader != null) {
             newRequest.setTo(responseToHeader);
         }
         // CONTACT header does not apply for ACK requests.
         newRequest.removeHeader(.);
         newRequest.removeHeader(.);
         ViaList via = newRequest.getViaHeaders();
         // Bug reported by Gianluca Martinello
         // The ACK MUST contain a single Via header field,
         // and this MUST be equal to the top Via header
         // field of the original
         // request.
         if(via != null && via.size() > 1) {
         	for(int i = 2; i < via.size(); i++) {
         		via.remove(i);
         	}
         }
         
         if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
             newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
 
         }
         return newRequest;
     }

    
Creates an ACK for non-2xx responses according to RFC3261 17.1.1.3

Returns:
A SIPRequest with an ACK method.
Throws:
javax.sip.SipException
java.lang.NullPointerException
java.text.ParseException
Author(s):
jvb
 
     public final SIPRequest createErrorAck(To responseToHeaderthrows SipException,
             ParseException {
 
         /*
          * The ACK request constructed by the client transaction MUST contain values for the
          * Call-ID, From, and Request-URI that are equal to the values of those header fields in
          * the request passed to the transport by the client transaction (call this the "original
          * request"). The To header field in the ACK MUST equal the To header field in the
          * response being acknowledged, and therefore will usually differ from the To header field
          * in the original request by the addition of the tag parameter. The ACK MUST contain a
          * single Via header field, and this MUST be equal to the top Via header field of the
          * original request. The CSeq header field in the ACK MUST contain the same value for the
          * sequence number as was present in the original request, but the method parameter MUST
          * be equal to "ACK".
          */
         SIPRequest newRequest = new SIPRequest();
         newRequest.setRequestLine((RequestLinethis..clone());
         newRequest.setMethod(.);
         newRequest.setHeader((Headerthis..clone());
         newRequest.setHeader((Headerthis..clone()); // ISSUE
         // 130
         // fix
         newRequest.setHeader((Headerthis..clone());
         newRequest.setHeader((HeaderresponseToHeader.clone());
         newRequest.addFirst((Headerthis.getTopmostVia().clone());
         newRequest.setHeader((Header.clone());
         newRequest.getCSeq().setMethod(.);
 
         /*
          * If the INVITE request whose response is being acknowledged had Route header fields,
          * those header fields MUST appear in the ACK. This is to ensure that the ACK can be
          * routed properly through any downstream stateless proxies.
          */
         if (this.getRouteHeaders() != null) {
             newRequest.setHeader((SIPHeaderListthis.getRouteHeaders().clone());
         }
         if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
             newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
 
         }
         return newRequest;
     }

     
Get the host from the topmost via header.

Returns:
the string representation of the host from the topmost via header.
 
     public String getViaHost() {
         Via via = (Viathis.getViaHeaders().getFirst();
         return via.getHost();
 
     }

    
Get the port from the topmost via header.

Returns:
the port from the topmost via header (5060 if there is no port indicated).
 
     public int getViaPort() {
         Via via = (Viathis.getViaHeaders().getFirst();
         if (via.hasPort())
             return via.getPort();
         else
             return 5060;
     }

    
Get the first line encoded.

Returns:
a string containing the encoded request line.
 
     public String getFirstLine() {
         if ( == null)
             return null;
         else
             return this..encode();
     }

    
Set the sip version.

Parameters:
sipVersion the sip version to set.
 
     public void setSIPVersion(String sipVersionthrows ParseException {
         if (sipVersion == null || !sipVersion.equalsIgnoreCase("SIP/2.0"))
             throw new ParseException("sipVersion", 0);
         this..setSipVersion(sipVersion);
     }

    
Get the SIP version.

Returns:
the SIP version from the request line.
 
     public String getSIPVersion() {
         return this..getSipVersion();
     }

    
Book keeping method to return the current tx for the request if one exists.

Returns:
the assigned tx.
 
     public Object getTransaction() {
         // Return an opaque pointer to the transaction object.
         // This is for consistency checking and quick lookup.
         return this.;
     }

    
Book keeping field to set the current tx for the request.

Parameters:
transaction
 
     public void setTransaction(Object transaction) {
         this. = transaction;
     }

    
Book keeping method to get the messasge channel for the request.

Returns:
the message channel for the request.
 
 
     public Object getMessageChannel() {
         // return opaque ptr to the message chanel on
         // which the message was recieved. For consistency
         // checking and lookup.
         return this.;
     }

    
Set the message channel for the request ( bookkeeping field ).

Parameters:
messageChannel
 
 
     public void setMessageChannel(Object messageChannel) {
         this. = messageChannel;
     }

    
Generates an Id for checking potentially merged requests.

Returns:
String to check for merged requests
    public String getMergeId() {
        /*
         * generate an identifier from the From tag, Call-ID, and CSeq
         */
        String fromTag = this.getFromTag();
        String cseq = this..toString();
        String callId = this..getCallId();
        /* NOTE : The RFC does NOT specify you need to include a Request URI 
         * This is added here for the case of Back to Back User Agents.
         */
        String requestUri = this.getRequestURI().toString();
        if (fromTag != null) {
            return new StringBuilder().append(requestUri).append(":").append(fromTag).append(":").append(cseq).append(":")
                    .append(callId).toString();
        } else
            return null;
    }

    

Parameters:
inviteTransaction the inviteTransaction to set
    public void setInviteTransaction(Object inviteTransaction) {
        this. = inviteTransaction;
    }

    

Returns:
the inviteTransaction
    public Object getInviteTransaction() {
        return ;
    }
    
    @Override
    public void cleanUp() {
    	super.cleanUp();
    }