跳到导航
BEA Dev2Dev Oracle and BEA
首页 资源中心 dev2dev学堂 在线技术论坛 User Group CodeShare
dev2dev 首页 > 资源中心 > 专家Blog > 专家Blog文章
Integration精华贴总结

时间:2005-09-09
作者:包力
浏览次数:
本文关键字:企业应用集成Integration 流程 Worklist workshop
文章工具
推荐给朋友 推荐给朋友
打印文章 打印文章

前言:

BEA  WebLogic Integration8.1产品面向解决企业系统集成、业务流程再造、B2B业务处理等业务需求,而这些在国内正是近几年新兴成长的市场,因此各位同仁碰到了各种各样的问题,包括从初级的如何学习Integration, 到高级的 流程的设计实现。这次,通对Integration版面的总结,希望将大家集中关心的问题归纳总结出来,对我们的深入学习和项目开发能够有所帮助。

同时总结很难面面俱到,希望各位多提宝贵意见,将内容更充实起来。

ntegration 介绍 BEA WebLogic Integration 产品介绍

BEA WebLogic Integration 8.1 是一个统一解决企业内部业务系统集成问题的新方案。BEA WebLogic Integration 提供的开发和运行时框架,将所有业务集成组件统一到一个单一、灵活的环境之下。这些组件涵盖业务流程管理、数据转换、业务伙伴集成、连通性、消息代理、应用监控和用户交互。

BEA WebLogic Integration 为快速交付业务集成、简化生产管理,提供了通用的开发环境,整合了业务集成领域各种不同的部件,其中包括 ERP、CRM、遗留应用、业务用户、供应链和业务伙伴。

BEA WebLogic Integration的主要功能
   
功能 说明
业务流程管理 使用户能够建立业务流程方案模型,围绕业务目标协调集成和自动化运行。
数据转换 利用简单的拖放映射功能,将数据从一种格式转换成另一种格式。输入数据和输出数据可进行任意格式间的转换 (结构化的XML、非 XML 或 Java 数据任意组合);可在一个业务流程内进行变换;允许有多个输入源;可进行复杂的运算,例如,连接、合并、按照关键字段分组。

消息代理 提供基于规则的消息路由,利用基于渠道的发布/订阅代理,以松散耦合的方式传输事件。在应用之间实现了高性能、低等待时间的消息路由
BEA WebLogic Integration 控件 非专家也能通过拖放代表集成资源的简单组件界面,取得快速集成的效果。有许多预先构建组件可以即取即用,用于访问数据库、文件、 HTTP、消息、服务代理,实现人与企业资源间的交互。
Worklist 系统(业务用户集成) 提供基于控件的功能,从任务创建者、任务实施者、任务管理者之类的最终用户,到处理流程异常、审核、状态跟踪等情况的业务流程,都允许交互。其中包括集中的用户和用户组管理、用户规则、授权,以确保流程内部协作的安全。
业务伙伴集成 通过最先进的标准协议,如 RosettaNet 和 ebXML,实现了与供应商、客户之间快速、安全的在线连接,具有安全消息传输、数字签名、加密、可恢复和可跟踪消息、配置动态更新功能。适用于各种合作伙伴,从完全的集线器,到集线器交互、轻量级合作伙伴客户机 (BEA WebLogic Integration 业务连接) ,直到通过门户、浏览器或FTP访问的零重量级客户访问,全都适用。对业务伙伴简档的管理,具有简洁高效的配置导入和导出功能。
应用集成和适配器 应用集成(AI)提供了各种访问功能,可以从 BEA WebLogic Workshop 控件,访问应用集成设计控制台、应用视图、预先构建的 BEA WebLogic 适配器和定制的适配器。
管理与控制 管理控制台提供了以集成为中心的全程管理功能,可以管理运行中的业务流程、部署的应用、消息代理流量、企业适配器的状态和使用情况、业务伙伴的活动和参数和工作表等,使管理人员具备全面、可靠地掌握分布式集成环境的能力。

更详细的内容可以参考Integration产品白皮书

流程方面: WLI81中调用Process的方法总结

在WLI81中,一个Process(*.JPD) 可以生成WSDL文件,Process Control,Service Broker Control。所以客户端可以有多种方式调用该JPD。在WLI81中客户端可以通过下面多种方法调用一个JPD。

  • 通过WLI81提供的JAVA API直接调用该JPD
  • 把JPD转化为一个WebService进行调用
  • 把JPD转化为一个Process Control,进行调用
  • 把JPD转化为一个Service Broker Control进行调用
  • 通过HTTP ,HTTPS式直接访问该JPD所对应的URL进行调用
  • 在WLI81SP2中可以通过JAVA PROXY方式调用一个JPD

以上每种方式都有其自己的特点以及一定的适用范围,下面分别说明。

  • 通过WLI81提供的JAVA API直接调用该JPD

可以通过调用EJB: RemoteWorklistManagerBean 的startProcess()方法启动一个Process.如下所示:

try
{
String str=”test the demo”;
String s=rwmb.startProcess("/demo/newOrder.jpd","clientRequest", str);
}
catch(Exception e)
{ 
e.printStackTrace();
}

采用这种方式,执行该段代码的用户必须属于Administrator 组。可以在JSP,JAVA客户端或PAGE FLOW中采用该方式直接调用JPD,这种方式比较简单直接。

  • 把JPD转化为一个Web Service进行调用

在Workshop中可以为一个JPD生成一个WSDL文件,然后客户端就可以以调用Web Service的方式调用该JPD。可以在支持Web Service的客户端中采用这种方式调用JPD。如在.NET平台上调用WLI81上的JPD就可以采用这种方式。

  • 把JPD转化为一个Process Control,进行调用

可以通过把JPD转化为Process Control,然后调用Process Control的clientRequest()方法调用一个JPD。如在Workshop开发环境中。可以通过下面的方法在一个JSP中以Process Control的方式调用一个JPD。

在一个jsp的source view中,将要在该JSP中调用的Process Control拖入该jsp,然后可以通过pageContext得到Control的实例:调用该Process Control的clientRequest()启动该Process.

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="netui-tags-databinding.tld" prefix="netui-data"%>
<%@ taglib uri="netui-tags-html.tld" prefix="netui"%>
<%@ taglib uri="netui-tags-template.tld" prefix="netui-template"%>
<netui-data:declareControl type="process.demo.approveControl" controlId="approveControl"></netui-data:declareControl>
<%
approveControl ac=(lapproveControl)pageContext.getAttribute("approveControl");
ac. clientRequest (applyid);
%>

调用该JPD的客户端必须与该JPD位于同一个WLI Domain中。它允许一个工作流(JPD),Web Service(JWS)或pageflow(JPF)向一个工作流(Target JPD)发出调用请求,同时也可以接收Target JPD的Callback。Process Control通常用于父流程调用子流程,事务上下文通过Process Control从父流程传递到子流程中,即Target JPD与client处于同一个事务中。

  • 把该JPD转化为一个Service Broker Control进行调用

Service Broker,从名字就可以知道它实现了对服务调用请求消息的代理功能。换而言之,服务代理接收服务调用请求消息,然后过滤服务调用请求消息,最后根据服务调用请求消息调用相应的服务。Service Broker一般用于:

  • 通过参数实现动态服务调用
  • 在流程中实现子流程调用
  • 实现企业间的应用集成

以下通过一个例子说明Service Broker Control的使用,场景为Process A通过Service Broker Control调用Process B,二者位于不同的两个Domain中。由于Serivce Broker Control是一个Dymamic Control,可以在WliConsole中设置Selector来实现依照输入参数选择调用不同的JPD,从而实现对于Target JPD的动态调用。


  • 生成Target JPD的WSDL文件

自动生成的WSDL文件中location部分默认标明localhost,为了在Client端可以找到Target JPD,需要将其中URL部分中的localhost更换为本机ip或机器名。

… …
<service name="paticipant">
<port name="paticipantSoap" binding="s0:paticipantSoap">
<soap:address location="http://CAITAO:7001/SBprocess/processes/paticipant.jpd"/>
</port>
</service>
… …
  • 在Client端的Application中import Target JPD的WSDL文件
  • 基于上述WSDL文件产生一个Service Broker Control,Process A即通过此Service Broker Control来调用Process B

  • Service Broker Control在生成时需要设置一个Xquery,可以实现对clientRequest参数的抽取,从而依照用户输入参数调用不同的Target JPD(这一点在后面的Dynamic Selector会提及)。

  • 生成的Service Broker Control有一个default的Http-url,说明默认的Service Broker Control调用此Url标识的Target JPD

Process A中只要调用配置好的Service Broker Control,即可调用http-url中指定的JPD资源。

  • Service Broker是一个Dynamic Control,可以通过wliconsole来设置selector,达到依照用户输入来分发请求到不同的Target JPD的目的。具体实施如下:
  • 屏蔽default的Http-Url,即在Service Broker Control的Property Editor中消去默认的Http-url。这一点非常重要,因为默认的http-url中指定的JPD资源可以屏蔽在wliconsole中Dynamic Selector指定的资源。
  • 进入wliconsole->Process Configuration->View Dynamic Controls,定位您当前需要设置Dynamic Selector的process
    • 选择Add Selector来添加选择条件

    例如筛选条件为:若Selector Value为‘liangyi’时,调用URI为

    http://10.130.2.139:7001/SBprocess/processes/paticipant.jpd的Target JPD,修改后显示如下:

    经过上述设置,只有当clientRequest中的XmlDocument经过Xquery查询后的字段值为‘liangyi’(此例中字段为Customer_Name)时才会调用End Point表明的Target JPD,其他的请求不能调用此Target JPD。

    • 通过HTTP,HTTPS方式直接访问一个JPD所对应的URL进行调用

    如上图所示,我们在WORKSHOP中开发测试JPD的时候,从WORKSHOP的测试页面中的”test soap”页,可以看到SOAP格式的Service Client Request和Service Response。所以我们可以拼一个SOAP格式的字符串,并通过HTTPPOST方式调用该JPD。并且可以取到调用的JPD的处理结果,如下所示。

    StringBuffer soapRequest = (new StringBuffer()).append("<SOAP-ENV:Envelope xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" ");
    soapRequest.append("xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" ");
    soapRequest.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><SOAP-ENV:Body>");
    soapRequest.append("<t xmlns=\"http://www.openuri.org/\">\r\n");
    soapRequest.append("<s>kkk</s>");
    soapRequest.append("</t>");
    soapRequest.append("\r\n</SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n");
    URL url = new URL("http://localhost:7001/wlidemo/demo.jpd ");
    URLConnection uc = url.openConnection();
    uc.setDoInput(true);
    uc.setDoOutput(true);
    uc.setRequestProperty("Content-Type", "text/xml");
    PrintWriter post = new PrintWriter(new OutputStreamWriter(uc.getOutputStream()),true);
    post.println(soapRequest);
    InputStreamReader isr = new InputStreamReader(uc.getInputStream());
    char[] resultBytes = new char[1024];
    int rcount = isr.read(resultBytes, 0, 1024);
    StringBuffer soapResponse = new StringBuffer();
    while(rcount!=-1)
    {
    soapResponse = soapResponse.append(resultBytes, 0 , rcount);
    rcount = isr.read(resultBytes, 0, 1024);
    }
    

    只要是支持HTTP,HTTPS的客户端都可以通过该方式调用JPD。如可以在C,C++环境中通过该方式调用一个JPD。

    • 通过JPD Proxy方式进行调用

    该方式WLI81SP2中提供,WLI81SP1中支持不完善。可以实现非Workshop J2EE客户端或独立java客户端调用WLI81上的JPD,Java Proxy是为任何普通Java Client端与JPD通信设计的。通过JPD Proxy的调用是Java RMI调用,当Client端通过JPD Proxy调用工作流时,其事务上下文将通过JPD Proxy传递给Target JPD,即Target JPD与Client端处于同一个事务中。示例实施步骤:

    • 在Workshop中运行需要调用Target JPD,得到Target JPD的JPD Proxy(jar文件)


    指定Package,默认为weblogic.wli.jpdproxy

    点击下载Target JPD jar包

    • 将上述jar文件引入client端所在的工程,以供程序调用。示例中是在与Target JPD相同的Application中设计Java Client端,所以把jar包引入到Application的APP-INF的lib中即可。
    • 在Application中建立一个Java Project,编写Java Client


    • 运行Java Client端,可以成功调用Target JPD。

    需要特别说明的是:JPD Proxy调用方式虽然适用于所有的Java Client端,但是它有一个局限-JPD Proxy不能接收Target JPD的Callback,即若Client使用JPD Proxy启动一个包含Client Callback的JPD,会在该流程尝试发出Callback给JPD Proxy时产生Runtime failure。

    通过Message Broker实现不同流程之间的相互调用

    如图:P1通过Message Broker 方式调用P2,P2把结果返回给P1,因为P1可能有多个INSTANCE在允许,所以P2必须把结果返回给调用它的INSTANCE。在WLI70中可通过

    EVENT,MESSAGE ADDRESS来实现。在WLI81中可通过下面的方式实现。

    首先定义一个CHANNEL:

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema targetNamespace="http://www.bea.com/demo"
    xmlns="http://www.bea.com/demo" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="
    qualified" attributeFormDefault="unqualified"> <xs:element name="DemoXML"> <xs:complexType> <xs:sequence> <xs:element name="processid" type="xs:string"/> <xs:element name="info" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>

    注意的是,其中的命名空间是http://www.bea.com/demo

    其中第一次publish的时候processid放置的是p2,info放置的是p11的processid

    在p2中会进行交换,再publish回去,虽然XML结构相同,但是两次channel不同,分别为xmlreq和xmlresp,见下面。

    channel文件

    <?xml version="1.0"?> 
    <channels xmlns="http://www.bea.com/wli/broker/channelfile" 
    channelPrefix="/EquipLogic" 
    xmlns:rt="http://www.bea.com/RepairTicket" xmlns:dm="http://www.bea.com/demo"> 
    <channel name ="Repairs" messageType="none"> 
    <channel name ="xmlreq" messageType="xml" 
    qualifiedMessageType="dm:DemoXML"/> 
    <channel name ="xmlresp" messageType="xml" 
    qualifiedMessageType="dm:DemoXML"/> 
    <channel name ="ok2repair" messageType="xml" 
    qualifiedMessageType="rt:repairTicket"/> 
    <channel name ="approval" messageType="xml" 
    qualifiedMessageType="rt:repairTicket"/> 
    </channel>
    </channels>
    

    这个例子中定义了四个channel,由于命名空间不同,所以前面定义的命名空间dm和rt不同。注意的是,其中qualifiedMessageType指向的是.xsd文件中定义的XML的root。

    我们在例子中会使用DemoXML的两个

    第一个Process:p11.jpd

    其中publish是发布了xmlreq的channel,同时subscribeWithFilterValue节点订阅了xmlresp的channel,同时设置filter的值为当前process的processid

    后面的Event choise使该process阻塞住,当p2的process发布了channel时,如果过滤的值满足filter条件,那么会执行Control receive,使流程继续下去。

    该Process中使用了两个MB control,一个是mbpub,一个是mbsub,分别对应发布和订阅channel,注意的是,mbsub中设置了filter条件,通过subscribeWithFilterValue进行订阅并设定filter条件。

    注意的是该Control中如下语句定义了过滤的Xpath:

    /** 
    * Defines a new Subscription control. 
    * @jc:mb-subscription-control xquery::
    *declare namespace ns0="http://www.bea.com/demo"
    *data($message/ns0:processid)::
    *channel-name="/EquipLogic/Repairs/xmlresp" 
    */
    

    第二个Process:p2.jpd

    该process过滤了channel,通过过滤processid=p2来启动。注意以下两点:

    * declare namespace ns1="http://www.bea.com/demo"
    /**
    * @jpd:mb-static-subscription filter-value-match="p2"
    xquery="data($message/ns1:processid)" message-body="
    {x0}" channel-name="/EquipLogic/Repairs/xmlreq" */

    其中订阅收到p11的channel以后,转换XML,然后通过control mbpub1来发布xmlrespchannel。P11就可以收到该channel,并继续往下运行。

    运行:(p11与P2)

    启动P2

    启动p11.jpd,输入p2,点击ClientRequest

    控制台会看到如下显示:

    p1:1064484827744:p2
    p2:10.130.0.202-1774cf.f7d7e97f33.-7fe6:<demo:DemoXML xmlns:demo="http://www.bea
    .com/demo"><demo:processid>p2</demo:processid><demo:info>1064484827744</demo:inf
    o></demo:DemoXML>
    p2:publish!<demo:DemoXML xmlns:demo="http://www.bea.com/demo"><demo:processid>10
    64484827744</demo:processid><demo:info>p2</demo:info></demo:DemoXML>
    p1:get message!<demo:DemoXML xmlns:demo="http://www.bea.com/demo"><demo:processi
    d>1064484827744</demo:processid><demo:info>p2</demo:info></demo:DemoXML>
    

    可以看到能正确进行交互。

    为了测试,可以使p2发生错误,然后多创建几个p11的实例,再使p2正确,然后创建p11以后,能看到只有当前实例接受和结束。

    运行:(p12与P2)

    修改p11到p12,可以指定实例id,测试。其中x0输入的是p2,如果不是p2不会激发p2.jpd,x1输入的是你希望接受的process的id,你可以先随便输入几个,这样就会创造几个p12在running的状态,然后在x1中输入前面创建的某个实例的id,然后测试该process是否结束。

    如何创建一个XMLBean

    一般一个PROCESS INTANCE 在启动时接收一个XMLBean当输入参数,在WLI81中,通常采用PageFlow来开发Processs的客户端,在PageFlow中可通过FormBean提取Form中各个字段的值。然后拼成一个长的XML字符串,再用XmlObject.Factory.parse(str) 转化为一个XML Object 或一个 XMLBean. 然后当启动流程的参数或在其他地方使用。如下所示:

    StringBuffer sb = new StringBuffer(10000); 
    sb.append("<settleQueryResult>"); 
    sb.append("<seqNumber>");
    sb.append(this.seqNumber); 
    sb.append("</seqNumber>"); 
    sb.append("<sender>");
    sb.append(settleOrderObj.sender); 
    sb.append("</sender>");
    sb.append("</settleQueryResult>");
    SettleQueryResultDocument doc;
    SettleQueryResultDocument.SettleQueryResult qr;
    doc= SettleQueryResultDocument.Factory.parse(sb.toString());
    qr=doc.get SettleQueryResult();
    

    更简单的方式是直接采用XMLBean的SET方法把值传入。如下所示:

    try
    {
    ShipOrderDocument sod;
    sod = ShipOrderDocument.Factory.newInstance();
    ShipOrder so=sod.addNewShipOrder();
    so.setBeginDate(form.getBeginDate());
    so.setCargoName(form.getCargoName()); 
    so.setOriginAddress(form.getOriginAddress());
    so.setQuantity(form.getQuantity());
    Context ctx = new InitialContext();
    RemoteWorklistManagerHome 
    pwmh=(RemoteWorklistManagerHome)ctx.lookup("RemoteWorklistManagerBean");
    RemoteWorklistManager rwmb=(RemoteWorklistManager)pwmh.create();
    com.bea.xml.XmlObject[] newOrder={sod}; 
    String s=rwmb.startProcess("/postPortal/shipOrder/shipOrder.jpd","clientRequest",
    newOrder);
    }
    catch(Exception e)
    {
    e.printStackTrace();
    }
    
    取得Process中变量的值

    可以通过MBEAN来取得Process中变量的值。代码如下:先用RemoteWorklistManager的startProcess()启动流程,并返回该流程实例的ID,再通过ProcessRuntimeMBean的getProcessVariable()方法和ProcessVariableValue的getValueRepresentation()方法取到变量的值. 该流程实例必须还没有结束才能取到变量的值.如果该流程实例已经结束,会抛异常:

    <2004-4-4 下午16时57分30秒 CST> <Error> <WLW> <000000> <Conversation not found.ServiceURI:/jpd0404Web/processes/vartest.jpd InstanceId:127.0.0.1-1531aca.fbb421
    c0ee.-7fb2
    java.lang.NullPointerException
    at com.bea.wli.management.adminhelper.AdminHelperBean.getProcessContaine
    rBean(AdminHelperBean.java:412)
    try
    {
    String fd[] = new String[1];
    fd[0]="***test***";
    Properties p = new Properties();
    p.put(Context.INITIAL_CONTEXT_FACTORY,
    "weblogic.jndi.WLInitialContextFactory");
    p.put(Context.PROVIDER_URL, "t3://127.0.0.1");
    p.put(Context.SECURITY_PRINCIPAL,"weblogic");
    p.put(Context.SECURITY_CREDENTIALS,"weblogic");
    Context ctx = new InitialContext(p);
    RemoteWorklistManagerHome pwmh=(RemoteWorklistManagerHome)ctx.lookup("RemoteWorklistManagerBean");
    RemoteWorklistManager rwmb=(RemoteWorklistManager)pwmh.create();
    String s=rwmb.startProcess("/jpd0404Web/processes/vartest.jpd","clientRequest", fd);
    ProcessRuntimeMBean prmb=MBeanHelper.getProcessRuntimeMBean();
    ProcessVariableValue pvv=prmb.getProcessVariable("/jpd0404Web/processes/vartest.jpd",s,"str1");
    String ss= (String)pvv.getValueRepresentation();
    System.out.println("ss= " + ss) ;
    }
    catch(Exception e)
    {
    e.printStackTrace();
    }
    

    采用这种方式,Client端必须和Process在同一个Project中才可以.

    还可以通过设置流程的启动方式为”Invoked synchronously via a client Request with Return”, 在其他地方通过JPD PROXY方式启动该流程,并把变量当返回值.

    PROXY的start()方法的返回值就是Process实例的返回的变量值.

    .

    另一种方式是把变量当返回值. 在客户端以HTTP方式调用该Process. 在客户端通过取HTTP连接的输出得到该Process的返回值.

    采用Xquery操作XML

    以下是XMLBean的Schema,和通过Schema转换和取得节点的方法:

    Schema:
    <?xml version="1.0" encoding="gb2312"?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="Demo">
    <xsd:complexType>
    <xsd:sequence>
    <xsd:element name="Node" minOccurs="1">
    <xsd:complexType>
    <xsd:sequence>
    <xsd:element name="name" type="xsd:string"/>
    <xsd:element name="value" type="xsd:string"/>
    <xsd:element name="type" type="xsd:string"/>
    </xsd:sequence>
    </xsd:complexType>
    </xsd:element>
    </xsd:sequence>
    </xsd:complexType>
    </xsd:element>
    </xsd:schema>
    

    从文件或者字符串中取得XMLBean,然后查询节点的例子:

    DemoDocument dd=
    DemoDocument.Factory.parse(new File("D:\\stepdoc.xml"));
    String s="$this/Demo/Node"; //查询节点的XQuery
    Node[] sarr=(Node[])dd.selectPath(s);
    for(int i=0;i<sarr.length;i++){
    System.out.println(sarr[i].getName()+":"+sarr[i].getValue());
    }
    System.out.println(dd.getDemo().getNode().getName());
    

    其他具体例子,可以参照Workshop帮助。

    LOG处理

    一种不好的做法是在Process的代码中通过System.out.println()直接打印调试信息。比较好的做法是通过context.getLogger()来打印LOG信息.

    context.getLogger("vartest.jpd").info("vartest.jpd启动");

    将在WLI81的启动窗口上打印出:

    <2004-4-4 下午14时16分26秒 CST> <Info> <WLW> <000000> <vartest.jpd启动>

    当然,还可以利用context.getLogger("vartest.jpd"). error()等打印出其他级别的LOG.

    可以写一个LOG函数,在其他地方直接调用就可以了

    public void log (String message) throws java.lang.Exception
    {
    Logger logger=this.context.getLogger("vartest.jpd ");
    logger.info(message);
    }
    

    更好的方法是通过LOG4J等来统一处理整个APPLICATION的LOG.

    注意: 要在CONSOLE中把该SERVER的LOG级别设置为INFO,才能打印出info级别的LOG.如下图所示.

    Process的Exception Handle

    “接收Partner发来的ebXML数据” 节点的代码如下:

    try
    {
    newOrder = SettleOrderDocument.Factory.parse(this.payload.toString());
    settleOrder = newOrder.getSettleOrder();
    }
    catch(Exception e)
    {
    e.printStackTrace();
    }
    seqNumber=settleOrder.getSeqNumber();
    sumAmount=settleOrder.getSumAmount();
    System.out.println(“seqNumber=”+ seqNumber);
    

    如果没有上面的OnException。当settleOrder=NULL时。流程将继续往后走到System.out.println(“seqNumber=”+ seqNumber);

    如果有了上面的OnException,当settleOrder=NULL,流程将只走到seqNumber=settleOrder.getSeqNumber(); 然后进入ProcessException()。

    如果“接收Partner发来的ebXML数据” 节点的代码如下:

    try
    {
    newOrder = SettleOrderDocument.Factory.parse(this.payload.toString());
    settleOrder = newOrder.getSettleOrder();
    seqNumber=settleOrder.getSeqNumber();
    sumAmount=settleOrder.getSumAmount();
    }
    catch(Exception e)
    {
    e.printStackTrace();
    }
    System.out.println(“seqNumber=”+ seqNumber);
    

    那么不管有没有OnException, 流程将继续往后走到System.out.println(“seqNumber=”+ seqNumber);

    改变process的会话周期

    process缺省的会话周期为1天,即流程实例1天有效。如果超过1天,还没有完成的process实例都会自动消失掉。有很多流程不可能在一天之内完成。可通过下面的方法改变process的会话周期,在WORKSHOP中点击Source View,然后在Property Editor ->conversation-lifetime-> max-age设定相应的会话周期。

    任务处理 Worklist介绍

    BEA WebLogic Integration 借助Worklist系统提供与业务用户快速集成的访问手段。Worklist系统可以管理用户、用户组和角色,以及任务到企业人员的路由。它使人们能在业务流程内协作,其中包括分配任务、跟踪任务状态、处理批准事项等。完整的工作流包括各种操作,例如接收、批准、修改和路由文档。经常与工作活动相伴的文档提供给人们完成任务所需的背景知识。它们构成了所有Worklist系统的核心组件。

    在 BEA WebLogic Workshop 环境中,BEA WebLogic Integration 提供了两种控件:任务控件和任务管理器控件,以支持各种工作表功能。

    这些控件都是受 BEA Workshop 框架管理的服务器端组件。它们对外提供Java接口,可以从业务流程直接调用。任务控件创建任务实例,管理其状态和数据等。任务执行器控件担当任务所有者角色,依靠它进行工作,完成任务,并提供各种管理优先级,其中包括任务的启动、停止、删除和分配。Worklist系统提供最终用户所需的各种功能,其中包括任务创建器、任务执行器和任务管理器,使它们与运行中的业务流程交互,以便处理流程例外、批准和状态跟踪等。

    已经向用户提供了一个Worklist用户界面示例(Worklist客户机),还可以创建定制的用户界面,以管理应用的Worklist组件。

    WLI 8.1对任务的处理

    对分派任务的处理:

    当前在业务处理中,任务的分配基本上有两种模式:

    串行处理,一个人完成任务之后,交给下一个人。典型的处理流程,公文审批流程:层级向上,科员->科长->处长等。

    并行处理:一个任务分拆为多个任务,分别交给不同的人完成,都完成之后,汇总处理结果。典型的处理流程:文档会签,根据审核人员名单,分别提请审核,最后结果汇总。

    对于串行处理方式:

    前端提交审批的人员名单和顺序,流程接收之后,可以创建审批任务。从审批名单中按顺序取出审批人员名字,将任务分配给他们。审批人员执行完任务之后,返回respons_xml 信息。如果当前审批没有完成,将任务交下一位继续审批。

    如下图所示:

    任务的并行处理

    对于并行处理,稍微要复杂一些:

    任务需要并行执行,因此在任务的分派上通过task factory实现创建多个任务。

    声明Control

    /**
    * @common:control
    */
    private processes.taskFactory taskfactory;//用来创建多个任务
    /**
    * @common:control
    */
    

    private processes.task tmptask;//进行任务的设置使用

    动态创建多个任务:

    tmptask=taskfactory.create();// create task 
    String taskid=null;
    taskid=tmptask.createTaskByName("taska");
    System.out.println("task 1"+taskid);
    tmptask.assignTaskToUser("usera");
    tmptask=taskfactory.create();
    taskid=tmptask.createTaskByName("taskb");
    System.out.println("task 2"+taskid);
    tmptask.assignTaskToUser("userb");
    

    任务的接收:

    任务的接收通过TaskFactory的TaskOnComplete方法来异步接收。

    taskfactory_onTaskCompleted(processes.task taskfactoryFactory_1, com.bea.xml.XmlObject response)该方法返回完成任务和任务处理响应信息。

    任务接收示例代码:

    this.taskinput = taskfactoryFactory_1;
    this.xmlresult = response;
    System.out.println("get task finish"+taskinput.getTaskId());
    

    流程示例如下:

     

    接收的处理结果:

    get task finish10.130.2.106-8c2ee7.fbc7e4b0d1.-7ff0
    get task finish10.130.2.106-8c2ee7.fbc7e4b0d1.-7fe5
    

    在实际使用时,可以通过前端提交任务名称、任务信息、任务执行人等信息,来动态创建出子任务。前端处理完成任务之后,再循环接收任务处理结果,并汇总。这样就实现了任务动态创建和分配。

    前端应用对任务的处理:

    对于前端任务的查询和操作可以通过taskworkercontrol 来实现。

    使用taskworker control客户查询他名下的任务可以创建一个方法,进行任务的查看。

    在taskworkercontrol中创建getAllTasks(String user)方法。返回的结果为TaskInfo[]。设定该方法selector中的claim参数为{user}。即将user用户claim状态下的任务以列表形式返回回来。

    代码如下:

    /**
    * @jc:select claimant="{user}"
    */
    public TaskInfo[] getAllTasks(String user);
    

    通过该方法就可以在前端的pageflow中查询用户名下的任务列表,从任务列表中取出任务ID,通过taskworker control就可以对任务可以进行操作(任务取消、任务启动、任务完成等)

    示例代码:

    System.out.println("user"+form.getUser());
    taskinfo=taskworker.getAllTasks(form.getUser());
    int length=taskinfo.length;
    for(int i=0;i<length;i++)
    {System.out.println(taskinfo[i].getTaskId());
    System.out.println("task request info:"+taskworker.getTaskRequest(taskinfo[i].getTaskId()));
    taskworker.startTask(taskinfo[i].getTaskId());
    taskworker.stopTask(taskinfo[i].getTaskId());
    }
    
    应用集成 SocketAdapter开发示例

    注:使用BEA Weblogic platform 8.2 中的ADK工具

    1 cd %WLI_HOME%\adapters\utils

    2 运行antEnv.cmd

    3 运行GenerateAdapterTemplate.cmd,并输入相关信息

    子目录:adkdemo

    type:socket

    vender:bease

    version:1.0

    包:com.bea.adkdemo

    4 在 InteractionImpl.java, ManagedConnectionFactoryImpl.java, ManagedConnectionImpl.java文件中加入:"import test.utils.*;"

    5 SPI

    • 修改ManagedConnectionFactoryImpl.java(创建与EIS的连接并管理EIS连接资源的实例)

    修改CreateManagedConnection方法覆盖为以下内容

    assertValidState();
    ILogger logger = getLogger();
    if (logger.isDebugEnabled()) {
    StringBuffer sb = new StringBuffer();
    sb.append(toString());
    sb.append(" >>>> createManagedConnection with parameters JAAS subject[");
    sb.append(subject);
    sb.append("] and SPI ConnectionRequestInfo[");
    sb.append(info);
    sb.append("]");
    logger.debug(sb.toString());
    }
    // Extract the username and password to use to open the connection to the
    // EIS with.
    String strUserName = getUserName();
    String strPassword = getPassword();
    PasswordCredential pc = getPasswordCredential(subject, info);
    if (pc != null) {
    strUserName = pc.getUserName();
    strPassword = new String(pc.getPassword());
    }
    try {
    logger.audit("attempting_to_open_connection", strUserName);
    // TODO: This is where you should open resources to establish connectivity
    // to the EIS...i.e. a real adapter would not create a new string here
    logger.audit("open_connection", strUserName);
    javaServersessionsession=getServerConnection();
    // A ManagedConnection instance is pooled/managed by the ConnectionManager
    // Consequently, it should encapsulate all resources needed to establish
    // a connection to the EIS
    return new ManagedConnectionImpl(session,
    this,
    getLogContext(),
    strUserName,
    false, // XA not supported 
    false); // local tx supported
    }
    catch (Exception exc) {
    logger.error(exc);
    Object[] aErr = new Object[] {
    strUserName,
    exc.getMessage()
    };
    String strMessage =
    logger.getI18NMessage("open_connection_exception", aErr);
    ResourceException resExc = new EISSystemException(strMessage);
    resExc.setLinkedException(exc);
    throw resExc;
    }
    

    加入:getServerConnection私有方法:

    private javaServersession getServerConnection()
    {
    String m_serverName=getServerName();
    String m_portNumber=getPortNumber();
    int port = Integer.parseInt(m_portNumber);
    javaServersession client=new javaServersession();
    client.GetSocket(m_serverName,port);
    return client;
    }
    
    • 修改ManagedConnectionImpl.java(将EIS连接资源封装到此类的实例中)
    • 修改ManagedConnectionImpl构造方法
    ManagedConnectionImpl(javaServersession tempJavaServerSession,
    AbstractManagedConnectionFactory myFactory,
    LogContext logContext,
    String strUserName,
    boolean bSupportsXAResource,
    boolean bSupportsLocalTx)
    throws ResourceException {...}
    
    • 在此方法中:

    将setPhysicalConnection(objPhysicalConnection)

    改为:setPhysicalConnection(tempJavaServerSession)

    改ManagedConnectionImpl.java的checkConnection中的

    javaServersession eisConn = null;
    try
    {
    eisConn = (javaServersession)getPhysicalConnection();
    }
    catch (Exception e)
    {
    logger.error(e);
    }
    if (eisConn == null ) {
    fireConnectionErrorOccurredEvent(null);
    bIsAlive = false;
    }
    else
    {
    bIsAlive = true;
    }
    

    否则有warning。

    • ResourceAdapterImpl.java(资源适配器的实现)

    打开ResourceAdapterImpl.java文件,加入以下蓝色代码:

    • 加入public String m_serverName,public String m_portNumber成员变量:
    • 相应加入以下4个方法:
    public String getServerName()
    {
    return m_serverName;
    }
    public void setServerName(String strServerName)
    {
    m_serverName=strServerName;
    }
    public String getPortNumber()
    {
    return m_portNumber;
    }
    public void setPortNumber(String strPortNumber)
    {
    m_portNumber=strPortNumber;
    }
    

    6 CCI

    • InteractionImpl.java(指定Service功能调用的请求/应答Schema)
    • 修改createRequestSchema方法:
    private DocumentRecord createRequestSchema(DocumentRecord input)
    throws javax.resource.ResourceException {
    // The input record should contain information about the service we are
    // creating a request schema for
    String strRootElement="ServiceRequest";
    SOMComplexType javaServerType = new SOMComplexType();
    SOMSequence javaServerSeq = javaServerType.addSequence();
    SOMElement javaServerSvcName = new SOMElement("ServiceName");
    SOMElement javaServerInputStr = new SOMElement("InputString");
    javaServerSeq.add(javaServerSvcName);
    javaServerSeq.add(javaServerInputStr);
    SOMSchema schema = new SOMSchema();
    SOMElement response = new SOMElement(strRootElement,javaServerType);
    schema.addElement(response);
    IDocumentDefinition def = DocumentFactory.createDocumentDefinition();
    def.setDocumentSchema(schema);
    def.setRootElementName(strRootElement);
    def.setDocumentSchemaName(strRootElement);
    return new DocumentDefinitionRecord(def);
    }
    
    • 修改createResponseSchema方法:
    protected DocumentRecord createResponseSchema(DocumentRecord input)
    throws javax.resource.ResourceException {
    // The input record should contain information about the service we are
    // creating a request schema for
    String strRootElement="ServiceResponse";
    SOMComplexType javaServerType = new SOMComplexType();
    SOMSequence javaServerSeq = javaServerType.addSequence();
    SOMElement javaServerOutputStr = new SOMElement("OutPutString");
    javaServerSeq.add(javaServerOutputStr);
    SOMSchema schema = new SOMSchema();
    SOMElement response = new SOMElement(strRootElement,javaServerType);
    schema.addElement(response);
    IDocumentDefinition def = DocumentFactory.createDocumentDefinition();
    def.setDocumentSchema(schema);
    def.setRootElementName(strRootElement);
    def.setDocumentSchemaName(strRootElement);
    return new DocumentDefinitionRecord(def);
    }
    

    修改InteractionImpl类中服务调用处理方法

    • protected DocumentRecord execute方法:
    protected DocumentRecord execute(InteractionSpec ixSpec, DocumentRecord input)
    throws javax.resource.ResourceException {
    ILogger logger = getLogger();
    // No need to check the args as our parent did that for us!
    if (ixSpec != null && ixSpec instanceof DesignTimeInteractionSpecImpl) {
    // This is a design time request!
    logger.info("cci_design_time_interaction", ixSpec);
    // Determine the type of design-time request
    DesignTimeInteractionSpecImpl dtIxSpec =
    (DesignTimeInteractionSpecImpl) ixSpec;
    
    if (dtIxSpec.isRequestSchemaRequest()) {
    return createRequestSchema(input);
    }
    else if (dtIxSpec.isResponseSchemaRequest()) {
    return createResponseSchema(input);
    }
    else if (dtIxSpec.isBrowseRequest()) {
    return browseEIS(input);
    }
    else {
    // This is an unknown design-time request!
    throw new javax.resource.NotSupportedException(dtIxSpec.toString());
    }
    }
    else if (ixSpec != null && ixSpec instanceof com.bea.adkdemo.cci.InteractionSpecImpl) {
    // This is a runtime request!
    logger.info("cci_runtime_interaction", ixSpec);
    // TODO: an real adapter would process the input document and generate an
    // output document at this point, we'll just register the input document
    // with our 'fake' EIS, and then return the input document. You'll want
    // to remove the following lines, and do work against your 'real' EIS.
    // Only register the document if this InteractionSpec specifically
    // requests it.
    String eisEventTypeToForce =
    ((com.bea.adkdemo.cci.InteractionSpecImpl) ixSpec).getEisEventTypeToForce();
    if (eisEventTypeToForce != null) {
    try {
    // Do some work against our 'fake' EIS
    com.bea.adkdemo.eis.EIS eis = com.bea.adkdemo.eis.EIS.getInstance();
    com.bea.adkdemo.eis.EISEvent eisEvent =
    new com.bea.adkdemo.eis.EISEvent(eisEventTypeToForce, input);
    logger.info("registering_eis_event", eisEvent);
    eis.registerEvent(eisEvent);
    }
    catch (Exception e) {
    javax.resource.ResourceException re =
    new javax.resource.ResourceException("Error notifying SampleEIS of service execution: " + e.getMessage());
    re.setLinkedException(e);
    throw re;
    }
    }
    DocumentRecord output=null;
    try
    {
    output=InvokeServerService(input);
    }
    catch(Exception e)
    {
    System.out.println(e);
    }
    return output;
    }
    else {
    // This is an unknown request!
    throw new javax.resource.NotSupportedException(ixSpec.toString());
    }
    }
    
    • 加入适配器服务真正完成的操作InvokeServerService方法
    private DocumentRecord InvokeServerService(DocumentRecord input)
    {
    DocumentRecord output=null;
    try
    { 
    IDocument outputInterface=DocumentFactory.createDocument();
    output=new DocumentRecord(outputInterface);
    String serviceName=input.getStringFrom("/ServiceRequest/ServiceName");
    String strInput=input.getStringFrom("/ServiceRequest/InputString");
    javaServersession session = (javaServersession) ((com.bea.adkdemo.cci.ConnectionImpl) getConnection()).getPhysicalConnection();
    String strOupput=session.GetString(serviceName+" "+strInput);
    output.addElement("","ServiceResponse");
    output.addElement("/ServiceResponse", "OutPutString", strOupput);
    }
    catch(DocumentException e)
    {
    System.out.println(e);
    }
    catch (ResourceException e)
    {
    System.out.println(e);
    }
    catch (Exception e)
    {
    System.out.println(e);
    }
    return output;
    }
    

    7 修改适配器应用视图配置Web应用中配置连接属性的页面confconn.jsp,文件在war目录下:

    修改为:

    <table>
    <tr>
    <td><adk:label name='confconn_label_ServerName' required='true'/></td>
    <td><adk:text name='serverName' maxlength='30' size='8' required='true'/></td>
    </tr>
    <tr>
    <td><adk:label name='confconn_label_PortNumber' required='true'/></td>
    <td><adk:text name='portNumber' maxlength='30' size='8' required='true'/></td>
    </tr>
    <tr>
    <td><adk:label name='confconn_label_userName' required='false'/></td>
    <td><adk:text name='userName' maxlength='30' size='8' required='false'/></td>
    </tr>
    <tr>
    <td><adk:label name='confconn_label_password' required='false'/></td>
    <td><adk:password name='password' maxlength='30' size='8' required='false'/></td>
    </tr>
    <td colspan='2'><adk:submit name='confconn_submit_connect' doAction='confconn'/></td>
    </tr>
    </table>
    

    8 改相关的配置文件

    • <adapter>-base.properties适配器中的参数名称配置

    加入

    confconn_label_ServerName=Server Name

    confconn_label_PortNumber=Port Number

    serverName=ServerName

    portNumber=PortNumber

    • ra.xml、weblogic-ra.xml、wli-ra.xml适配器配置描述文件

    进入src/rar/meta-inf目录,修改ra.xml

    加入:

    <config-property>
    <config-property-name>ServerName</config-property-name>
    <config-property-type>java.lang.String</config-property-type>
    </config-property>
    <config-property>
    <config-property-name>PortNumber</config-property-name>
    <config-property-type>java.lang.String</config-property-type>
    </config-property>
    

    修改weblogic-ra.xml文件,加入参数的初始值

    <map-config-property>
    <map-config-property-name>ServerName</map-config-property-name>
    <map-config-property-value>localhost</map-config-property-value>
    </map-config-property>
    <map-config-property>
    <map-config-property-name>PortNumber</map-config-property-name>
    <map-config-property-value>0</map-config-property-value>
    </map-config-property>(无初始值有warning)
    

    进入src目录,修改wli-ra.xml文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <connector>
    <display-name>WLI Resource Adapter</display-name>
    <vendor-name>BEA</vendor-name>
    <eis-type>Socket</eis-type>
    <resourceadapter-version>1.0</resourceadapter-version>
    <resourceadapter>
    <!--注意:如果类的路径不同,需要修改此处--><resourceadapter-class>com.bea.adkdemo.spi.ResourceAdapterImpl</resourceadapter-class>
    <!-- ResourceAdapter default configuration properties -->
    <config-property>
    <config-property-name>UserName</config-property-name>
    <config-property-type>java.lang.String</config-property-type>
    <config-property-value></config-property-value>
    </config-property>
    <config-property>
    <config-property-name>Password</config-property-name>
    <config-property-type>java.lang.String</config-property-type>
    <config-property-value></config-property-value>
    </config-property>
    <config-property>
    <config-property-name>ServerName</config-property-name>
    <config-property-type>java.lang.String</config-property-type>
    <config-property-value></config-property-value>
    </config-property>
    <config-property>
    <config-property-name>PortNumber</config-property-name>
    <config-property-type>java.lang.String</config-property-type>
    <config-property-value></config-property-value>
    </config-property>
    <inbound-resourceadapter>
    <messageadapter>
    <messagelistener>
    <messagelistener-type>EventMessageEndpoint</messagelistener-type>
    <activationspec>
    <activationspec-class>com.bea.wlai.event.EventActivationSpecImpl</activationspec-class>
    </activationspec>
    </messagelistener>
    </messageadapter>
    </inbound-resourceadapter>
    </resourceadapter>
    </connector>
    

    9 修改Adapter项目编译文件build.xml

    在<!-- Step 3: Add any additional jars/classes that are specific to your adapter-->下加入:<property name='JAVASERVERJARFILE' value='./jsession.zip'/>

    在<!--Step 4: Setup the classpath for compiling, etc.-->下加入:

    <pathelement path='${JAVASERVERJARFILE}'/>

    10 拷贝C:\bea\weblogic81\integration\adapters\utils\antEnv.cmd到project目录下。

    将jsession.zip文件拷贝到porject目录下

    11 进入project目录,执行antEnv.cmd

    12将C:\bea\weblogic81\integration\adapters\adkdemo\src\war\WEB-INF\web.xml
    拷贝到C:\bea\weblogic81\integration\adapters\src\war\WEB-INF下,否则有warning

    13 执行ant,会在project平级目录下生成lib目录,

    14 在startweblogic脚本startweblogic.cmd中的classpath环境变量中加入jsession.zip的路径和lib目录下sample-eis.jar的路径。红色对应你本机相应目录。

    set CLASSPATH=%CLASSPATH%;C:\bea\weblogic81\integration\adapters\adkdemo\project\jsession.zip;
    C:\bea\weblogic81\integration\adapters\adkdemo\lib\sample-eis.jar;

    15 启动对应的weblogic platform

    16 将lib目录下的BEASE_SOCKET_1_0.ear部署到服务器上。

    ★★★具体API祥述可见http://e-docs.bea.com/wli/docs81/javadoc/index.html ,从而满足实际生产中的需要。

    DB Event实现机制

    因为数据库不能将数据直接发给Integration Server,所以进一步的分析。Event的实现过程是,在WLIAV Console配置DB Event,在对应的数据库生成trigger。该trigger通过数据库表的变化,将变化数据保存在辅助表中。Server对辅助表轮询,如果发生变化,生成消息发布到对应的channel上,从而实现了Event触发。

    Event的配置:

    使用DB Adapter在WLI Application Integration Console可以进行service和event配置。配置完成数据库连接之后,可以配置一个新的Event。

    在Event配置选项中:下图:

    从Browse DBMS,选择 Table Name和Schema Name。

    选择消息的触发类型,(Insert, Update and Delete)

    当创建好Event之后,注意要配置Event Connections,见下图:

    SleepCount:轮询时间

    配置完成之后,就可以对该Event进行测试。

    配置内容保存在:

    {Integration Domain}\wliconfig\AdapterInstanceConfiguration.xml

    Trigger的生成:

    在配置好Event保存,后端Adapter调用EventGenerator.java和对应DB的triggerGenerator.class,在对应的数据库上生成trigger。生成trigger java file可以在下面目录找到。

    {beahome}\weblogic81\integration\adapters\dbms\src\com\bea\adapter\dbms\utils\triggers

    以PointBase中插入记录为例:

    在数据库生成trigger: PLAN_HISTORY_I和PROCEDURES: PLAN_HISTORY_I

    从pointbase console不能直接看到trigger和procedures内容,可以在数据库文件workshop$1.wal和workshop.dbn查看到。

    该trigger:调用pointbase.PBPUBLIC_PLAN_HISTORY_Events.AfterInsert方法将数据库的变化写入到数据库表:Weblogic EVENT和EVENT_DATA

    (PBPUBLIC_PLAN_HISTORY_Events.java可以在{integration Domain}/pointbase中看到,它由PointBaseEventProcedureClassBuilder.java生成)

    Weblogic EVENT表:

             
    Table_name Trigger_type Time_created Event_id Handled
    PBPUBLIC.PLAN_HISTORY INSERT 2003-12-25 1 0

    如果该event消息被处理,则Handled为1

    EVENT_DATA表:

             
    EVENT_ID COLUMN_NAME COLUMN_TYPE STRING_VALUE IS_NEW
    1 PLAN_TITLE VARCHAR A005 0
    1 PLAN_CONTENT VARCHAR 4 0

    以使用Oracle库定义触发Event为例:

    配置数据库的连接:

    JDBC Driver:oracle.jdbc.xa.client.OracleXADataSource

    JDBC URL:jdbc:oracle:thin:@localhost:1521:OracleDB

    选择相应的表,创建insert event。

    注意:选择的表是在该用户权限之下,否则会在测试是不成功。

    接着创建Event Connection

    创建insert Event应用视图之后,测试视图时,会提示如下错误:

    Could not create Resource Adapter instance '____test__TestAV_TestAV__Default': c

    om.bea.connector.ResourceWrapperException: Could not start EventRouter in Resour

    ce Adapter missing propertiesCould not start EventRouter in Resource AdapterEven

    tGenerator: CannotInit TABLE 'system.EVENT' does not exist in com.bea.adapter.db

    DECLARE temp integer;

    这是因为Oracle数据库中尚未建立辅助表:EVENT, EVENT_DATA, EVENT_GENERATOR和EVENT_GENERATOR_EVENT.

    这是需要运行event.sql脚本,创建上述表。脚本的位置在:{beahome}\weblogic81\integration\adapters\dbms\sql\oracle

    创建成功之后,就可以再次测试视图,测试成功之后在触发表下会生成trigger,如下所示:

    Begin
    insert into SYSTEM.EVENT
    (TABLE_NAME, TRIGGER_TYPE, TIME_CREATED, EVENT_ID)
    values ('SYSTEM.TEST', 'insert', sysdate, 0);
    select count(*) into temp from SYSTEM.EVENT;
    update SYSTEM.EVENT set EVENT_ID = temp where EVENT_ID=0;
    Insert into SYSTEM.EVENT_DATA ( EVENT_ID, COLUMN_NAME, COLUMN_TYPE, STRING_VALUE ) 
    values( temp, 'NAME', 'VARCHAR', :new.NAME); 
    Insert into SYSTEM.EVENT_DATA ( EVENT_ID, COLUMN_NAME, COLUMN_TYPE, STRING_VALUE ) 
    values( temp, 'AGE', 'DECIMAL', :new.AGE); 
    end;
    

    Event Publish:

    在Event Publish之后,创建出相应的schema和channel文件,设计的流程就可以进行消息订阅了。

    运行时,Adapter轮询检查辅助表的数据是否变化,如果发生变化,生成消息放在channel上,触发相应流程。从而实现了DB Event消息的接收。

    Event消息可以在wli console ->Message Broker相应的channel中检查是否收到,以及是否有流程来订阅这一消息。

    示例,使用Oracle中的表作为触发表:

    部署 从开发环境发布应用到生产环境

    在WORKSHOP中把整个应用编译成一个EAR文件,把该EAR文件直接放到DOMAIN的applications目录下,该APPLICATION中的每个Project都要创建两个JMS Queue. 如该applications有一个名为AccountSyn的Project。就要创建两个JMS QUEUE。JNDI如下。

    AccountSyn.queue.AsyncDispatcher

    AccountSyn.queue.AsyncDispatcher_error

    在创建时,可同时打开开发环境与生产环境的CONSOLE,进行比较。对照创建生产环境上的JMS QUEUE。创建完毕后,要重新启动WLI才能生效。

    管理

    BEA Integration 提供丰富的Meta Data管理功能。

    对XML数据,提供XML Schema, XML的编辑工具XML SPY.并可根据XML Schema自动生成XMLBean,通过XMLBean把XML数据转化为对象,可以非常方便进行XML到JAVA数据类型,JAVA数据类型到XML的转化.不用通过DOM,SAX等写很复杂的代码来实现XML 解析的工作,提供图形化的定义工具可非常简单的进行XML到XML, XML-到非XML的转化工作.如下图所示.

    对非XML数据,可通过BEA Integration中的FormatBuilder进行非XML数据到XML数据的转化.

    BEA Integration 对Meta Data管理的原理图如下所示。

     

    BEA Integration提供REPOSITORY管理各种Meta Data和资源文件。BEA Integration自动把XML Schema文件,XMLBean,MFL保存到REPOSITORY中,自动做管理. 并可以方便的进行导入导出操作. BEA Integration还可以把应用中用到的各种图片等当成资源保存到REPOSITORY中.更方便的进行管理和使用.如下图所示。

    BEA Integration提供丰富的DEBUG功能,可以对JSP,EJB,WERSERVICE, WORKFLOW(PROCESS),各种Java Control进行调试. 并提供丰富的调试手段.可设置断点,进行单步调试,并可随时观察变量的值.如下图所示.

    此外,对WEB SERVICE, WORKFLOW(PROCESS)等还提供单元测试工具,可自动为他们生成客户端.进行单元调试工作.如下图所示:

    BEA Integration提供丰富的性能监测工具.从Weblogic Server的Console中可以直接监控到系统JVM对CPU,内存的使用情况,EJB,Servlet的调用次数及每次调用的平均处理时间.JMS队列中的消息情况.事务的处理情况等非常详细的性能信息。

    BEA Integration可以对JVM,EJB,Servlet,JDBC,JMS等进行性能调优.调优可在Weblogic Server的Console中进行,并利用Console提供的性能监控工具来协助调优. BEA Integration提供详细的性能调优文档.

    BEA Integration提供统一的用户权限管理,Weblogic Integration,Weblogic Portal的用户权限管理都是基于Weblogic Server的安全域. 通过它进行统一的认证,授权工作. 缺剩的安全域采用内置的LDAP Server保存用户资料,进行认证,授权工作.也可以采用其他的LDAP Server或采用数据库来配置安全域.用户还可定制自己的安全域.

    BEA Integration的安全机制和服务能够提供端到端的安全保证,它对安全规则、安全政策提供统一的管理,并且可以很方便地将业务需求上的应用安全通过映射的方式将业务规则映射到安全政策上。一个用户或操作员如果想访问BEA Integration的资源,必须有相应的授权。在BEA Integration中安全机制是有一组可配置的安全提供商、用户、组、安全角色、安全政策等组合而成的,它在相关的安全域上检查分配给这个用户的安全角色及用户要访问资源的安全政策来决定该用户是否拥有对该资源的访问权限。

    ·用户(User):用户是在安全域中可以被认证的实体,一个用户可以是一个人(如应用的最终用户)、也可以是一个软件实体(如一个客户端应用),每一个用户在安全域内有一个唯一的标识。它可以被放在与安全角色相关的组中,也可以直接同安全角色相关。

    ·组(Groups):组是用户的一个逻辑集合。通常组里的成员都有相似性,通过管理组比管理大量的单个个人要效率高的多。例如一个系统管理员可以将用户归在组中,然后一次性地为这些用户定义安全规则(为组分配安全角色)。

    ·安全角色(Security Roles):它是基于特定条件授予用户或组对应用资源的权限。这中权限是动态授予的,这些条件可以是基于用户名、组成员或时间等。

    ·安全政策(Security Policies):它是在应用资源和用户、组、安全角色之间的一种关联,它保护了对资源的未授权访问。

    Weblogic Integration提供基于规则的权限控制,如可以决定某个角色可以在某一个时间段(如从8:00-18:00)才可以访问某一个EJB或Servlet.

    BEA Integration提供丰富的流程监管功能. 可知道流程的开始时间,当前执行到哪一步.流程变量的值.当前流程处于怎么状态(正在运行,完成,出现异常等),系统管理员还可以结束,挂起,重起一个流程..

    BEA Integration还提供流程的SLA管理功能.当一个流程的某个任务超过规定的时间还没有处理完,将自动进行报警.

    BEA Integration提供PDF或SVG格式的图形。可清楚地显示某一个流程实例当前执行到哪一步。如下图所示。

    BEA Integration提供丰富的审计管理功能,审计提供了计算机活动的一个电子痕迹,在Weblogic Integration安全结构中用Audit Provider来提供审计服务。配置好后,在每一个安全操作(如操作员的进入、退出、被授权使用那些资源等)前、后都会执行审计事件记录。是否对特殊的事件进行审计取决于Audit Provider自身或特殊的审计条件和严重级别。这些审计信息可以写到LDAP服务器、数据库或文本文件中。

    一些子系统维护了额外的操作日志以提供在操作环境下对子系统交互的审计,例如HTTP子系统可以将所有HTTP访问的日志放在一个文本文件中,JTA子系统保留一个交易日志以报告对交易情况的统计。

    Audit Provider可以在Weblogic Server的Console中进行配置。如下图所示。

    入门
    Integration快速入门:

    通过这个手把手的实例,您可以快速体验WebLogic Integration在业务流程设计,管理,集成领域的强大功能。
    http://dev2dev.bea.com.cn/techdoc/200304590.html

    另外从http://dev2dev.bea.com可以下载到最佳实践,包括应用集成、错误处理、事务处理等示例可供参考。

    dot dot dot

    dot
      作者其它文章
    您对本文的评价
    您对这篇文章的看法如何?
    太棒了!5分 不错啊 4分 一般般 3分 有待提高 2分 不好 1分

       
    相关产品