Chapter 18 Writing Custom Fields This chapter describes how to write custom fields for use in Process Manager applications. This chapter includes the following sections:
This chapter describes how to write custom fields for use in Process Manager applications.
Introduction
Defining Field Properties in a JSB File
Writing the Java Classes
Packaging a Custom Field
Adding a Custom Field to an Application
Method Reference
support for data types that are more complex than the data types available with built-in fields.
a convenient way of representing multi-dimensional values, or other high-level data objects, in a process. For example, custom fields can represent a "shopping cart," an account, or a service order.
a way of accessing data objects that are stored in resources external to Process Manager, such as PeopleSoft or CICS.
Figure 18.1    Functional view of a custom field
Define the field properties that will be visible in Process Builder. Field properties are defined in a JavaScript bean (JSB) file. For details, see "Defining Field Properties in a JSB File".
Write the Java classes that implement the custom field. At a minimum, you must implement two interfaces, IDataElement and IPresentationElement. For details, see "Writing the Java Classes".
Package the JSB and Java classes into a zip or jar archive. For details, see "Packaging a Custom Field".
In Process Builder, insert a data field and add the archive file as a new class. For details, see "Adding a Custom Field to an Application".
builder\com\netscape\workflow\fields
Warning: Do not modify the original JSB files for predefined data fields. If you do, the data fields may no longer work.
<JSB>
<JSB_DESCRIPTOR ...>
<JSB_PROPERTY ...>
...
</JSB>
The file is surrounded by an opening <JSB> tag and a closing </JSB> tag. The other two tags are described in the following sections:
JSB_DESCRIPTOR Tag
JSB_PROPERTY Tag
<JSB_DESCRIPTOR NAME="com.netscape.pm.sample.ShoppingCartField" DISPLAYNAME="Shopping Cart Field" SHORTDESCRIPTION="Shopping Cart Field">
The NAME attribute is the full path name for the data field class, using a dot (.) as the directory separator.
/**
* Properties related to this specific format of field
*/
<JSB_PROPERTY NAME="dbtype"
TYPE="string"
DISPLAYNAME="DB Type"
SHORTDESCRIPTION="DB Type"
DEFAULTVALUE="ORACLE"
VALUESET="ORACLE,SYBASE">
<JSB_PROPERTY NAME="dbidentifier"
DISPLAYNAME="DB Identifier"
SHORTDESCRIPTION="DB Identifier">
<JSB_PROPERTY NAME="dbuser"
DISPLAYNAME="DB User"
SHORTDESCRIPTION="DB User">
<JSB_PROPERTY NAME="dbpassword"
DISPLAYNAME="DB Password"
SHORTDESCRIPTION="DB Password">
The JSB_PROPERTY attributes and required property names are described in the next two sections.
<JSB_PROPERTY NAME="myname" ISDESIGNTIMEREADONLY>
<JSB_PROPERTY NAME="myname" ISEXPERT>
Consider the Design Issues
Implement IPresentationElement and IDataElement
Consider Your Data and Data Sources
Design a Data Manager
Design a Thread-safe Class
Use an Entity Key
What data types do you want the custom field to accept? For example, in what format will the data be? This could well depend on where the data is coming from.
What data sources will the custom field be required to access? For example, will the custom field access a PeopleSoft application? an SAP R/3 application? a relational database?
Figure 18.2    A custom field acts as a data manager
Here is the Java code to implement the shopping cart items:
public class ItemSet
{
Hashtable mItems = new Hashtable();
public void addItem( Item item ) {
mItems.put( item.getItemId(), item ); }
public Item getItem( String itemId ) {
return mItems.get( itemId ); }
public Enumeration items( ) {
return mItems.elements(); }
}
public class Item
String mItemId;
int mQuantity = 0;
float mPrice = 0.0f;
public Item( String itemId, int quantity, float price )
mItemId = itemId;
mQuantity = quantity;
mPrice = price;
public String getItemId( ) { return mItemId; }
public int getQuantity( ) { return mQuantity; }
public float getPrice( ) { return mPrice; }
JavaScript Code
The data stored in the process instance will be an instance of ItemSet. To retrieve information about each item in the set, you can write an automation script. This script will access the shopping cart custom field by using getData(), as shown here:
function automationScript( )
var pi = getProcessInstance();
var items = pi.getData( "shopping_cart" );
for( var e = items.elements(); e.hasMoreElements(); )
// we have a reference to an Item object
var item = e.nextElement();
var itemId = item.getItemId();
return true;
When it is time to store the set of items, the custom field will retrieve the current set from the process instance. The field will then translate the items from their Java object representation to a set of SQL rows.
getEntityKey(fieldName)
This call returns the entity key for the custom field whose name is fieldName. The entity key is available once the process instance has been loaded. When calling this method, you must convert the retrieved string value into the particular object type you require.
setEntityKey(fieldName, key)
Defines key as the entity key for the custom field whose name is fieldName. You must call setEntityKey() before you store your data. Otherwise, you might not have a handle back to your data. When setting the entity key for a custom field, the key can be any arbitrary object, but the key is stored as a string.
long basketID = pi.getInstanceId();
Implement IPresentationElement and IDataElement IDataElement has two methods: display() and update(). IPresentationElement has four methods: create(), store(), load(), and archive(). You must implement these methods in the Java class for your custom field.
import com.netscape.pm.model.BasicCustomField;
public class myCustomField
extends BasicCustomField
For implementation details on IDataElement, IPresentationElement, and BasicCustomField, see the section "Method Reference" on page 408.
Displaying a Work Item
Initiating a Process Instance
Completing a Work Item
Accessing a Custom Field from a Script
Figure 18.3    Methods invoked when displaying a work item
The display() method (on IPresentationElement) displays the custom field in the HTML form.
The load() method (on IDataElement) fetches the value that the field will display.
Figure 18.4    Methods invoked when initiating a process instance
The display() method (on IPresentationElement) displays the custom field at the entry point step. Optionally, the load() method (on IDataElement) fetches an initial value to display.
When the user clicks the submit button, the HTTP POST or HTTP GET request is submitted to PAE. This results in a call to create(). Note that all fields have their create() method invoked, regardless of whether the field exists on the entry point form.
Assuming the field is set for EDIT mode, the field's update() method is called.
When the process instance is ready to store itself, the field's store() method is called. The store() method is called only if the field's data was modified by a previous use of setData().
Figure 18.5    Methods invoked when completing a work item
Figure 18.6    Methods invoked when accessing a custom field from a script
The load() method is called to fetch the data.
The load() method typically uses setData(). Whenever a setData() is performed, the store() method is called when the process instance is ready to store itself. As a result, the store() method may be called even though the field's data has not changed.
ShoppingCartField.jsb is the JSB file for this custom field.
ShoppingCartField.class is the class file for this custom field.
ShoppingCart.class and ShoppingCartItem.class are class files representing data objects.
ShoppingCartParser.class is an auxiliary class that is used to output data in XML format.
Figure 18.7    Directory structure for the ShoppingCartField custom field
From the Insert menu, choose Data Field.
In the "Create a New Data Field" dialog box, enter a name for the new field and then click Add New Class. An example is shown in Figure 18.8: Figure 18.8    Creating a data field from a new class
Figure 18.8    Creating a data field from a new class
In the "Select the field JAR Package" dialog box, select the archive that represents your custom field class, then click Open. An example is shown in Figure 18.9: Figure 18.9    Selecting the archive that represents a custom field class
Figure 18.9    Selecting the archive that represents a custom field class
In the "Create a New Data Field" dialog box, add the field to the Data Dictionary in either of two ways:
Click Add to add the field without setting its properties first. The Create a New Data Field dialog box remains open, and you can add more items.
Click Add & Define to add the field and set its properties immediately. The Inspector window appears for the data field you added, as shown in Figure 18.10 Figure 18.10    Setting properties for the new custom field
Figure 18.10    Setting properties for the new custom field
Set the properties and close the window when you are done.
IPresentationElement Interface
IDataElement Interface
BasicCustomField Class
IPMElement Interface
public void display( IProcessInstance pi, IHTMLPage html, int displayMode, String displayFormat ) throws Exception
Syntax 2 This version displays the field when the user is viewing the entry point form.
public void display( IHTMLPage html, int displayMode, String displayFormat ) throws Exception
Arguments
pi. Object representing the process instance.
html. Object representing the HTML page to be returned to the user.
displayMode. Mode that the field should be displaying itself in. Possible values are MODE_EDIT, MODE_VIEW and MODE_HIDDEN.
displayFormat . Additional formatting information available to the field. This value is specified from the "Display Format" property of the Inspector window of the field when it is placed in the form. This value is specific to a process designer. One possible use is to distinguish between a secure viewing mode and a non-secure viewing mode, such as for credit card information. In such a case, the display format could contain either the value "secure" or "not secure."
public void update( IProcessInstance pi, IPMRequest rq ) throws Exception
html. Object representing the HTTP request.
public void create( IProcessInstance pi) throws Exception
public void store( IProcessInstance pi) throws Exception
public void load( IProcessInstance pi) throws Exception
public void update( IProcessInstance pi, OutputStream os) throws Exception
os. The output stream to write the data to.
In addition, BasicCustomField provides the loadDataElementProperties() method, described next.
protected void loadDataElementProperties( Hashtable entry ) throws Exception
entry. The hashtable containing field configuration properties.
<JSB_PROPERTY NAME="dbidentifier" TYPE="string" DISPLAYNAME="External DB Identifier" SHORTDESCRIPTION="Local alias used to connect to external DB server" ISEXPERT>
Given the previous JSB code, the following Java code implements the loadDataElementProperties() method. The method will first read the property and then, based on the value, set the instance variable mDBIdentifier.
protected void loadDataElementProperties( Hashtable entry ) throws Exception { String dbIdentifier = (String) entry.get( "dbidentifier" ); if( dbIdentifier == null ) throw new Exception( "DB Identifier not specified" ); else mDBIdentifier = dbIdentifier; }
IPMElement Interface The BasicCustomField class implements the IPMElement interface, which has two methods: getName() and getPrettyName(). These methods make it easier to implement your custom field.
public String getName()
Arguments None.
public void create( IProcessInstance pi ) throws Exception { // Assign a default value for this field. Just an empty shopping cart... // pi.setData( getName(), new ShoppingCart() ); }
getPrettyName() Summary Returns the "pretty name" of the current element.
public String getPrettyName()