If you use IBM WebSphere Process Server then you already know about its many
features. In this article, learn how to harness the power of the Dojo TreeWidget to
manage your processes in WebSphere Process Server. Through an example, explore how to
manipulate hierarchical data structures and create a Web 2.0-style user interface (UI) to
manage your data.
You can download the sample code used in this article from the Download table below.
The dojox.Grid, an important component of the Dojo widget, lets you
easily operate and present remote data and data from web pages.
TreeGrid has advantages of both dijit.Tree and
dojox.Grid: It has tree's ability to handle the hierarchical data structures and grid's data
presentation capabilities. Just like the dojox.Grid, there are two
approaches to building a TreeGrid: declaratively or programmatically. Figure 1
shows a simple TreeGrid.
Figure 1. Simple Dojo TreeGrid
TreeGrid adopted a Model-View-Controller (MVC)
design pattern, as shown below.
Figure 2. Architecture of TreeGrid
TreeGrid maintains a data model to manage the
original data that will be used by TreeGrid to present the data with a great UI.
TreeGrid can access the data store to fetch or handle the data via the
APIs provided by the dojo.data.api, which is the standard way to access the
data in Dojo. Dojo provides lots of data stores that have implemented
APIs of the dojo.data.api, including: ItemFileReadStore and
ItemFileWriteStore (users can read or handle the JSON data using them);
XmlStore, CsvStore, and OpmlStore for the other data formats; and so
on. Table 1 summarizes the data stores.
Table 1. Implemented Dojo DataStores
| DataStore | Purpose |
|---|---|
| dojo.data.ItemFileReadStore | Read-only data store for JSON data |
| dojo.data.ItemFileWriteStore | Read/Write data store for JSON data |
| dojox.data.CsvStore | Read-only data store for CVS data |
| dojox.data.OpmlStore | Read-only data store for Outline Processor Markup Language (OPML) data |
| dojox.data.HtmlTableStore | Read-only data store for HTML table data |
| dojox.data.XmlStore | Read/Write data store for XML data |
| dojox.data.FlickrStore | Read-only data store for queried data of flickr.com. An excellent example of a web service data store. |
| dojox.data.FlickrRestStore | Advanced version of the dojox.data.FlickrStore |
| dojox.data.QueryReadStore | Read-only data store for JSON data from the server side |
| dojox.data.AtomReadStore | Read-only data store for the Atom XML data |
The view is for retrieving and presenting the application
data to the user properly. You can customize the view of TreeGrid by
defining the structure parameter. There are two
different kinds of
TreeGrid views. The columnar TreeGrid has a layout more like a
typical tree style, as shown in Figure 3. This view is created when you specify a
TreeModel to the TreeGrid.
Figure 3. Columnar TreeGrid
The other TreeGrid view is a nested TreeGrid, which is
defined by a nested structure, as shown below.
Figure 4. Nested TreeGrid
The controller handles and responds to events. The TreeGrid inherits from
dojo.grid.DataGrid, so all event handlers pertaining to the DataGrid
apply here. You can also customize your own event handler
by binding the function to the grid events, thereby
controlling the data and behaviors more effectively.
TreeGrid can be defined either declaratively in
HTML or programmatically.
Most properties of TreeGrid are optional except
for structure and store
(or treeModel if you need to create a columnar
TreeGrid).
Structure is a JSON object that defines the
TreeGrid view layout. It
can also be indicated by markup when the TreeGrid is defined
declaratively in HTML. The value of store
should be the name of a JavaScript
variable that holds the store object used to get data for TreeGrid.
Listing 1 shows a definition of a TreeGrid that's defined declaratively.
Listing 1. Sample TreeGrid definition
<table dojoType="dojox.grid.TreeGrid" store="storeId">
<thead>
<tr>
<th field="field1" width="200px">Field 1</th>
<th field="childAttr">
<table>
<thead>
<tr>
<th field="cField1" width="200px">Child Field 1</th>
<th field="cField2" width="200px">Child Field 2</th>
</tr>
</thead>
</table>
</th>
</tr>
</thead>
</table>
|
Build the process server proxy
WebSphere Process Server provides various programming
interfaces, such as EJB, Web Service, JMS, and REST, for you to manage the
processes. However, only EJB APIs provide the complete function set. To
leverage the power of the EJB API, you need to build a proxy that
connects TreeGrid to the process server.
Set up the sample process application
The first step is to create a sample integration solution named SimpleSolution, which contains only one module. To simplify the example, we built a process with one receive/reply and a human task. The human task does nothing but enter an arbitrary string value as the return value of the reply action. Figure 5 shows the definition of the process. Remember, you can download the sample code used in this article from the Download table below.
Figure 5. Process definition
Manage processes with the process server API
It is assumed that the IDE you're using is WebSphere Integration Developer, and that the proxy application is running on the process server. (Or, you need to install the process server client on your server.) The example first creates a dynamic web project. You'll see that the required process server libraries are referenced automatically.
Figure 6. SimpleBridge dynamic web project
Process server provides a rich set of APIs to manipulate the processes. You need to locate the EJB service to access these APIs. Listing 2 shows how to access the business flow manager service.
Listing 2. Access business flow manager service
// Obtain the default initial JNDI context
InitialContext initialContext = new InitialContext();
// Lookup the remote home interface of the BusinessFlowManager bean
Object result = initialContext.lookup("com/ibm/bpe/api/BusinessFlowManagerHome");
// Convert the lookup result to the proper type
BusinessFlowManagerHome processHome =
(BusinessFlowManagerHome) javax.rmi.PortableRemoteObject.narrow(result,
BusinessFlowManagerHome.class);
BusinessFlowManager processManager = processHome.create();
|
Once you get the instance of BusinessWorkflowManager, you have the power to
create, work on, and complete the processes. You can use the code
in Listing 3 to access the process template.
Listing 3. Access the process template
ProcessTemplateData[] processTemplates =
processManager.queryProcessTemplates(null, null, 0, null);
for(int i = 0; i < processTemplates.length; i++){
//Do something to the process template
}
|
Use the code in Listing 4 to create a process instance with a process template and to specify a value for the initial input parameter.
Listing 4. Create a process instance
ProcessTemplateData template = processManager.getProcessTemplate(templateName);
if(template != null){
// create a message for the single starting receive activity
ClientObjectWrapper input = processManager.createMessage(template.getID(),
template.getInputMessageTypeName());
DataObject myMessage = null;
if (input.getObject() != null && input.getObject() instanceof DataObject) {
myMessage = (DataObject) input.getObject();
// set the strings in the message, for example, a parameter named “input”
myMessage.setString("input", initialString);
}
// start the process
PIID piid = processManager.initiate(template.getName(), instanceName, input);
}
|
Once the above steps are complete, go to http://localhost:9080/bpc and click Started By Me. You can see that the instance you just created is there, as shown below.
Figure 7. Sample process instance
Go to My To-dos, and you'll see that there's a human task ready for you to deal with, as shown in Figure 8. This is the human task defined in the process definition.
Figure 8. Human task to be handled
Before you can deal with the human task you need to find it. You can use the
query method of the process manager to get the
task you want, as shown in Listing 5.
Listing 5. Get the To-do tasks
QueryResultSet result = processManager.query(
"ACTIVITY.AIID, TASK.NAME",
"ACTIVITY.STATE = ACTIVITY.STATE.STATE_READY AND " +
"ACTIVITY.KIND = ACTIVITY.KIND.KIND_STAFF AND " +
"WORK_ITEM.REASON = WORK_ITEM.REASON.REASON_POTENTIAL_OWNER AND " +
"PROCESS_INSTANCE.NAME = '" + entity.getAttributeValue("NAME") + "'",
(String)null, (Integer)null, (TimeZone)null);
for(int k = 0; k < result.size(); k++){
// Get the AIID and the name of the task
result.next();
out.print("{id:'" + result.getOID(1) + "',");
out.print("label:'" + result.getString(2) + "'}");
}
|
To work with the task you first have to claim it. Only by claiming it can you get the value of the input parameter and complete the task. Listing 6 shows how to claim a task and get the value of the input parameter.
Listing 6. Claim a task and get the value of the input parameter
ClientObjectWrapper input = processManager.claim(aiid);
DataObject activityInput = null;
if (input.getObject() != null && input.getObject() instanceof DataObject) {
activityInput = (DataObject) input.getObject();
String inputStr = activityInput.getString("input");
}
processManager.cancelClaim(aiid);
|
At this point you can finally work on the task and complete it. Listing 7 shows an example.
Listing 7. Work on the tasks
ActivityInstanceData activity = processManager.getActivityInstance(aiid);
ClientObjectWrapper output = processManager.createMessage(aiid,
activity.getOutputMessageTypeName());
DataObject myMessage = null ;
if(output.getObject() != null && output.getObject() instanceof DataObject) {
myMessage = (DataObject) output.getObject();
// set the parts in your message, for example, an order number
myMessage.setString("output", msg);
}
//complete the activity
processManager.complete(aiid, output);
Define the data exchange format
|
JSON is definitely the preferred data exchange format. You need to return
the data as a JSON object tree so that TreeGrid can receive it. The
structure is fairly straightforward. Template is the parent node of the
process instances associated with the template; the to-do tasks are the
children of the process instances.
Listing 8. Data format
{
identifier: "id",
label: "label",
items: [{
id: "1",
label: "Template 1",
instances: [{
id: "2",
label: "Instance 1",
tasks: [{
id: "3",
label: "ToDo 1",
},
{
id: "4",
label: "ToDo 2",
}]
}]
}
}
|
Manage the processes with Dojo TreeGrid
Once you set up WebSphere Process Server, a TreeGrid can be created to receive and present
the process data provided by the process server. Some controls can also
be added to TreeGrid to manage those processes.
As mentioned previously, the store attribute in the
<table> tag (see Listing 1) indicates which
DataStore you want
to use to obtain the data. Since you need to connect to the process proxy,
let's go through an example with dojox.data.JsonRestStore. JsonRestStore is
a Dojo data store interface to JSON HTTP/REST web storage services that
support read and write through GET, PUT, POST, and DELETE. JsonRestStore could also
be defined in the HTML markup, as shown in Listing 9.
Listing 9. JsonRestStore declaration
<span dojoType="dojox.data.JsonRestStore"
jsId="jsonStore" target="SimpleSolution/ShowAll/">
</span>
|
The target attribute indicates the target URL
for the server-side data
source. It assumes you're in the same domain, so the value of target would be a relative path. jsId is the identifier of this store.
In this example, TreeGrid is defined
declaratively in the HTML with a
<table> tag. The nested <th> tags define the columns in
the table. Listing 10 shows the declaration of TreeGrid. The structure corresponds to the
data format above.
Listing 10. TreeGrid declaration
<table dojoType="dojox.grid.TreeGrid" class="grid" autoHeight="true" jsId="grid"
store="jsonStore" rowSelector="true" defaultOpen=true>
<thead>
<tr>
<th field="label" width="20em" formatter="processSummary">Process Template</th>
<th field="instances" aggregate="sum">
<table>
<thead>
<tr>
<th field="label" width="20em" formatter="instanceSummary">Instance</th>
<th field="tasks" aggregate="sum">
<table>
<thead>
<tr>
<th field="label" width="25em" formatter="taskSummary">Tasks</th>
<th field="status" width="20em">Status</th>
</tr>
</thead>
</table>
</th>
</tr>
</thead>
</table>
</tr>
</thead>
</table>
|
At this point you should get the TreeGrid shown below.
Figure 9. TreeGrid presenting process data
It's quite simple, but the job is only half done. The next step is to add
some controls in TreeGrid so it
can communicate with WebSphere Process Server and manage the processes.
Communicate with WebSphere Process Server
In this section you'll add some controls in TreeGrid. Since Dojo 1.4,
a widget can be added in the grid cell by a formatter (a JavaScript
function with return values shown in the grid cell). The formatter can
also help to format the summary cells in TreeGrid.
As shown in Listing 11, two kinds of widgets are going to be added to
TreeGrid by the formatters:
- dijit.form.ComboBox, for changing the task status
- dijit.form.Button, for submitting the request
Listing 11. Controller formatters
// create an object to save all these ComboBox
var comboObj = {};
var fmtStatus = function(value, idx, treepath){
// summary:
// format the cell to a comboBox Widget
// value: string
// the attribute value of this cell
// idx: integer
// row index, it would be negative if the cell is header cell or summary cell
if(idx >= 0) {
// get the identifier
var id = jsonStore.getIdentity(grid.getItem(treepath));
comboObj[id] = new dijit.form.ComboBox({
store: comboStore,
searchAttr:"status"
});
comboObj[id].setValue(value);
return comboObj[id];
}else{
// for summary cell
return "";
}
}
var fmtSubmit = function(value, idx){
if(idx >= 0){
return new dijit.form.Button({
label: "submit",
onClick: dojo.hitch(null, "submit", value)});
}else{
return "";
}
}
|
You need to add the formatters to the columns of the TreeGrid, as shown below.
Listing 12. Add formatter to the column
<th field="status" width="20em" formatter=” fmtStatus”>Status</th> <th field="id" width="20em" formatter=” fmtSubmit”>Action</th> |
Now the TreeGrid should look like Figure 10.
Figure 10. TreeGrid with controller
The Dojo Ajax IO functions, dojo.xhr*, can be introduced for communication with WebSphere Process Server. An XHR request is sent to the server to submit the new status once the Submit button is clicked. The grid would be refreshed to reflect the processes correctly after receiving the response of the server, as shown in Listing 13.
Listing 13. Communicate with WebSphere Process Server
var submit = function(id){
var status = comboObj[id].getValue();
dojo.xhrPost({
url: "SimpleSolution/" + status + "/" + id,
load: function(data){
if(data === "successful"){
grid.update();
}else{
console.warn("operation failed:", data);
}
},
error: function(error){
console.err(error);
}
});
}
|
Now, each time you click Submit an XHR request is sent to WebSphere Process Server. You'll know if the operation is successful from the service response.
In this article you learned how to use Dojo TreeGrid to manipulate the processes
of WebSphere Process Server. TreeGrid
inherently can handle hierarchical
data structures. You can have a Web 2.0-style UI to operate on the data
easily by customizing TreeGrid for your
specific application needs.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample code for this article | code.zip | 26KB | HTTP |
Information about download methods
Learn
- Access all of the official Dojo documentation, including information for getting started, reference guides, what's new, and a developer's notebook.
- Learn all about the Dojo toolkit and get the toolkit documentation.
- Read about Dojo hierarchical data and access through dojo.data.
- IBM developerWorks WebSphere zone provides technical resources for the WebSphere software platform.
- IBM developerWorks Web development zone specializes in articles covering various web-based solutions.
Get products and technologies
- Get the Dojo
code. Dojo toolkit 1.6 is used in this article.
- Download IBM product
evaluation versions or explore
the online trials in the IBM SOA Sandbox and get your hands on
application development tools and middleware products from DB2®,
Lotus®,
Rational®, Tivoli®, and WebSphere®.
Discuss
- Create your My developerWorks profile today and set up a watchlist on Dojo.
Get connected and stay connected with My developerWorks.
- Find other developerWorks members interested in web development.
- Share what you know: Join one of our developerWorks groups focused on web topics.
- Roland Barcia talks about Web 2.0 and middleware in his blog.
- Follow developerWorks' members' shared bookmarks on web topics.
- Get answers quickly: Visit the Web 2.0 Apps forum.
- Get answers quickly: Visit the Ajax forum.

Wang Qiang is a software engineer on the IBM ORIA team at the IBM China Development Lab in Shanghai. He is currently focusing on Dojo Grid development and Dojo TreeGrid enhancement.






