IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  WebSphere  >

客户端调用流程的几种方法讨论

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

伟 方国, IBM软件部工程师

2005 年 12 月 27 日

本文详细介绍了如何通过服务组件架构、业务流程引擎、Web服务三种不同的方式来调用一个简单的HelloWorld业务流程。

概览

随着IBM推出新的基于流程整合产品――WebSphere Process Server,流程的构建和调用有了一些新的变化。首先,流程在WebSphere Process Server中是作为一个业务服务组件的形式存在。其次,服务组件编程模型的出现,给流程的调用方式带来一些新的变化。第三,由于业务流程引擎(BPC,Business Process Choreographer)本身实现的一些改进,也给流程的调用带来一些变化。本文结合WebSphere Process Server中的流程功能,通过使用WebSphere Integration Developer V6(简称WID)这个集成开发工具,介绍几种常用的流程调用方式,从而使读者能够在应用中方便的集成流程功能。





回页首


1.1 流程的第一个例子――HelloWorld

在构建应用之前,先对WID工具进行一个简单的配置。WID是一个基于Eclipse框架的开发工具,但是为了减少开发工具的资源消耗,WID缺省是没有装载与J2EE和Web服务相关的插件。由于开发本文中的例子需要用到这些功能,因此需要事先设置一下。设置的方法是通过窗口菜单进入首选项配置,并打开J2EE开发和Web服务开发的支持,并按确定。其设置的图示如下:



为了介绍流程的几种调用方式,首先需要构建出一个流程。本文的重点不在于流程本身,因此,我们以一个最为简单的流程作为调用对象。与任何一种编程语言的学习一样,我们开始编写一个"流程版"的HelloWorld。下面简单的描述HelloWorld流程的创建步骤。

1. 首先创建应用模块――HelloWorld。在业务集成透视图中,通过右键菜单打开模块创建向导,创建一个名为HelloWorld的模块。

2. 创建一个共享库――HelloWorldLib。这个共享库的目的是存放不同模块共享的一些资源,比如接口定义,数据定义等。在本例中我们把流程的接口定义放在共享库中。如下图所示:



3. 为流程创建一个WSDL接口――HelloWorldInterface。在HelloWorldLib共享库下面的接口列表中,通过向导创建一个名为HelloWorldInterface的WSDL接口。接口的操作名为hello,参数名为helloInput和helloOutput,为了简单起见两个参数的类型选为String类型。构建完后接口如下图所示:



4. 编辑HelloWorld模块的依赖设置。为了能够让HelloWorld模块访问到HelloWorldLib共享库中定义的资源,我们需要编辑HelloWorld模块的依赖设置。双击HelloWorld模块(或选择右键菜单中的打开依赖编辑器),然后添加需要依赖的共享库。如下图所示:



这样,HelloWorld模块中就可以访问到HelloWorldLib共享库中定义的资源了。

5. 创建流程――HelloWorldProcess。在HelloWorld模块下面展开业务逻辑(Business Logic)并选择流程(Processes),通过右键菜单打开流程创建向导。流程名称设定为HelloWorldProcess,流程接口选择在上一步中已经建立的HelloWorldInterface,操作选择接口中定义的hello操作。点击完成按钮,我们可以看到下面的流程编辑器:



上面所示的流程是一个根据流程接口定义创建的一个初始化流程,一般包括Receive节点(流程的入口)和Reply节点(流程的出口,取决于接口是否定义返回参数)。由于流程本身也是一个服务组件,因此右上角的Interface Partners显示的就是调用流程组件的接口,即流程的客户端。Reference Partners显示的就是组件调用其它服务的引用,在这个例子中由于流程没有调用其它服务故暂时为空。Variables是变量定义区,在缺省情况下,流程创建向导根据接口参数名称自动生成变量,在这个例子中自动为流程定义了HelloInput和HelloOutput两个变量,它们的类型同接口定义中指定的类型,即String。Correlation Sets是关联关系集合,它的作用是为了让请求能够与流程实例匹配上(可以类比Web应用中SessionID的作用),由于我们的流程例子是不可中断流程(Non-Interruptible Process或Microflow),因此在这个例子中不需要关联关系集合。

6. 为流程添加业务逻辑。为了简化流程的构建,我们仅为这个流程添加一个Snippet节点。这是一种基于图形化编程或Java语言编程的节点。通过把控制面板上的Snippet节点拖拉到Receive节点和Reply节点之间即可,并把节点名称改为HelloWorld。如下图所示:



我们的业务逻辑非常简单,就是返回流程输入和一个"Hello World"字符串。因此,选中HelloWorld这个Snippet节点,然后在属性栏的详细选项中用Java方式输入业务逻辑代码,如下图所示:



7. 把流程组件添加到模块编辑器(Assembly Diagram)中。在前面4个步骤,我们构建了一个流程业务组件――HelloWorldProcess。为了使用这个流程组件,需要把它添加到模块中去。最为简单的添加方式是打开模块编辑器,然后把HelloWorldProcess拖拉到模块编辑器中保存即可。如下图所示:



8. 至此,HelloWorld流程就构建完成了。下面分别讨论几种不同的调用流程的方式。





回页首


1.2 基于服务组件架构(SCA)的调用方式

虽然从WebSphere Process Server这个产品名称中看,这是一个侧重于流程集成的应用服务器平台,但是从技术架构上讲,流程只是WebSphere Process Server中众多服务组件的一个,它与其它的服务组件比如人员任务,POJO,业务规则组件,选择器等都是同一层次的。这一点,也可以通过WID中的业务逻辑(Business Processes)下的树型组织架构看出来。因此,我们可以通过调用服务组件的方式来调用流程。

为了使得客户端调用与流程本身相对独立,我们将单独为流程客户端建立一个应用模块(SCAClient)。由于每个模块分别对应一个J2EE的企业应用程序,因此流程客户端应用与流程应用是两个相互独立的企业应用程序。这样整个调用架构就会相对比较灵活。下面描述如何创建一个基于服务组件架构的流程客户端。

1. 在HelloWorld模块中为流程组件提供一个导出端点(Export)。由于流程客户端与HelloWorld流程在不同的模块中,因此需要在HelloWorld模块中为流程创建一个导出端点。选择HelloWorldProcess,然后通过右键菜单创建导出端点。由于流程客户端将以SCA的方式调用流程组件,因此选择SCA绑定方式。如下图所示:



生成的Export缺省名称为HelloWorldProcessExport。

2. 为流程客户端创建一个模块。创建一个名称为SCAClient的模块,并编辑它的依赖项,使得它依赖于HelloWorldLib共享库。

3. 在SCAClient模块中创建导入端点(Import)。为了在SCAClient模块中使用HelloWorldProcess,我们需要在SCAClient模块中创建Import,来与HelloWorld模块中的Export相对应。最为简单的创建方法是直接把HelloWorldProcessExport拖拉到SCAClient模块的编辑器中,如下图所示:



4. 在SCAClient模块中创建Standalone Reference。为了使客户端的JSP页面能够访问上面的Import1端点,需要为其添加一个Standalone Reference,把它与Import1连接起来,并且选择WSDL接口类型,如下图所示:



这个Standalone Reference的引用名称为HelloWorldInterfacePartner。

5. 构建调用流程的index.jsp页面。把WID切换到J2EE透视图的导航视图,然后在SCAClientWeb这个Web项目中生成一个index.jsp页面,如下图所示:



6. 分析JSP代码。这里JSP调用HelloWorld流程的代码与调用其它服务组件基本上是一样的。主要步骤首先生成ServiceManager,然后调用ServiceManager的locateService方法来拿到Standalone Reference的服务引用,最后调用服务的业务方法,即流程接口的hello方法。主要代码片断如下


ServiceManager serviceManager = new ServiceManager();
Service service = (Service) serviceManager.locateService("HelloWorldInterfacePartner");
String msg = request.getParameter("message"); //从JSP中得到的输入
DataObject resp = (DataObject) service.invoke("hello",msg);

7. 至此,通过SCA的方式调用流程的工作已经全部做完。现在就可以在WID的测试环境中发布HelloWorldApp和SCAClientApp两个应用,然后通过上述的index.jsp页面来调用HelloWorld流程。所有在本部分使用到模块的代码,请参考本文附的项目交换文件,SCAClient.zip。





回页首


1.3 基于Web服务的调用方式

从BPEL规范来讲,基于BPEL的流程主要是通过Web服务接口来调用其它服务的,而且这个流程本身也以Web服务接口对外,即可以通过Web服务的方式来调用它。而调用一个Web服务最为主要的一个信息是服务的描述,也即WSDL文件。一个完整的WSDL文件一般包含的内容有:1. 服务接口描述,包括类型定义、变量定义和端口类型定义等。2. 绑定信息定义,主要是与SOAP协议相关的信息,比如传输协议、编码方式等。3. 服务实现信息定义,主要是实际服务提供者的一些信息,比如服务地址等。从前面流程的构建中我们已经看到,在WebSphere Process Server中流程的接口主要就是WSDL类型的。但是,这些WSDL接口文件中并没有包含绑定信息和服务实现信息,如下图所示:



因此,不能直接使用描述流程接口的WSDL文件通过Web服务的方式来调用流程。而对于Web服务调用而言,绑定信息和服务实现信息是必须的。那如何解决这个问题呢?WID通过Export的Web服务绑定方式来提供原先WSDL接口中所缺少的信息。下面描述如何创建一个基于Web服务的流程客户端。

1. 修改HelloWorldProcessExport的绑定方式。打开HelloWorld模块的模块编辑器,通过右键菜单删除原先的SCA绑定方式,然后选择新的Web服务绑定方式,如下图所示:



选择Web服务绑定会提示要不要自动生成包含绑定信息的WSDL文件,并且选择SOAP/HTTP的传输方式。在Export的绑定信息栏中可以看到如下绑定:



2. 生成一个客户端Web项目。把WID切换到J2EE透视图,然后创建一个动态Web项目,名称为WebServiceClient,企业应用项目为WebServiceClientEAR。如下图所示:



3. 准备WSDL文件。现在我们要为生成Web服务客户端准备WSDL文件。在J2EE透视图的项目导航视图中,首先根据Web服务生成客户端向导的要求,在WebServiceClient项目的WebContent/WEB-INF/下创建一个wsdl的目录。然后,把HelloWorld模块下的HelloWorldProcessExport_HelloWorldInterfaceHttp_Service.wsdl文件和HelloWorldLib共享库下的HelloWorldInterface.wsdl文件拷贝到上面新建的wsdl目录下。这两个文件构成我们需要的完整的HelloWorld流程Web服务描述文件。

4. 通过Web服务的客户端创建向导生成Web服务客户端代理。选择HelloWorldProcessExport_HelloWorldInterfaceHttp_Service.wsdl文件,通过右键菜单启动Web服务客户端创建向导,如下图所示:



5. 选择Java类型的客户端代理。在向导中选择客户端代理类型,如下图所示:



6. 指定客户端代理所属的项目类型和名称。在向导中选择Web服务客户端项目类型和名称,如下图所示:



客户端类型这里选择Web类型,客户端项目选择前面专门创建的WebServiceClient及其所属的WebServiceClientEAR企业应用项目。Web服务客户端创建完成之后,向导会自动把WebServiceClientEAR应用发布到WID的测试服务器上,并启动测试服务器。

7. 创建调用Web服务的index.jsp页面。我们已经创建了Web服务的客户端代理,现在需要在JSP页面中使用这个代理。首先需要在WebServiceClient的WebContent下生成一个index.jsp页面,如下图所示:



8. JSP的代码分析。在这个JSP中,主要通过HelloWorldInterfaceProxy类来调用Web服务,调用流程的hello方法。HelloWorldInterfaceProxy是Web服务客户端向导生成的能够直接调用Web服务方法的代理,通过它来调用Web服务是非常方便的。主要代码片断如下:


HelloWorldInterface proxy = new HelloWorldInterfaceProxy(); 
//这个proxy是实现HelloWorldInterface这个Web服务SEI的。
String msg = request.getParameter("message");
String resp = proxy.hello(msg);

由于使用了Web客户端的代理,我们可以直接调用流程服务的业务方法。

9. 至此,通过Web服务的方式调用流程的工作已经全部做完。现在就可以在WID的测试环境中发布HelloWorldApp和WebServiceClientEAR两个应用,然后通过上述的index.jsp页面来调用HelloWorld流程。所有在本部分使用到模块的代码,请参考本文附的项目交换文件,WebServiceClient.zip。





回页首


1.4 通过BPC的应用程序接口

业务流程引擎(BPC)为应用程序访问流程提供了无状态会话BEAN,使得流程客户端可以通过fa?ade的方式使用EJB来访问流程。根据客户端访问流程方式的不同,BPC提供了两个不同的无状态会话BEAN。如果客户端程序与业务流程运行在同一个JVM中,那么客户端可以可以使用本地的无状态会话BEAN访问,com.ibm.bpe.api.LocalBusinessFlowManager。如果客户端程序与业务流程运行在不同的JVM中,那么客户端可以可以使用远程的无状态会话BEAN访问,com.ibm.bpe.api.BusinessFlowManager。

在前面的流程调用方式中,需要为HelloWorldProcess组件提供Standalone Reference或者是Export端点。在通过上述无状态会话BEAN的方式下,这些都是不需要的。下面描述如何创建一个基于BPC应用编程接口的流程客户端。

1. 删除HelloWorld模块中的Export端点。打开HelloWorld的模块编辑器,删除HelloWorldProcessExport端点。

2. 生成一个客户端Web项目。把WID切换到J2EE透视图,然后创建一个动态Web项目,名称为BPCClient,企业应用项目为BPCClientEAR。(这一步可以参考Web服务客户端项目的创建过程。)

3. 在Web项目中配置EJB引用。打开BPCClient的web.xml文件,并在Web部署描述符编辑器中切换到"引用"页面,然后添加一个本地的EJB引用,并输入相应的配置。在这个例子中,由于BPCClient应用和HelloWorld流程运行在同一个JVM中,因此我们选择LocalBusinessFlowManager这个无状态会话BEAN。引用名:ejb/LocalBusinessFlowManagerHome。选择不在工作区的EJB选项,这是因为LocalBusinessFlowManager这个EJB不在我们工作区中,而在bpe.jar包中。本地Home接口选com.ibm.bpe.api.LocalBusinessFlowManagerHome。本地接口选com.ibm.bpe.api.LocalBusinessFlowManager。具体如下图所示:



4. 在Web项目中配置EJB绑定。同样在Web部署描述符编辑器的引用页,指定WebSphere EJB的绑定信息,这里JNDI名称为com/ibm/bpe/api/BusinessFlowManangerHome。如下图所示:



5. 创建调用流程的index.jsp页面。在这部分,我们也是通过一个JSP页面来调用上述BusinessFlowManager这个无状态会话BEAN,因此需要在BPCClient的WebContent下创建一个index.jsp页面,如下图所示:



6. JSP代码分析。这个JSP是通过BPC应用程序编程接口调用流程的核心。在这个JSP中,我们首先要通过JNDI找到LocalBusinessFlowManagerHome,然后生成相应的LocalBusinessFlowManager。这部分的代码片断如下:


InitialContext ctx = new InitialContext();
LocalBusinessFlowManagerHome mgrHome =
(LocalBusinessFlowManagerHome)ctx.lookup("java:comp/env/ejb/LocalBusinessFlowManagerHome");
LocalBusinessFlowManager mgr = mgrHome.create();
	

调用流程的代码是通过LocalBusinessFlowManager的call方法。方法的简单说明如下:

public ClientObjectWrapper call(java.lang.String processTemplateName, 
ClientObjectWrapper inputMessage);

因此,我们需要构建一个代表输入参数的ClientOjbectWrapper。生成一个代表输入参数的ClientObjectWrapper有多种方式,这里采用先构建一个DataObject,然后调用ClientObjectWrapper构造方法的方式。具体代码实现如下:


ServiceManager serviceMgr = new ServiceManager();
BOFactory bofactory = (BOFactory)serviceMgr.locateService("com/ibm/websphere/bo/BOFactory");
DataObject input = bofactory.createByElement("http://HelloWorld/HelloWorldInterface", "hello");
input.setString("helloInput", msg);
ClientObjectWrapper inputWrapper = new ClientObjectWrapper(input);
	

BOFactory的createByElement根据流程的WSDL接口生成一个代表参数的一个DataObject。在生成代表输入的ClientObjectWrapper之后,调用流程就变得相对比较简单,具体代码片断如下:


ClientObjectWrapper outputWrapper = mgr.call("HelloWorldProcess", inputWrapper);
	DataObject output = (DataObject) outputWrapper.getObject();
	resp = output.getString("helloOutput");

7. 至此,通过BPC应用程序编程接口的调用流程的工作已经全部做完。现在就可以在WID的测试环境中发布HelloWorldApp和BPCClientEAR两个应用,然后通过上述的index.jsp页面来调用HelloWorld流程。所有在本部分使用到模块的代码,请参考本文附的项目交换文件,BPCClient.zip。





回页首


1.5 结束语

本文首先构建了一个"流程版"的HelloWorld,并在此基础上分别介绍了WebSphere Process Server中三种不同客户端调用流程的方式。虽然这三种方式都是常用的调用流程,但是它们使用的环境不太一样。第一种方式主要是在服务组件编程模式的环境中使用。基于Web 服务的方式相对是一种标准化的,具有良好跨平台和分布计算能力的一种调用方式。而基于BPC编程接口的方式则是一种集成最为紧密,相对耦合度也是最高的一种方式。因此,具体选用哪种方式要结合实际需求而定。





回页首


1.6 参考资料

1. SCA编程模型入门 ――这篇文章介绍了SCA的一些基本概念。

2. WebSphere Process Server和WebSphere Integration Developer的信息中心――信息中心提供了关于这两个新产品比较完整的信息,并可以查询在例子程序中使用到的具体API细节。





回页首


1.7 下载



关于作者

方国伟,IBM软件部工程师。在WebSphere家族产品有多年的工作经验。目前主要工作重点和兴趣在WebSphere应用服务器及J2EE和Web Services相关技术的应用。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款