Part 1 of this series introduced you to the FileNet P8 BPM and IBM Content Manager architectures. The article used a fictitious ABC Company's Auto Insurance Claim system to show you how to integrate these two powerful products.
Part 2 introduces the FileNet P8 work performers and shows you how to implement the Java business entities. You will learn to create a Java gateway class and see how to use Java serialization to circumvent certain limitations.
In order to use a third party content repository, FileNet Business Process Management (BPM) needs the capability to communicate with the IBM Content Manager repository. FileNet work performers can enable BPM to interact with third party codes or applications.
In FileNet P8, work performers enable an application to perform an operation or a set of operations associated with a workflow. Typically, work performers are designed without a user interface and are used to perform automatic workflow operations, such as those associated with a specific step in a workflow definition. Work performer operations associated with workflow steps include logging in and establishing a process engine session, polling a user queue or system queue (attempting to find operations related to a particular workflow step), locking the retrieved object, processing the work (data update and so on), and cycling back to queue polling. Simply put, work performers are needed to interact with third party applications.
There are two types of work performers, component integrator-based and daemon-based. The component integrator-based performer is adopted in this example.
The component integrator-based work performer is a component implemented as either a Java class or Java Messaging Service (JMS) event. A Java component can be used to perform all operations associated with a workflow. Figure 1 illustrates the component integrator architecture:
Figure 1. FileNet P8 component integrator architecture
The Java or JMS component can be managed by the component manager. The component manager configures and communicates with service adapters. At runtime, the component manager polls component queues for work items that request JMS or processing by Java components, and connects a work item requesting a component to the appropriate service adapter. The Java adapter handles process calls to Java objects, which are represented to the process engine as operations on queues (work items) where each operation is done by a method of the Java class. The Java adapter executes the interface to the Java component, then automatically waits for a response from this component, updates the work item, and dispatches this work item to the next workflow step. The JMS adapter places messages on the JMS Queue and dispatches the associated work item. The JMS adapter handles posting of process events to a message queue (in the form of an XML event based on the step element for the given operation).
Implement the Java business entities for the ABC Company
The ABC Company wants to store all the content data in the existing IBM Content Manager. And it also wants to use FileNet BPM to build a process centric application. So you need to implement work performers in BPM in order to manipulate the content in the existing IBM Content Manager.
You may encapsulate the third party application logic and expose the interface when implementing the Java component. For ABC Company's case, you first implement the Java business entities which can access the data in the IBM Content Manger. Figure 2 shows the Java business entities architecture:
Figure 2. Java business entities architecture
As the architecture shows, you can create the data transfer object (DTO) and the data
access object (DAO) which are corresponding to each class in the class diagram (Part
1; Figure 4). Taking class "AutoClaim" as an example, we've created a DTO class AutoClaim.java and a DAO class AutoClaimDAO.java.
The following Java code is AutoClaim.java. It contains the property definitions and
related getter and setter methods. It represents the data value for one item in the IBM Content Manager repository.
Listing 1. The sample DTO - AutoClaim.java
public class AutoClaim
{
public AutoClaim ()
{
}
private String claimID;
public String getClaimID()
{
return this.claimID;
}
public void setClaimID(String claimID)
{
this.claimID = claimID;
}
private Integer claimStatus;
public Integer getClaimStatus()
{
return this.claimStatus;
}
public void setClaimStatus(Integer claimStatus)
{
this.claimStatus = claimStatus;
}
private String openingDate;
public String getOpeningDate()
{
return this.openingDate;
}
public void setOpeningDate(String openingDate)
{
this.openingDate = openingDate;
}
private Integer claimAmount;
public Integer getClaimAmount() {
return claimAmount;
}
public void setClaimAmount(Integer claimAmount) {
this.claimAmount = claimAmount;
}
private String eventID;
public String getEventID() {
return this.eventID;
}
public void setEventID(String eventID) {
this.eventID = eventID;
}
private String pidString;
public String getPidString() {
return pidString;
}
public void setPidString(String pidString) {
this.pidString = pidString;
}
}
|
The following Java code is AutoClaimDAO.java which is a data access object. It contains
all the methods which call IBM Content Manager OOAPI to manipulate the data in the IBM Content Manager.
Listing 2. The sample DAO - AutoClaimDAO.java
public class AutoClaimDAO
{
private String itemType;
public AutoClaimDAO()
{
itemType = "AutoClaim";
}
public String create(AutoClaim autoClaim) throws DKException, Exception
{
String pidString = null;
DKDatastoreICM dsICM = SConnectDisconnectICM.connect();
DKDDO ddo = dsICM.createDDO("AutoClaim", DKConstant.DK_CM_ITEM);
setAttrToDDO(ddo, autoClaim);
ddo.add();
pidString = ddo.getPidObject().pidString();
dsICM.disconnect();
return pidString;
}
public AutoClaim retrieveAutoClaimByClaimID(String claimID)
throws DKUsageError, DKException, Exception
{
AutoClaim autoClaim = null;
String queryString = "/AutoClaim[@Claim=\""+claimID+"\"]";
DKDatastoreICM dsICM = SConnectDisconnectICM.connect();
dkIterator dkIter =
(dkIterator) SConnectDisconnectICM.search(dsICM, queryString, 0, true);
if(dkIter.more())
{
autoClaim = new AutoClaim();
DKDDO ddo = (DKDDO)dkIter.next();
ddo.retrieve(DKConstant.DK_CM_CONTENT_ITEMTREE +
DKConstant.DK_CM_CONTENT_NO);
setValueToAutoClaim(ddo, autoClaim);
autoClaim.setPidString( ddo.getPidObject().pidString() );
}
dsICM.disconnect();
return autoClaim;
}
public void update(String pidString, AutoClaim autoClaim)
throws DKUsageError, DKException, Exception
{
DKDatastoreICM dsICM = SConnectDisconnectICM.connect();
DKDDO ddo= dsICM.createDDO(pidString);
ddo.retrieve(DKConstant.DK_CM_CONTENT_ITEMTREE +
DKConstant.DK_CM_CONTENT_NO);
DKDatastoreExtICM ext = new DKDatastoreExtICM(dsICM);
if(!ext.isCheckedOut(ddo))
{
ext.checkOut(ddo);
}
setAttrToDDO(ddo, autoClaim);
dsICM.updateObject(ddo, DKConstant.DK_CM_CHECKIN);
dsICM.disconnect();
}
public void delete(String pidString) throws DKUsageError, DKException, Exception
{
DKDatastoreICM dsICM = SConnectDisconnectICM.connect();
DKDDO ddo = dsICM.createDDO(pidString);
ddo.del();
dsICM.disconnect();
}
public void setAttrToDDO(DKDDO ddo, AutoClaim autoClaim) throws DKUsageError
{
if(autoClaim.getClaimID()!=null)
ddo.setData(ddo.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,"ClaimID"),
autoClaim.getClaimID());
if(autoClaim.getClaimStatus()!=null)
ddo.setData(ddo.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,"ClaimStatus"),
autoClaim.getClaimStatus());
if(autoClaim.getOpeningDate()!=null)
ddo.setData(ddo.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,"OpeningDate"),
autoClaim.getOpeningDate());
if(autoClaim.getClaimAmount()!=null)
ddo.setData(ddo.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,"ClaimAmount"),
autoClaim.getClaimAmount());
if( autoClaim.getEventID() != null )
ddo.setData( ddo.dataId( DKConstant.DK_CM_NAMESPACE_ATTR, "EventID" ),
autoClaim.getEventID() );
}
public void setValueToAutoClaim(DKDDO ddo, AutoClaim autoClaim)
throws DKUsageError
{
Object attr = null;
attr = ddo.getData(ddo.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,
"ClaimID"));
if(attr!=null)
{
autoClaim.setClaimID((String)attr);
attr = null;
}
attr = ddo.getData(ddo.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,
"ClaimStatus"));
if(attr!=null)
{
autoClaim.setClaimStatus((Integer)attr);
attr = null;
}
attr = ddo.getData(ddo.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,
"OpeningDate"));
if(attr!=null)
{
autoClaim.setOpeningDate((String)attr);
attr = null;
}
attr = ddo.getData(ddo.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,
"ClaimAmount"));
if(attr!=null)
{
autoClaim.setClaimAmount((Integer)attr);
attr = null;
}
attr = ddo.getData(ddo.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,
"EventID"));
if(attr!=null)
{
autoClaim.setEventID( (String) attr );
attr = null;
}
}
...
}
|
For other classes in the class diagram, there are similar Java classes such as AutoPolicy.java and AutoPolicyDAO.java.
You can download the Eclipse project which contains all these
Java class source code.
Implement the gateway class for the Java business entities
Now you have got a set of Java business entities and also a lot of operation methods in these entities. But in the FileNet Component Integrator, one component queue can only expose one Java class's methods. And you should conform to the following rules:
- The class must have a constructor without any parameters.
- The methods must be public.
- The methods can only contain allowable component operation parameter types. Refer to the component operation parameter types.
If you want to interact with the multiple Java classes from a third party application and
would like to register only one component queue for this application, you should wrap all
the Java classes' methods into one gateway class. Thus for ABC Company's Auto Insurance
Claim system, you should wrap all the DAO operation methods into one gateway class --
ICMOperation.java -- shown in the following Java code.
Listing 3. The sample wrapper class - ICMOperation.java
public class ICMOperation
{
public void createAutoClaim(String claimID,Integer claimStatus,
String openingDate,Integer claimAmount, String eventID) throws Exception
{
AutoClaim autoClaim = new AutoClaim();
autoClaim.setClaimID(claimID);
autoClaim.setClaimStatus(claimStatus);
autoClaim.setOpeningDate(openingDate);
autoClaim.setClaimAmount(claimAmount);
autoClaim.setEventID( eventID );
AutoClaimDAO dao = new AutoClaimDAO();
dao.create( autoClaim );
}
public Integer retrieveClaimStatusByClaimID(String claimID) throws Exception
{
AutoClaim autoClaim = getAutoClaim( claimID );
return autoClaim.getClaimStatus();
}
public void updateClaimStatusByClaimID( String claimID, Integer claimStatus )
throws Exception
{
AutoClaimDAO dao = new AutoClaimDAO();
AutoClaim autoClaim = dao.retrieveAutoClaimByClaimID( claimID );
autoClaim.setClaimStatus( claimStatus );
dao.update( autoClaim );
}
private AutoClaim getAutoClaim( String claimID ) throws Exception
{
return new AutoClaimDAO().retrieveAutoClaimByClaimID( claimID );
}
...
}
|
A workaround using Java object parameters in Component Integrator
FileNet P8 Component Integrator only supports some primitive parameter types. But generally, some Java objects are always used as parameters in an operation method. Here, we introduce a solution to overcome this limitation: Java serialization. Figure 3 shows this solution.
Figure 3. Java serialization solution
Using Java serialization, you can serialize the original Java object to a string in
memory. When you need to get the original Java object, you can deserialize the string to
the original Java object. Take AutoClaimDAO.java as an example.
If you want to use the DTO AutoClaim.java as the parameter
in the operation methods, you need to write two utility methods. One is to serialize the AutoClaim Java object to a string, while the other is to deserialize the string to the original AutoClaim Java object. The following Java code snippet shows these two methods.
Listing 4. The sample code of serialization and deserialization
public AutoClaim parseStringToAutoClaim( String autoClaimString )
throws IOException, ClassNotFoundException
{
ObjectInputStream objInput = null;
try
{
objInput = new ObjectInputStream( new ByteArrayInputStream(
new BASE64Decoder().decodeBuffer( autoClaimString ) ) );
return (AutoClaim) objInput.readObject();
}
finally
if( objInput != null )
{
objInput.close();
}
}
}
public String parseAutoClaimToString( AutoClaim autoClaim ) throws IOException
{
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
ObjectOutputStream objOutput = null;
try
{
objOutput = new ObjectOutputStream( byteOutput );
objOutput.writeObject( autoClaim );
return new BASE64Encoder().encode( byteOutput.toByteArray() );
}
finally
{
byteOutput.close();
if( objOutput != null )
{
objOutput.close();
}
}
}
|
Then you should make AutoClaim serializable. The only thing needed is to let AutoClaim implement java.io.Serializable interface. The following code shows the serializable AutoClaim.
Listing 5. The sample code implements serializable
public class AutoClaim implements Serializable{
private static final long serialVersionUID = 4599855634813333505L;
...
} |
Now you can register the method which uses string to represent the Java object. And in the
client application, you should use the deserialization method to get the original Java
object. Take a look at the following code. We use a method in the registered class ICMOperation
to retrieve the AutoClaim Java object. After getting the
result, first use the serialization method to serialize the AutoClaim Java object to a string object, then return the string to a
client. Once the client gets the string, use the deserialization method to
deserialize the string to an AutoClaim object.
Listing 6. The sample code to walk around the parameter limitation
public String retrieveAutoClaimByClaimID( String claimID ) throws Exception
{
AutoClaim autoClaim = getAutoClaim( claimID );
return new AutoClaimDAO().parseAutoClaimToString( autoClaim );
}
|
Now we have Java business entities and a Java gateway class which expose all the operation methods. You can download all these source codes in an Eclipse Java project. Notice that the compiler compliance level should be set to 1.4 when creating corresponding jar files due to the compatibility of the component integrator.
In Part 2 of this series, you have taken a look at the FileNet work performers and seen the component integrator-based work performer in detail. You've created the Java business entities and prepared a Java gateway class. We also introduced a solution to overcome the FileNet component integrator's parameter limitation.
Part 3 describes how to implement the work performers for ABC Company's Auto Insurance Claim system.
| Description | Name | Size | Download method |
|---|---|---|---|
| Java Business Entities project for eclipse | BO.zip | 10MB | HTTP |
Information about download methods
Learn
-
Visit the developerWorks Enterprise Content Management to expand your Content Manager skills and link to articles, tutorials, documentation, and so on.
-
Visit the IBM DB2 Content
Managemen V8.3 Information Center to learn how to use CM OOAPI to program.
-
Visit the FileNet Business Process Manager to learn more about Business Process Management skills.
-
Visit the IBM FileNet P8 4.0 to learn more about the whole platform about FileNet P8.
Get products and technologies
- Download
FileNet Content Manager demo
to see how IBM FileNet P8 integrates content, process, and compliance to streamline, manage, and optimize an auto claim handling process.
- Download
IBM product evaluation versions
and get your hands on application development tools and middleware products from
DB2®, Lotus®, Rational®, Tivoli®, and
WebSphere®.
Discuss
- Check out
developerWorks blogs and get involved in the developerWorks community.
Comments (Undergoing maintenance)








