You may use Oracle Beehive RESTful Web Services to develop a complete instant messaging (IM) application or integrate instant messaging features into your application. Oracle Beehive provides a complete XMPP server implementation, and all instant messaging APIs are usable with non-BDK clients connected to Oracle Beehive through XMPP.
The following topics are covered:
Instant messaging consists of three technology areas: presence, roster, and instant messages. This structure is based on common industry conventions, summarized in the XMPP specification (RFC 3920). This section covers the following topics:
A presence is the advertisement by an individual as to how he or she can (or cannot) be reached. A user's presence consists of a set of contact methods. A contact method contains information about a specific method to contact a user, It consists of an address (for example, im:emma@example.com), a resource (lab-computer), and a status (AVAILABLE).
For example, Emma is at the office in front of her workstation. She is logged in to her favorite IM client and chatting with her colleague Ryan. She then walks away from her desk and signs on to another computer in the lab. Now there are two ways to reach Emma: her workspace IM client or the IM client on the lab computer. Each one of these logged in IM clients advertises a contact method for Emma; these two contact methods constitute Emma's presence. If Emma is courteous, she may have set her status to AWAY with the comment Going to the Lab when she left her workstation. When she signed in at the lab, she became AVAILABLE on the lab computer. From the perspective of Ryan's IM client, he saw her status change from AVAILABLE to AWAY to AVAILABLE.
Although Emma's presence consists of two contact methods, most IM clients (such as Ryan's) compress this information into a single iconic representation, showing the most recent (or most reachable) status across all contact methods.
A resource is a token indicating how to route messages to a user at a given point. It enables the system, in this example, to send a message to Emma in just the lab when she is in fact available at two locations.
A user's roster is most often called a buddy list. A roster consists of a set of roster entries. A roster entry describes the mutual subscription state between the roster's owner and another user. A mutual subscription state describes whether one user can watch the presence the other.
For example, Ryan's roster consists of two people: Jun and Emma. It contains two roster entries, one that describes the mutual subscription state between Ryan and Emma and the other between Ryan and Jun. Joey is new to the department and wants to add Ryan to his buddy list. Using his IM client, he requests the buddy ryan@example.com. At this point, a message is sent to Ryan's IM client, which adds a roster entry to Ryan's roster. This entry lists the relationship from Ryan to Joey as ALLOWED and Joey to Ryan as PENDING. This means Ryan can watch Joey's presence (and by convention, send him instant messages). For Joey to be able to see Ryan's presence, Ryan must update the mutual subscription state from PENDING to ALLOWED.
When users think of instant messages, they likely think of a conversation. Most IM clients present a conversation as a chronologically ordered set of instant messages (which are sometimes called stanzas). However, XMPP servers (such as Oracle Beehive) have no notion of a "conversation" of instant messages. Instead, the XMPP server determines, for each individual instant message, the most appropriate address and resource to send it.
For example, when Ryan chatted with Emma at her workstation, his messages were sent to im:emma@example.com#office-workstation (where im:emma@example.com is the address, and office-workstation is the resource). When Emma left her office and went to the lab, Ryan's IM client was informed of the changes to Emma's presence (and thus the changed resource in her contact methods). Consequently, his IM client will send subsequent messages to im:emma@example.com#lab-computer.
Suppose Emma is logged into her workstation and her smartphone's IM client, and Ryan wants to initiate a conversation with her. Most IM clients will not ask Ryan how he would like to reach Emma. In this case, his IM client sends his first instant message to im:emma@example.com, without specifying a resource. The system delivers this to any reachable resource where it knows Emma is available. The resource from which Emma replies is be used for subsequent messages from Ryan's IM client.
This section discusses aspects of Oracle Beehive RESTful Web Services that facilitate the creation of rich clients. It covers the following topics:
Although you may use Oracle Beehive RESTful Web Services in virtually any computing environment, it is designed to accommodate more constrained environments. In particular, JavaScript clients running in browsers have restrictions in their ability to create real-time effects. This poses a problem since instant messaging technology derives its value from its real-time nature: its frantic interactivity of IM conversations and ability to present up-to-date presence. The traditional XMPP permanent socket to the server is unavailable to the JavaScript client. The browser can only ask for data; it cannot be "pushed" data. To compensate for this, many Web applications employ a "long poll" technique. Oracle Beehive RESTful Web Services does the same.
Long Polling works as follows: Clients that want real-time updates ask the server, "Is there anything new for me?" The HTTP server then either responds with one or more new pieces of data, or it blocks. A block means that the HTTP request does not return to the client. Over time, one of two things happen: data is found (and returned) or the connection is dropped (by, for example, the browser or firewall). When the call returns, any returned data is dispatched into the application and the same call is repeated.
On the server, there is a queue for each connected client. As data arrives from within the system (such as presence changes and instant Messages) they are placed on the Oracle Beehive Event Notification Service queue. If the client is currently waiting on the queue (for a response to "Is there anything new for me?"), it is immediately returned. If the client is not in an outstanding request (it is still processing the last batch), data is enqueued for the client's return.
The following properties control the behavior of polling. These properties are part of the _BdkService:PrivateProperties component:
Name | Description | Optional? | Mutable? | Initial Value | Minimum Value | Maximum Value |
---|---|---|---|---|---|---|
PresenceConnectionsLimit | Maximum number of presence connections a single client may establish through Oracle Beehive RESTful Web Services. Setting this property to 0 disables presence connection initiation. | false | true | 2 | 0 | 10 |
NotificationQueuePollConcurrencyLimit | Maximum number of concurrent poll operations allowed on the server. | false | true | 100 | 1 | 1000 |
NotificationQueueSuspendThreshold | Maximum number of pending notifications that can be held by Oracle Beehive RESTful Web Services for the client. After the queue reaches that size, a special marker added to the notifications queue and further notifications are suspended. | false | true | 100 | 1 | 1000 |
NotificationQueuePollTimeout | Number of milliseconds the server will wait for notifications to appear in the queue during polling operations. Larger numbers save traffic and CPU but increase the number of utilized threads. | false | true | 2000 | 10 | 10000 |
NotificationSessionTTL | Number of seconds the event session stays open while client is not polling. | false | true | 60 | 10 | 1800 |
As mentioned previously, instant messaging consists of three distinct technology areas: presence, roster, and instant messages. You may, for example, create an application that just shows the presence of users without any ability to send them instant messages. However, since these three areas are frequently used together, Oracle Beehive RESTful Web Services contains a data type called InstantMessagingSession to simplify IM client development.
InstantMessagingSession is
exposed as a single RESTful Web service
URI, /imsg/{name}
,
where {name}
is a unique string to serve as the resource (recall that the resource
disambiguates a user who is logged into two or more locations).
Invoking this URI returns an object of type InstantMessagingSession
that contains the current user's roster and the current presence
(contact methods) for all members of the roster. It ensures that
session subscriptions are setup for all users on the roster and the
resource itself, so presence changes and new messages arrive into
Oracle Beehive Event Notification Service.
This section covers common usage patterns with Oracle Beehive RESTful Web Services Presence/IM/Roster facilities.
Refer to "Conventions for Describing Oracle Beehive RESTful Web Services Procedures".
To get started embedding IM, presence, or roster in your application, you must first start an IM session:
1. (InstantMseeagingSession) POST /imsg/{name} () ()
The {name}
is an arbitrary identifier chosen
by your application. It represents the resource of the logged in user's
connection to the system.
It is an error in any XMPP (or XMPP-like) system to have two connected clients with the same resource. Behavior varies between systems. In Oracle Beehive, the second attempt to connect with the same resource results in an error.
The returned from starting the IM Session is an InstantMessagingSession object. It contains two members:
The data type Roster is used in
two places. It is returned as a
member of InstantMessagingSession. It is also the payload received when
any roster changes take place. A Roster consists of an array of
RosterEntries. RosterEntries store the mutual subscription state for
everyone on your roster. When (and only this one time) the roster
(contained in InstantMessagingSession) is returned from the call to /imsg/{name}
,
the roster contains a sub-type of RosterEntry called
PresenceRosterEntry. This type extends RosterEntry and also contains
the current presence of each user on the Roster.
The last step required to get started is to retrieve the current user's IM address. This is used later when sending IM messages:
2. (OrganizationUser) /my/user () (projection=EMPTY_WITH_ALL_ADDRESSES)
The returned object contains a
data type that has an addresses
member. Go through each address, looking for the one starting with im:
.
This is the current user's IM address. Note that your application may
not require this step if it has already retrieved the user's
information.
The Oracle Beehive server manages a queue of pending notifications for each connected IM session. To keep track of IM, presence. and roster changes, retrieve the data types instantMessagingEvent, presenceChangeEvent, and presenceRosterChangeEvent from the Pending Event Notifications queue.
Devote a loop in your
application to constantly call the URI /session/events
.
Expect that the call sometimes returns an error indicating that the
connection was closed without any data. Firewalls and other network
entities may impose timeouts tighter than either client or server. If
any form of "connection closed for timeout" error occur, simply call
the method again. If your server has become unreachable for any reason,
you may test it by invoking a benign API such as /session/anticsrf
.
If the call does not end in an error, it may still return no data as indicated by the HTTP status code. Again, anticipate this in your application continue with the loop. If it returns data, it will be a list of change events. In your application, process the following event types. Note that you may encounter other types, but you may ignore them in an IM/Presence/Roster application:
As discussed in the section "Presence", when an application changes the user's presence, it actually updates the user's contact methods. To update a user's contact methods, call the following:
() PUT /my/presence/connections/{id} (contactMethodUpdater) ()
{id}
is the PresenceConnectionId returned when
the InstantMessagingSession was started. Refer to "Initializing
InstantMessagingSession".
The request payload of this method is ContactMethodUpdater. The two most interesting members are as follows:
Roster changes are received through the Pending Event Notification queue. Refer to "Retrieving Pushed IM/Presence/Roster Changes".
An incoming IM conversation refers to an IM conversation started by someone else, with the current user as the other endpoint. These conversations start by receiving a IntantMessagingEvent from an address not currently active in a chat window. The messages should be of ChatState ACTIVE without any message body, but be prepared for a message in any ChatState. Note that proper state transitions are defined by the XMPP specification, but Oracle Beehive cannot control applications that do not follow specifications.
Note also that offline messages (which are sent to the current user when he or she was not logged in and saved by the server) may be received.
To start an IM conversation, simply send a blank message (of type InstantMessage) with the member chatEventType set to ACTIVE to the address of the target user (set in the InstantMessage's instantMessageHeader member) as specified by one of his or her contact methods:
POST () /imsg/send (instantMessage) ()
Use the entire address,
including any trailing #XXXXX
token. This format is specified by XMPP, where the format of an IM
address is im:address#resource
.
If the user has more than one
reachable contact method with an im:
address, you broadcast to all known resources for that user.
Often a user is logged into
more than one resource, with both having
the AVAILABLE status in the ContactMethod. To start an IM conversation
with such a person, follow the instructions in "Starting IM
Conversation", but
remove all characters after the #
in the address
(including the #
).
This tells the server to send the IM
to all endpoints with this user's address.
Once a message is received from
that user, you now know which of the
several resources (#XXXXX
)
to use for subsequent
messages.
Stopping the IM session ends all conversations and removes the current ContactMethod (a "logout"). To retain the IM session but terminate a single conversation, send a blank (no body) message with the ChatState GONE.
To make a buddy request, which occurs when the current user wants to add someone to his or her roster, call the following URI to update the current user's presence subscription:
() PUT /my/presence/roster () (subscriber = address of other user, state = outbound subscription state)
Often (by convention) a user requesting someone to be their buddy implicitly wants the return (the other user can see the current user's presence). To follow this convention, set the state request parameter to ALLOWED.
Users often walk away from their IM client without changing their status to AWAY. Most clients will eventually adjust their status based on inactivity, but there is a good chance that the user will be concurrently ACTIVE at two resources (clients). This may even happen when your application has an open chat window.
To watch for this, create a method to choose the correct resource to address each user on the roster. As you receive InstantMessages from a given user, note the address member of the fromParticipant in the Header. This is the most up-to-date location where that user has been known to be actively sending and receiving messages.
Note that presence changes should be used to locate points where the user is active, but presence changes may lag based on IM client characteristics.
Often, IM clients display messages such as "User is typing" or "User has stopped typing." This is a liveliness indicator from the other party. It is relayed through blank instantMessages with the chatState COMPOSING and PAUSED. Note all client send such messages; anticipate that you may only receive text stanzas from some users.
|
Top |