For quick development of new application features, server-side JavaScript is supported. You can use JavaScript to perform common programming tasks like arithmetic operations, string operations, and variable value testing. At runtime, the SCE compiles JavaScript code into byte code for high performance execution by the server-side JavaScript engine.
A maximum of 3 scripts can be associated with any PAC. The timing of when the scripts are to be run must be specified when the script is added.
Each application has a global script area used to define common JavaScript functions that can be called from a PAC-level script. The global script area can only contain global function definitions, and it cannot contain global variables.
The SCE supports the #include
statement to allow external JavaScript files to be included in many different applications.
The following example illustrates the use of an #include
statement to allow external JavaScript files to be included in many different applications.
/* include a file of common JavaScript functions I might want to use */
#include "my_scripts.jsh"
/* plus define a function of my own that is just used in this applications*/
function isMyAddress( var ipAddress ){
if( ipAddress == Server.ipAddress ){
return true;
}
else{
return false;
}
The following objects are in the object model:
Standard ECMA objects (such as String, Array, Date, RegExp) provide powerful and expressive capabilities and are fully supported by the JavaScript execution environment. For more information, see the ECMAScript Language Specification, Edition 3.
Application server integration objects enable JavaScript code to interact with an XTML application built using the SCE. For more information, see Application Server Integration Objects.
SIP objects provide the ability to easily parse and create SIP headers and messages. For more information, see SIP Objects.
SDP objects are used for describing the attributes of a communication session. SIP message bodies include a session description encoded using SDP to describe the required attributes of a session. For more information, see SDP Objects.
RADIUS objects are used for carrying authentication, authorization, and billing information between network access devices and shared authentication servers. For more information, see RADIUS Objects.
IN objects provide the ability to easily parse and create Intelligent Network (IN) parameters and messages. For more information, see IN Objects.
You can add JavaScript code to the PACs in your function using the JavaScript Editor window in the SCE user interface.
Right-click the PAC that you want to associate the script with, and then click JavaScript Editor. The JavaScript Editor window appears.
Tip
You can also open this window by pressing F2, or by clicking
In the Function field in the tool bar, leave the default option or select <global> to add a global script area.
Tip
The Action field allows you to move to other PACs in the application by selecting them from the list.
In the Timing field in the tool bar, select when the script will be executed.
If first is selected, the script executes before the PAC.
If middle is selected, the script executes when the PAC has finished executing, but before any custom results are evaluated.
If last is selected, the script executes after the application server evaluates custom results to determine the next PAC to be executed, but before the application server leaves the element.
Enter the JavaScript code in the text box in the window.
Tip
When you enter predefined objects, a drop-down list will appear with possible suggestions for completing the object.
When finished, click the compile button to check your code. If there are any coding errors, an error message appears.
Click Apply to save and apply changes, and then close the window.
One of the issues when integrating a JavaScript execution environment into a client or server execution environment is deciding what type of client or server functionality to expose to the scripting environment. In the case of XTML, integration is needed so that variables defined in an XTML document can be accessed or updated from JavaScript.
In addition, some of the application management capabilities provided by the application server are exposed to the scripting environment. This integration is provided by means of three JavaScript objects: Session, Server, and Result. These objects created by the application server are available to every running application session to use in any JavaScript code.
The Session object enables JavaScript code to access or update the value of any XTML application variable. Variables that have been defined in an XTML document can be accessed as a property of the Session object. When JavaScript code accesses a property of the Session object, the value of the corresponding variable is automatically retrieved and used. When JavaScript code assigns a value to a property of the Session object, the corresponding XTML variable is updated with the new variable.
Assigning an arbitrary JavaScript object to an XTML variable converts the object to a string and assigns the XTML variable the string value. However, you can copy XTML variable objects with assignment, such as copying session variables to each other.
Note
You should lock shared variables only when you can unlock them in the same JavaScript segment.
In addition to the properties for each XTML variable, the Session object has three predefined properties that can be distinguished from XTML variables because they start with an underscore (_).
The Session object has no methods.
/* let's increment the number of retries and see if the user has had enough
changes*/
if( ++Session.nRetries > 3 )
Session.try again = 1;
else
Session.try again = 0;
/* save my session id in an application variable */
Session.myId = Session._sessionId;
The Server object allows JavaScript code to use some of the special-purpose application management capabilities provided by the XTML server.
Property |
Type |
Description |
---|---|---|
id |
Number |
Read-only property that holds the integer identifier of the XTML server process in which this JavaScript is executing. |
ipAddress |
String |
Read-only property that holds the IP address of the local host on which the XTML Server process is running. |
sipAddress |
String |
Read-only property that holds the IP address where the SIP stack is executing. Note that in a distributed environment the SIP stack can be executing on a different machine from the application. |
sipPort |
Number |
Read-only property that holds the UDP port that the SIP stack is listening on. |
soapAddress |
String |
Read-only property that holds the IP address that the SOAP agent is running on. |
soapPort |
Number |
Read-only property that holds the UDP port on which the SOAP agent is listening on. |
Method |
Returns |
Description |
---|---|---|
enableEvents (bool bEnable) |
Void |
Enables or disables event handling in the current application session. When event handling is disabled, incoming asynchronous events are queued until event handling is enabled again. |
getUTCTime |
Integer |
Returns the current time in terms of number of seconds since 1970, in GMT time zone. |
lockSharedVariables |
Void |
Locks shared variables for updates. If a session wishes to update a shared variable it must first lock them, then perform the update, then unlock them. |
logError(string message) |
Void |
Logs an error message to the system log. |
logInfo(string message) |
Void |
Logs an informational message to the system log. |
trace(string message) |
Void |
Logs a message to the application trace file, if tracing is turned on for this session. |
unlockSharedVariables |
Void |
Unlocks shared variables. |
convertIpAddressIntToString(int address) |
String |
Returns the dot-decimal representation of an IP address that is provided as an integer value. |
convertIpAddressStringToInt(string address) |
Integer |
Returns the integer representation of an IP address that is provided as string (dotdecimal or dns name format). |
getUTCTimeAsString |
String |
Returns the current UTC time in a string formatted as
Note This format is required with certain RADIUS Cisco vendor-specific attributes that handle time. For example, h323-setup-time, h323-connect-time, h323-disconnect-time, etc. |
generateCiscoH323ConfId |
String |
Returns a string formatted in accordance with Cisco
specifications for RADIUS call identifier vendor-specific
attributes
|
/* let's disable events because I want to treat the next few XTML actions in
my app as a critical section, during which I don't want to be interrupted by
jangups, etc */
Server.enableEvents ( false );
Server.logInfo ( "disabling events in session " + Session. sessionId );
/* get the current time so we can write it to the database */
Session.strConnectTime = Server.getUTCTimeAsString();
The Result object allows JavaScript code to examine the result of the currently executing PAC.
Property |
Type |
Description |
---|---|---|
id |
Number |
Read-only property that holds the integer identifier of
the result of the currently executing PAC. Results are
identified in ascending numeric order, starting with one
for the topmost result displayed in the SCE for the
PAC. In most PACs, for example, the Default result has
an ID of |
name |
String |
Read-only property that holds the name of the result for the currently executing PAC. |
Note
The Result properties return different values in the middle and last scripts if a custom result is true. In a middle script, the predefined result that was the outcome of the PAC is returned because custom results have not yet been evaluated. In a last script, the values returned will be for the custom result, if one was selected, or for the predefined result.
Note
If a first script accesses the Result object, the ID property will be zero, and the name property will be undefined-result because the PAC has not yet returned a result.
The Result object has no methods.
/* log an error if result of the current PAC was not 'Success' */
if( Result.id != 2 ) {
Server.logInfo("Error: exiting with result " + Result.name );
The tasks required to build SIP-based applications include parsing the SIP message headers, extracting the information relevant to the application, and executing call flow logic based on that information. The SIP object model is provided to simplify that task. This object parses incoming SIP messages and allows you to access SIP header information as simple object properties. Additionally, it allows you to create SIP message headers by setting object properties.
For descriptions of each SIP object, see the JavaScript Common Method Objects User’s Guide.
Each SIP object has a name with the format SipXXX, such as SipUrl or SipTo, and implements a common set of methods, which are described in the following table.
Method |
Description |
---|---|
void decode(string) |
Parses the provided string into a set of individual information elements. These information elements can then be accessed as object properties. |
string encode() |
Returns the string representation of the object in SIP format. |
Typically, an application creates a SIP header object, calls the decode method to parse a header, accesses and updates the properties of the object corresponding to particular information elements, and calls the encode method to return the modified SIP header. The following example shows this sequence:
var to = new SipTo(); /* create an object that wraps a Sip
To: header */
to.decode( Session.strToHdr ); /* parse the To: header */
to.displayName = "John Smith"; /* change display name */
Session.strToHdr = to.encode(); /* write the modified header back to the
variable*/
SIP objects also implement the standard JavaScript toString method that is automatically called whenever an object is referenced directly in a context in which a string value is needed. In addition, the constructor can optionally take a single parameter that is the string to parse. Therefore, the previous example can also be written in the following way:
var to = new SipTo( Session.strToHdr ); /* create the object parse in
one step*/
to.displayName = "John Smith"; /* change display name */
Session.strToHdr = to; /* write the changed header back*/
The following are several examples of how SIP objects can be used.
var url = new
SipUrl("sip:+12065551212@acmecom:5060;user=phone;postd=12;isub=99?hi=there&go=away");
Server.logInfo ("SipUrl.user: " + url.user );
Server.logInfo ("SipUrl.password: " + url.password );
Server.logInfo ("SipUrl.host: " + url.host );
Server.logInfo ("SipUrl.port " + url.port );
Server.logInfo ("SipUrl.phoneNumber: " +url.phoneNumber );
Server.logInfo ("SipUrl.userParm: " + url.userParm );
Server.logInfo("SipUrl.postdial: " + url.postdial );
Server.logInfo("SipUrl.isdn: " + url.isdn );
Server.logInfo("number of headers: " + url.headers.length );
Server.logInfo("headers:")
nItems = url.headers.length;
for( var i = 0; i < nItems; i++ )
{
Server.logInfo("param #" + i + ": " + url.headers[i] );
}
Server.logInfo("now changing transport to tcp");
url.transport = "tcp";
Server.logInfo("url is now: " + url );
var route = new SipRoute("John Doe<john@company.com>, <userB@hostB.com>");
Server.LogInfo("route.nameAddr.length: " + route.nameAddrs.length );
for( var i = 0; i < route.nameAddrs.length; i++ )
{
/* the SipRoute object has a 'nameAddrs' property which is an Array of
SipNameAddr's */
Server.logInfo("route.nameAddrs[" + i + "].displayName: " +
route.nameAddrs[i].displayName);
Server.logInfo("route.nameAddrs[" + i + "].url: " +
route.nameAddrs[i].url);
}
Server.logInfo("my ip address is: " + Server.ipAddress );
Server.logInfo("my session id is: " + Session._sessionId );
var url = new SipUrl( Server.ipAddress );
url.port = 5060;
Server.logInfo("simple url with local host and no user " + url );
var cseq = new SipCSeq(Session.current_cseq);
/* I need to increment the Cseq from the last time and change the method */
cseq.method = "BYE";
cseq.increment(); /* if it was "5 INVITE" it's now "6 BYE" */
Session.current_cseq = cseq;
var vias = new SipViaArray("SIP/2.0/UDP kton.bell-tel.com;branch=123xyz (here
is a comment )\nSIP/2.0/UDP john@company.com");
Server.logInfo("there are " + vias.vias.length + " via headers");
for( var i = 0; i < vias.vias.length; i++ )
{
Server.logInfo("via.protocol: " + vias.vias[i].protocol);
Server.logInfo("via.version: " + vias.vias[i].version);
Server.logInfo("via.transport: " + vias.vias[i].transport);
Server.logInfo("via.branch: " + vias.vias[i].branch);
Server.logInfo("via.comment: " + vias.vias[i].comment);
Server.logInfo("via.url: " + vias.vias[i].url);
Server.logInfo("via.url.host: " + vias.vias[i].url.host);
Server.logInfo("via: " + vias.vias[i]);
}
Server.logInfo("via header will be like this:\n" + vias );
var retry = new SipRetryAfter( "Mon, 21 Jul 1997 18:48:34 GMT;duration=600(in
meeting)");
Server.logInfo("retry.date = " + retry.date );
Server.logInfo("retry.duration = " + retry.duration );
Server.logInfo("retry.comment = " + retry.comment );
Server.logInfo("retry.deltaSeconds = " + retry.deltaSeconds );
Server.logInfo("retry = " + retry );
var myDate = retry.date;
/* try out some of the ECMA Date() methods */
Server.logInfo("myDate.getYear() = " + myDate.getYear() );
Server.logInfo("myDate.getMonth() = " + myDate.getMonth() );
Server.logInfo("myDate.getDay() = " + myDate.getDay() );
Server.logInfo("myDate.getDate() = " + myDate.getDate() );
Server.logInfo("myDate.getHour() = " + myDate.getHours() );
Server.logInfo("myDate.getMinutes() = " + myDate.getMinutes() );
Server.logInfo("myDate.getSeconds() = " + myDate.getSeconds() );
Server.logInfo("myDate.toGMTString() = " + myDate.toGMTString() );
Server.logInfo("myDate = " + myDate.toString() );
var callid = new SipCallID("100@company.com");
Server.logInfo("callid.localID = " + callid.localID );
Server.logInfo("callid.host = " + callid.host );
/* let's create a new call id by incrementing the localID portion */
var i = parseInt( callid.localID ) + 1;
Server.logInfo(" new local callid will be " + i );
callid.localID = i.toString();
Server.logInfo("callid is now: " + callid );
var accept = new SipAccept("application/sdp;level=1, application/sip-cgi,
text/html");
for( var i = 0; i < accept.contentTypes.length; i++ )
{
Server.logInfo("accept.contentTypes[" + i + "].type = " +
accept.contentTypes[i].type );
Server.logInfo("accept.contentTypes[" + i + "].subtype = " +
accept.contentTypes[i].subtype );
Server.logInfo("accept.contentTypes[" + i + "].attribute = " +
accept.contentTypes[i].attribute );
Server.logInfo("accept.contentTypes[" + i + "].value = " +
accept.contentTypes[i].value );
}
Server.logInfo("accept: " + accept );
var ct = new SipContentType();
ct.decode("application/sdp; level=1");
ct.decode(" application/sdp; audio");
Server.logInfo("ct.type: " + ct.type );
Server.logInfo("ct.subtype: " + ct.subtype );
Server.logInfo("ct.attribute: " + ct.attribute );
Server.logInfo("ct.level: " + ct.level );
/* change the subtype information */
ct.subtype = "sip-cgi";
Server.logInfo("ct: " + ct );
var status = new SipStatus("SIP/2.0 200 OK" );
Server.logInfo("status.version: " + status.version );
Server.logInfo("status.code: " + status.code );
Server.logInfo("status.reason: " + status.reason );
var route = new SipRoute("John Doe<userA@hostA.com>, <userB@hostB.com>");
Server.logInfo("route.nameAddr.length: " + route.nameAddrs.length );
for( var i = 0; i < route.nameAddrs.length; i++ )
{
Server.logInfo("route.nameAddrs[" + i + "].displayName: " +
route.nameAddrs[i].displayName);
Server.logInfo("route.nameAddrs[" + i + "].url: " +
route.nameAddrs[i].url);
}
var via = new SipVia("SIP/2.0/UDP kton.bell-tel.com;branch=123xyz (here's a
comment )");
Server.logInfo("via.protocol: " + via.protocol);
Server.logInfo("via.version: " + via.version);
Server.logInfo("via.transport: " + via.transport);
Server.logInfo("via.branch: " + via.branch);
Server.logInfo("via.comment: " + via.comment);
Server.logInfo("via.url: " + via.url);
Server.logInfo("via.url.host: " + via.url.host);
Server.logInfo("via: " + via);
Server.logInfo("via.encode(): " + via.encode());
/* here's a url with all the trimmins */
var to = new SipTo("John
Doe<sip:+12065551212@company.com:5060;user=phone;postd=12;isub=99;transport
=udp;method=invite;a=b;c=d?x1=23&y2=25>; tag=123xyz");
Server.logInfo("to.displayName: " + to.displayName );
Server.logInfo("to.url: " + to.url );
Server.logInfo("to.tag: " + to.tag );
/* note the url property is itself an object, so we can directly access its
properties */
Server.logInfo("to.url.user: " + to.url.user );
Server.logInfo("to.url.host: " + to.url.host );
Server.logInfo("to.url.port: " + to.url.port );
Server.logInfo("to.url.phoneNumber: " + to.url.phoneNumber );
Server.logInfo("to.url.transport: " + to.url.transport );
Server.logInfo("number of params: " + to.url.parms.length );
Server.logInfo("params:")
var nItems = to.url.parms.length;
for( var i = 0; i < nItems; i++ )
{
Server.logInfo("param #" + i + ": " + to.url.parms[i] );
}
Server.logInfo("number of headers: " + to.url.headers.length );
Server.logInfo("headers:")
nItems = to.url.headers.length;
for( var i = 0; i < nItems; i++ )
{
Server.logInfo("param #" + i + ": " + to.url.headers[i] );
}
Server.logInfo("now changing transport to tcp");
to.url.transport = "tcp";
Server.logInfo("to: " + to.encode() );
Server.logInfo("to.tag: " + to.tag );
Server.logInfo("to.encode(): " + to.encode() );
Server.logInfo("to.toString(): " + to.toString() );
to.decode( "jdoe@company.com" );
Server.logInfo("to.encode(): " + to.encode() );
var url = new
SipUrl("sip:+12065551212@company.com:5060;user=phone;postd=12;isub=99;transp
or
t=udp;method=invite?hi=there&go=away");
Server.logInfo("SipUrl.user: " + url.user );
Server.logInfo("SipUrl.password:" + url.password );
Server.logInfo("SipUrl.host: " + url.host );
Server.logInfo("SipUrl.port: " + url.port );
Server.logInfo("SipUrl.phoneNumber: " + url.phoneNumber );
Server.logInfo("SipUrl.userParm: " + url.userParm );
Server.logInfo("SipUrl.maddr: " + url.maddr );
Server.logInfo("SipUrl.transport: " + url.transport );
Server.logInfo("SipUrl.postdial: " + url.postdial );
Server.logInfo("SipUrl.isdn: " + url.isdn );
SDP objects, together with SIP, are used for describing the attributes of a communication session. SIP message bodies include a session description encoded using SDP to describe the required attributes of a session.
For descriptions of each SDP object, see the JavaScript Common Method Objects User’s Guide.
SDP objects implement the encode and decode common methods that the SIP objects implement. For more information, see Common Methods.
This example shows some of the SDP objects used in JavaScript code.
var sdp = new Sdp(Session.strContent);
/* save the remote ip address and port to send to */
Session.strRemoteAddress = sdp.connection.address;
if( sdp.media.length > 1 ) /* do we have at least one media line ? */
{
Session.nRemotePort = sdp.media[0].port;
}
/* check to see if any of the payloads offered are G.711 */
var bFoundG711 = false;
for( var i = 0; I < sdp.media.length; i++ )
{
/* we're only interested in audio media streams */
if( sdp.media[i].type == "audio" )
{
/* cycle through all the payloads offered for this media stream */
for( var j = 0; j < sdp.media[i].rtpmaps.length; j++ )
{
/* payload type 0 is u-law PCM coded single channel at 8Khz*/
if( sdp.media[i].rtpMaps[j].type == 0 )
{
bFoundG711 = true;
break;
}
}
/* create my sdp, which will only offer G.711 */
var myRtpMap = new SdpRtpMap();
myRtpMap.type =0;
/* eliminate all choices but this */
sdp.media.rtpMaps.length = 0;
sdp.media.rtpMaps[0] = myRtpMap;
RADIUS objects are used for carrying authentication, authorization, and billing information between network access devices and shared authentication servers. IMSWorkX products support both the core RADIUS spec (RFC 2865) and the accounting extensions (RFC 2866).
For descriptions of each RADIUS object, see the JavaScript Common Method Objects User’s Guide.
This example shows some of the RADIUS objects used in JavaScript code.
/* In this example we set up a vendor-specific attribute for an outgoing
message.
Here we create one vendor-specific variable with three subattributes */
var vsa = new RadiusVSA;
vsa.vendorId = 9; /* Cisco */
vsa.attributes.push( RadiusVSAAttribute( 27, "h323-call-type=VoIP" ) );
vsa.attributes.push( RadiusVSAAttribute( 1, "subscriber=RegularLine" ) );
vsa.attributes.push( RadiusVSAAttribute( 33, "h323-gw-id=" ) );
/* encode the vendor-specific attribute to an xtml string for sending */
Session.strVsa = vsa.encode();
/* simply put the 'strVsa' xtml variable in the 'Send RADIUS Message' PAC for
the vendor-specific attribute */
/* this creates three vendor-specific variables, each with one subattributes */
var vsa = new RadiusVSA;
vsa.vendorId = 9; /* Cisco */
vsa.attributes.push( RadiusVSAAttribute( 27, "h323-call-type=VoIP" ) );
/* encode the vendor-specific attribute to an xtml object for sending */
/* the xtml object must be set up as an array, as illustrated below */
Session.oVsa[0] = vsa.encode();
/* clear and reuse the RadiusVSA variable, then add it to the next element of
the array*/
vsa.length = 0;
vsa.attributes.push( RadiusVSAAttribute( 1, "subscriber=RegularLine" ) );
Session.oVsa[1] = vsa.encode();
vsa.length = 0;
vsa.attributes.push( RadiusVSAAttribute( 33, "h323-gw-id=" ) );
Session.oVsa[2] = vsa.encode();
/* simply put the 'oVsa' xtml variable in the 'Send RADIUS Message' PAC for
the vendor-specific attribute */
/* In this example we use some Javascript helper methods to create conf-ids
and store time values in a format consistent with Cisco IVR scripts */
var vsa = new RadiusVSA;
vsa.vendorId = 9; /* Cisco */
vsa.attributes.push( RadiusVSAAttribute( 28, "h323-connect-time=" +
Server.getUTCTimeAsString()) );
vsa.attributes.push( RadiusVSAAttribute( 24, "h323-conf-id=" +
Server. generateCiscoH323ConfId() );
/* encode the vendor-specific attribute to an xtml string for sending */
Session.strVsa = vsa.encode();
The tasks required to build IN-based applications include parsing the IN message parameters, extracting the information relevant to the application, and executing call flow logic based on that information. The IN object model is provided to simplify that task. This object parses incoming IN messages and allows you to access IN parameter information as simple object properties. Additionally, it allows you to create IN message parameters by setting object properties.
For descriptions of each IN object, see the JavaScript Common Method Objects User’s Guide.
Each IN object has a name that is the same as the name of the message and implements a common set of methods, which are described in the following table.
Method |
Description |
---|---|
void decode(string) |
Parses the provided string into a set of individual information elements. These information elements can then be accessed as object properties. |
string encode() |
Returns the string representation of the object in IN format. |
Typically, an application creates an IN object, calls the decode method to parse an object, accesses and updates the properties of the object corresponding to particular information elements, and then calls the encode method to return the modified IN object. The following example shows this sequence:
var called = new CalledPartyID(); /* create an object that wraps a CalledPartyID parameter */
called.decode( Session.bsCalledParty ); /* parse the CalledPartyID parameter */
called.nature_of_number = 100; /* change the nature of number */
called.numbering_plan = 7; /* change the numbering plan */
called.digits = "01234"; /* change the digits */
Session.bsCalledParty = called.encode(); /* write the modified parameter back to the variable */