javax.microedition.sip
Class SipRefreshHelper

java.lang.Object
  extended by javax.microedition.sip.SipRefreshHelper

public class SipRefreshHelper
extends java.lang.Object

This class implements the functionality that facilitates the handling of refreshing requests on behalf of the application. Some SIP requests (REGISTER, SUBSCRIBE, ...) need to be timely refreshed (binding between end point and server, see RFC 3261 - chapter 10.2.1 page 58). For example the REGISTER request (RFC 3261, chapter 10 page 56) needs to be re-sent to ensure that the originating end point is still well and alive. The request's validity is proposed by the end point in the request and confirmed in the response by the registrar/notifier for example in expires header (RFC 3261, chapter 2 page 5). The handling of such binding would significantly increase application complexity and size. As a consequence the SipRefreshHelper can be used to facilitate such operations. The specification does not define the strategy for timely refreshing of registrations and subscriptions, implementations may choose the algorithm of when to send the refresh request.

The implementation must support refreshing REGISTER and SUBSCRIBE requests using the features of this class, however it is not mandated that refreshing PUBLISH requests is supported by the refreshHelper mechanism. Note that even if the SipRefreshHelper provides no support for PUBLISH, refreshing PUBLISH requests is possible by sending the appropriate SIP request from the application.

When the application wants to send a refreshable request it:

A reference to the SipRefreshHelper object is obtained by calling the static method SipRefreshHelper.getInstance() (singleton pattern).

Finally, using the refresh ID returned from enableRefresh(SipRefreshListener) the application can:

When all refresh tasks belonging to one refresh listener are stopped, the listener reference will be removed from the SipRefreshHelper.

In case of failure of either the original request or a subsequent refresh request the refreshing is automatically stopped and the failure response is reported in the refreshEvent() callback. The corresponding refresh ID is invalidated, so calling update() with the same ID will throw an exception. The application has to start a new refresh task if it wishes so and the implementation will assign a new refresh ID.

An implementation compliant to this specification MUST report the refresh responses to the refreshEvent callback in case of failure response codes (3xx – 6xx), and it MAY report them in case of successful refreshing (2xx). It MUST NOT report provisional (1xx) responses.

If a response arrives to a refresh request that was updated by the application since the request was sent then the response is not reported in the refreshEvent() callback.

If refresh responses are not received due to network problems, SipRefreshHelper reports failure to the user in the refreshEvent() callback. The implementations are free to choose a suitable SIP error code (like 408 – Timeout) or an implementation specific code (with the exception of 0, 1xx and 2xx) and reason phrase.

Code example where REGISTER is sent, updated and finally stopped:

 class SipRefreshExample implements SipClientConnectionListener,
         SipRefreshListener {
 
     int refreshID = 0;
 
     int refreshStatus = 0;
 
     SipRefreshHelper refHelper = null;
 
     public void sendRegister() {
         SipClientConnection sc = null;
         try {
             // Initialize connection to the registrar host.com
             sc = (SipClientConnection) Connector.open
                            ("sip:host.com");
             sc.setListener(this);
             // Initialize request and set From, To and Contact 
          // headers
             sc.initRequest("REGISTER", null);
             sc.setHeader("From", "sip:sippy.user@host.com");
             sc.setHeader("To", "sip:sippy.user@host.com");
             sc.setHeader("Contact", 
                       "<sip:UserB@192.168.200.201>;expires=3600");
             sc.setHeader("Contact",
                       "<mailto:UserB@biloxi.com>;expires=4294967295");
             refreshID = sc.enableRefresh(this);
             sc.send();
             refHelper = SipRefreshHelper.getInstance();
             //-----------------------------
             // do something else for a while
             //------------------------------
             // update REGISTER, with new "mailto:" Contact 
          // and no content
             
             // check that refresh was successful (2xx)
             if (refreshStatus >= 200 && refreshStatus < 300) { 
                 String c[] = {"<mailto:UserB@company.com>"};
                 refHelper.update(refreshID, c, null, 0, 6000);
             }
             //-----------------------------
             // do something else for a while
             //------------------------------
             // stop REGISTER refresh altogether

             
 
             // check that refresh is still ok
             if (refreshStatus >= 200 && refreshStatus < 300) { 
                 refHelper.stop(refreshID);
             }
         } catch (Exception ex) { // handle Exceptions 
         }
     }


     public void notifyResponse(SipClientConnection scc) {
         try {
             // retrieve the response received 
             scc.receive(0);
             if (scc.getStatusCode() >= 200 && 
              scc.getStatusCode() < 300) {
                 // handle 2xx response
             } else {
                 // handle possible error responses
             }
         } catch (Exception ex) {
             // handle Exceptions 
         }
     }
 
     public void refreshEvent(int ID, int statusCode, 
                           String reasonPhrase) {
         refreshStatus = statusCode;
         if (statusCode == 0) {
             // stopped refresh 
         } else if (statusCode >= 200 && statusCode < 300) {
             // successful refresh
         } else {
             // failed request 
         }
     }
 }
 

See Also:
SipClientConnection.enableRefresh(SipRefreshListener)

Method Summary
static SipRefreshHelper getInstance()
          Returns the instance of SipRefreshHelper
 void stop(int refreshID)
          Stop refreshing a specific request related to refeshID.
 java.io.OutputStream update(int refreshID, java.lang.String[] contact, java.lang.String type, int length, int expires)
          Updates one refreshed request with new values.
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Method Detail

getInstance

public static SipRefreshHelper getInstance()

Returns the instance of SipRefreshHelper

Returns:
the instance of SipRefreshHelper singleton

stop

public void stop(int refreshID)
          throws SipException

Stop refreshing a specific request related to refeshID. The possible binding between end point and registrar/notifier is cancelled. The way of cancellation depends on the SIP method used in the original request. The implementation must comply to the relevant specifications when creating the SIP request for cancelling the binding, that is:

An event will be sent to the listeners with the appropriate refreshID, statusCode = 0 and reasonPhrase = "refresh stopped".

If the stop() operation fails (e.g due to error in the native SIP stack) then refreshing is stopped and a refresh event is sent to the listeners with status code 0 and an implementation dependent error phrase.

The method can not be called in every phase of the refresh operation. There is no exact state machine defined for refresh operations but some possible scenarios in which the method MAY throw SipException.INVALID_STATE are the following: stop is called after initial registration request is sent but before 2xx-OK response arrives, stop is called during an asynchronous update operation. Note that no exception is thrown if stop is called before the initial request is sent, as in this case the binding to be cancelled is not yet established so no SIP message must be sent out, the method returns without any action.

Parameters:
refreshID - the ID of the refresh to be stopped. If the ID does not match any refresh task the method throws SipException.INVALID_STATE.
Throws:
SipException - INVALID_STATE if the refreshID doesn't represent an ongoing refresh operation (e.g. the refresh is already stopped by the application or because of an error) or stop can not be called in the current state of the refresh operation. See the details in the method definition section.

update

public java.io.OutputStream update(int refreshID,
                                   java.lang.String[] contact,
                                   java.lang.String type,
                                   int length,
                                   int expires)
                            throws SipException

Updates one refreshed request with new values.

Note that SipRefrehHelper sends the updated request in an independent transaction which implies that even if the header values are updated, it does not change the header values of the original request object. So if the application keeps a reference to the original client connection object, the headers of that object are not touched after the update() is executed.

Giving null or empty string as type or 0 as length means that subsequent refresh request will have no content. It does not mean that the request will contain the content of the original request unmodified.

Similarly to stop() the way of constructing the updated SIP request depends on the method used. The implementation must comply to the relevant RFCs.

If the update() operation fails (e.g due to error in the native SIP stack) then refreshing is stopped and a refresh event is sent to the listeners with the status code of the response received. If the status code is not available then an implementation dependent error code (and response phrase) is reported in the refreshEvent. The implementations are free to choose a suitable SIP error code (like 408 – Timeout) or an implementation specific code (with the exception of 0, 1xx and 2xx) and reason phrase. The behaviour is the same in case the OutputStream.close() operation fails within an update() operation.

The method can not be called in every phase of the refresh operation. There is no exact state machine defined for refresh operations but some possible scenarios in which SipException.INVALID_STATE MAY be thrown: update is called when the refresh is not yet active (e.g. after initial registration request is sent but before 2xx response arrives) or update is called before a previous update operation ends.

Parameters:
refreshID - ID returned from enableRefresh(...). If the ID does not match any refresh task the method throws SipException.INVALID_STATE.
contact - new Contact headers as String array. Replaces all old values. Multiple Contact header values are applicable only for REGISTER method. If contact param is null or empty the system will set the Contact header.
type - value of Content-Type (null or empty, no content).
length - value of Content-Length (<=0, no content).
expires - value of Expires (-1, no Expires header), (0, stop the refresh)
Returns:
Returns the OutputStream to fill the content. If the update does not have new content (type = null and/or length <= 0) method returns null and the message is sent automatically.
Throws:
java.lang.IllegalArgumentException - if some input parameter is invalid
SipException - INVALID_STATE if the refreshID doesn't represent an ongoing refresh operation (e.g. the refresh is already stopped by the application or because of an error) or update can not be called in the current state of the refresh operation. See the details in the method definition section.


Copyright © 2007 Nokia Corporation. All Rights Reserved.
Java is a trademark of Sun Microsystems, Inc.