Oracle® Communications Converged Application Server Developer's Guide Release 5.1 Part Number E27707-01 |
|
|
PDF · Mobi · ePub |
Converged Application Server provides APIs that allow you to create rich messaging and media services for subscribers. This chapter describes the APIs provided by the Service Foundation Toolkit (SFT) that can be used to create Instant Message (IM) servers. The high level APIs abstract the protocol level details of SIP, IMS, and MSRP (and their inherent complexity), simplifying development of IM services.
Rich Communication Suite (RCS) provides rich messaging and media services for subscribers. The specification includes support for RCS-e (“e” for enhanced), which introduces IMS voice sessions (VoIP/VoLTE) that can be enriched for IM and chat, file transfer, and image sharing. RCS-e is designed to lower the entry barrier for RCS by providing operators and developers with a framework in which to deploy RCS functionality without needing to implement the full RCS profiles.
Converged Application Server provides APIs that can be used to create RCS-e compliant Instant Message (IM) servers. The high level APIs abstract the protocol level details of SIP, IMS, and MSRP (and their inherent complexity), simplifying development of RCS-e services.
The capability discovery process in RCS-e is handled using SIP OPTIONS and is the process by which a user is able to understand what RCS-e services are available on another user's equipment. In comparison to RCS, which only has feature tags for Image and Video Share, there are several more feature tags that are possible with RCS-e. The feature tags are sent in the Accept-Contact header of the SIP OPTIONS message by the requesting user equipment. The responding user equipment sends the response in the Contact header of the 200 OK message.
Figure 25-1 shows the RCS-e capabilities exchange signalling process.
End-user A, using device A, sends a SIP REGISTER request to the IMS core network.
The IMS core responds with a SIP 200 OK to the SIP REGISTER request. At this point, User A restarts its registration timer.
User A sends a SIP PUBLISH message with its capabilities to the IMS core.
The IMS core responds with a SIP 200 OK.
When User A decides that they wish to exchange device capabilities with User B, their device (user equipment) sends a SIP OPTIONS request to the IMS core.
The IMS core routes the SIP OPTIONS request to User B.
User B responds to User A with an SIP 200 OK message, containing the capabilities of User B's device.
If the terminating user has multiple devices, the terminating network applies a SIP-AS that sends multiple OPTIONS AS to each device, and aggregates the capabilities into a single OPTIONS response back to the user that sent the OPTIONS request.
Capability discovery uses the following event types in the @CommunicationEvent
annotation in the com.oracle.sft.api.bean
package. For more information on these interfaces and their usage, refer to the Converged Application Server API Reference.
Table 25-1 @CommunicationEvent Event Types for Capability Discovery
Event Type | Description |
---|---|
|
Specifies that the query process has returned a response, and can be appropriately handled. |
|
Specifies that the process of querying (such as querying for device capabilities) is started. |
Capability discovery uses of the following interfaces in the com.oracle.sft.api
package. For more information on these interfaces and their usage, refer to the Converged Application Server API Reference.
Table 25-2 Capability Discovery Interfaces
Class | Description |
---|---|
|
Queries for a message exchange (or interaction) between two user agents—such as SIP OPTIONS—via the AS.
|
|
Represents the data structure of the RCS-e capabilities. |
|
Allows the application to process the incoming SIP OPTIONS 200 OK message with either a QUERYING or QUERIED event, and represents the capability between participants in a
|
The following sections illustrate the use of the QueryInteraction
and CapabilityMessage
interfaces.
Example 25-1 queries for the capabilities of a device by sending SIP OPTIONS, which allows a UA to query another UA or proxy server for its capabilities. QueryInteraction
gets the context of the communication via the CommunicationContext
interface's getCommunication()
method.
The CapabilityMessage
interface makes a call to the @CommunicationContext
interface's getMessage()
method, which passes the SIP OPTIONS message from the current communication session to the optionsMsg
object variable.
Example 25-1 Querying to Determine Device Capabilities
@CommunicationEvent(type = CommunicationEvent.Type.QUERYING ) void handleOptions() { // Retrieve SIP message exchange information from CommunicationContext. QueryInteraction ui = (QueryInteraction)ctx.getCommunication(); CapabilityMessage optionMsg = (CapabilityMessage)ctx.getMessage();
Upon receiving the user's capabilities via SIP OPTIONS, you can use the Capability
interface's getCapabilites()
method to retrieve the capabilities of the user's equipment. Example 25-2 retrieves the user's contact capabilities, and then accepts them using the getAvailableCapabilities()
method.
Example 25-2 Check If User Is Registered and RCS-e Capable
boolean isRegistered = true; boolean isRcseEnabled = true; if ( isRegistered && isRcseEnabled ) { // Get the contact capabilities and accept-accept capability Capability senderCapability = optionMsg.getCapabilities(); Capability senderAcceptedCapability = optionMsg.getAvailableCapabilities();
If the application is functioning as a User Agent Client (UAC), the application responds with SIP 200 OK message and its RCS-e capabilities. Example 25-3 illustrates how a response message is created.
Example 25-3 Client RCS-e Capability Response
... @Context CommunicationService service; ... Capability myCapability = service.createCapability(); List<Feature> myRcse = new ArrayList<RcseFeature> (); myRcse.add(Feature.RCSE_CHAT); myRcse.add(Feature.RCSE_FT); myRcse.add(Feature.VIDEO_SHARE_3GPP); myRcse.add(Feature.RCSE_IMAGE_SHARE); myCapability.setFeatures(myRcse); optionMsg.consume(myCapability); ...
Example 25-4 shows a CommunicationBean in which Converged Application Server acts as both a User Agent Client (UAC) and User Agent Server (UAS). The CommunicationBean in this example performs the following functions:
The SIP OPTIONS message from the requesting user (User A) carries the capability tags in both the Contact and Accept-Contact header.
The SIP 200 OK response from a receiving user carries the capability tags in the Contact header.
If a receiving user is not registered, User A receives a SIP 480 TEMPORARILY UNAVAILABLE or SIP 408 REQUEST TIMEOUT response.
If a receiving user is not provisioned to use RCS-e, User A receives a 404 NOT FOUND response.
Example 25-4 Capability Discovery Using a UAC and UAS
@CommunicationBean public class MyCommunicationBean { @Context CommunicationSession session; @Context CommunicationContext ctx; @Context CommunicationService service; @CommunicationEvent(type = CommunicationEvent.Type.QUERYING ) void handleOptions() { // Retrieve option information from CommunicationContext. QueryInteraction ui = (QueryInteraction)ctx.getCommunication(); CapabilityMessage optionMsg = (CapabilityMessage)ctx.getMessage(); /** The application checks whether the receiver is registered, and if * they are RCS-e enabled. boolean isRegistered = true; boolean isRcseEnabled = true; if ( isRegistered && isRcseEnabled ) { // Get the contact capabilities and accept the capability Capability senderCapability = optionMsg.getCapabilities(); Capability senderAcceptedCapability = optionMsg.getAvailableCapabilities(); /** The application acts as a UAS, forwarding the SIP OPTIONS message by default * When acting as a UAC, the application responds with SIP 200 OK with its RCS-e features. */ Capability myCapability = service.createCapability(); List<Feature> myRcse = new ArrayList<RcseFeature> (); myRcse.add(Feature.RCSE_CHAT); myRcse.add(Feature.RCSE_FT); myRcse.add(Feature.VIDEO_SHARE_3GPP); myRcse.add(Feature.RCSE_IMAGE_SHARE); myCapability.setFeatures(myRcse); optionMsg.consume(myCapability); ui.end(); }else if (!isRegistered ){ optionMsg.reject(Reason.NOT_AVAILABLE); ui.end(); }else if (!isRcseEnabled ){ optionMsg.reject(Reason.NOT_FOUND); ui.end(); } } /** On receiving a SIP 200 OK response in the SIP Options header, the application gets * the received user's capabilites, then forwards the SIP 200 OK or ends the SIP dialog. */ @CommunicationEvent(type = CommunicationEvent.Type.QUERIED ) void handleOptionsResponse() { QueryInteraction ui = (QueryInteraction)ctx.getCommunication(); CapabilityMessage optionMsg = (CapabilityMessage)ctx.getMessage(); Capability myCapability = optionMsg.getCapabilities(); /** If the application is acting as a UAS, it does nothing, and the * response is forwarded by default. * If the application is acting as a UAC, it terminates communication. ui.end(); }
Using SIP OPTIONS, an application can discover service capabilities before establishing a communication session. This discovery mechanism allows users to determine what services are available prior to establishing a call or IM session. A SIP OPTIONS message is sent in-dialog during the establishment of a voice call or IM session to obtain the real-time capabilities of the service. Converged Application Server supports in-dialog SIP OPTIONS-based capability discovery and capability update during 1-to-1 chat and 1-to-1 call.
Note:
SFT provides APIs to obtain service capabilities from a received SIP OPTIONS 200 OK message, but does not provide APIs to create or send in-dialog SIP OPTIONS messages.Example 25-5 illustrates how to retrieve the SIP OPTIONS message containing service capabilities information from the CommunicationContext interface using CapabilityMessage.
Example 25-5 In-Dialog SIP OPTIONS-based Capability Discovery
@CommunicationBean
public class MyCommunicationBean {
@Context CommunicationSession session;
@Context CommunicationContext ctx;
@Context CommunicationService service;
@CommunicationEvent(type = CommunicationEvent.Type.QUERYING )
void handleOptions() {
//Get SIP OPTION information from CommunicationContext.
Conversation ui = (Conversation)ctx.getCommunication();
CapabilityMessage optionMsg = (CapabilityMessage)ctx.getMessage();
//Receive the contact and accept-accept capabilities
Capability senderCapability = optionMsg.getCapabilities();
Capability senderAcceptedCapability = optionMsg.getAcceptCapabilities();
}
//Receive 200 OK response via SIP OPTIONS.
//The application gets the receiving user's capability, then forwards this 200 OK
//or terminates this SIP dialog.
@CommunicationEvent(type = CommunicationEvent.Type.QUERIED )
void handleOptionsResponse() {
Conversation ui = (Conversation )ctx.getCommunication();
CapabilityMessage optionMsg = (CapabilityMessage)ctx.getMessage();
Capability myCapability = optionMsg.getCapabilities();
}
...
End User Confirmation Request (EUCR) is a mechanism by which an application server communicates with a user about a service, and queries for confirmation as to what actions to take. In the client device's user interface (UI) this might equate to a pop-up menu or similar UI element that the user can interact with to confirm or deny a specific service request.
The sequence of steps to perform a EUCR is as follows:
The end user confirmation request is implemented using a SIP MESSAGE method containing an XML payload of type application/end-user-confirmation-request+xml
that is sent by the application server to the end user's RCS-e client (for example, a mobile phone).
Upon receipt of the SIP MESSAGE, the end user's device checks the P-Asserted-Identity of the incoming message, and matches it against the configured URI for the service, and extracts the request information from the XML payload body. A dialog or notification is displayed on the end user's device (UX dependant) displaying the confirmation request and any related information.
The end user's confirmation response is encapsulated in an XML body with a payload of type application/end-user-confirmation-response+xml
, and returned either in the SIP MESSAGE response back to the MNO, or in a new SIP MESSAGE.
The information contained in the end user confirmation request is:
id: Unique identifier of the request.
type: Determines the behavior of the receiving device. The type can take one of the following two values:
volatile—the answer is returned in the SIP 200 OK response. If the SIP INFO message times out without end user input, the request is discarded.
persistent—the answer is returned in a new SIP MESSAGE request. The confirmation request does not time out.
pin: Determines whether a pin number is requested of the end user. It can take one of the following two values: true or false. If the attribute is not present it is considered false. Pin requests can be used to add a higher degree of confirmation authentication, and can be used to allow operations such as parental control or other security features.
Subject: Text to display within the notification, or as a dialog box title.
Text: Text to display within the body of the dialog box.
(Optional) If the type of the confirmation request is persistent, the MNO can send an optional acknowledgement message of the transaction back to the user with a welcome message, an error message, or additional instructions. The acknowledgement message is encapsulated in an XML body with a payload of type application/end-user-confirmationack+ xml
and returned in the SIP 200 OK body of the confirmation SIP MESSAGE.
The end user confirmation response is:
id: Unique identifier of the request.
value: Specifies if the end user accepts or declines the request. It takes one of the following two values: accept or decline
The information contained in the end user acknowledgement response is:
id: Unique identifier of the request.
status: with the end user confirmation. It can take one of the following two values: ok or error
Subject: Text to display within the notification, or as a dialog box title.
Text: Text to display within the body of the dialog box.
EUCR makes use of the following classes in the com.oracle.sft.api
package. For more information on these interfaces and their usage, refer to the Converged Application Server API Reference.
Table 25-3 Interfaces for EUCR
Class | Description |
---|---|
|
Represents the data structure for the End User Confirmation Request, End User Confirmation Response, and End User Confirmation Acknowledgement messages. |
|
Represents the Subject and Text message displayed on the end user client during EUCR exchange. |
|
The extended Message for EUCR exchange. |
|
Represents a two party IM conversation. The application uses this communication type to send and receive messages. For EUCR,
|
|
Specifies events pertaining to a Communication. Any method using this annotation is invoked when the
|
|
A utility class to create objects that are not related to a |
Example 25-6 shows the code to sends a EUCR in response to initiating a file transfer. If the user chooses to confirm the request, they will be charged an additional amount on their bill.
Example 25-6 EUCR In Response to a File Transfer
@CommunicationBean public class MyCommunicationBean { @Context CommunicationSession session; @Context CommunicationContext ctx; @Context CommunicationService service; private boolean authorization = false; private Message origMsg; @CommunicationEvent(type=CommunicationEvent.Type.INITIALIZATION ) void handleInit() { origMsg = ctx.getMessage(); Interaction ii = (Interaction ) ctx.getCommunication(); if ( ii instanceof MSRPConversation){ MSRPConversation MSRPConv = (MSRPConversation) ii; Participant receiver = MSRPConv.getParticipant(); Participant sender = MSRPConv.getInitiator (); IMConversation newIM = session.createIMConversation("imserver@example.com"); newIM.addParticipant(sender.getName()); /** * EndUserConfirmationData request = service.createEndUserConfirmationData(); request.setId("EucrTest1"); request.setPinRequired(true); request.setBehaviour(Behaviour.Persistent ); // Constructor to create a new IMConversation, and send the EUCR. newIM.createEndUserConfirmationRequestMessage(request).send(); EndUserConfirmationDisplay display; display = request.createDisplayText("Extra Charge","Charing Conditions", "en"); request.setCondition(display); display = request.createDisplayText("????,"0?1?/M", "ch"); request.setCondition(display); try { } catch (InterruptedException e) { e.printStackTrace(); } if( !authorization){ origMsg.reject(Reason.DECLINE); MSRPConv.end(); } } } //** * Handles SIP MESSAGE 200 OK containing the EUCR response is received by IMConversation * @CommunicationEvent(type=CommunicationEvent.Type.CONFIRMATION_RESPONDED) void handleEUCResponseMessage() { IMConversation IMConv = (IMConversation) ctx.getCommunication(); byte[] content = ctx.getMessage().getContent().toString().getBytes(); EndUserConfirmationMessage msg = (EndUserConfirmationMessage) ctx.getMessage(); EndUserConfirmationData resp = msg.getData(); EndUserConfirmationData ack = resp.createAcknowledgement(); if ( resp.getAction().equalsIgnoreCase("accept")){ resp.setAcknowledgement( resp.createDisplayText("Welcome", "Hello", "en")); msg.consume(); this.authorization = true; IMConv.end(); }else { resp.setAcknowledgement( resp.createDisplayText("Sorry", "Can Not Access", "en")); msg.consume() this.authorization = false; IMConv.end(); } } }
Message Session Relay Protocol (MSRP) is a protocol for transmitting a series of related instant messages in the context of a session. Message sessions are treated like any other media stream when set up via a rendezvous or session creation protocol such as the Session Initiation Protocol (SIP). MSRP Sessions are defined in RFC 4975.
To support store and forward status reporting and message disposition, RCS-e uses Instant Message Disposition Notification (IMDN) to request and forward dispositions of all exchanged messages. Converged Application Server supports Page Mode instant messaging, which uses the SIP method MESSAGE as defined in RFC 3428. Page Mode instant messaging establishes no sessions. Instant Message Disposition Notification (IMDN) is defined in RFC 5438.
Instant messages are constructed using the Common Presence and Instant Messaging (CPIM) message format defined in RFC 3862. Converged Application Server supports the following aspects of RFC 5438 when constructing Instant Messages in the CPIM message format:
Adding a Message-ID header field
If the IM Sender requests the reception of IMDNs, the IM Sender must include a Message-ID header field. The Message-ID header field enables the IM Sender to match any IMDNs with their corresponding IMs. See Section 7.1.1.1 for more information.
Automatically adding a DataTime header field
Some devices are not able to retain state over long periods of time. For example, mobile devices may have memory limitations. These limitations mean that these devices may not be able to, or may choose not to, keep sent messages for the purposes of correlating IMDNs with sent IMs. To make some use of IMDN in this case, a time stamp is added to the IM to indicate when the user sent the message. The IMDN returns the time stamp to enable the user to correlate the IM with the IMDN. The DateTime CPIM header field for this purpose. Thus, if the IM Sender wants an IMDN, the IM Sender must include the DateTime CPIM header field. See Section 7.1.1.2 for more information.
Adding a Disposition-Notification header field
The Disposition-Notification header field conveys the type of disposition notification requested by the IM Sender. There are three types of disposition notification: delivery, processing, and display. The delivery notification is further subdivided into failure and success delivery notifications. An IM Sender requests failure delivery notification by including a Disposition-Notification header field with a value of negative-delivery
. A success notification is requested by including a Disposition-Notification header field with the value positive-delivery
. The IM Sender can request both types of delivery notifications for the same IM.
The IM Sender can request a processing notification by including a Disposition-Notification header field with value processing
.
The IM Sender can also request a display notification. The IM Sender MUST include a Disposition-Notification header field with the value display
to request a display IMDN.
The absence of this header field, or the presence of the header field with an empty value, indicates that the IM Sender is not requesting any IMDNs. Disposition-Notification header field values are comma-separated. The IM Sender may request more than one type of IMDN for a single IM.
See Section 7.1.1.2 for more information.
Parsing aggregated IMDNS
An IM Sender may send an IM to multiple recipients in one Transport Protocol Message (typically using a URI-List server) and request IMDNs. An IM Sender that requests IMDNs must be able to receive multiple aggregated or non-aggregated IMDNs. See Section 8.3 for more information.
Converged Application Server supports following aspects of RFC 5438 when constructing the IMDN:
Constructing Delivery notifications
Constructing Display notifications
Constructing Processing notifications
Constructing Aggregated IMDNs
Refer to RFC 5438 for more information on these aspects of creating IMDNs.
IMDN makes use of the following classes in the com.oracle.sft.api
package. For more information on these interfaces and their usage, refer to the Converged Application Server API Reference.
Class | Description |
---|---|
|
The extension to |
|
Represents the data carried in the Disposition message. |
|
The data structure for disposition notification. You use this interface to construct and parse IMDN payloads. |
|
Specifies events pertaining to a Communication. Any method using this annotation is invoked when the
|
|
Represents a two party IM conversation. The application uses this communication type to send and receive messages. For IMDN, |
|
Represents a multi-party, Page Mode instant message session. For IMDN, |
Example 25-7 creates an instant message with an IMDN in the message header for a two-party IM conversation.
Example 25-7 Creating an Instant Message With an IMDN Request
public class CpimServlet extends HttpServlet{ /** CommunicationSession session = (CommunicationSession)request.getSession().getAttribute(CommunicationSession.NAME); CommunicationService service = (CommunicationService)request.getSession().getAttribute(CommunicationService.NAME); java.io.PrintWriter out = response.getWriter(); String party1 = request.getParameter("Party1"); String party2 = request.getParameter("Party2"); try { out.println("<html>"); IMConversation conv = session.createIMConversation(party1); conv.addParticipant(party2); CommonPresenceInstantMessage cpimReq = conv.createCommonPresenceInstantMessage (); cpimReq.setHeader(Header.Subject.toString(), "imdn test"); DispositionContext disposCxt = cpimReq.buildDispositionContext("hello world!", "text/plain"); disposCxt.setDispositionRequest(RequestType.negative_delivery); disposCxt.setDispositionRequest(RequestType.processing); cpimReq.setDispositionContext(disposCxt); cpimReq.send(); }
Example 25-8 creates a CommunicationBean
that acts as an intermediary server (a store-and-forward server) for a two-party conversation using the IMConversation
interface. The actual IMDN message is not stored, but content disposition is performed so that Store/Forward information status reporting can be done according to RFC 5438.
Example 25-8 Creating an IMDN with CommunicationBean
@ServiceAttributes(domainName = "example.com") @CommunicationBean public class CpimBean { @Context CommunicationSession session; @Context CommunicationContext ctx; @Context CommunicationService service; private DispositionContext aggregationContext; @CommunicationEvent(type=CommunicationEvent.Type.MESSAGEARRIVED) void handleMessage ( ){ //** If the message contains a disposition request, the server forwards the message * to the recipient. If the message is sent to multiple recipients, the server * behaves as specifed RFC 5365. /* IMConversation conv = (IMConversation) ctx.getCommunication(); CommonPresenceInstantMessage msg = (CommonPresenceInstantMessage)conv.getMessage(); DispositionContext getImdns = msg.getDispositionContext(); if (getImdns == null ){ System.out.println("Received CPIM message "); } if (getImdns != null && getImdns.getDispositionNotifications()== null){ System.out.println("Received Disposition Request "); msg.consume(); CommonPresenceInstantMessage imdnMsg = conv .createCommonPresenceInstantMessage(); imdnMsg.setDispositionContext( getImdns()); imdnMsg.send(); } } @CommunicationEvent(type=CommunicationEvent.Type.DISPOSITION_REQUEST_SUCCESS_RESPONDED) void handleImdnSuccessResponse ( ){ IMConversation conv = (IMConversation) ctx.getCommunication(); CommonPresenceInstantMessage msg = (CommonPresenceInstantMessage )conv.getMessage( ); DispositionContext origCxt = msg.getDispositionContext(); CommonPresenceInstantMessage newMsg = conv.createCommonPresenceInstantMessage (); if ( origCxt.isDispositionRequest( RequestType.positive_delivery ){ newMsg.buildDispositionContext(msg,Type.delivery ,Status.delivered); } if(imdnMsg.getDispositionContext()!= null && imdnMsg.getDispositionContext().getDispositionNotifications() != null ) newMsg.send( conv.getParticipant() ); } @CommunicationEvent(type=CommunicationEvent.Type.DISPOSITION_REQUEST_FAILURE_RESONDED) void handleImdnFailureResponse( ){ IMConversation conv = (IMConversation) ctx.getCommunication(); CommonPresenceInstantMessage msg = (CommonPresenceInstantMessage )conv.getMessage( ); DispositionContext origCxt = msg.getDispositionContext(); CommonPresenceInstantMessage newMsg = conv.createCommonPresenceInstantMessage (); if ( origCxt.isDispositionRequest( RequestType.negative_delivery ){ newMsg.buildDispositionContext(msg, Type.delivery ,Status.failed); } // If the message is stored, if ( origCxt.isDispositionRequest( RequestType.processing ){ newMsg.buildDispositionContext(nsg,Type.processing ,Status.stored); } if(imdnMsg.getDispositionContext()!= null && imdnMsg.getDispositionContext().getDispositionNotifications() != null ) newMsg.send( conv.getParticipant() ); } @CommunicationEvent(type=CommunicationEvent.Type.MESSAGE_SUCCESS_RESPONDED) void handleResponse() { System.out.println(" Enter MESSAGE_SUCCESS_RESONDED event "); IMConversation conv = (IMConversation) ctx.getCommunication(); CommonPresenceInstantMessage msg = (CommonPresenceInstantMessage)ctx.getMessage(); if (msg!= null && msg.getDispositionContext()!= null && msg.getDispositionContext().getDispositionNotifications()!=null ){ System.out.println(" Disposition Notification Message is Responed "); conv.end(); } } @CommunicationEvent(type=CommunicationEvent.Type.MESSAGE_FAILURE_RESPONDED) void handleErrorResponse() { System.out.println(" Enter MMESSAGE_FAILUER_RESPONDED event "); }