The Source for Java Technology Collaboration


Third party call control

Contributed by Jayway AB

Abstract

This is a web based third party call control application with instant user feedback.
Third party call control (3pcc) is the term for session setup done by another party than the ones actually exchanging media.
The third party is in control of the session and can terminate it or manipulate it in other ways e.g. re-inviting the parties to change media properties.

Prerequisites

JBoss and Java versions

This application has been tested on Mobicents running on JBoss 3.2.6 and JBoss 3.2.7 using jdk1.4 or jdk1.5

Eclipse & Ant

If you use Ant from within Eclipse:

Window --> Preferences --> Ant --> Runtime --> Global Entries must include $JAVA_HOME/lib/tools.jar

where $JAVA_HOME should be replaced by your concrete path to the Java installation.

Example /opt/jdk1.5.0_06/lib/tools.jar

  • Ensure that the environment variable JBOSS_HOME is set to your JBoss installation folder.
Ex: /opt/jboss-3.2.7

  • Since the project has dependencies into the JBoss installation structure, ensure that you have defined an Eclipse classpath variable that is referencing your JBoss installation folder. Use

Wndow --> Preferences --> Java --> Build Path --> Classpath Variables

to create a new classpath variable called 'JBOSS_HOME'.

Mobicents & Sip RA

You need Mobicents deployed with the sip RA.
Note: You may run the sip proxy included in the Mobicents distribution but sip BYE requests will be processed by the proxy app which is not relevant. You may get disturbed by the debug messages for this.

The recommended installation procedure is to use the "auto-deploy-sip" target and comment out the part in the bean shell script that deploys the proxy.

See the scripts/sip-deploy-sipraonly.bsh which you can use.

To build and deploy Mobicents simply run the "auto-deploy-sip" target and (optionally) replace the $JBOSS_HOME/server/all/deploy-mobicents/scripts/sip-deploy.bsh file with the scripts/sip-deploy-sipraonly.bsh.

Mobicents rar ipaddress issue

If you use another ipaddress than 127.0.0.1 for running JBoss it may be necessary to edit the file server/all/deploy/mobicents.sar/slee-ds.xml by changing "localhost" to your ipaddress in the following line:

<config-property name="SleeJndiName" type="java.lang.String">jnp://localhost:1099/SleeService</config-property>

It has been observed that it is not possible to communicate on 127.0.0.1:1099 on a Linux system unless this change is performed.

Install and run

SLEE service

Go to '3pcc_sip_slee' and run the target 'auto-deploy-ThirdPCCTrigger'

Note: This target installs the bean shell script "thirdPCCTrigger-deploy.bsh" which
must be processed after the sip RA has been deployed.
To achieve this its name must be alphanumerically preceded by "sip-deploy-sipraonly.bsh" or whatever name you use for this file.
(You don't have to change anything but if you by any reason would change the name of this file beware of this restriction)

Web application

The web app can be run in two modes, using two different call services - 'Servlet' and 'WebService'.
Which call service to use is configured in a simple property file.
When using the 'Servlet' call service, it is the the web app (i.e. servlet) that invokes the SLEE service (by using the SleeConnection?).
On the other hand, when the 'WebService' call service is used, the web app uses a web service client to invoke (over ParlayX?) a web service (WS) on the machine on which the SLEE service is deployed.
This enables the web server and the SLEE container to be deployed on two physically separate machines.

Plain web app

Run JBoss by:

  • Go to $JBOSS_HOME
  • Issue ./bin/run.sh -c all -b youripaddress (on a Unix system)
    or ./bin/run -c all -b youripaddress (on Windows)

Go to '3pcc' and run the target 'deploy-3pcc_web_app-(hot)'

Point your browser to http://youripaddress:8080/thirdpcc

Web app + web service

There is a target that deploys the web app and the web service on the localhost, emulating the case where they are indeed deployed on separate machines.

Start JBoss and then run the target 'deploy-3pcc_web_app+web_service-(hot)'

Point your browser to http://youripaddress:8080/thirdpcc and verify that web service is in fact used

There is yet another target for deploying only the web app and the integrated WS client - 'deploy-3pcc_web_app+ws_client-(hot)'.
However, before executing this target, you need to deploy the SLEE service and the WS server on "the other machine", since the WS client is generated based ona WSDD retrieved from the WS server.

If you run into problems when installing and/or running the application, please consult the READMEs and the release notes in the specific subproject - it's all there!

Note: In order to switch call service ('Servlet' and 'WebService'), you need to stop JBoss, undeploy, change call service (in 3pcc_web/common/etc/callservice.properties) and then deploy again!
It's not enough to change the file in the deployed dir, since this info is read by a singleton at deploy time!

Note: The sip UAs used must not be registered with the proxy shipped in Mobicents, this does not work.
Instead let the 3pcc application address the sip UAs directly by calling them by ipaddress or register with another proxy.
One recommended proxy that has been tested with the application is Sip Express Router freely available at www.iptel.org.
Another good proxy to use is Jain Sip Presence Proxy. (Easier to use and setup than Sip Express Router)

One way of verifying that the installation of the SLEE service is successful is to use SleeGraph (another Mobicents example application) which should show this:


Click to see full image.

Screenshots from the web GUI:

Call launch form


Click to see full image.

Status feedback page


Click to see full image.

Metrics

Having run the application it can be interesting to try out one of the built in features in JSLEE - the usage facility.
It is very easy to provide usage statistics by defining custom interfaces available from the Sbbs of an application.

This application provides a set of metrics that are available via MBeans, point your browser to
http://localhost:8080/jmx-console and scroll down to he 'slee' section, click on

SbbUsageMBean=ServiceID[se.jayway.sip.slee.service.ThirdPCCTrigger-service#Jayway#0.1]/SbbID[se.jayway.sip.slee.sbb.CallControlSbb#Jayway#0.1]


Click to see full image.

Design

This section outlines sample design subjects in the application

Sbb design

JSLEE defines a component model for asynchronous, event based applications and the components are called Service Building Blocks, Sbbs.
There are two Sbb components making up the call control logic.
Only one is strictly necessary and the reason for splitting the functionality into two is that
one of the components, CallControlSbb, is made reusable because it has no dependencies
to any custom events used to trigger the callflow or terminate it and there is no
dependency from CallControlSbb to ThirdPCCTriggerSbb.

Responsibilities of respective component:

  • ThirdPCCTriggerSbb -- Receive custom events for triggering, terminating and cancelling the callflow.

  • CallControlSbb -- Manage the core sip callflow and sharing state of the callflow to external components that wish to monitor progress.

The interaction between ThirdPCCTriggerSbb and CallControlSbb is of two types: a) ThirdPCCTriggerSbb has a child relation to CallControlSbb and creates a child when the callflow is initiated.

b) ThirdPCCTriggerSbb invokes synchronous methods of the local interface of CallControlSbb for termination/cancelling of the callflow.

It is possible to use CallControlSbb in another application that uses these two interaction mechanisms.
The CallControlSbb only depends on the event types defined in the sip RA.

State sharing between slee application and external components.

This is implemented by passing an interface (

StateCallback
) from the web app to the SLEE app. The
StateCallback
object is a property of the ThirdPCCTriggerEvent. The implementation here is very simple and can only be used if the servlet container and JSLEE container are colocated in the same JVM. Implementations suitable for clusters can use e.g. JMS to distribute the state to be communicated from Sbbs to the web app. This would be transparent to the JSLEE application.

State machine

The state pattern suggests itself in this application.
The state machine is derivable from the simple callflow recommended in IETF recommended callflows for 3pcc
and is illustrated in the diagram


Click to see full image.

The state classes are inner classes of CallControlSbb which is handy.
However, to make the state machine itself reusable the state classes can be made ordinary, non-inner classes.
This is probably the right way to go and the next step will be to indentify the interface that CallControlSbb
must implement to externalize the state classes.

The most interesting purpose with this refactoring is to write new CallControllSbbs that implement
the different state sharing mechanisms.

Release Notes

For complete feature set and interoperability information see release notes.
Users are encouraged to update this page with new interoperability information.

Code walkaround

Let's take a look at some code to get a feeling for what it's like coding a JSLEE application.

Controller Servlet

We start out in the web application controller servlet where http requests are accepted and JSLEE events are fired off to
control the sip service.

  ThirdPCCTriggerEvent event = new ThirdPCCTriggerEvent(caller, callee);

  //Retrieve GUID
  guid = event.getGUID();

  final String eventName = "se.jayway.sip.slee.event.ThirdPCCTriggerEvent";
  final String eventVendor = "Jayway";
  final String eventVersion = "0.1";

This code shows a custom event class that encapsulates the sip addresses of the parties.
It also produces a GUID for the 3pcc session that is later used to query for call status information or terminating the session.

The final String objects are used to identify an EventID which the JSLEE container maintains and is defined in the deployment descriptor of the service.

Now for the part that actually fires off an event:

SleeConnection conn = null;

// Now go on and establish the connection

conn = factory.getConnection(); // factory is of type SleeConnectionFactory

EventTypeID eventTypeID = conn.getEventTypeID(eventName, eventVendor, eventVersion);
         
conn.fireEvent(event, eventTypeID, null, null);

This fires off our event without specifying an optional ExternalActivityHandle or Address (the two null arguments).

SLEE Service

ThirdPCCTriggerSbb

Now some interesting things will happen in the JSLEE container.
Note that we fire off an event on the JSLEE container as a whole,
we didn't specify an application or an Sbb component.
It's the job of the JSLEE container to find out what Sbb components, if any will receive the fired event.

The root Sbb of the application is ThirdPCCTriggerSbb and this is the part of its sbb-jar.xml that makes
the JSLEE instantiate a new root Sbb for our event:

<event event-direction="Receive" initial-event="True">
   <event-name>ThirdPCCTriggerEvent</event-name>
      <event-type-ref>
         <event-type-name>se.jayway.sip.slee.event.ThirdPCCTriggerEvent</event-type-name>
   <event-type-vendor>Jayway</event-type-vendor>
   <event-type-version>0.1</event-type-version>
   </event-type-ref>
   <initial-event-select variable="ActivityContext" />
</event>

We also have to inform the container what Sbb is the root Sbb of our service, this is done in the service.xml deployment descriptor:

<service-xml>
    <service>
        <description/>
        <service-name>se.jayway.sip.slee.service.ThirdPCCTrigger-service</service-name>
        <service-vendor>Jayway</service-vendor>
        <service-version>0.1</service-version>
        <root-sbb>
            <description/>
            <sbb-name>se.jayway.sip.slee.sbb.ThirdPCCTriggerSbb</sbb-name>
            <sbb-vendor>Jayway</sbb-vendor>
            <sbb-version>0.1</sbb-version>
        </root-sbb>
        <default-priority>0</default-priority>
    </service>
</service-xml>

The job of the ThirdPCCTriggerSbb is to receive events and perform corresponding work, remember that the core sip signalling work is the duty of the CallControlSbb.
When the event arrives the JSLEE container at some stage invokes the

onThirdPCCTriggerEvent
method.

This method illustrates a powerful mechanism on JSLEE in that it uses the child relation to CallControlSbb and attaches the child to a newly created ActivityContextInterface object that corresponds to a sip client transaction in which the first INVITE is sent:

// Build the INVITE request
Request request = sipUtils.buildInvite(callerAddress, calleeAddress, null, 1);
// Create a new transaction based on the generated request
ClientTransaction ct = sipProvider.getNewClientTransaction(request);
         
// Get activity context from factory
ActivityContextInterface ac = activityContextInterfaceFactory.getActivityContextInterface(ct);

Now we have a sip request, its client transaction and corresponding ActivityContextInterface, we go on and create a child Sbb, attach it to the activity context and send the request:

ChildRelation relation = getCallControlSbbChild();
// Create child SBB
child = relation.create();

// Attach child SBB to the activity context
ac.attach(child);

// Send the INVITE request
ct.sendRequest();

CallControlSbb

Now that the sip signalling is initiated we must take care of the responses that will arrive and carry out the rest of the work.
This is done in the onXXXEvent methods in CallControlSbb that process events defined in the Sip RA.

One of the most important methods is the onSuccessRespEvent and this is some of the code that runs when the 200 OK of the first INVITE arrives:

         Object content = event.getResponse().getContent(); // This is the SDP from the callee (first party) that will be sent to caller
         String contentString = null;
         if (content instanceof byte[]) {
            contentString = new String((byte[]) content);

         } else if (content instanceof String) {
            contentString = (String) content;
         }

         final byte[] sdpOffer = contentString.getBytes();
         
         // Get the addresses from the sessions
         SessionAssociation sa = (SessionAssociation) cache.get(calleeCallId);
         Session calleeSession = sa.getCalleeSession();         
         Address calleeAddress = calleeSession.getSipAddress();
         // We use the identity of the third party call controller as caller address
         Address callControlAddress = sipUtils.convertURIToAddress(getCallControlSipAddress());
         try {
            callControlAddress.setDisplayName(((SipURI)calleeAddress.getURI()).getUser());  
         } catch (ParseException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
         }
         Session callerSession = sa.getCallerSession();
         Address callerAddress = callerSession.getSipAddress();

         Request request = sipUtils.buildInvite(callControlAddress, callerAddress, sdpOffer, 1);

This shows the work of managing the association between the two dialogs of the parties in the call setup and managing display names e.t.c.
Note that we use a special (configurable) sip address of the call controller but use the display name of the parties.

When we send the second invite there is a similar mechanism in creating a new ActivityContextInterface corresponding to a new sip client transaction
but this time we attach the same Sbb instance to the new activity. An Sbb can be associated to multiple activities.

ActivityContextInterface aci = activityContextInterfaceFactory.getActivityContextInterface(ct);

            SbbLocalObject mySelf = sbbContext.getSbbLocalObject();
            // Attach child SBB to the activity context
            aci.attach(mySelf);
            ct.sendRequest(); // ct  is a ClientTransaction

Future work

  • Externalize the state machine to facilitate reuse of it in different call control components

Related Resources

-- Main.jamattsson - 21 Apr 2006

Topic 3pccExample . { Edit | Ref-By | Printable | Diffs r14 < r13 < r12 < r11 < r10 | More }
 XML java.net RSS

Revision r14 - 17 Dec 2006 - 03:44:44 - Main.ivelin
Parents: MobicentsExamples