FileDocCategorySizeDatePackage
Request.javaAPI DocphoneME MR2 API (J2ME)32038Wed May 02 18:00:42 BST 2007gov.nist.siplite.message

Request

public final class Request extends Message
The SIP Request structure-- this belongs to the parser who fills it up.
version
JAIN-SIP-1.1 This code is in the public domain.

Fields Summary
public static final String
ACK
Acknowledgement request.
public static final String
BYE
End of session request.
public static final String
CANCEL
Terminate session request.
public static final String
INVITE
Invitation request.
public static final String
OPTIONS
Optional settings request.
public static final String
REGISTER
Regsitration request.
public static final String
NOTIFY
Notification request.
public static final String
SUBSCRIBE
Subscription for notification request.
public static final String
MESSAGE
Message request.
public static final String
REFER
Redirection request.
public static final String
INFO
Basic information request.
public static final String
PRACK
PRACK ??? RFC.
public static final String
UPDATE
Update request.
public static final String
PUBLISH
Publish request.
public static final String
DEFAULT_USER
Default user name is "ip".
public static final int
DEFAULT_TTL
Default time to live is 1 second.
public static final String
DEFAULT_TRANSPORT
Default transport is "udp".
public static final String
DEFAULT_METHOD
Default method is to intiate an INVITE.
private Object
transactionPointer
Current transaction pointer.
protected RequestLine
requestLine
Current requestline.
Constructors Summary
public Request()
Constructor.

 super(); 
Methods Summary
protected voidcheckHeaders()
Checks 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.

        String prefix = "Missing Header ";

        /* Check for required headers */

        if (getCSeqHeader() == null) {
            throw new ParseException(prefix + Header.CSEQ, 0);
        }
        if (getTo() == null) {
            throw new ParseException(prefix + Header.TO, 0);
        }
        if (getFromHeader() == null) {
            throw new ParseException(prefix + Header.FROM, 0);
        }
        if (getViaHeaders() == null) {
            throw new ParseException(prefix + Header.VIA, 0);
        }

    /*
     * BUGBUG
     * Need to revisit this check later...
     * for now we just leave this to the
     * application to catch.
     */

        if (requestLine != null && requestLine.getMethod() != null &&
                getCSeqHeader().getMethod() != null &&
                compareToIgnoreCase
                (requestLine.getMethod(), getCSeqHeader().getMethod()) != 0) {
            throw
                    new ParseException
                    ("CSEQ method mismatch with Request-Line ", 0);

        }

    
public java.lang.Objectclone()
Makes a clone (deep copy) of this object. You can use this if you want to modify a request while preserving the original

return
a deep copy of this object.


        Request retval = (Request) super.clone();
        if (this.requestLine != null) {
            retval.requestLine = (RequestLine) this.requestLine.clone();
            retval.setRequestLineDefaults();
        }
        return retval;
    
public gov.nist.siplite.message.RequestcreateACKRequest()
Creates an ACK request from this request. This is suitable for generating an ACK for an INVITE client transaction.

return
an ACK request that is generated from this request.
throws
SipException if the request can't be created.

        RequestLine rl = (RequestLine) requestLine.clone();
        rl.setMethod(ACK);
        return createRequest(rl, false);
    
public gov.nist.siplite.message.RequestcreateAckRequest(ToHeader responseToHeader)
Creates a default ACK Request message for this original request. Note that the defaultACK Request does not include the content of the original Request. 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.

param
responseToHeader To header to use for this request.
return
A Request with an ACK method.
throws
SipException if the request can't be created.

        Request newRequest;
        Enumeration headerIterator;
        Header nextHeader;

        newRequest = new Request();
        newRequest.setRequestLine
                ((RequestLine)this.requestLine.clone());
        newRequest.setMethod(ACK);
        headerIterator = getHeaders();
        while (headerIterator.hasMoreElements()) {
            nextHeader = (Header)headerIterator.nextElement();
            if (nextHeader.getHeaderName().equals
                    (Header.ROUTE)) {

                // Route header for ACK is assigned by the
                // Dialog if necessary.
                continue;
            } else if (nextHeader.getHeaderName().equals
                    (Header.PROXY_AUTHORIZATION)) {
                // Remove proxy auth header.
                // Assigned by the Dialog if necessary.
                continue;
            } else if (nextHeader instanceof ContentLengthHeader) {
                // Adding content is responsibility of user.
                nextHeader = (Header) nextHeader.clone();
                ((ContentLengthHeader)nextHeader).setContentLength(0);

            } else if (nextHeader instanceof ContentTypeHeader) {
                // Content type header is removed since
                // content length is 0. Bug fix from
                // Antonis Kyardas.
                continue;
            } else if (nextHeader instanceof CSeqHeader) {
                CSeqHeader cseq = (CSeqHeader) nextHeader.clone();
                cseq.setMethod(ACK);
                nextHeader = cseq;
            } else if (nextHeader instanceof ToHeader) {
                if (responseToHeader != null) {
                    nextHeader = responseToHeader;
                } else {
                    nextHeader = (Header) nextHeader.clone();
                }
            } else {
                nextHeader = (Header) nextHeader.clone();
            }

            newRequest.attachHeader(nextHeader, false);
        }

        return newRequest;
    
public gov.nist.siplite.message.RequestcreateBYERequest(boolean switchHeaders)
Creates a BYE request from this request.

param
switchHeaders is a boolean flag that causes from and isServerTransaction to headers to be swapped. Set this to true if you are the server of the dialog and are generating a BYE request for the dialog.
return
a new default BYE request.
throws
SipException if the request can't be created.

        RequestLine rl = (RequestLine) requestLine.clone();
        rl.setMethod(BYE);
        return createRequest(rl, switchHeaders);
    
public gov.nist.siplite.message.RequestcreateCancelRequest()
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). Acknowledgement: Added by Jeff Keyser.

return
A CANCEL Request with a copy all the original headers from this request except for Require, ProxyRequire.
throws
SipException if the request can't be created.

        Request newRequest;
        Enumeration headerIterator;
        Header nextHeader;

        newRequest = new Request();

        // JSR180: Request-URI  // copy from original request
        RequestLine cancelRequestLine = 
            (RequestLine)this.getRequestLine().clone();
        cancelRequestLine.setMethod(CANCEL);
        newRequest.setRequestLine(cancelRequestLine);
        newRequest.setMethod(CANCEL);

        // JSR180: To           // copy from original request
        ToHeader toHeader = this.getTo();
        if (toHeader != null) {
            newRequest.setHeader(toHeader);
        }

        // JSR180: From         // copy from original request
        FromHeader fromHeader = this.getFromHeader();
        if (fromHeader != null) {
            newRequest.setHeader(fromHeader);
        }

        // JSR180: CSeq         // same value for the sequence
        // number as was present in the original request, but
        // the method parameter MUST be equal to "CANCEL"
        CSeqHeader cseqHeader = (CSeqHeader)this.getCSeqHeader().clone();
        if (cseqHeader != null) {
            cseqHeader.setMethod(CANCEL);
            newRequest.setHeader(cseqHeader);
        }

        // JSR180: Call-ID      // copy from original request
        CallIdHeader callIdHeader = this.getCallId();
        if (callIdHeader != null) {
            newRequest.setHeader(callIdHeader);
        }

        // JSR180: Via          // single value equal to the
        // top Via header field of the request being cancelled
        ViaHeader viaHeader = this.getTopmostVia();
        if (viaHeader != null) {
            newRequest.setHeader(viaHeader);
        }

        // JSR180: Route        // If the request being cancelled
        // contains a Route header field, the CANCEL request MUST
        // include that Route header field's values
        RouteList routeList = this.getRouteHeaders();
        if (routeList != null) {
            newRequest.setHeaders(routeList.getHeaders());
        }

        // JSR180: Max-Forwards (TBD)// header field serves to limit the
        // number of hops a request can transit on the way to its destination.
        // Current version: copy from original request
        MaxForwardsHeader mfHeader =
            (MaxForwardsHeader)getHeader(Header.MAX_FORWARDS);
        if (mfHeader != null) {
            newRequest.setHeader(mfHeader);
        }

        return newRequest;
    
public gov.nist.siplite.message.RequestcreateRequest(RequestLine requestLine, boolean switchHeaders)
Creates a new default Request from the original request. Warning: the newly created Request, shares the headers of this request but we generate any new headers that we need to modify so the original request is umodified. However, if you modify the shared headers after this request is created, then the newly created request will also be modified. If you want to modify the original request without affecting the returned Request make sure you clone it before calling this method. Following are the differences between the original request headers and the generated request headers.
  • Contact headers are not included in the newly created request. Setting the appropriate sequence number is the responsibility of the caller.
  • RouteList is not copied for ACK and CANCEL
  • Note that we DO NOT copy the body of the argument into the returned header. We do not copy the content type header from the original request either. These have to be added seperately and the content length has to be correctly set if necessary the content length is set to 0 in the returned header.
  • Contact List is not copied from the original request.
  • RecordRoute List is not included from original request.
  • Via header is not included from the original request.

param
requestLine is the new request line.
param
switchHeaders is a boolean flag that causes to and from headers to switch (set this to true if you are the server of the transaction and are generating a BYE request). If the headers are switched, we generate new FromHeader and To headers otherwise we just use the incoming headers.
return
a new Default SIP Request which has the requestLine specified.
throws
SipException if the request can't be created.

        Request newRequest = new Request();
        newRequest.requestLine = requestLine;
        Enumeration headerIterator = this.getHeaders();
        while (headerIterator.hasMoreElements()) {
            Header nextHeader =
                    (Header)headerIterator.nextElement();
            // For BYE and cancel set the CSeqHeader header to the
            // appropriate method.
            if (nextHeader instanceof CSeqHeader) {
                CSeqHeader newCseq = (CSeqHeader) nextHeader.clone();
                nextHeader = newCseq;
                newCseq.setMethod(requestLine.getMethod());
            } else if (requestLine.getMethod().equals(ACK) &&
                    nextHeader instanceof ContactList) {
                // ACKS never get Contact headers.
                continue;
            } else if (nextHeader instanceof ViaList) {
                ViaHeader via = (ViaHeader)
                (((ViaList)nextHeader).getFirst().clone());
                via.removeParameter(SIPConstants.GENERAL_BRANCH);
                nextHeader = via;
                // Cancel and ACK preserve the branch ID.
            } else if (nextHeader instanceof RouteList) {
                continue; // Route is kept by dialog.
            } else if (nextHeader instanceof RecordRouteList) {
                continue; // RR is added by the caller.
            } else if (nextHeader instanceof ContactList) {
                continue;
            } else if (nextHeader instanceof ToHeader) {
                ToHeader to = (ToHeader) nextHeader;
                if (switchHeaders) {
                    nextHeader = new FromHeader(to);
                    ((FromHeader) nextHeader).removeTag();
                } else {
                    nextHeader = (Header) to.clone();
                    ((ToHeader) nextHeader).removeTag();
                }
            } else if (nextHeader instanceof FromHeader) {
                FromHeader from = (FromHeader) nextHeader;
                if (switchHeaders) {
                    nextHeader = new ToHeader(from);
                    ((ToHeader) nextHeader).removeTag();
                } else {
                    nextHeader = (Header) from.clone();
                    ((FromHeader) nextHeader).removeTag();
                }
            } else if (nextHeader instanceof ContentLengthHeader) {
                ContentLengthHeader cl =
                        (ContentLengthHeader)
                        nextHeader.clone();
                cl.setContentLength(0);
                nextHeader = cl;
            } else if (nextHeader instanceof ContentTypeHeader) {
                continue;
            } else if (nextHeader instanceof MaxForwardsHeader) {
                // Header is regenerated if the request is to be switched
                if (switchHeaders) {
                    MaxForwardsHeader mf  =
                            (MaxForwardsHeader)
                            nextHeader.clone();
                    mf.setMaxForwards(70);
                    nextHeader = mf;
                }
            } else if (!(nextHeader instanceof CallIdHeader) &&
                    !(nextHeader instanceof MaxForwardsHeader)) {
                // Route is kept by dialog.
                // RR is added by the caller.
                // Contact is added by the Caller
                // Any extension headers must be added
                // by the caller.
                continue;
            }

            newRequest.attachHeader(nextHeader, false);

        }
        return newRequest;

    
public ResponsecreateResponse(int statusCode)
Creates a default Response 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.

param
statusCode Status code for the response. Reason phrase is generated.
return
A Response with the status and reason supplied, and a copy of all the original headers from this request.

        String reasonPhrase = Response.getReasonPhrase(statusCode);
        return createResponse(statusCode, reasonPhrase);
    
public ResponsecreateResponse(int statusCode, java.lang.String reasonPhrase)
Creates a default Response 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.

param
statusCode Status code for the response.
param
reasonPhrase Reason phrase for this response.
return
A Response with the status and reason supplied.
throws
IllegalArgumentException if some argument has an invalid value.

        Response newResponse;
        Enumeration headerIterator;
        Header nextHeader;

        newResponse = new Response();
        try {
            newResponse.setStatusCode(statusCode);
        } catch (ParseException ex) {
            throw new IllegalArgumentException("Bad code " + statusCode);
        }

        if (reasonPhrase != null) {
            newResponse.setReasonPhrase(reasonPhrase);
        } else {
            newResponse.setReasonPhrase(Response.getReasonPhrase(statusCode));
        }

        headerIterator = super.getHeaders();

        // Time stamp header should be stamped with delay but
        // we dont support this.
        while (headerIterator.hasMoreElements()) {
            nextHeader = (Header)headerIterator.nextElement();
            if (nextHeader instanceof FromHeader ||
                    nextHeader instanceof ToHeader ||
                    nextHeader instanceof ViaList ||
                    nextHeader instanceof CallIdHeader ||
                    nextHeader instanceof RecordRouteList ||
                    nextHeader instanceof CSeqHeader ||
                    // RFC 3265, 3.1.1 200-class responses to SUBSCRIBE
                    // requests also MUST contain an "Expires" header.
                    nextHeader instanceof ExpiresHeader ||
                    Utils.equalsIgnoreCase(nextHeader.getName(),
                        Header.TIMESTAMP)) {
                try {
                    newResponse.attachHeader(nextHeader, false);
                } catch (SipException ex) {
                    if (Logging.REPORT_LEVEL <= Logging.ERROR) {
                        Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
                            "Request.createResponse(): can't attach header '" +
                                nextHeader.getHeaderName() + "'.");
                        ex.printStackTrace();
                    }
                }
            } else if (Utils.equalsIgnoreCase(nextHeader.getName(),
                        Header.REQUIRE)) {
                /*
                 * RFC3262, SECTION 3
                 * If the next header contains "Require" header with option
                 * tag as "100rel", we should add this header and also include 
                 * RSeq header field
                 */
                boolean isReliableProvResponse = Header.isReliableTagPresent(
                        nextHeader.getHeaderValue());
                
                if (isReliableProvResponse) {
                    try {
                        newResponse.attachHeader(nextHeader, true);
                    } catch (SipException ex) {
                        if (Logging.REPORT_LEVEL <= Logging.ERROR) {
                            Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
                                "Request.createResponse(): can't attach header" 
                                    +  nextHeader.getHeaderName() + "'.");
                            // ex.printStackTrace();
                        }
                    }
                }
                
            }
        }

        // RFC 3903, p. 5:
        // The Record-Route header field has no meaning in PUBLISH
        // requests or responses, and MUST be ignored if present.
        //
        // RFC 3261, p. 63:
        // Registrars MUST ignore the Record-Route header field if it is
        // included in a REGISTER request. Registrars MUST NOT include a
        // Record-Route header field in any response to a REGISTER request.
        String method = getMethod();
        if (method.equals(Request.PUBLISH) ||
                method.equals(Request.REGISTER)) {
            newResponse.removeHeader(Header.RECORD_ROUTE);
        }

        return newResponse;
    
public java.lang.Stringencode()
Encodes the SIP Request as a string.

return
an encoded String containing the encoded SIP Message.

        String retval;
        if (requestLine != null) {
            this.setRequestLineDefaults();
            retval = requestLine.encode() + super.encode();
        } else
            retval = super.encode();
        return retval;
    
public byte[]encodeAsBytes()
Encodes 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.

return
a byte array containing the Request encoded as a byte array.

        byte[] rlbytes = null;
        if (requestLine != null) {
            try {
                rlbytes = requestLine.encode().getBytes("UTF-8");
            } catch (UnsupportedEncodingException ex) {
                InternalErrorHandler.handleException(ex);
            }
        }
        byte[] superbytes = super.encodeAsBytes();
        byte[] retval = new byte[rlbytes.length + superbytes.length];
        int i = 0;
        System.arraycopy(rlbytes, 0, retval, 0, rlbytes.length);
        System.arraycopy
                (superbytes, 0, retval, rlbytes.length, superbytes.length);
        return retval;
    
public booleanequals(java.lang.Object other)
Compares for equality.

param
other object to compare ourselves with.
return
true if objects match

        if (! this.getClass().equals(other.getClass()))
            return false;
        Request that = (Request) other;

        boolean retval = requestLine.equals(that.requestLine) &&
                super.equals(other);

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION && !retval) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
                "this ... >>>>" + encode());
            Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
                "other ... >>>>" + that.encode());
        }

        return retval;
    
public AcceptContactHeadergetAcceptContact()
Gets the Accept-Contact header (null if one does not exist).

return
Accept-Contact header

        return (AcceptContactHeader) getHeader(Header.ACCEPT_CONTACT);
    
public java.lang.StringgetFirstLine()
Gets the first line encoded.

return
a string containing the encoded request line.

        if (requestLine == null)
            return null;
        else
            return this.requestLine.encode();
    
public java.lang.StringgetMethod()
Gets the method from the request line.

return
the method from the request line if the method exits and null if the request line or the method does not exist.

        if (requestLine == null)
            return null;
        else
            return requestLine.getMethod();
    
public RequestLinegetRequestLine()
Gets the Request Line of the Request.

return
the request line of the SIP Request.



                        
       
        return requestLine;
    
public URIgetRequestURI()
A conveniance function to access the Request URI.

return
the requestURI if it exists.

        if (this.requestLine == null)
            return null;
        else
            return this.requestLine.getUri();
    
public java.lang.StringgetSIPVersion()
Gets the SIP version.

return
the SIP version from the request line.

        return this.requestLine.getSipVersion();
    
public java.lang.ObjectgetTransaction()
Gets the transaction pointer.

return
the transaction pointer

        // Return an opaque pointer to the transaction object.
        // This is for consistency checking and quick lookup.
        return this.transactionPointer;
    
public java.lang.StringgetViaHost()
Gets the host from the topmost via header.

return
the string representation of the host from the topmost via header.

        ViaHeader via = (ViaHeader) this.getViaHeaders().getFirst();
        return via.getHost();

    
public intgetViaPort()
Gets the port from the topmost via header.

return
the port from the topmost via header (5060 if there is no port indicated).

        ViaHeader via = (ViaHeader) this.getViaHeaders().getFirst();
        if (via.hasPort())
            return via.getPort();
        else
            return 5060;
    
protected voidsetDefaults()
Sets the default values in the request URI if necessary.

        // The request line may be unparseable (set to null by the
        // exception handler.
        if (requestLine == null)
            return;
        String method = requestLine.getMethod();
        // The requestLine may be malformed!
        if (method == null)
            return;
        URI u = requestLine.getUri();
        if (u == null)
            return;
        if (method.compareTo(REGISTER) == 0
                || method.compareTo(INVITE) == 0) {
            if (u instanceof SipURI) {
                SipURI sipUri = (SipURI) u;
                sipUri.setUserParam(DEFAULT_USER);
                try {
                    sipUri.setTransportParam(DEFAULT_TRANSPORT);
                } catch (ParseException ex) {}
            }
        }
    
public voidsetMethod(java.lang.String method)
Sets the method.

param
method is the method to set.
throws
IllegalArgumentException if the method is null

        if (method == null)
            throw new IllegalArgumentException("null method");
        if (this.requestLine == null) {
            this.requestLine = new RequestLine();
        }
        this.requestLine.setMethod(method);
        if (this.cSeqHeader != null) {
            this.cSeqHeader.setMethod(method);
        }
    
public voidsetRequestLine(RequestLine requestLine)
Sets the request line of the SIP Request.

param
requestLine is the request line to set in the SIP Request.

        this.requestLine = requestLine;
    
protected voidsetRequestLineDefaults()
Patch up the request line as necessary.

        String method = requestLine.getMethod();
        if (method == null) {
            CSeqHeader cseq = (CSeqHeader) this.getCSeqHeader();
            if (cseq != null) {
                method = cseq.getMethod();
                requestLine.setMethod(method);
            }
        }
    
public voidsetRequestURI(URI uri)
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.

param
uri the new Request URI of this request message

        if (this.requestLine == null) {
            this.requestLine = new RequestLine();
        }
        this.requestLine.setUri((URI)uri);
    
public voidsetSIPVersion(java.lang.String sipVersion)
Sets the sip version.

param
sipVersion the sip version to set.

        if (sipVersion == null || !sipVersion.equals("SIP/2.0"))
            throw new ParseException("sipVersion", 0);
        this.requestLine.setSIPVersion(sipVersion);
    
public voidsetTransaction(java.lang.Object transaction)
Sets the transaction pointer.

param
transaction thenew transaction pointer

        this.transactionPointer = transaction;
    
public java.lang.StringtoString()
Alias for encode above.

return
encoded string of object contents

 return this.encode();