PingIM Internals
This section details the internal operations and structure of the PingIM
Xpression. While overall design and implementation are discussed, low-level
details at the granularity of individual method calls are not included in
this section (for that, please refer to the Javadoc documentation). This
section focuses primarily on application architecture and implementation.
A basic understanding of Java , object-oriented
design, Internet telephony, LDAP ,
and XML is assumed.
PingIM is composed of six major components: Objects, SIP Listeners,
Actions, Systems. Each component is carefully defined below.
[In this section, words that are presented in bold correspond to
a Java class in the edu.columbia.coms6901.pingtel.pingim package.]
Objects
The two object types for PingIM are fairly straightforward: Buddy
and Subscriber.
A Buddy, as the reader may correctly infer, is a representation
of a friend on the buddy list. Or more technically, a buddy is an
instantiation of a buddy object -- a data representation of an LDAP entry
that falls within the LDAP subtree of the local user (
Illustration ). The components of a buddy reflect the attributes
of the LDAP entry: CN (common name), description, SIP address, buddy
type, etc. As is mentioned in previous sections, there are three buddy
types: PingIM Buddy (an instant messaging associate who is
running PingIM or a compatible client), a Phone book Buddy (equivalent
to an entry in the address book), and an X10 Buddy (a X10-controlled
device that is connected to a SIP gateway).
All buddies are stored as elements of a Java Vector in the PingIM BuddyList.
Whenever the user changes between the three application modes (IM,
Phonebook, X10) or refreshes the display, PingIM re-examines the LDAP directory
for new entries.
A Subscriber, like an IM buddy, represents a user of PingIM or a
compatible instant messaging client. A subscriber is a instant messaging
peer who has asked to be notified of the local user's state (e.g., present,
away, busy, etc.) More technically, a subscriber has successfully requested
(via a SIP SUBSCRIBE message) to be notified (via a SIP NOTIFY message) whenever
the local user changes state or exits the PingIM application. A subscriber
has included the local user in his/her buddy list. Analogous to the
BuddyList, subscribers are kept in a Java Vector, a component of the
Subscribers class.
SIP Listeners
The second major component of PingIM are the SIP listeners.
The listeners are hooks into the underlying SIP stack that wait for
incoming SIP messages. PingIM is concerned with only three specific
incoming message types: SUBSCRIBE, NOTIFY, and MESSAGE.
Upon arrival of a SUBSCRIBE message, the handleMessage method of
the SUBSCRIBEListener class is executed. Depending upon the contents
of the SUBSCRIBE message, a subscriber is either added, deleted, or refreshed
(subscriptions expire after a certain time) from the SubscribersList.
In order to allow multiple instances of PingIM to bind to the same
LDAP user and search base, a design decision was reached to store subscription
information in the PingTel phone's memory rather than in the LDAP directory.
When a user leaves the PingIM application, a NOTIFY message is sent
to all subscribers informing them that the current instance is going off-line
and that their subscription has ended.
Whenever an incoming SIP NOTIFY message arrives at the phone, The NOTIFYListener
becomes active. An incoming NOTIFY message contains information regarding
a state change for a buddy on the local buddy list. When the NOTIFYListener
finds the matching Buddy object, that buddy's state is changed to reflect
the new value.
State information is passed in the payload of the SIP NOTIFY message in
XML format. Since memory is limited on PingTel Xpressa phones, an XML
interpreter with a small footprint is required. For the PingIM project,
the open-source KXML parser was chosen.
KXML is a small (~ 20kb) XML pull parser designed specifically for
Java-embedded devices, and is well-suited for the requirements of the PingIM
application.
The MESSAGEListener listens for incoming SIP MESSAGE messages. If
the sender of the message is on the local user's buddy list, then the message
is immediately displayed and the local user is alerted via an audible tone.
If, on the other hand, the sender is not on the local user's buddy list,
the user is presented with three options: ignore the message, display the
message, or display the message and add the sender to the buddy list.
When the user of the PingTel phone or softphone switches to another Xpression,
the three aforementioned listeners continue to wait for incoming messages.
Thus, for example, a user is alerted to an incoming instant message
even if he is using another PingTel Xpression. The listeners only stop
when the user explicitly opts to exit PingIM or when the phone loses power.
Actions
The next component of the PingIM application are the four SIP Message actions.
SUBSCRIBEMessage, NOTIFYMessage, and MESSAGEMessage
are analogous to the SUBSCRIBEListener, NOTIFYListener, and MESSAGEListener
classes described above. Each message action reflects the relevant SIP
message.
The SUBSCRIBEMessage is fairly straightforward. It contains no payload,
and asks for a one-hour subscription to the recipient buddy. If accepted,
the buddy must send NOTIFY messages back to the local user whenever its state
changes, so long as the subscription is still valid. In addition, the
SUBSCRIBEMessage may also be used to cancel an existing subscription.
The MESSAGEMessage contains a plain text (Content-Type set to text/plain)
representation of the instant message. As of this release of PingIM,
there is no support for extended text functionality such as bold or italicized
text.
As is mentioned above, the NOTIFYMessage contains information about the
state or presence of the local instance of PingIM. For easy interoperability
with other instant messaging clients, this information is captured in
XML.
Finally, the DOMessage is used to send actions (i.e., "turn on"/"turn off")
to X10-enabled devices. The payload of the DOMessage is coded in DMP,
an XML-based format used for sending commands. DOMessages should be
directed to a X10 SIP proxy, which will relay the X10 command to the apropriate
device.
Systems
The business logic of the PingIM application is encapsulated in the three
systems modules: LDAPHandler, GuiUtilities, and MenuSystem
.
The first of the three systems modules, LDAPHandler, contains routines for
interfacing with the LDAP data store. Methods for creating the initial
directory context, adding and deleting elements, and searching through the
LDAP tree are contained within the LDAPHandler class.
GuiUtilities is a collection of utility functions for common user interface
tasks. Methods for alerts, prompts, confirmation dialogues, logging,
and error reporting are all present within this class.
The MenuSystem class handles most of the human-PingIM interface. The
three major menus (IM, Phone book, and X10) are presented using method calls
belonging to this class. As mentioned above, the graphical user interface
builds upon the available basic menu types provided in the PingTel AWT.
Bringing It All Together
The PingIM Java class is invoked when a user starts the PingIM application.
The first time the application is started, the program instantiates
an LDAPHandler object and retrieves buddy information from the LDAP directory.
Subscription requests are sent to each PingIM buddy. The three
listeners, SUBSCRIBEListener, NOTIFYListener, and MESSAGEListener are started,
and the user is presented with the buddy list menu, courtesy of the MenuSystem
class.
At the same time, a thread which supports presence information begins execution.
The thread periodically checks for expired subscriptions: Any
Subscriber whose subscription has expired is removed from SubscriberList.
Similarly, for each local subscription to a Buddy on the BuddyList which
is about to expire, a new SUBSCRIBEMessage is sent. Lastly, the thread
periodically sends SUBSCRIBEMessages to buddies that have previously been
offline or have previously rejected incoming SIP SUBSCRIBE requests.
When the application is exited, the PingIM class stops the thread and shuts
down the three listeners. The LDAP context is closed, and PingIM application
terminates.
The Source Code
The source code has been documented using the Javadoc utility.
The Javadoc for this project may be found here.
In addition, the code itself is well commented.