The Server Code

The code for the server will look very familiar if you have developed HTTP servlets in the past. If you don't know servlets, you should first familiarize yourself with them. The SIP Servlet Specification is an extension of the HTTP Servlet Specification. The syntax, the container's behavior, and even the method names are similar.

I'll now dissect the example in question. It is roughly composed of three sections:

1. Lifecycle methods

These methods are called by the container when the servlet is started up or is shut down:

In the initialization method I create a global (context-scope) attribute that all sessions share. This is the list of users. I also retrieve the address of this chat room (servlet parameter) for future use.

2. Message-processing methods

SIP servlets differ slightly from HTTP servlets. With HTTP servlets, you process incoming requests and send out response messages. With SIP servlets, you can both send and receive requests and responses. I'll show you how to do this.

The following methods are called by the container when messages (requests and responses) are received. They are called by the container following the path on this chart, and you can override them to process the messages according to their type:

void service(ServletRequest, ServletResponse)

If you override, don't forget to call super.service().

The default implementation calls one of the following methods:

void doRequest(SipServletRequest)

If you override, don't forget to call super.doRequest().

The default implementation calls one of the following methods:

void doResponse(SipServletResponse)

If you override, don't forget to call super.doResponse().

The default implementation calls one of the following methods:

One of these request methods (self-explanatory):

doAck(SipServletRequest)

doBye(SipServletRequest)

doCancel(SipServletRequest)

doInfo(SipServletRequest)

doInvite(SipServletRequest)

doMessage(SipServletRequest)

doNotify(SipServletRequest)

doOptions(SipServletRequest)

doPrack(SipServletRequest)

doRegister(SipServletRequest)

doRequest(SipServletRequest)

doResponse(SipServletResponse)

doSubscribe(SipServletRequest)

One of these response methods:

doProvisionalResponse(SipServletResponse)—Corresponds to the 1xx-class response messages.

doSuccessResponse(SipServletResponse)—Corresponds to the 2xx-class response messages.

doRedirectResponse(SipServletResponse)—Corresponds to the 3xx-class response messages.

doErrorResponse(SipServletResponse)—Corresponds to the 4xx-, 5xx-, and 6xx-class response messages.

As an example, a MESSAGE message would hit the following methods:

service(), passing in a SipServletRequest (you must do a cast), and null

doRequest()

doMessage()

Usually, only methods on the last level are overridden, unless non-standard SIP messages are involved, or you want to gather statistics about messages.

The first method is called when a MESSAGE message arrives. It first replies with a 200 OK message to indicate that it accepts the message. Then it processes server commands like /join. Finally, it calls a business logic method to broadcast the incoming message.

An incoming error-response message indicates that the last request failed. This may mean that one of the users got disconnected. Simply remove that user from the list.

A success response message means the last MESSAGE message was accepted properly by the instant messenger. We no longer need the session so we discard it. Typically, MESSAGE messages are sent statelessly—connection information isn't kept between messages. (This isn't the case for an INVITE message, which opens a stateful session until a BYE is sent.)