 | 级别: 初级 Alan Yaung (ayaung@us.ibm.com), 高级软件工程师,内容管理开发,Silicon Valley Laboratory, IBM Allan Tham (thamawh@my.ibm.com), DB2 Presales 技术专家, ASEAN Techline, IBM
2005 年 8 月 04 日 本系列教程将介绍 IBM DB2® Content Manager® 文档路由,由三部分组成,本文是第 2 部分,将提供一个索赔过程案例研究,展示实现和使用 API 的一些示例。
简介
工作空间的有效协作对企业的成功有很大的贡献。但是无论在同一部门中还是不同部门之间,由于不能有效地协作,常常造成知识共享和信息的损失。结果令客户不满意而最终减少了收入。
目前,多数企业内容管理解决方案都提供了使信息无缝流动到目标接收方的机制。及时将信息、文档和备忘录传递给担任不同角色的用户或用户组的机制,是在高度协作环境中成功实现业务实践的关键。
工作流是 IBM Enterprise Content Management 解决方案中不可分的一部分。工作流可具有不同的形式。IBM DB2 ® Content Manager® 提供了集成式工作流解决方案,即内建的文档路由(document routing)。对于更复杂的环境,客户可以选择 WebSphere® MQ Workflow。本系列教程将带领您深入了解 IBM DB2 Content Manager 文档路由。我们还比较了 IBM DB2 Content Manager 文档路由和 WebSphere MQ Workflow,帮助您更好地理解两者的区别和功能。本系列教程的内容划分如下:
- IBM DB2 Content Manager 文档路由,第 1 部分:过程建模导航
- IBM DB2 Content Manager 文档路由简介
- IBM DB2 Content Manager 文档路由的功能
- IBM DB2 Content Manager 文档路由的新特性
- 案例研究 —— 索赔过程
- 实现 —— 索赔过程
- 对比表 —— WebSphere MQ Workflow 和 IBM DB2 Content Manager 文档路由
-
IBM DB2 Content Manager 文档路由,第 2 部分:API 导航
使用同一个案例研究介绍如何使用 API 开发解决方案。
-
IBM DB2 Content Manager 文档路由,第 3 部分:客户机导航
实际使用同一案例研究中定义的工作流体验您的劳动成果。这篇文章将讨论客户机应用程序:
- eClient —— 基于 Web 的客户机
- pClient —— 基于 Windows 的客户机
- CM Portlet —— 基于 Portlet 的客户机
IBM DB2 Content Manager 文档路由 API 概述
本系列的 第 1 部分 讨论了 DB2 Content Manager 文档路由中的过程建模能力。大部分过程建模都可在 System Administration Client 图形化的过程生成器中完成。针对与客户机有关的文档路由任务,为那些希望自己定制应用程序的客户提供运行时 API。虽然默认的 DB2 Content Manager Windows Client、eClient 和 portlet 使用了这些 API,但有时候客户还是愿意从头开发自己的客户机。不过,本文只介绍文档路由运行时 API 的基础知识,并没有详尽地讨论它的每个方面。可以利用下一节的代码分析快速启动一个定制项目。
下面将简要讨论一下各种类及其主要功能(要获得完整的列表,请参阅 参考资料 部分):
DKDocRoutingServiceICM —— 这个类提供了通过某一过程来传递和访问工作包以及容器数据的方法。如 start、terminate、 continue、suspend、resume、listWorkPackages 和 setWorkPackageContainerData。
DKDocRoutingServiceMgmtICM —— 定义了管理文档路由定义类的方法:DKProcessICM、DKWorkNodeICM、DKWorkListICM、DKWorkFlowActionICM 和 DKWorkFlowActionListICM。
DKProcessICM —— 这个类代表一个过程定义,包含过程图和过程的路径列表。
DKWorkNodeICM —— 这个类代表一个工作节点定义,详细规定了预期的或者适用的任务(如已有的 Workflow ActionList 和库服务器)来执行过程中的特定步骤。
DKWorkPackageICM —— 这个类代表传递任务中的一个工作包。它包含传递文档的持久标识符和传递状态的信息(如过程名、工作节点名和完成的时间)。
DKWorkListICM —— 这个类代表工作包集合的一个筛选视图(基于工作节点和优先级这样的标准)。
DKWorkFlowActionListICM —— 这个类包含工作流的动作集合。使客户机应用程序能够显示工作点上可用的工作流动作。
DKWorkFlowActionICM —— 这个类定义了一个工作流动作,它可以是动态链接库(DLL)、可执行文件、Java 类文件,等等。它使客户机应用程序能够执行自己的操作。
先决条件
为了运行本文提供的示例代码,必须具备以下条件:
- 建立 第 1 部分 所述的索赔场景。
- 建立适当的代码运行环境。
- Windows® —— 在 %IBMCMROOT%\BIN 目录下运行 cmbenv81.bat。
IBM DB2 Content Manager Document Routing 定制代码流程详解
这一节说明如何使用 Content Manager 文档路由完成不同的客户机任务。这一节的重点是 API 调用,同时给出解释。可以从 下载 部分得到完整的示例代码。
这个程序用于完成上一期文章“IBM DB2 Content Manager 文档路由,第 1 部分:过程建模导航”中定义的自动索赔过程,过程图如 图 1 所示。
图 1. 简单的索赔过程工作流
连接到数据存储
连接到 Content Manager 数据存储。
// Connect to CM
dsICM = new DKDatastoreICM();
dsICM.connect(db,userid,pw,"SCHEMA=icmadmin");
System.out.println("datastore connected db " + db + " userid " + userid );
|
创建索赔文件夹
创建一个名为 XYZClaimFolder 的文件夹。
// Create a folder XYZClaimFolder
ddo = dsICM.createDDO("XYZ_ClaimFolder", DKConstant.DK_CM_FOLDER);
|
计算索赔金额
generateClaimAmount 方法根据两个随机数 R1 和 R2 计算索赔金额,其中 0.0 < = R1, R2 < = 1.0
- 第一个随机数(R1)判定索赔额是否低于 $500。
- 如果低于 $500,则将索赔额设为 R2 * $500。
- 如果大于或等于 $500,则将索赔额设为 $500 + R2 * $500。
private static double generateClaimAmount() {
double randomNumber1 = Math.random();
double randomNumber2 = Math.random();
double claim_amount = 0;
if (randomNumber1 >= 0.5) {
claim_amount = 500 + Math.round(randomNumber2 * 500);
} else {
claim_amount = Math.round(randomNumber2 * 500);
}
return claim_amount;
|
设置文件夹属性
设置文件夹的 CLAIM_AMOUNT 和 XYZ_ClaimNumber 属性,将文件夹添加到持久数据存储中。
CLAIM_AMOUNT 的值设为 generateClaimAmount() 方法生成的索赔金额。XYZ_ClaimNumber 的值设为一个随意选择的字符串“2-123456”。
1 claim_amount = generateClaimAmount();
System.out.println("*** generated claim amount = " + claim_amount);
2 ddoFolder.setData((short)ddoFolder.dataId("CLAIM_AMOUNT"), new Double(claim_amount));
3 ddoFolder.setData((short)ddoFolder.dataId("XYZ_ClaimNumber"), new String("2-123456"));
4 ddoFolder.add();
|
该例中,执行的操作是:
- 根据两个随机数计算索赔金额(参见上一节)。
- 设置索赔金额。
- 设置索赔编号。
- 将文件夹添加到持久数据存储中。
创建传递服务对象
获得一个传递服务对象。
System.out.println("Creating Routing Service Object");
1 DKDocRoutingServiceICM routingService = new DKDocRoutingServiceICM(dsICM);
System.out.println("Created Routing Service Object");
|
这个例子中,执行的操作是:
- 创建了一个 DKDocRoutingServiceICM 对象。
清除工作包
清除所有的工作包,这一步保证没有运行的过程。
System.out.println("Deleting all workpackages...");
1 DKSequentialCollection coll = (DKSequentialCollection)routingService.listWorkPackages("AllWorklist", "");
dkIterator iter = null;
if (coll != null) {
2 iter = coll.createIterator();
while (iter.more()) {
DKWorkPackageICM wp = (DKWorkPackageICM)iter.next();
3 routingService.terminateProcess(wp.getPidString());
}
}
System.out.println ("All workpackages were deleted");
|
在这里,执行的操作是:
- 创建了一个集合。
- 创建了一个用于循环的迭代器。
- 终止过程。
启动 SimpleAutoClaimProcess
用创建的文件夹启动 SimpleAutoClaimProcess 过程。
String workPackagePidStr = routingService.startProcess(pn,
ddoFolder.getPidObject().pidString(),
100,
userid,
null);
System.out.println("Started an instance of process "
+ pn
+ " Workpackage PID ="
+ workPackagePidStr);
|
向文件夹中添加文档
在此之前文件夹是空的。
// Add documents into the folder
1 addItemsToFolder(dsICM, ddoFolder);
System.out.println("*** Documents were added into the folder");
|
此处执行的操作是:
- 调用
addItemsToFolder 方法向文件夹中添加了两个文档。addItemsToFolder 包装器代码可从 sampleDocRouting.java 中找到。
SubmitClaim 工作节点
在“SubmitClaim”工作节点查询 AllWorklist 工作列表,以找到工作包。
// at the SubmitClaim worknode
coll = null;
iter = null;
System.out.println("-------- Calling listWorkPackages --------");
1 coll = (DKSequentialCollection)routingService.listWorkPackages("AllWorklist", "");
if (coll != null) {
iter = coll.createIterator();
while (iter.more()) {
DKWorkPackageICM wp = (DKWorkPackageICM)iter.next();
2 displayWorkPackageInfo(wp);
// Query the AllWorklist worklist and locate the workpackage on the
// "SubmitClaim" worknode.
// If process name is SimpleAutoClaimProcess and worknode name is
// SubmitClaim then continue the process
3 if (wp.getProcessName().equals("SimpleAutoClaimProcess")
&& wp.getWorkNodeName().equals("SubmitClaim")) {
4 routingService.continueProcess(wp.getPidString(), "Continue", userid);
System.out.println("*** Called continueProcess on SubmitClaim");
break;
}
}
}
|
在这里执行的操作是:
- 创建了一个集合和一个用于遍历的迭代器。
- 调用方法
displayWorkPackageInfo。displayWorkPackage 包装器的代码可在 sampleDocRouting.java 中找到。它显示了一些工作包信息,其中包括:
- Persistent ID(持久标识符)
- Priority(优先级)
- Time last moved(上一次转移的时间)
- Suspend state(挂起状态)
- Notify state(通知状态)
- Notify time(通知时间)
- Resume time(恢复时间)
- Process completion time(过程完成时间)
- Persistent ID of the item(项目的持久性标识符)
- Process name(过程名)
- Worknode name(工作节点名)
- Owner(所有者)
- Container data(容器数据)
- 在 SubmitClaim 工作节点查询 AllWorklist 工作列表定位工作包。如果过程名是 SimpleAutoClaimProcess,工作节点名是 SubmitClaim,继续该过程。
- 继续该过程。
WaitForReportAndEstimate 汇集点
在汇集点 WaitForReportAndEstimate,如果满足汇集点的条件,下面的代码片段会将工作包向前移动。
coll = null;
iter = null;
System.out.println("-------- Calling listWorkPackages --------");
coll = (DKSequentialCollection)routingService.listWorkPackages("AllWorklist", "");
if (coll != null) {
iter = coll.createIterator();
while (iter.more()) {
DKWorkPackageICM wp = (DKWorkPackageICM)iter.next();
displayWorkPackageInfo(wp);
if (wp.getProcessName().equals("SimpleAutoClaimProcess")
&& wp.getWorkNodeName().equals("WaitForReportAndEstimate")) {
routingService.continueProcess(wp.getPidString(), "Continue", userid);
System.out.println("*** Called continueProcess on WaitForReportAndEstimate");
break;
}
}
}
|
决策点 1:索赔金额
在自动索赔过程的第一个决策点,工作流可以沿着索赔金额超过 $500 或者小于 $500 两条路径前进。
在示例程序中,审批决策采用随机数来模拟。下面的方法模拟了审批决策。
private static DKNVPair generateApprovalDecision() {
DKNVPair decision = null;
double randomNumber = Math.random();
if (randomNumber >= 0.5) {
decision = new DKNVPair("APPROVE","ACCEPT");
} else {
decision = new DKNVPair("APPROVE","REJECT");
}
return decision;
}
|
下面的例子说明了第一个决策点的程序逻辑。它使用 generateApprovalDecision 方法按照下列算法决定接受或拒绝用随机数产生的索赔:
- 如果过程名是 SimpleAutoClaimProcess 并且工作包名是 ReviewCredit,继续该过程。
- 如果过程名是 SimpleAutoClaimProcess,工作节点名是 ReviewLargerClaim:
- 根据随机数设置 APPROVE 值(如果随机数 > = 0.5 接受,否则拒绝)
- 继续该过程。
- 如果过程名是 SimpleAutoClaimProcess,而工作节点名是 ReviewSmallClaim:
- 根据随机数设置 APPROVE 值(如果随机数 > = 0.5 接受,否则拒绝)
- 继续该过程。
// at the first decision point
coll = null;
iter = null;
System.out.println("-------- Calling listWorkPackages --------");
coll = (DKSequentialCollection)routingService.listWorkPackages("AllWorklist", "");
if (coll != null) {
boolean ReviewCreditFound = false;
boolean ReviewLargeClaimFound = false;
iter = coll.createIterator();
while (iter.more()) {
DKWorkPackageICM wp = (DKWorkPackageICM)iter.next();
displayWorkPackageInfo(wp);
1 if (wp.getProcessName().equals("SimpleAutoClaimProcess")
&& wp.getWorkNodeName().equals("ReviewCredit")) {
ReviewCreditFound = true;
routingService.continueProcess(wp.getPidString(), "Continue", userid);
System.out.println("*** Called continueProcess on ReviewCredit");
if (ReviewCreditFound && ReviewLargeClaimFound) break;
}
2 if (wp.getProcessName().equals("SimpleAutoClaimProcess")
&& wp.getWorkNodeName().equals("ReviewLargeClaim")) {
ReviewLargeClaimFound = true;
DKSequentialCollection CNTcoll = new DKSequentialCollection();
decision = generateApprovalDecision();
CNTcoll.addElement(decision);
dkIterator CNTiter = null;
if (CNTcoll != null) {
CNTiter = CNTcoll.createIterator();
System.out.println("-------- container data --------");
while (CNTiter.more()) {
DKNVPair CNTData = (DKNVPair)CNTiter.next();
System.out.println(" Name=["
+ CNTData.getName()
+ "] Value=["
+ CNTData.getValue()
+ "]");
CNTData = null;
}
}
routingService.continueProcess(wp.getPidString(), "Continue", userid, CNTcoll);
System.out.println("*** Called continueProcess on ReviewLargeClaim");
if (ReviewCreditFound && ReviewLargeClaimFound) break;
}
3 if (wp.getProcessName().equals("SimpleAutoClaimProcess")
&& wp.getWorkNodeName().equals("ReviewSmallClaim")) {
DKSequentialCollection CNTcoll = new DKSequentialCollection();
decision = generateApprovalDecision();
CNTcoll.addElement(decision);
dkIterator CNTiter = null;
if (CNTcoll != null) {
CNTiter = CNTcoll.createIterator();
System.out.println(" Container data:");
while (CNTiter.more()) {
DKNVPair CNTData = (DKNVPair)CNTiter.next();
System.out.println(" --- Name=["
+ CNTData.getName()
+ "] Value=["
+ CNTData.getValue()
+ "]");
CNTData = null;
}
}
routingService.continueProcess(wp.getPidString(), "Continue", userid, CNTcoll);
System.out.println("*** Called continueProcess on ReviewSmallClaim");
break;
}
}
}
|
CheckFraudHistory 业务应用程序节点
在 CheckFraudHistory 业务应用程序节点上,如果用户退出失败,那么请继续此过程。
// at the business application node
// if user exit fails, this will continue the process
coll = null;
iter = null;
System.out.println("-------- Calling listWorkPackages --------");
coll = (DKSequentialCollection)routingService.listWorkPackages("AllWorklist", "");
if (coll != null) {
iter = coll.createIterator();
while (iter.more()) {
DKWorkPackageICM wp = (DKWorkPackageICM)iter.next();
displayWorkPackageInfo(wp);
if (wp.getProcessName().equals("SimpleAutoClaimProcess")
&& wp.getWorkNodeName().equals("CheckFraudHistory")) {
routingService.continueProcess(wp.getPidString(), "Continue", userid);
System.out.println("*** Called continueProcess on CheckFraudHistory");
break;
}
}
}
|
决策点 2:接受或拒绝
在第二个决策点上:
// at the second decision point
coll = null;
iter = null;
System.out.println("-------- Calling listWorkPackages --------");
coll = (DKSequentialCollection)routingService.listWorkPackages("AllWorklist", "");
if (coll != null) {
iter = coll.createIterator();
while (iter.more()) {
DKWorkPackageICM wp = (DKWorkPackageICM)iter.next();
displayWorkPackageInfo(wp);
1 if (wp.getProcessName().equals("PayClaimSubProcess")
&& wp.getWorkNodeName().equals("PayClaim")) {
routingService.continueProcess(wp.getPidString(), "Continue", userid);
System.out.println("*** Called continueProcess on PayClaim");
break;
}
2 if (wp.getProcessName().equals("SimpleAutoClaimProcess")
&& wp.getWorkNodeName().equals("SendRejectionLetter")) {
routingService.continueProcess(wp.getPidString(), "Continue", userid);
System.out.println("*** Called continueProcess on SendRejectionLetter");
break;
}
}
}
|
在这里:
- 如果过程名是 PayClaimSubProcess 过程,工作节点名是 PayClaim,继续该过程。
- 如果过程名是 SimpleAutoClaimProcess 过程,而工作节点名是 SendRejectionLetter,继续该过程。该过程就结束了。
SendThankYouLetter 工作节点
在 SendThankYouLetter 调用 Continue。
// at the SendThankYouLetter worknode
coll = null;
iter = null;
System.out.println("-------- Calling listWorkPackages --------");
coll = (DKSequentialCollection)routingService.listWorkPackages("AllWorklist", "");
if (coll != null) {
iter = coll.createIterator();
while (iter.more()) {
DKWorkPackageICM wp = (DKWorkPackageICM)iter.next();
displayWorkPackageInfo(wp);
1 if (wp.getProcessName().equals("SimpleAutoClaimProcess")
&& wp.getWorkNodeName().equals("SendThankYouLetter")) {
routingService.continueProcess(wp.getPidString(), "Continue", userid);
System.out.println("*** Called continueProcess on SendThankYouLetter");
break;
}
}
}
|
在这里:
- 如果过程名是 SimpleAutoClaimProcess,工作节点名是 SendThankYouLetter,继续该过程。该过程已经结束了。
断开与数据存储的连接
断开与 CM 数据存储的连接。
dsICM.disconnect();
System.out.println("disconnected from ICM");
|
示例结果
注意:示例程序的执行通常产生如下所示的结果。当然 Pid 字符串、Item ID 和 Component ID 可能不同。
datastore connected db icmnlsdb userid icmadmin
*** generated claim amount = 518.0
*** A folder was created
Item Pid string =95 3 ICM8 icmnlsdb15 XYZ_ClaimFolder59 26 A1001001A05F20B51410I8968818
A05F20B51410I896881 14 1025
Item ID = A1001001A05F20B51410I89688
Component ID = A05F20B51410I89688
Version ID = 1
Creating Routing Service Object
Created Routing Service Object
Deleting all workpackages...
All workpackages were deleted
Started an instance of process SimpleAutoClaimProcess Workpackage PID =90 3 ICM8 icmnlsdb11
WORKPACKAGE58 26 A1001001A05E06B64714I6505618...
*** Documents were added into the folder
-------- Calling listWorkPackages --------
-------- Workpackage Query --------
PID = 90 3 ICM8 icmnlsdb11 WORKPACKAGE58 26 A1001001A05E06B64714I6505618
A05F20B51411D360121 13 204
Priority = 100
Last Moved time = 2005-06-20-22.14.11.326000
Suspend state = 0
Notify state = 0
Item PID = 95 3 ICM8 icmnlsdb15 XYZ_ClaimFolder59 26 A1001001A05F20B51410I8968818
A05F20B51410I896881 14 1025
Process name = SimpleAutoClaimProcess
Worknode name = SubmitClaim
Owner = ICMADMIN
*** Called continueProcess on SubmitClaim
-------- Calling listWorkPackages --------
-------- Workpackage Query --------
PID = 90 3 ICM8 icmnlsdb11 WORKPACKAGE58 26 A1001001A05E24B71046G2636118
A05F20B51412E676731 13 204
Priority = 100
Last Moved time = 2005-06-20-22.14.12.458000
Suspend state = 0
Notify state = 0
Item PID = 95 3 ICM8 icmnlsdb15 XYZ_ClaimFolder59 26 A1001001A05F20B51410I8968818
A05F20B51410I896881 14 1025
Process name = SimpleAutoClaimProcess
Worknode name = ReviewCredit
Owner = ICMADMIN
-------- Workpackage Query --------
PID = 90 3 ICM8 icmnlsdb11 WORKPACKAGE58 26 A1001001A05E06B65354A8617918
A05F20B51412E562781 13 204
Priority = 100
Last Moved time = 2005-06-20-22.14.12.448000
Suspend state = 0
Notify state = 0
Item PID = 95 3 ICM8 icmnlsdb15 XYZ_ClaimFolder59 26 A1001001A05F20B51410I8968818
A05F20B51410I896881 14 1025
Process name = SimpleAutoClaimProcess
Worknode name = ReviewLargeClaim
Owner = ICMADMIN
-------- Calling listWorkPackages --------
-------- Workpackage Query --------
PID = 90 3 ICM8 icmnlsdb11 WORKPACKAGE58 26 A1001001A05E24B71046G2636118
A05F20B51412E676731 13 204
Priority = 100
Last Moved time = 2005-06-20-22.14.12.458000
Suspend state = 0
Notify state = 0
Item PID = 95 3 ICM8 icmnlsdb15 XYZ_ClaimFolder59 26 A1001001A05F20B51410I8968818
A05F20B51410I896881 14 1025
Process name = SimpleAutoClaimProcess
Worknode name = ReviewCredit
Owner = ICMADMIN
*** Called continueProcess on ReviewCredit
-------- Workpackage Query --------
PID = 90 3 ICM8 icmnlsdb11 WORKPACKAGE58 26 A1001001A05E06B65354A8617918
A05F20B51412E562781 13 204
Priority = 100
Last Moved time = 2005-06-20-22.14.12.448000
Suspend state = 0
Notify state = 0
Item PID = 95 3 ICM8 icmnlsdb15 XYZ_ClaimFolder59 26 A1001001A05F20B51410I8968818
A05F20B51410I896881 14 1025
Process name = SimpleAutoClaimProcess
Worknode name = ReviewLargeClaim
Owner = ICMADMIN
-------- container data --------
Name=[APPROVE] Value=[REJECT]
*** Called continueProcess on ReviewLargeClaim
-------- Calling listWorkPackages --------
-------- Workpackage Query --------
PID = 90 3 ICM8 icmnlsdb11 WORKPACKAGE58 26 A1001001A05E06B65840A5228118
A05F20B51411D360121 13 204
Priority = 100
Last Moved time = 2005-06-20-22.14.12.899000
Suspend state = 0
Notify state = 0
Item PID = 95 3 ICM8 icmnlsdb15 XYZ_ClaimFolder59 26 A1001001A05F20B51410I8968818
A05F20B51410I896881 14 1025
Process name = SimpleAutoClaimProcess
Worknode name = SendRejectionLetter
Owner = ICMADMIN
Container data:
--- Name=[APPROVE] Value=[REJECT]
-------- Calling listWorkPackages --------
-------- Workpackage Query --------
PID = 90 3 ICM8 icmnlsdb11 WORKPACKAGE58 26 A1001001A05E06B65840A5228118
A05F20B51411D360121 13 204
Priority = 100
Last Moved time = 2005-06-20-22.14.12.899000
Suspend state = 0
Notify state = 0
Item PID = 95 3 ICM8 icmnlsdb15 XYZ_ClaimFolder59 26 A1001001A05F20B51410I8968818
A05F20B51410I896881 14 1025
Process name = SimpleAutoClaimProcess
Worknode name = SendRejectionLetter
Owner = ICMADMIN
Container data:
--- Name=[APPROVE] Value=[REJECT]
*** Called continueProcess on SendRejectionLetter
-------- Calling listWorkPackages --------
disconnected from ICM
|
编译用户退出代码
下面所示的用户退出代码被编译成动态链接库(如 DLL)。
#include <stdio.h>
1 #include "WXV2TUE.h"
#include <windows.h>
#include <process.h>
extern long WXV2TBAUE (ICMUSERSTRUCT *pCMStruct) {
char envStr[256];
2 ICMCONTAINERDATA_STRUCT * pContainerDataStruct;
FILE *_file;
3 strcpy(envStr, "c:\\temp\\test.txt");
4 pContainerDataStruct =
(ICMCONTAINERDATA_STRUCT *) malloc (sizeof(ICMCONTAINERDATA_STRUCT) * pCMStruct->sNumContainerData);
_file = fopen(envStr, "aw");
fprintf(_file, "*** Enterint Business Application node user exit\n");
5 fprintf(_file, "*** The number of container data structures from LS is: %d \n",
pCMStruct->sNumContainerData);
6 fprintf(_file,"*** WP Comp ID from LS is: %s \n", pCMStruct->szWPCompID );
7 fprintf(_file,"*** WP Item ID from LS is: %s \n", pCMStruct->szWPItemID );
8 strcpy(pCMStruct->szRouteSel, "Continue");
fprintf(_file,"*** Routed to the next node\n");
fprintf(_file, "*** Leaving Business Application node user exit\n");
9 if (pContainerDataStruct != 0) free(pContainerDataStruct);
fclose(_file);
return 0;
}
|
在这里执行的操作是:
- 包括 WXV2TUE.h 头文件。
- 声明指向容器结构 ICMCONTAINERDATA_STRUCT 的指针。
- 将输出文件路径设置为“c:\temp\test.txt”。
- 根据容器数据的多少为容器结构分配内存。
- 打印容器数据的大小。
- 打印工作包的组件 ID。
- 打印工作包的项目 ID。
- 将路径选择设置为“Continue”。
- 释放容器结构所占的内存。
test.txt 示例文件
在用户退出代码时,在 c:\temp 目录中创建 test.txt 文件。
*** Enterint Business Application node user exit
*** The number of container data structures from LS is: 0
*** WP Comp ID from LS is: A05F20B82328A18196
*** WP Item ID from LS is: A1001001A05E06B72338I29494
*** Routed to the next node
*** Leaving Business Application node user exit
|
结束语
本文是关于文档路由的第二篇文章,为那些希望通过应用程序编程接口开发文档路由应用程序的客户提供了一个跳板。它概述了 DB2 Document Routing API,并以第 1 部分介绍的简单自动索赔过程为基础,引导您分析了示例实现代码。无论是新手还是工作流专家,本文讨论的文档路由 API 都能为您带来一定的裨益。
现在我们已经介绍了过程建模和 API 用法,下一期文章将讨论文档路由的客户机应用。
致谢
特别感谢 IBM 硅谷实验室的内容管理开发人员 Ying-Pong Chen 花时间审阅本文。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| C code sample | WXV2TBAUE.c | 28KB |
FTP | HTTP |
|---|
| document rounting sample | sampleDocRouting.java | 2KB |
FTP | HTTP |
|---|
参考资料 学习
讨论
作者简介  | |  | Alan Yaung 是 IBM Silicon Valley Laboratory 内容管理开发的高级软件工程师。他是 Content Management Workflow Team 的主管。他有 8 年多企业内容管理解决方案产品开发的经验。Alan 是一位 Content Manager Certified Solution Designer。他拥有 20 多项已批准的和待批准的专利。 |
 | 
|  | Allan Tham 是一位 DB2 Content Manager Technical Presales Support for Business Partners。他帮助业务合作伙伴解决各种技术问题。Allan 通过了 DB2 Content Management 管理员认证。加入 IBM 之前,Allan 在终端用户环境中工作,在那里做了三年的 Oracle DBA。 |
对本文的评价
|  |