Introduction
You can find programming
guides and examples for programming various aspects of the IBM® Business
Process Manager system, in this article.
In Process Designer all
variables are JavaScript variables so you can use JavaScript code snippets
inside your components to improve the behavior of your model.
Variable availability
You
can only use certain JavaScript objects inside a specific context. In some
contexts, certain objects are automatically instantiated.
Table 1. Object
availability
|
Object
|
Context Allowed
|
Context Instantiated
|
Context Denied
|
TWLogger
|
All
|
None
|
None
|
TW
|
Process
|
Process
|
ScoreBoard
|
TWScoreboard
|
ScoreBoard
|
ScoreBoard
|
Process, Service
|
Chart
|
ScoreBoard
|
Filter Layout,
Datasource
|
None
|
TWDate
|
All
|
None
|
None
|
TWMap
|
All
|
None
|
None
|
String
|
All
|
None
|
None
|
XMLDocument
|
All
|
None
|
None
|
XMLElement
|
All
|
None
|
None
|
XMLNodelist
|
All
|
None
|
None
|
listOf
|
All
|
None
|
None
|
ic
|
All
|
None
|
None
|
Alert
|
All
|
None
|
None
|
Event
|
All
|
None
|
None
|
External JavaScript libraries
Process Designer provides a
number of JavaScript libraries. You can also import or create your own
libraries.
Using JSON
JSON is a string representation of a
JavaScript object that can be transmitted over the network. You can use it to
pass parameters inside IBM® BPM.
An Open Source JavaScript
implementation is available to both parse and construct JSON strings. Part of
this package is a JavaScript source file called json2.js.
Add this file to your toolkit or
process application as a server managed file to provide new global methods and
objects.
Example
This example illustrates how to taking a List of
Complex data structure and building a JSON representation:
var newArray = new Array();
for (var j=0;
j<tw.local.myPurchase.listLength; j++)
{
var newObj = new Object();
for (var property in tw.local.myPurchase[j].propertyNames)
{
var name = tw.local.myPurchase[j].propertyNames[property];
newObj[name] = tw.local.myPurchase[j][name];
}
newArray.push(newObj);
}
var jsonText =
JSON.stringify(newArray);
log.error("jsonText = " +
jsonText);
Within a browser or the coach, you can use the Dojo
classes to work with JSON:
- dojo.fromJson(string) parses
a JSON string to return a JavaScript object.
- dojo.toJson(Object)
returns a JSON string given a JavaScript object.
Using the Dojo Toolkit
Dojo is an open source set of
JavaScript libraries that enhance the capabilities of native JavaScript. The
Dojo Toolkit is supplied and loaded by Coach Pages.
Commonly,
Dojo is thought as a visual language for building rich web pages. Although this
is an important component of the Dojo Toolkit, it is not its only function.
If you are developing complex
Coach Views using Dojo or another JavaScript library and need advanced features
for JavaScript development, debugging, and testing, consider using an IDE tool,
such as Rational® Application Developer, to initially create the JavaScript.
You can then use the JavaScript that you develop as part of your Coach views in
Process Designer.
Procedure
- Open a Coach component.
- Use Dojo calls. For example,
use var x = dojo.byId("name of control"); to
return the DOM node of the control by name.
JavaScript reference examples
This section provides
JavaScript examples.
Starting a new process
A new instance of a process
can be started by using the tw.system.startProcessByName() function.
The method tw.system.startProcessByName()
returns a TWProcessInstance object and takes 2 parameters:
name (String)
Name of the process.
inputValues (Map)
Map containing the input parameters for the
process.
var inputs = new tw.object.Map();
inputs.put("parm1",
"parm1 value");
inputs.put("parm2",
"parm2 value");
tw.system.startProcessByName("StartProcess2",
inputs);
Thread hung exceptions
Under certain circumstances, an attempt to start a
process instance using the tw.system.startProcessByName()
function might be blocked, and in the system out log you might see a thread
hung exception for a thread holding a database connection. This might happen in
the following circumstance:
- You have defined an
undercover agent (UCA) message event with an attached service.
- In the attached service you
are starting a new process instance using the tw.system.startProcessByName()
function.
- The process you are starting
has variables defined that are exposed to Business Data Search, and the
process creation hangs.
The
recommended solution is to use the BPMN (Business Process Model and Notation)
best practice, and model the process with a start message event.
Getting the current process instance
The current process
instance can be retrieved through the TWProcessInstance variable called tw.system.currentProcessInstance.
Getting the current userid
The current user ID can be
retrieved through the TWUser variable in tw.system.user.
Starting an external application
You can start an external
application such as a batch file or a shell script by performing that task
using the JavaScript LiveScript mechanism.
This sample illustrates how to
run a batch file on a Windows system.
var runtime =
java.lang.Runtime.getRuntime();
runtime.exec("C:\\RunMe.bat");
Returning the owner of a task
You can know the identity of a
user who has completed a given task.
You can do this by defining an
output parameter for the human service to store the name of the user that
completed the task.
Within the human service,
before its termination, use the following code to declare the output
parameter:var user = tw.system.currentTask.assignedTo;
It returns a TWUser object.
The name property can be used
to determine the userid of the user that claimed the task.
Returning a list of reference links
You can return a list of all
reference links of the current process application or toolkit on a server by
running the tw.system.model.processApp.getLinks() method.
This
tw.system.model.processApp.getLinks() method allows for returning reference
links in the toolkits referenced by the process application, and results can be
filtered. The tw.system.model.processApp.getLinks() link property returns only
the reference links for the current process application (not its children), and
the results are not filtered.
Parameters
The method
tw.system.model.processApp.getLinks() returns an array of TWLink and takes two
parameters:includeReferencedToolkitsThis is a boolean flag that indicates if
the links should be collected recursively on all library item elements
contained in the process application and dependent toolkits. linkFilterThis is
a JavaScript function that takes TWLink as parameter and returns a boolean
value that indicates whether the link should be excluded from the result.
The signature of the
linkFilter argument function is boolean linkFilterFunction(TWLink twlink), and
that the filter function is called for each reference link result. The filter
function returns true if the TWLink value in question is filtered out
(excluded), or false if it is not filtered out.
You can collect the names and
URLs of the links using the assetType Change Request from your process
application and its children, and then assign them to local variables in your
process.
This example assumes that the
following two private variables have been defined: requestLinksName of type
String List, and requestLinksURL of type String List. Make sure to select Has
Default for both. The requestLinksName variable is an array that contain the
names of all the links, and the requestLinksURL variable is an array that
contain the URLs of all the links obtained by getLinks() that were not filtered
out by the linkFilter function.
The following example is an
specific example of how to narrow down the list of returned links to be only
those of the Change Request asset type for that process application (and child
projects). However, getLinks() can be used to return all reference links.
var
linkFilter = function (twlink) {
if (twlink != null &&
TWLink.AssetTypes.CHANGE_REQUEST == twlink.assetTypeNamespace){
return false;
}else{
return true;
}
}
var
requestLinks = tw.system.model.processApp.getLinks(true, linkFilter);
if(requestLinks
!= null){
for(var i=0; i<requestLinks.length;
i++){
tw.local.requestLinksName[i] =
requestLinks[i].name;
tw.local.requestLinksURL[i] =
requestLinks[i].url;
}
}
Attention:
If the call is done from the context of another process application, only the
links of the process application can be obtained. The filtered list will not
include any children.
Extracting a managed file
If a process application or a
toolkit contains a managed file, you can extract it from the runtime to
evaluate its content.
This example illustrates how
to extract a managed file by writing its content to a local file.
var managedFile =
tw.system.model.findManagedFileByPath("lsw-services.jar",
TWManagedFile.Types.Server);
log.error("Got the
managed file!: " + managedFile);
managedFile.writeDataToFile("C:\\lsw-services.jar");
Note: The
first parameter of the tw.system.model.findManagedFileByPath API is
managedFilePath, which does not support '!' notation to reference the contents
of an archive.
Searching processes and tasks
You can search a specific task
in a current process.
The JavaScript object of type
TWSearch can be used to perform a search. It has three primary methods:
Ø execute()
Ø executeForProcessInstances()
Ø executeForTasks()
The TWSearch object has a
number of properties that are used to govern the data queried for and
returned.TWSearch.columnsThe columns of data to be
returned.TWSearch.conditionsThe queries to be executed (of type
TWSearchCondition).A call to TWSearch using the execute() method can return a
TWSearchResults object.
log.error("Starting to
find other tasks ....");
log.error("This process:
" + tw.system.currentProcessInstance.id);
var col1 = new
TWSearchColumn();
col1.name =
TWSearchColumn.ProcessInstanceColumns.ID;
col1.type =
TWSearchColumn.Types.ProcessInstance;
var search = new TWSearch();
search.columns = new
Array(col1);
var condition = new
TWSearchCondition();
condition.column = new
TWSearchColumn();
condition.column.name =
TWSearchColumn.ProcessInstanceColumns.ID;
condition.column.type =
TWSearchColumn.Types.ProcessInstance;
condition.operator =
TWSearchCondition.Operations.Equals;
condition.value =
"270";
search.conditions = new
Array(condition);
var order1 = new
TWSearchOrdering();
order1.column = col1;
order1.order =
TWSearchOrdering.Orders.Descending;
search.orderBy = new
Array(order1);
search.organizedBy =
TWSearch.OrganizeByTypes.ProcessInstance;
var results =
search.execute();
log.error("Result.rows.length
= " + results.rows.length);
for (var i=0;
i<results.rows.length; i++)
{
...
}
Calling Java through JavaScript
JavaScript inside IBM® BPM can
invoke Java through the Live Connect technology.
LiveConnect is the name of an
application programming interface that provides JavaScript with the ability to
call methods of Java classes and vice-versa using the existing Java
infrastructure.
Working with document attachments
Document attachments can be associated with
process instances. These can be added through coach controls or through
programmatic additions.
The relevant JavaScript
components are:
TWDocument
The description of a document.
tw.system.findDocumentByID()
Finds a document from its ID.
TWProcessInstance.documents
An array of TWDocument objects
associated with an instance of a process.
TWProcessInstance.addDocument()
Adds a document to a process
instance.
TWProcessInstance.findDocuments()
Locates documents associated
with the current instance.
Note: The
addDocument() function will not work when called from JavaScript locally coded
in a BPD activity but works fine when coded in a general service.
Using the addDocuments() method
The addDocuments() method has
the following parameters:type (String)Either TWDocument.Types.URL or
TWDocument.Types.File.name (String)Name of the document.fileLocation
(String)The path to the file on the server or URI.hideInPortal (Boolean)A flag
which describes whether or not the document is to be visible in the process
portal.createdBy (TWUser)properties (Map)
The following code sample
illustrates how to use the addDocuments() method.
var myMap = new
tw.object.Map();
var hide = false;
var user = tw.system.user;
tw.system.currentProcessInstance.addDocument(
TWDocument.Types.File,
"name",
"C:\\Projects\\WLE\\Images\\ibm.jpg",
hide,
user,
myMap);
Retrieving data from XML
The following examples show
you how to pull data out from an XMLDocument (or any XML type) using the
following XML.
Generally speaking, walking
the XML as shown below is more efficient that using XPath because it does not
call the parser.
The XML example here is the
resultSet from an Integration Component. For the purposes of the example,
assume that the XML below is stored in a variable called myXML.
<resultSet
recordCount="2" columnCount="2">
<record>
<column name="FIRST_NAME">Daniel</column>
<column
name="ZIP">78703</column>
</record>
<record>
<column
name="FIRST_NAME">Helen</column>
<column
name="ZIP">15228</column>
</record>
</resultSet>
The following examples illustrate how
to retrieve specific values from the XML variable.
tw.local.myXML.resultSet
Returns a node list
of records.
tw.local.myXML.resultSet.record[1]
Returns a node list
of columns. In the previous example, the values "Helen" and
"15228".
tw.local.myXML.resultSet.record[1].column[0].getAttribute(
"name")
Returns
"FIRST_NAME".
tw.local.myXML.resultSet.record[1].column[1].getAttribute("name")
Returns
"ZIP".
tw.local.myXML.resultSet.record[1].column[1].getText()
Returns 15228.