JBoss.orgCommunity Documentation
Copyright © 2010 Red Hat, Inc.
Abstract
This is user guide to USSD example.
This manual uses several conventions to highlight certain words and phrases and draw attention to specific pieces of information.
In PDF and paper editions, this manual uses typefaces drawn from the Liberation Fonts set. The Liberation Fonts set is also used in HTML editions if the set is installed on your system. If not, alternative but equivalent typefaces are displayed. Note: Red Hat Enterprise Linux 5 and later includes the Liberation Fonts set by default.
Four typographic conventions are used to call attention to specific words and phrases. These conventions, and the circumstances they apply to, are as follows.
Mono-spaced Bold
Used to highlight system input, including shell commands, file names and paths. Also used to highlight key caps and key-combinations. For example:
To see the contents of the file
my_next_bestselling_novel
in your current working directory, enter thecat my_next_bestselling_novel
command at the shell prompt and press Enter to execute the command.
The above includes a file name, a shell command and a key cap, all presented in Mono-spaced Bold and all distinguishable thanks to context.
Key-combinations can be distinguished from key caps by the hyphen connecting each part of a key-combination. For example:
Press Enter to execute the command.
Press Ctrl+Alt+F1 to switch to the first virtual terminal. Press Ctrl+Alt+F7 to return to your X-Windows session.
The first sentence highlights the particular key cap to press. The second highlights two sets of three key caps, each set pressed simultaneously.
If source code is discussed, class names, methods, functions, variable names and returned values mentioned within a paragraph will be presented as above, in Mono-spaced Bold
. For example:
File-related classes include
filesystem
for file systems,file
for files, anddir
for directories. Each class has its own associated set of permissions.
Proportional Bold
This denotes words or phrases encountered on a system, including application names; dialogue box text; labelled buttons; check-box and radio button labels; menu titles and sub-menu titles. For example:
Choose Mouse Preferences. In the Buttons tab, click the Left-handed mouse check box and click to switch the primary mouse button from the left to the right (making the mouse suitable for use in the left hand).
from the main menu bar to launchTo insert a special character into a gedit file, choose from the main menu bar. Next, choose from the Character Map menu bar, type the name of the character in the Search field and click . The character you sought will be highlighted in the Character Table. Double-click this highlighted character to place it in the Text to copy field and then click the button. Now switch back to your document and choose from the gedit menu bar.
The above text includes application names; system-wide menu names and items; application-specific menu names; and buttons and text found within a GUI interface, all presented in Proportional Bold and all distinguishable by context.
Note the
shorthand used to indicate traversal through a menu and its sub-menus. This is to avoid the difficult-to-follow 'Select from the sub-menu in the menu of the main menu bar' approach.
or Mono-spaced Bold Italic
Proportional Bold Italic
Whether Mono-spaced Bold or Proportional Bold, the addition of Italics indicates replaceable or variable text. Italics denotes text you do not input literally or displayed text that changes depending on circumstance. For example:
To connect to a remote machine using ssh, type
ssh
at a shell prompt. If the remote machine isusername
@domain.name
example.com
and your username on that machine is john, typessh john@example.com
.The
mount -o remount
command remounts the named file system. For example, to remount thefile-system
/home
file system, the command ismount -o remount /home
.To see the version of a currently installed package, use the
rpm -q
command. It will return a result as follows:package
.
package-version-release
Note the words in bold italics above username, domain.name, file-system, package, version and release. Each word is a placeholder, either for text you enter when issuing a command or for text displayed by the system.
Aside from standard usage for presenting the title of a work, italics denotes the first use of a new and important term. For example:
When the Apache HTTP Server accepts requests, it dispatches child processes or threads to handle them. This group of child processes or threads is known as a server-pool. Under Apache HTTP Server 2.0, the responsibility for creating and maintaining these server-pools has been abstracted to a group of modules called Multi-Processing Modules (MPMs). Unlike other modules, only one module from the MPM group can be loaded by the Apache HTTP Server.
Two, commonly multi-line, data types are set off visually from the surrounding text.
Output sent to a terminal is set in Mono-spaced Roman
and presented thus:
books Desktop documentation drafts mss photos stuff svn books_tests Desktop1 downloads images notes scripts svgs
Source-code listings are also set in Mono-spaced Roman
but are presented and highlighted as follows:
package org.jboss.book.jca.ex1; import javax.naming.InitialContext; public class ExClient { public static void main(String args[]) throws Exception { InitialContext iniCtx = new InitialContext(); Object ref = iniCtx.lookup("EchoBean"); EchoHome home = (EchoHome) ref; Echo echo = home.create(); System.out.println("Created Echo"); System.out.println("Echo.echo('Hello') = " + echo.echo("Hello")); } }
Finally, we use three visual styles to draw attention to information that might otherwise be overlooked.
A note is a tip or shortcut or alternative approach to the task at hand. Ignoring a note should have no negative consequences, but you might miss out on a trick that makes your life easier.
Important boxes detail things that are easily missed: configuration changes that only apply to the current session, or services that need restarting before an update will apply. Ignoring Important boxes won't cause data loss but may cause irritation and frustration.
A Warning should not be ignored. Ignoring warnings will most likely cause data loss.
If you find a typographical error in this manual, or if you have thought of a way to make this manual better, we would love to hear from you! Please submit a report in the the Issue Tracker, against the product Mobicents JAIN SLEE USSD Example, or contact the authors.
When submitting a bug report, be sure to mention the manual's identifier: JAIN_SLEE_USSD_EXAMPLE_User_Guide
If you have a suggestion for improving the documentation, try to be as specific as possible when describing it. If you have found an error, please include the section number and some of the surrounding text so we can find it easily.
This example is a JAIN SLEE application which acts as simple USSD service provider. Its purpose is to ilustrate how USSD requests are consumed and integrated with JBPM defined state machine.
Ensure that the following requirements have been met before continuing with the install.
The Example doesn't change the Mobicents JAIN SLEE Hardware Requirements, refer to Mobicents JAIN SLEE documentation for more information.
Downloading the source code
Subversion is used to manage its source code. Instructions for using Subversion, including install, can be found at http://svnbook.red-bean.com
Use SVN to checkout a specific release source, the base URL is http://mobicents.googlecode.com/svn/tags/servers/jain-slee/2.x.y/examples/ussd, then add the specific release version, lets consider 1.0.0.BETA1.
[usr]$ svn co http://mobicents.googlecode.com/svn/tags/servers/jain-slee/2.x.y/examples/ussd/1.0.0.BETA1 slee-example-ussd-1.0.0.BETA1
Building the source code
Maven 2.0.9 (or higher) is used to build the release. Instructions for using Maven2, including install, can be found at http://maven.apache.org
Use Maven to build the binary.
[usr]$ cd slee-example-ussd-1.0.0.BETA1 [usr]$ mvn install
Once the process finishes you should have the deployable-unit
jar file in the target
directory, if Mobicents JAIN SLEE is installed and environment variable JBOSS_HOME is pointing to its underlying JBoss Application Server directory, then the deployable unit jar will also be deployed in the container.
Similar process as for Section 2.2.1, “Release Source Code Building”, the only change is the SVN source code URL, which is http://mobicents.googlecode.com/svn/trunk/servers/jain-slee/examples/ussd.
To install the Example simply execute provided ant script build.xml
default target:
[usr]$ ant
The script will copy the Example's deployable unit jar to the default
Mobicents JAIN SLEE server profile deploy directory, to deploy to another server profile use the argument -Dnode=
.
To uninstall the Example simply execute provided ant script build.xml
undeploy
target:
[usr]$ ant undeploy
The script will delete the Example's deployable unit jar from the default
Mobicents JAIN SLEE server profile deploy directory, to undeploy from another server profile use the argument -Dnode=
.
USSD Example is very simple example in terms of code complexity. It responds to USSD requests carried within SIP messages. Based on requests and JBPM process declaration, service responds with specific prompt.
General design is depicted on following diagram:
USSD Top overview
USSD Example JBPM module is used to drive conversation with USSD user.
Process defined in standard JPDL XML consumes USSD string (digits) and provides prompt sent back to user. Logically JBPM process(state and transitions) create interactive menu accessed by USSD user.
Defined process and source are not mature code. It is designed to be easy to edit for user to alter decision process and menu.
JBPM process consists of states, transitions and in case of this example, decisions. I this example decision element chooses transition based on provided input.
By convention there are two types of transitions, distinguished by names:
with name equal to digit - this transition moves user down(or up, depending on transition destination) in menu
with name equal to "
end
" - this transition is chosen when no user input can not be
matched to any defined transition
General overview of decision design is depicted on diagram below:
Decision overview
In this example, JBPM process simulates interactive menu. Each JBPM state represent menu position. Each transition represent menu position change.
Menu position have associated prompt. Its content is what accessing user sees on devices display(for instance cell phone)
Example declares following menu:
Lists schedule of trains in Pune.
Lists schedule of trains in some artificial town.
Lists schedule of trains in Volgograd.
terminates interaction
Lists location of train stations in Pune.
Lists location of train stations in some artificial town.
Lists location of train stations in Volgograd.
terminates interaction
Lists ticket discounts.
Trap which loops back to itself.
SLEE part of this example is simple. It performs following tasks:
Gateway creates
SIP
dialog by means of
INVITE
- which carries initial
USSD
request.
INFO
messages
Subsequent requests are sent as in Dialog
INFO
messages.
SIP messages carry XML encoded USSD string(please refer to gateway documentation for details). String is fed into JBPM in order to fetch response to be sent.
Flow diagram below depicts how service acts:
USSD SLEE Service flow diagram
USSD Example JBPM related source is simple. Example defines two custom classes to perform additional tasks within flow. Also XML process definition consists of simple, not complex menu to ease learning process.
Decisions are performed by custom handler, its source looks as follows:
package org.mobicents.example.ss7.ussd.jbpm;
import java.util.Map;
import org.apache.log4j.Logger;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.node.DecisionHandler;
public class USSDDecisionHandler implements DecisionHandler {
private static final Logger logger = Logger.getLogger(USSDDecisionHandler.class);
public static final String _INPUT_ = "ussd.input";
public static final String _END_ = "end";
public String decide(ExecutionContext ctx) throws Exception {
//get what we got from user
String input = (String) ctx.getVariable(_INPUT_);
Map transitions = ctx.getNode().getLeavingTransitionsMap();
if(transitions.get(input) == null)
{
return _END_;
}else
{
return ""+input;
}
}
}
Handler expects user input to be passed as context variable with specific name. Its value is set by process user(here, by service, refer Section 4.2.3.4, “USSD Processing” ). In case there is no transition under passed input, handler falls back to predefined transition(not it MUST be present in XML definition).
Decision handler is bound into process with following declaration:
<decision name="welcome_decision" expr="#{ussd.input}">
<handler class="org.mobicents.example.ss7.ussd.jbpm.USSDDecisionHandler" />
<transition name="1" to="schedule" />
<transition name="2" to="location" />
<transition name="3" to="discount" />
<transition name="4" to="promo" />
<!-- this is default transition to end, it has to be present -->
<transition name="end" to="end" />
</decision>
Prompt is set in process context by custom handler. Handler is activated once process enters state(it is defined in XML definition of process). Source looks as follows:
package org.mobicents.example.ss7.ussd.jbpm;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
public class USSDPromptHandler implements ActionHandler {
public static final String _PROMPT_ = "ussd.prompt";
private String prompt;
private boolean end = false;
/**
* @return the end
*/
public boolean isEnd() {
return end;
}
/**
* @param end
* the end to set
*/
public void setEnd(boolean end) {
this.end = end;
}
/**
* @return the prompt
*/
public String getPrompt() {
return prompt;
}
/**
* @param prompt
* the prompt to set
*/
public void setPrompt(String prompt) {
this.prompt = prompt;
}
public void execute(ExecutionContext ctx) throws Exception {
ctx.setVariable(_PROMPT_, prompt);
if (end) {
// make transition
ctx.leaveNode();
}
}
}
Note that this handler has additional property. This property
controls whether process should move to another state, once proper
prompt is set, or not. Process state which set this property to true
MUST
declare single transition, refer to
Section 4.1.3, “XML Process definition”
for details
Prompt handler is bound into process with following declaration:
<state name="welcome">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>Welcome to train station scheduler service. Press following digits for 1) Train schedule. 2) Station location. 3) Discount rates. 4) Promo</prompt>
</action>
</event>
<transition name="welcome" to="welcome_decision" />
</state>
Process is defined in single file,
trainstation.jpdl.xml
. Its content looks as follows:
<?xml version="1.0" encoding="UTF-8"?>
<process name="TrainStationDecisions" xmlns="urn:jbpm.org:jpdl-3.2">
<start-state>
<transition to="welcome" />
</start-state>
<state name="welcome">
![]()
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>Welcome to train station scheduler service. Press following digits for 1) Train schedule. 2) Station location. 3) Discount rates. 4) Promo</prompt>
</action>
</event>
![]()
<transition name="welcome" to="welcome_decision" />
</state>
![]()
<decision name="welcome_decision" expr="#{ussd.input}">
![]()
<handler class="org.mobicents.example.ss7.ussd.jbpm.USSDDecisionHandler" />
![]()
<transition name="1" to="schedule" />
<transition name="2" to="location" />
<transition name="3" to="discount" />
<transition name="4" to="promo" />
![]()
<!-- this is default transition to end, it has to be present -->
<transition name="end" to="end" />
</decision>
<!-- SCHEDULE -->
<state name="schedule">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>Please pick city 1) Pune. 2) Test location. 3) Volgograd. 4) End</prompt>
</action>
</event>
<transition name="decide" to="schedule_decision" />
</state>
<decision name="schedule_decision" expr="#{ussd.input}">
<handler class="org.mobicents.example.ss7.ussd.jbpm.USSDDecisionHandler" />
<transition name="1" to="schedule_pune" />
<transition name="2" to="schedule_test" />
<transition name="3" to="schedule_volgograd" />
<transition name="4" to="end" />
<!-- this is default transition to end, it has to be present -->
<transition name="end" to="end" />
</decision>
<state name="schedule_pune">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>Trains leave to each destination on each odd hour.</prompt>
<end>true</end>
</action>
</event>
<transition name="end" to="end" />
</state>>
<state name="schedule_test">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>Test location does not have any means of transport!</prompt>
<end>true</end>
</action>
</event>
<transition name="end" to="end" />
</state>
<state name="schedule_volgograd">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>Test location does not have any means of transport!</prompt>
<end>true</end>
</action>
</event>
<transition name="end" to="end" />
</state>
<!-- LOCATION -->
<state name="location">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>Please pick city 1) Pune. 2) Test location. 3) Volgograd. 4) End</prompt>
</action>
</event>
<transition name="decide" to="location_decision" />
</state>
<decision name="location_decision" expr="#{ussd.input}">
<handler class="org.mobicents.example.ss7.ussd.jbpm.USSDDecisionHandler" />
<transition name="1" to="location_pune" />
<transition name="2" to="location_test" />
<transition name="3" to="location_volgograd" />
<transition name="4" to="end" />
<!-- this is default transition to end, it has to be present -->
<transition name="end" to="end" />
</decision>
<state name="location_pune">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>Train station is located at 353, Laxmi Road, Near Vijay Talkies .</prompt>
<end>true</end>
</action>
</event>
<transition name="end" to="end" />
</state>
<state name="location_test">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>Test location does not have any means of transport!</prompt>
<end>true</end>
</action>
</event>
<transition name="end" to="end" />
</state>
<state name="location_volgograd">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>Train stations are located at: xxx</prompt>
<end>true</end>
</action>
</event>
<transition name="end" to="end" />
</state>
<!-- DISCOUNT -->
<state name="discount">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>There are no DISCOUNT! Pay the price!</prompt>
<end>true</end>
</action>
</event>
<transition name="end" to="end" />
</state>
<!-- PROMO -->
<state name="promo">
<event type='node-enter'>
<action class='org.mobicents.example.ss7.ussd.jbpm.USSDPromptHandler'>
<prompt>You are now trapped in endles loop! Press something!</prompt>
<end>true</end>
</action>
</event>
<transition name="decide" to="discount_decision" />
</state>
<decision name="discount_decision" expr="#{ussd.input}">
<handler class="org.mobicents.example.ss7.ussd.jbpm.USSDDecisionHandler" />
<transition name="0" to="end" />
<transition name="end" to="discount" />
</decision>
<end-state name="end" />
</process>
XML definition has following, distinct elements:
USSD Example SLEE part is very small. It consists of single service and SBB.
SBB reuses USSD gateway library to perform XML encoding/decoding, please refer to gateway documentation for details.
Service is defined with simple XML file: service.xml
. It defines service id and root SBB.
File content looks as follows:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Right now 1.1 service dtd is not accessible on sun -->
<!DOCTYPE service-xml PUBLIC "-//Sun Microsystems, Inc.//DTD JAIN SLEE Service 1.1//EN" "http://java.sun.com/dtd/slee-service_1_0.dtd">
<service-xml>
<service>
<service-name>USSD Sip Train Scheduler</service-name>
<service-vendor>org.mobicents</service-vendor>
<service-version>1.0</service-version>
<root-sbb>
<sbb-name>USSDSipSbb</sbb-name>
<sbb-vendor>org.mobicents</sbb-vendor>
<sbb-version>1.0</sbb-version>
</root-sbb>
<default-priority>0</default-priority>
</service>
</service-xml>
SBB is defined with single, XML file: sbb-jar.xml
It contains following definitions:
<description>XXX</description>
<sbb-name>USSDSipSbb</sbb-name>
<sbb-vendor>org.mobicents</sbb-vendor>
<sbb-version>1.0</sbb-version>
<sbb-alias>XxX</sbb-alias>
<library-ref>
<library-name>library-ussdgateway</library-name>
<library-vendor>org.mobicents</library-vendor>
<library-version>2.0</library-version>
</library-ref>
<library-ref>
<library-name>library-ussdexample</library-name>
<library-vendor>org.mobicents</library-vendor>
<library-version>1.0</library-version>
</library-ref>
<sbb-classes>
<sbb-abstract-class>
<sbb-abstract-class-name>
org.mobicents.example.ss7.ussd.SipUSSDSbb
</sbb-abstract-class-name>
<cmp-field>
<description>Holds active JBPM process instance</description>
<cmp-field-name>processInstance</cmp-field-name>
</cmp-field>
</sbb-abstract-class>
</sbb-classes>
<!-- SLEE -->
<event event-direction="Receive" initial-event="True">
<event-name>StartServiceEvent</event-name>
<event-type-ref>
<event-type-name>
javax.slee.serviceactivity.ServiceStartedEvent
</event-type-name>
<event-type-vendor>javax.slee</event-type-vendor>
<event-type-version>1.1</event-type-version>
</event-type-ref>
<initial-event-select variable="ActivityContext" />
</event>
<event event-direction="Receive" initial-event="False">
<event-name>ActivityEndEvent</event-name>
<event-type-ref>
<event-type-name>
javax.slee.ActivityEndEvent
</event-type-name>
<event-type-vendor>javax.slee</event-type-vendor>
<event-type-version>1.0</event-type-version>
</event-type-ref>
</event>
<!-- initial -->
<event event-direction="Receive" initial-event="True">
<event-name>InviteEvent</event-name>
<event-type-ref>
<event-type-name>javax.sip.message.Request.INVITE</event-type-name>
<event-type-vendor>net.java.slee</event-type-vendor>
<event-type-version>1.2</event-type-version>
</event-type-ref>
<initial-event-selector-method-name>
callIDSelect
</initial-event-selector-method-name>
</event>
<!-- Intermediate: if any -->
<event event-direction="Receive" initial-event="True">
<event-name>InfoEvent</event-name>
<event-type-ref>
<event-type-name>javax.sip.Dialog.INFO</event-type-name>
<event-type-vendor>net.java.slee</event-type-vendor>
<event-type-version>1.2</event-type-version>
</event-type-ref>
<initial-event-selector-method-name>
callIDSelect
</initial-event-selector-method-name>
</event>
<!-- final -->
<event event-direction="Receive" initial-event="True">
<event-name>ByeEvent</event-name>
<event-type-ref>
<event-type-name>javax.sip.Dialog.BYE</event-type-name>
<event-type-vendor>net.java.slee</event-type-vendor>
<event-type-version>1.2</event-type-version>
</event-type-ref>
<initial-event-selector-method-name>
callIDSelect
</initial-event-selector-method-name>
</event>
<event event-direction="Receive" initial-event="True">
<event-name>CancelEvent</event-name>
<event-type-ref>
<event-type-name>javax.sip.message.Request.CANCEL</event-type-name>
<event-type-vendor>net.java.slee</event-type-vendor>
<event-type-version>1.2</event-type-version>
</event-type-ref>
<initial-event-selector-method-name>
callIDSelect
</initial-event-selector-method-name>
</event>
<!-- success -->
<event event-direction="Receive" initial-event="False">
<event-name>SuccessEvent</event-name>
<event-type-ref>
<event-type-name>javax.sip.message.Response.SUCCESS</event-type-name>
<event-type-vendor>net.java.slee</event-type-vendor>
<event-type-version>1.2</event-type-version>
</event-type-ref>
<initial-event-selector-method-name>
callIDSelect
</initial-event-selector-method-name>
</event>
<resource-adaptor-type-binding>
<resource-adaptor-type-ref>
<resource-adaptor-type-name>
JAIN SIP
</resource-adaptor-type-name>
<resource-adaptor-type-vendor>
javax.sip
</resource-adaptor-type-vendor>
<resource-adaptor-type-version>
1.2
</resource-adaptor-type-version>
</resource-adaptor-type-ref>
<activity-context-interface-factory-name>
slee/resources/jainsip/1.2/acifactory
</activity-context-interface-factory-name>
<resource-adaptor-entity-binding>
<resource-adaptor-object-name>
slee/resources/jainsip/1.2/provider
</resource-adaptor-object-name>
<resource-adaptor-entity-link>
SipRA
</resource-adaptor-entity-link>
</resource-adaptor-entity-binding>
</resource-adaptor-type-binding>
Source of service is contained in single java
compilation unit: org.mobicents.example.ss7.ussd.SipUSSDSbb.java
Aside regular callback methods SLEE requires to be implemented, it has following content:
JBPM is initialized in service start event handler:
public void onStartServiceEvent(javax.slee.serviceactivity.ServiceStartedEvent event, ActivityContextInterface aci) {
ServiceActivity sa = (ServiceActivity) aci.getActivity();
if (sa.getService().equals(this.sbbContext.getService())) {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
jbpmContext = jbpmConfiguration.createJbpmContext();
ProcessDefinition pd = ProcessDefinition.parseXmlInputStream(Thread.currentThread().getContextClassLoader()
.getResourceAsStream(JPDL_FILE));
jbpmContext.deployProcessDefinition(pd);
}
}
Service declares version 1.0 of event, thats why there is check on service!
JBPM is cleaned in activity end event handler:
public void onActivityEndEvent(ActivityEndEvent event, ActivityContextInterface aci) {
if (jbpmContext != null && aci.getActivity() instanceof ServiceActivity) {
// just in case
ServiceActivity sa = (ServiceActivity) aci.getActivity();
if (sa.getService().equals(this.sbbContext.getService())) {
jbpmContext.close();
jbpmContext = null;
}
}
}
Service declares version 1.0 of event, thats why there is check on service!
SIP event handlers are input point for this example. SIP messages (either INVITE
or INFO
) carry XML encoded USSD string.
// initial
public void onInviteEvent(RequestEvent event, ActivityContextInterface ac) {
// its initial request
try {
DialogActivity da = (DialogActivity) this.provider.getNewDialog(event.getServerTransaction());
da.terminateOnBye(true);
ActivityContextInterface daACI = this.acif.getActivityContextInterface(da);
daACI.attach(this.sbbContext.getSbbLocalObject());
ProcessInstance pi = jbpmContext.newProcessInstance(PROCESS_NAME);
this.setProcessInstance(pi);
} catch (SipException e) {
e.printStackTrace();
handleError(event.getServerTransaction(), Response.BAD_REQUEST, e);
return;
}
processUssd(event);
}
// intermediate
public void onInfoEvent(RequestEvent event, ActivityContextInterface ac) {
processUssd(event);
}
// final
public void onByeEvent(RequestEvent event, ActivityContextInterface ac) {
// something should be here?
sendResponse(null, event.getServerTransaction());
}
public void onCancelEvent(CancelRequestEvent event, ActivityContextInterface ac) {
this.provider.acceptCancel(event, false);
}
// success
public void onSuccessEvent(ResponseEvent event, ActivityContextInterface ac) {
// nothing,
}
USSD string is extracted with JAXB library from USSD gateway and fed into JBPM, it is done as follows:
private void processUssd(RequestEvent event) {
//this method is called for INVITE and INFO received by SBB
// now lets get USSD
USSDRequest extracted = extractUssd(event);
if (extracted == null) {
// error has been handled
return;
}
String drooled = processUssd(extracted);
// send ok
if (drooled != null) {
sendResponse(drooled, event.getServerTransaction());
if (isSessionDead()) {
// in this case, send bye over dialog
sendBye();
}
}
}
private boolean isSessionDead() {
ProcessInstance pi = this.getProcessInstance();
if(pi == null || pi.getEnd()!=null)
{
return true;
}
else
{
return false;
}
}
private USSDRequest extractUssd(RequestEvent event) {
Request sipRequest = event.getRequest();
ContentTypeHeader cth = (ContentTypeHeader) event.getRequest()
.getHeader(ContentTypeHeader.NAME);
if (cth == null) {
// FIXME: break
return null;
} else {
if (!cth.getContentType().equals(CONTENT_TYPE)
|| !cth.getContentSubType().equals(CONTENT_SUB_TYPE)
|| sipRequest.getContent() == null) {
// break,
return null;
}
}
try {
![]()
Unmarshaller uMarshaller = jAXBContext.createUnmarshaller();
ByteArrayInputStream bis = new ByteArrayInputStream(sipRequest.getRawContent());
JAXBElement<USSDRequest> data = (JAXBElement<USSDRequest>) uMarshaller.unmarshal(bis);
return data.getValue();
} catch (JAXBException e) {
// FIXME: tear down
e.printStackTrace();
}
return null;
}
private String processUssd(USSDRequest extracted) {
![]()
ProcessInstance pi = this.getProcessInstance();
![]()
pi.getContextInstance().setVariable(USSDDecisionHandler._INPUT_, extracted.getUssdString());
![]()
pi.signal();
![]()
String data = (String) pi.getContextInstance().getVariable(USSDPromptHandler._PROMPT_);
![]()
USSDResponse response = this.objectFactory.createUSSDResponse();
response.setInvokeId(extracted.getInvokeId());
response.setUssdCoding(extracted.getUssdCoding());
response.setUssdString(data);
response.setEnd(isSessionDead());
response.setLastResult(true);
![]()
try {
Marshaller marshaller = jAXBContext.createMarshaller();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
JAXBElement<USSDResponse> res = this.objectFactory.createResponse(response);
marshaller.marshal(res, bos);
return new String(bos.toByteArray());
} catch (JAXBException e) {
e.printStackTrace();
}
return null;
}
Unmarshall JAXB pojo from SIP message content, if present. | |
Fetch JBPM process instance from CMP. | |
Set process instance context variable to received USSD string. | |
Signal process instance to transit to another state(to decision element actually). | |
Fetch context instance variable with prompt content. | |
Create JAXB pojo based on received request (JAXB pojo) and USSD prompt. | |
Marshal |
Example does not require any additional setup except USSD gateway and simulator. Example should be deployed as follows:
Deploy overview
To run example simply make call from USSD simulator to preconfigured number( by default its #123*) and follow instructions displayed there.
Example declares single tracer: javax.slee.SbbNotification [service=ServiceID[name=USSD Sip Train Scheduler,vendor=org.mobicents, version=1.0],sbb=SbbID[name=USSDSipSbb,vendor=org.mobicents, version=1.0]].SipUSSDSbb
Spaces where introduced to render page correctly. Please remove them when using copy/paste.
Revision History | |||
---|---|---|---|
Revision 1.0 | Wed June 2 2010 | ||
|