org.cafesip.sipunit
Class Subscription

java.lang.Object
  extended by org.cafesip.sipunit.Subscription
All Implemented Interfaces:
MessageListener, RequestListener, SipActionObject

public class Subscription
extends java.lang.Object
implements MessageListener, SipActionObject

The Subscription class represents a buddy from a SipPhone buddy list or a single-shot fetch performed by a SipPhone. The Subscription object is used by a test program to proceed through the SUBSCRIBE-NOTIFY sequence(s) and to find out details at any given time about the subscription such as the subscription state, amount of time left on the subscription if still active, termination reason if terminated, current or last known presence status/information (tuples/devices, notes, etc.), errors encountered during received NOTIFY message validation, and details of received responses and requests if needed.

Please read the SipUnit User Guide, Presence section (at least the operation overview part) for information on how to use SipUnit presence capabilities.

As in the case of other objects like SipPhone, SipCall, etc., operation-invoking methods of this class return an object or true if successful. In case of an error or caller-specified timeout, a null object or a false is returned. The getErrorMessage(), getReturnCode() and getException() methods may be used for further diagnostics. See SipPhone or SipActionObject javadoc for more details on using these methods.


Method Summary
 void clearEventErrors()
          This method clears errors accumulated while collecting SUBSCRIBE responses and NOTIFY requests.
 javax.sip.message.Request createSubscribeMessage(int duration, java.lang.String eventId)
          This method creates and returns to the caller the next SUBSCRIBE message that would be sent out, so that the user can modify it before it gets sent out (ie, to introduce errors - insert incorrect content, remove content, etc.).
 java.lang.String format()
          The format() method can be used to obtain a human-readable string containing the result of the last operation - either a successful indication or all of the error information associated with the last operation performed.
 java.util.ArrayList<SipRequest> getAllReceivedRequests()
          This method returns all the NOTIFY requests received on this subscription.
 java.util.ArrayList<SipResponse> getAllReceivedResponses()
          This method returns all the responses received on this subscription, including any that required re-initiation of the subscription (ie, authentication challenge).
 java.lang.String getBuddyUri()
          This method returns the URI of the user that this Subscription is for.
 javax.sip.ResponseEvent getCurrentSubscribeResponse()
          This method returns the most recent SUBSCRIBE response received from the network for this subscription.
 java.lang.String getErrorMessage()
          The getErrorMessage() method returns a descriptive, human-readable string indicating the cause of the problem encountered during the last operation performed.
 java.util.LinkedList<java.lang.String> getEventErrors()
          This method returns any errors accumulated during collection of SUBSCRIBE responses and NOTIFY requests.
 java.lang.Throwable getException()
          This method is used to get the Exception object generated during the last operation performed.
 SipRequest getLastReceivedRequest()
          This method returns the last request received on this subscription.
 SipResponse getLastReceivedResponse()
          This method returns the last response received on this subscription.
 javax.sip.message.Request getLastSentRequest()
          This method returns the last SUBSCRIBE request that was sent out for this Subscription.
 java.util.HashMap<java.lang.String,PresenceDeviceInfo> getPresenceDevices()
          Gets the list of known devices for this Subscription (buddy, watchee).
 java.util.ArrayList<java.lang.Object> getPresenceExtensions()
          Gets the list of extensions pertaining to this Subscription as received in the last NOTIFY message (at the top 'presence' element level).
 java.util.ArrayList<PresenceNote> getPresenceNotes()
          Gets the list of notes pertaining to this Subscription as received in the last NOTIFY message (at the top 'presence' element level).
 int getReturnCode()
          This method returns the status code of the current or last operation performed.
 java.lang.String getTerminationReason()
          Returns the subscription termination reason for this subscription.
 int getTimeLeft()
          Returns the number of seconds left in the subscription, if active, or the number of seconds that were remaining at the time the subscription was terminated.
 boolean isRemovalComplete()
          This method, called after removing a buddy from the buddy list, indicates if an unsubscribe sequence was initiated due to the removal or not.
 boolean isSubscriptionActive()
          Indicates if the subscription state is ACTIVE.
 boolean isSubscriptionPending()
          Indicates if the subscription state is PENDING.
 boolean isSubscriptionTerminated()
          Indicates if the subscription state is TERMINATED.
 void processEvent(java.util.EventObject event)
          For internal SipUnit use only.
 javax.sip.message.Response processNotify(javax.sip.RequestEvent requestEvent)
          This method validates the given (received) NOTIFY request, updates the subscription information based on the NOTIFY contents, and creates and returns the correctly formed response that should be sent back in reply to the NOTIFY, based on the NOTIFY content that was received.
 boolean processSubscribeResponse(long timeout)
          This method processes the initial SUBSCRIBE response received after sending a SUBSCRIBE request and takes the SUBSCRIBE transaction to its completion by collecting any remaining responses from the far end for this transaction, handling authentication challenge if needed, and updating the Subscription object with the results of the SUBSCRIBE sequence.
 boolean replyToNotify(javax.sip.RequestEvent reqevent, javax.sip.message.Response response)
          This method sends the given response to the network in reply to the given request that was previously received.
 javax.sip.RequestEvent waitNotify(long timeout)
          The waitNotify() method allows received NOTIFY messages to be examined and processed by the test program, one by one.
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Method Detail

createSubscribeMessage

public javax.sip.message.Request createSubscribeMessage(int duration,
                                                        java.lang.String eventId)
This method creates and returns to the caller the next SUBSCRIBE message that would be sent out, so that the user can modify it before it gets sent out (ie, to introduce errors - insert incorrect content, remove content, etc.). The idea is to call this method which will create the SUBSCRIBE request correctly, then modify the returned request yourself, then call one of the SipPhone buddy methods (refreshBuddy(), removeBuddy()) that take Request as a parameter, which will result in the request being sent out.

If you don't need to modify the next SUBSCRIBE request to introduce errors, don't bother with this method and just call one of the alternative SipPhone buddy methods (refreshBuddy(), removeBuddy(), etc.) that doesn't take a Request parameter - it will create and send the request in one step.

Effective use of this method requires knowledge of the JAIN SIP API Request and Header classes. Use those to modify the request returned by this method.

Note that the SipPhone methods addBuddy() and fetchPresenceInfo() do not have any signatures that take Request as a parameter. The reason is because a correct initial SUBSCRIBE request is needed to initialize the Subscription object properly. If you want to send out a bad initial SUBSCRIBE message to see what your test target does, use the SipPhone's base class SipSession (low-level) methods to send the bad request and get the resulting response (and that should be the end of that test method).

Parameters:
duration - the duration in seconds to put in the SUBSCRIBE message.
eventId - the event "id" to use in the SUBSCRIBE message, or null for no event "id" parameter. Whatever is indicated here will be used subsequently (for error checking SUBSCRIBE responses and NOTIFYs from the server as well as for sending subsequent SUBSCRIBEs) unless changed by the caller later on another SipPhone buddy method call (refreshBuddy(), removeBuddy(), fetch, etc.).
Returns:
a SUBSCRIBE Request object if creation is successful, null otherwise.

processEvent

public void processEvent(java.util.EventObject event)
Description copied from interface: RequestListener
For internal SipUnit use only.

Specified by:
processEvent in interface RequestListener
Parameters:
event - Event received.

processSubscribeResponse

public boolean processSubscribeResponse(long timeout)
This method processes the initial SUBSCRIBE response received after sending a SUBSCRIBE request and takes the SUBSCRIBE transaction to its completion by collecting any remaining responses from the far end for this transaction, handling authentication challenge if needed, and updating the Subscription object with the results of the SUBSCRIBE sequence.

Call this method after calling any of the SipPhone buddy/fetch methods that initiate a SUBSCRIBE sequence (addBuddy(), refreshBuddy(), fetchPresenceInfo(), etc.) and getting back a positive indication.

If a success indication is returned by this method, you may call other methods on this object to find out the result of the SUBSCRIBE sequence: isSubscriptionXyz() for subscription state information, getTimeLeft() which is set based on the received response.

The next step is to call waitNotify() to retrieve/wait for the NOTIFY request from the server.

Parameters:
timeout - The maximum amount of time to wait for the SUBSCRIBE transaction to complete, in milliseconds. Use a value of 0 to wait indefinitely.
Returns:
true if the response(s) received were valid and no errors were encountered, false otherwise.

processNotify

public javax.sip.message.Response processNotify(javax.sip.RequestEvent requestEvent)
This method validates the given (received) NOTIFY request, updates the subscription information based on the NOTIFY contents, and creates and returns the correctly formed response that should be sent back in reply to the NOTIFY, based on the NOTIFY content that was received. Call this method after getting a NOTIFY request from method waitNotify().

If a null value is returned by this method, call getReturnCode() and/or getErrorMessage() to see why.

If a non-null response object is returned by this method, it doesn't mean that NOTIFY validation passed. If there was invalid content in the NOTIFY, the response object returned by this method will have the appropriate error code (489 Bad Event, etc.) that should be sent in reply to the NOTIFY. You can call getReturnCode() to find out the status code contained in the returned response (or you can examine the response in detail using JAIN-SIP API). A return code of 200 OK means that the received NOTIFY had correct content and the presence information stored in this Subscription object has been updated with the NOTIFY message contents. Call methods getPresenceDevices(), getPresenceExtensions(), getPresenceNotes(), isSubscriptionXyz(), getTerminationReason() and/or getTimeLeft() to see the newly updated presence information.

The next step is to invoke replyToNotify() to send a response to the network. The caller may modify (corrupt) the response returned by this method (using the JAIN-SIP API) before passing it to replyToNotify().

Validation performed by this method includes: event header present, event type correct ("presence"), event ID matches sent SUBSCRIBE, subscription state header present, received expiry not greater than that sent in SUBSCRIBE, reception of NOTIFY request without having sent a SUBSCRIBE, supported content type/subtype, matching (correct) presentity in NOTIFY body, correctly formed xml body document, valid document content.

Parameters:
requestEvent - the NOTIFY request event obtained from waitNotify()
Returns:
a correct javax.sip.message.Response that should be sent back in reply, or null if an error was encountered.

replyToNotify

public boolean replyToNotify(javax.sip.RequestEvent reqevent,
                             javax.sip.message.Response response)
This method sends the given response to the network in reply to the given request that was previously received. Call this method after processNotify() has handled the received request.

Parameters:
reqevent - The object returned by waitNotify().
response - The object returned by processNotify(), or a user-modified version of it.
Returns:
true if the response is successfully sent out, false otherwise.

getPresenceDevices

public java.util.HashMap<java.lang.String,PresenceDeviceInfo> getPresenceDevices()
Gets the list of known devices for this Subscription (buddy, watchee). This list represents the list of 'tuple's received in the last NOTIFY message.

Returns:
A HashMap containing zero or more PresenceDeviceInfo objects, indexed/keyed by the unique IDs received for each in the NOTIFY messages (tuple elements).

getPresenceNotes

public java.util.ArrayList<PresenceNote> getPresenceNotes()
Gets the list of notes pertaining to this Subscription as received in the last NOTIFY message (at the top 'presence' element level).

Returns:
An ArrayList containing zero or more PresenceNote objects.

getPresenceExtensions

public java.util.ArrayList<java.lang.Object> getPresenceExtensions()
Gets the list of extensions pertaining to this Subscription as received in the last NOTIFY message (at the top 'presence' element level).

Returns:
An ArrayList containing zero or more Object.

getTimeLeft

public int getTimeLeft()
Returns the number of seconds left in the subscription, if active, or the number of seconds that were remaining at the time the subscription was terminated.

Returns:
Returns the timeLeft in seconds.

format

public java.lang.String format()
Description copied from interface: SipActionObject
The format() method can be used to obtain a human-readable string containing the result of the last operation - either a successful indication or all of the error information associated with the last operation performed.

Specified by:
format in interface SipActionObject
Returns:
A string fully describing the error information associated with the last operation performed, or a successful indication if no error occurred.

getLastReceivedResponse

public SipResponse getLastReceivedResponse()
This method returns the last response received on this subscription.

Specified by:
getLastReceivedResponse in interface MessageListener
Returns:
A SipResponse object representing the last response message received, or null if none has been received.
See Also:
MessageListener.getLastReceivedResponse()

getLastReceivedRequest

public SipRequest getLastReceivedRequest()
This method returns the last request received on this subscription.

Specified by:
getLastReceivedRequest in interface MessageListener
Returns:
A SipRequest object representing the last request message received, or null if none has been received.
See Also:
MessageListener.getLastReceivedRequest()

getAllReceivedResponses

public java.util.ArrayList<SipResponse> getAllReceivedResponses()
This method returns all the responses received on this subscription, including any that required re-initiation of the subscription (ie, authentication challenge). Not included are out-of-sequence (late) SUBSCRIBE responses.

Specified by:
getAllReceivedResponses in interface MessageListener
Returns:
ArrayList of zero or more SipResponse objects.
See Also:
MessageListener.getAllReceivedResponses()

getAllReceivedRequests

public java.util.ArrayList<SipRequest> getAllReceivedRequests()
This method returns all the NOTIFY requests received on this subscription. (Retransmissions aren't included.)

Specified by:
getAllReceivedRequests in interface MessageListener
Returns:
ArrayList of zero or more SipRequest objects.
See Also:
MessageListener.getAllReceivedRequests()

isSubscriptionTerminated

public boolean isSubscriptionTerminated()
Indicates if the subscription state is TERMINATED.

Returns:
true if so, false if not.

isSubscriptionActive

public boolean isSubscriptionActive()
Indicates if the subscription state is ACTIVE.

Returns:
true if so, false if not.

isSubscriptionPending

public boolean isSubscriptionPending()
Indicates if the subscription state is PENDING.

Returns:
true if so, false if not.

getTerminationReason

public java.lang.String getTerminationReason()
Returns the subscription termination reason for this subscription. Call this method when the subscription has been terminated (method isSubscriptionTerminated() returns true).

Returns:
Returns the termination reason or null if the subscription is not terminated.

getErrorMessage

public java.lang.String getErrorMessage()
Description copied from interface: SipActionObject
The getErrorMessage() method returns a descriptive, human-readable string indicating the cause of the problem encountered during the last operation performed. If an exception was involved, this string will contain the name of the Exception class and the exception message.

Specified by:
getErrorMessage in interface SipActionObject
Returns:
A descriptive string describing the cause of the problem encountered during the last operation performed, or an empty string if no problem was encountered.

getException

public java.lang.Throwable getException()
Description copied from interface: SipActionObject
This method is used to get the Exception object generated during the last operation performed. It applies whenever the getReturnCode() method returns internal SipUnit return code EXCEPTION_ENCOUNTERED.

Specified by:
getException in interface SipActionObject
Returns:
The Throwable object generated during the last operation performed, or null if an Exception didn't occur.

getReturnCode

public int getReturnCode()
Description copied from interface: SipActionObject
This method returns the status code of the current or last operation performed. It returns either the SIP response code received from the network (defined in SipResponse, along with the corresponding textual equivalent) or a SipUnit internal status/return code (defined in SipSession, along with the corresponding textual equivalent). SipUnit internal codes are in a specially designated range (SipSession.SIPUNIT_INTERNAL_RETURNCODE_MIN and upward).

Specified by:
getReturnCode in interface SipActionObject
Returns:
The status code of the last operation performed, or the status code so far of the current ongoing operation.

getBuddyUri

public java.lang.String getBuddyUri()
This method returns the URI of the user that this Subscription is for.

Returns:
The user's URI.

getEventErrors

public java.util.LinkedList<java.lang.String> getEventErrors()
This method returns any errors accumulated during collection of SUBSCRIBE responses and NOTIFY requests. Since this happens automatically, asynchronous of the test program activity, there's not a handy way like a method call return code to report these errors if they happen. They are errors like: No CSEQ header in received NOTIFY, error or exception resending SUBSCRIBE with authorization header, unexpected null transaction object at response timeout, etc. You should at various points call SipTestCase.assertNoEventErrors() during a test to verify none have been encountered.

The case where a NOTIFY is received by a SipPhone but there is no matching subscription results in 481 response being sent back and an event error entry in each Subscription object associated with that SipPhone (to ensure it will be seen by the test program).

Aside from being put in the event error list, event errors are output with the SipUnit trace if you have it turned on (SipStack.setTraceEnabled(true)). You can clear this list by calling clearEventErrors().

Returns:
LinkedList (never null) of zero or more String

clearEventErrors

public void clearEventErrors()
This method clears errors accumulated while collecting SUBSCRIBE responses and NOTIFY requests. See related method getEventErrors().


waitNotify

public javax.sip.RequestEvent waitNotify(long timeout)
The waitNotify() method allows received NOTIFY messages to be examined and processed by the test program, one by one. Call this method whenever you are expecting a NOTIFY to be received and your test program has nothing else to do until then. If there are already one or more unexamined-as-yet-by-the-test-program NOTIFY messages accumulated when this method is called, it returns the next in line (FIFO) immediately. Otherwise, it waits for the next NOTIFY message to be received from the network for this subscription.

This method blocks until one of the following occurs: 1) A NOTIFY message is received, for this subscription. The received NOTIFY javax.sip.RequestEvent object is returned in this case. The calling program may examine the returned object (requires knowledge of JAIN SIP). The next step for the caller is to pass the object returned by this method to processNotify() for handling. 2) The wait timeout period specified by the parameter to this method expires. Null is returned in this case. 3) An error occurs. Null is returned in this case.

A NOTIFY message whose CSEQ# is not greater than those previously received is discarded and not returned by this method.

Parameters:
timeout - The maximum amount of time to wait, in milliseconds. Use a value of 0 to wait indefinitely.
Returns:
A RequestEvent (received NOTIFY) or null in the case of wait timeout or error. If null is returned, call getReturnCode() and/or getErrorMessage() and, if applicable, getException() for further diagnostics.

getCurrentSubscribeResponse

public javax.sip.ResponseEvent getCurrentSubscribeResponse()
This method returns the most recent SUBSCRIBE response received from the network for this subscription. Knowledge of JAIN-SIP API is required to examine the object returned from this method. Alternately, call getLastReceivedResponse() to see the primary values (status, reason) contained in the last received response.

Returns:
javax.sip.ResponseEvent - last received SUBSCRIBE response.

getLastSentRequest

public javax.sip.message.Request getLastSentRequest()
This method returns the last SUBSCRIBE request that was sent out for this Subscription.

Returns:
javax.sip.message.Request last sent out

isRemovalComplete

public boolean isRemovalComplete()
This method, called after removing a buddy from the buddy list, indicates if an unsubscribe sequence was initiated due to the removal or not.

Returns:
true if unsubscribe was not necessary (because the subscription was already terminated) and false if a SUBSCRIBE/NOTIFY sequence was initiated due to the removal of the buddy from the list.


http://www.cafesip.org