本文主要向读者介绍了在IBM WebSphere Integration Developer中使用SCA的Web服务绑定在外部Web Service和标准SCA组件之间传递SOAP Header的基本配置方法和注意事项。本文所解决的技术问题主要应用在使用企业服务总线的SOA业务场景中,尤其是使用了IBM的WESB服务器对标准Web Service请求、应答做基于SOAP Header的中介流转的这一技术环节中。
1. 引言
随着SCA (Service Component Architecture)规范的广泛推广, SCA编程模型和IBM 支持SCA的产品系列如WebSphere Process Service(WPS),IBM WebSphere Enterprise Service Bus(WESB)越来越多的应用于实际的大型IT生产环境和业务集成中。SCA组件对业务数据进行操作,并使用统一的数据格式——SDO(Service Data Object)来表达业务数据,并在SCA组件之间进行传递。
但是在许多实际项目运营过程中,搭建单纯的符合SCA规范的IT架构一般难以实现,基于SOA可重用理念,很多情况下需要实现SCA组件和外部非SCA模块之间的集成,而这些模块往往是基于已有的J2EE平台实现的EJB、JMS终端或者能够接受SOAP消息的Web Service。IBM WebSphere Integration Developer(WID)在集成图(Assembly Diagram)上提供了SCA导入组件来引用外部的各种类型的服务组件,以及SCA导出组件来将内部的SCA组件暴露为可以和外部多种模块交互的服务接口,而所有这些交互类型都通过导入、导出组件上的绑定(Binding)类型来指定。截止到2007年初IBM发布的WID V6.0.2,用户可以指定的绑定类型包括:
SCA 绑定
Web服务绑定
无状态Session Bean绑定
消息绑定,包括JMS 绑定,MQ 绑定,MQ JMS 绑定
本文侧重于SCA导入、导出组件中对Web Service Binding的应用。该绑定能够在标准SOAP消息和SDO之间进行格式转换。SDO在进入SCA世界后被包装了相关的SCA协议头而成为在SCA组件之间传递的SMO(Service Message Object)。理论上来讲,SMO应该有完整的元数据格式以映射到SOAP的Schema,其中除了用于传递功能性调用的SOAP Body外,用于携带QoS以及非功能需求的SOAP Header也是重要的组成部分。WID的实现也确实做到了这一点,但是笔者在组内的项目中经历了一番挫折才认识到WPS运行时环境对实现SOAP Header在SOAP和SMO之间传递的特殊配置要求。本文就是想共享这方面的经验,希望无论是从事实际项目开发的软件工程师,还是在实验室中从事相关课题技术探索的研究人员能够从中获益,节省宝贵的研发时间。
2. 一个典型场景
笔者通过对所从事的项目进行技术抽象,得出以下的典型场景:
图1 一个典型的使用SCA中间模块基于SOAP Header进行服务选取的场景
如图1所示,假设一个Web服务请求客户端需要请求两个Web服务:Echo Web服务1和Echo Web 服务2。这两个Web服务虽然都提供了回应请求字符串的功能,但是他们的接口描述不同。该场景希望对服务请求进行中介,并选取了SCA中介模块来实现服务请求的路由、请求消息转换,面向服务请求客户端屏蔽中介细节,提供统一的服务调用界面。并且,服务请求客户端可以通过在Web服务请求的SOAP Header中嵌入路由信息,来标明每次请求所希望调用的远程Web服务。
该场景虽然只是一个技术抽象,但是可以被赋予多种IT内涵和业务语义,比较典型的有:
基于WS-Policy服务非功能属性的服务匹配和选取。在这种情况下,每个被选取的Web服务都通过WSDL绑定声明了不同的WS-Policy断言。只有客户端SOAP请求中所携带的非功能性需求与当前服务的WS-Policy断言能力相符,该服务才可以被匹配从而进行调用。而一般情况下这种动态服务选取会将备选的Web服务元数据(包括WSDL,XSD以及WS-Policy)发布到一个元数据注册中心(目前IBM推荐的主流产品是WebSphere Registry & Repository),由请求中介在运行时进行查询匹配(WID V6.0.2已经有中介组件支持对WSRR的查询)。已有的基于WS-Policy框架的服务策略规范(如WS-RM, WS-Security等)都将每次服务调用中的非功能需求嵌在SOAP Header中,在这种情况下,服务中介必须实现基于SOAP Header的服务匹配;WebSphere Business Services Fabric(WBSF)是IBM新近推出的支持业务领域服务及服务策略建模、开发和运行时支持的新款产品。该产品已经在保险业得到广泛应用,并且成为IBM在SOA监管(Governance)方向的核心产品之一。基于该产品开发的业务策略也和每个备选的Web服务关联,并要求服务请求的SOAP Header中嵌入相应的与业务相关的选择条件,从而由WSBF做运行时策略使能,完成服务的选取。WSBF在未来也将架构于WPS/WESB之上,因而也面临本文所提及的问题。
本文的目的不是介入以上对相关IBM产品和Web服务规范应用的讨论,因而采用图1的简单的技术抽象来说明如何解决使用SCA Web服务绑定来传递SOAP Header这一问题。以下在第3节中将给出通常情况下使用WID来实现满足图1要求的SCA中介模块的基本做法,并说明问题所在;在第4节中将对第3节的配置进行修改,从而解决问题。
3. 初配SCA 中介模块——SOAP Header丢失
3.1 安装供选择的Web服务
从文章的“下载”一节中下载得到两个Echo Web服务的EAR文件EchoEJB1EAR.ear和EchoEJB2EAR.ear,并依照以下步骤安装并启动两个Echo Web服务:
启动WID后,切换到“J2EE” 视图,在Servers子窗口中选择“WebSphere ESB Server V6.0”并启动该服务器;
选择“File->Import->EAR file”,并导入以上两个Echo Web服务的EAR文件到当前的工作台中;
在Servers子窗口中右键点击“WebSphere ESB Server V6.0”,选择“Add and remove projects…”,并在弹出的窗口中选择添加“EchoEJB1EAR”和“EchoEJB2EAR”到WESB中。
至此,两个Echo Web服务已经成功完成了在WESB服务器中的安装和启动。
3.2 创建并配置SCA中介模块
接下来需要创建一个SCA中介模块来完成服务路由。依照以下步骤进行:
选择“File->New->Projects…->Mediation Module”,并在弹出的对话框中给定生成的中介模块名称为“EchoServiceRouter”。点击“Finish”;
拷贝以上导入的两个Web服务的WSDL文件到该中介模块工程中。具体的做法是:在“J2EE” 视图的“Project Explorer”子窗口中,选择“EJB Projects->EchoEJB1->ejbModule->META-INFO->wsdl->EchoSvr1.wsdl”,右键点击,选择Copy。切换到“Business Integration”视图,在“Business Integration”子窗口中选择“EchoServiceRouter->Interfaces”,右键点击并选择Paste。Echo Web服务1的WSDL被复制完毕。用同样的办法拷贝得到Echo Web服务2的WSDL;
在“EchoServiceRouter”工程下双击“Assembly Diagram”,打开该中介模块的集成图。重命名缺省生成的中介组件为“EchoServiceRouter”。右键点击该组件,选择“Add->Interface->EchoSvr1”。这样就把该中介模块对外的服务接口设为Echo Web服务1的接口类型。由于Echo Web服务2的接口类型与之不同,需要在编辑中介流程时对请求消息做消息格式转换;
在集成图空白处点击右键,选择“Add->Import”,重命名生成的导入组件为“EchoService1Import”。用与上一步相同的办法设置该导入组件的接口为EchoSvr1。右键点击该导入组件,选择“Generate Binding…->Web Service Binding”,在弹出的窗口中选择“Use an existing web service port”,并通过“Browse”按钮选择EchoSvr1 Web服务端口。设置完毕后,选中“EchoService1Import”组件,它的Properties子窗口如图2所示:
图2 “EchoService1Import”导入组件的绑定配置
用与上相同的方法添加导入组件“EchoService2Import”,设置它的接口类型和Web服务绑定为EchoSvr2。在集成图中选择Wire工具,分别将“EchoServiceRouter”组件连接到“EchoService1Import”和“EchoService2Import”;
右键点击“EchoServiceRouter”组件,选择“Generate Export…->Web Service Binding”,在弹出的窗口中选择“soap/http”,点击OK。重命名缺省生成的到处组件为“EchoServiceRouterExport”。选中“EchoServiceRouterExport”组件,它的Properties子窗口如图3所示:
图3 “EchoServiceRouterExport”导出组件的绑定配置
因为该中介模块要部署在服务端口号为9081的WESB上,所以将以上缺省生成的Web服务地址端口由9080改为9081,并保存。
在集成图空白处点击右键,选择“Arrange Contents Automatically”,并保存集成图。至此,“EchoServiceRouter”中介模块的组件集成如下图所示:
图4 “EchoServiceRouter”中介模块的集成图设置
3.3 在SCA中介模块中实现中介流
SCA中介模块中,中介组件的实现为中介流。为第2节所述的场景实现中介流的步骤如下所示:
在集成图中双击“EchoServiceRouter”组件,在弹出的对话框中选择Yes;接着在弹出的“Generate Implementation”对话框中选择OK,中介流编辑器被打开。对应于集成图中的导入、导出组件的三个操作在编辑器的上部被显示出来;
分别将左部EchoSvr1接口中的echo操作和右部EchoSvr1Partner接口中echo操作以及EchoSvr2Partner接口中的echoMessage操作连接起来;
现在可以在中介流编辑器的下部编辑中介流的具体行为了。在请求中介流的选择卡下,先拖拽一个“Message Filter”中介单元(Mediation Primitive)到编辑器中,它用于依据传入到中介模块的消息内容进行消息路由;再拖拽一个“XSL Transformation”中介单元到编辑器中,它用于转换从中介模块输入的消息格式到Echo Web服务2可接受的格式。最后拖拽两个“Message Logger”中介单元到编辑器中,它们分别用于将送往Echo Web服务1和Echo Web服务2的SMO以XML格式写入数据库,作为日志;
右键点击“Message Filter”中介单元,选择“Add Output Terminal”,接受弹出对话框的缺省设置;
如下图所示将以上的中介单元连接起来形成请求中介流:
图5 “EchoServiceRouter”中介模块的请求中介流
其中“XSL Transformation”中介单元有个红叉,主要是因为还没有对它的属性进行配置,在下面的步骤中我们将完成这个功能。注意,以上步骤生成的“Message Filter”中介单元新的输出口match1需要和“XSL Transformation”中介单元连接起来,而“Message Filter”原有的输出口default和“MessageLogger1”中介单元连接起来。
选中“Message Filter”中介单元,在Properties子窗口红选择detail项,在Filters一节点击Add按钮。在弹出的“Add/Edit”对话框中为该中介单元的match1输出口定义一个过滤条件,结果如下图所示:
图6 “Message Filter”中介单元在请求中介流中的过滤条件设置
该过滤条件“headers/SOAPHeader[1]/name[self::node()=”routerCriterion”] and /headers/SOAPHeader[1]/nameSpace[self::node()=”http://cn.ibm.com/example“] and /headers/SOAPHeader[1]/value/routerCriterion[self::node()=”GOLD”]”表明当传入的消息满足的第一个SOAP Header项的名称为“routerCriterion”,值为“GOLD”时,消息由match1输出口流出;
选中“XSL Transformation”中介单元,在Properties子窗口红选择detail项,点击“New…”按钮。在弹出的“New XSLT Mapping”对话框中选择“Message Root”为“/”,并点击“Finish”以打开消息映射编辑器。如下图对请求消息格式进行映射:
图7 “XSL Transformation”中介单元在请求中介流中的消息映射
保存并关闭该映射文件;
分别选中两个“Message Logger”中介单元,在Properties子窗口红选择detail项,选择“Root”为“/”。在中介流编辑器中进行保存,这样就完成了整个请求中介流的编辑(现在上面的红叉将会消失);
在中介流编辑器下部的响应中介流选择页面上,用类似的方法如下编辑响应中介流:
图8 “EchoServiceRouter”中介模块的响应中介流
其中“XSL Transformation”中介单元的消息映射如下所示:
图9 “XSL Transformation”中介单元在响应中介流中的消息映射
这样我们就完成了整个中介流的设定。回到集成图,点击保存,该SCA中介模块被正确编译。
3.4 SCA中介模块的部署
在“Servers”子窗口右键点击“WebSphere ESB Server V6.0”,选择“Add and remove projects…”,并在弹出的窗口中选择添加“EchoServiceRouterApp”到WESB中。点击“Finish”后,就完成了在上一节开发的SCA中介模块在WESB服务器的部署。
3.5 安装并部署服务请求客户端
从文章的“下载”一节中下载得到服务请求客户端的WAR文件EchoSvrClientEAR.ear,并依照以下步骤安装到当前的工作台:
切换到“J2EE” 视图,选择“File->Import->EAR file”,并导入下载得到的服务请求客户端到当前的工作台中;
在Servers子窗口中右键点击“WebSphere ESB Server V6.0”,选择“Add and remove projects…”,并在弹出的窗口中选择添加“EchoSvrClientEAR”到WESB中。
至此,该服务请求客户端已经部署到了WESB服务器中。
在开始运行测试之前,再看一下以上服务请求客户端的实现的关键之处。除了一个JSP文件用于生成客户端测试界面,和发起对SCA中介模块导出的Web服务的请求调用外,该JSP引用了一个Java Bean,用于构造客户端的SOAP消息,并发到SCA中介模块所导出的Web服务地址上。以下给出了关键代码片断,完整的代码实现在动态网页工程EchoSvrClient中的com.ibm.example.bean.EchoBean.java中。
列表1 客户端的关键代码片段
public String echo(String msg) throws Exception {
…
SOAPMessage message = mf.createMessage();
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope env = soapPart.getEnvelope();
//构造SOAP Body
SOAPBody body = env.getBody();
Name name = env.createName(“echo”, “q0″, ”http://ejbs”);
SOAPBodyElement bodyElem = body.addBodyElement (name);
name = env.createName(“message”);
SOAPElement soapElem = bodyElem.addChildElement (name);
soapElem.addTextNode(msg);
//构造SOAP Header
SOAPHeader header = env.getHeader();
name = env.createName(“routerCriterion”, “exp”,
“http://cn.ibm.com/example“);
SOAPHeaderElement headerElem = header.addHeaderElement(name);
headerElem.addTextNode(“GOLD”);
message.saveChanges();
…
}
从以上片断可以看出,该除了在SOAP消息中添加基本的消息体用于表达请求的操作和参数外,在SOAP Header中添加了一个名为“routerCriterion”,值为“GOLD”的Header项,这与SCA中介模块请求中介流中的消息过滤条件一致。
3.6 运行测试
依照以下步骤运行该实例:
打开浏览器,输入http://localhost:9081/EchoSvrClient/request.jsp,并回车;
在显示的网页中的文本框中输入要被Echo的消息内容,例如“This is just a test!”,点击“Invoke”按钮;
Web服务成功返回,网上上显示被Echo的消息为“[Echo Service2] This is just a test!”。
问题出来了,这与原先设想的由Echo Web服务1来Echo这条消息出现了误差。根据在SCA中介模块中的配置,从客户端发出的SOAP消息应该具有相应的SOAP Header,并且满足请求中介流中消息过滤中介组件的match1输出口的条件,这样该消息应该被路由到对应于Echo Web服务1的导入组件。为什么会这样?
好在通过以上的中介流设置已经对所有的中介路径都做了消息日志,因此可以到WESB对应的消息日志数据库中去查看一下刚刚在中介组件中传递的SMO消息内容,结果是:
列表2 错误配置下中介组件在日志中所捕获的SMO
>http://www.ibm.com/websphere/sibx/smo/v6.0.1”
>
很明显,消息路由的错误是因为SOAP Header根本没有进入SCA中介模块,并得到SMO的传输。难道这是WESB的一个bug吗?其实不是,原因在于先前在SCA中介模块中的配置有问题。
4. 重配SCA中介模块——SOAP Header被传递
原来,WESB的运行时环境在经过Web服务绑定时需要将由SOAP格式表达的消息转换为DataObject类型的Java对象。在这个转换的过程中,WESB需要预先装载SOAP消息中各个XML元素的XML Schema类型定义,不妨称之为SOAP消息的内容数据。装载完毕后,每当一个SOAP实例到来,在转换的过程中,首先从已经装载的元数据列表中查找对应的元数据项,并根据这个元数据项,使用XSD到DataObject的映射规则,生成相应的DataObject对象容器,而后才会将SOAP消息中的具体数据填入DataObject。如果一旦没有找到对应的XSD元数据,该项转换就会被忽略。
那么为什么从上面的SMO内容看SOAP Body部分被转换了而SOAP Header则没有呢?很明显,我们在SCA中介模块的配置过程中已经指定了所有涉及的WSDL文件,这些文件描述了SOAP Body中可能会用到的XML元素的XSD(直接在WSDL文件中的Schema标签下定义,或者通过导入XSD文件给出),它们其实也就是服务调用的请求、响应数据格式。但是我们并没有给出SOAP Header部分的XSD定义,当然WESB运行时环境也就不认识它了。
知道了原因,解决的办法也很简单:
在WID的工作台中切换到“Business Integration”视图。在“Business Integration”子窗口中选择“EchoServiceRouter->Data Types”。点击右键,选择”New->Business Object”;
在弹出的“New Business Object”对话框中去掉“Namespace”右端的“Default”复选框选择,并输入“http://cn.ibm.com/example”;在“Name”栏输入“routerCriterion”,点击Finish。关闭打开业务数据编辑器,在“Data Types”下选中刚刚创建的“routerCriterion”,点击右键,选择“Open With->Text Editor”。如下修改“routerCriterion”的XSD定义:
列表3 为要传递的SOAP Header制定的XSD
targetNamespace=”http://cn.ibm.com/example“>
保存后,在“Business Integration”子窗口中选择“EchoServiceRouter->Web Service Ports->EchoSvr1”,点击右键,选择“Open With->Text Editor”。在打开的编辑器中,对该WSDL文件的Schema元素做如下修改:
列表4 在中介模块的WSDL文档中添加的对SOAP Header XSD的引用
>http://www.ibm.com/websphere/sibx/smo/v6.0.1”
http://cn.ibm.com/example”>http://cn.ibm.com/example“>
可以看到,这一次由于指定了SOAP Header项的XSD,WESB运行时环境能够生成相应的DataObject对象容器,SOAP Header通过Web服务绑定得到了传输,在中介模块的请求中介流中,服务过滤中介单元也能正确的完成消息的路由。
5. 结束语
本文通过对一个具体的基于SCA中介模块根据SOAP Header做服务路由的场景的技术分析,说明了在WID中开发类似应用时所需要特别注意的配置,从而也阐明了WPS或者WESB运行时环境在Web服务绑定上完成SOAP消息到DataObject对象转换的基本原理。
本文对SOAP Header通过SCA Web服务绑定进行传递这一技术细节的探讨在于旨在抛砖引玉,希望所有在使用WID、WPS和WESB做实际项目开发和原型设计的软件工程师们能从中获益,提出在SCA编程模式下更新、更有实用价值的模式。如果本文有幸帮助一些技术人员解决了他们的技术难题,那是我们最大的收获。
作者简介
刘昕鹏,IBM软件工程师,工作在IBM中国软件开发实验室 – SOA Design Center,从事SOA Policy及SOA Governance相关的工作,对J2EE、SOA、MDA/MDD、AOP、语义网等相关技术有浓厚兴趣。作者目前主要负责SOA Policy Toolkits项目的设计与开发工作。
薛亮,IBM资深软件工程师,工作在IBM中国软件开发实验室 – SOA Design Center,从事SOA Policy及SOA Governance相关的工作,对J2EE、SOA、Registry and Repository等相关技术有浓厚兴趣。作者目前主要从事Registry and Repository Federation项目的设计与开发工作。
高希斌,现为中科院研究生院硕士研究生 ,2006.7~2006.12期间在IBM中国软件开发实验室 SOA Design Center 实习,期间从事SOA Policy相关的工作。作者目前主要从事网格方面的开发。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
SAP收购CallidusCloud 与Salesforce竞争
一直被称为后台办公巨头的SAP现在似乎也想在前台办公大展拳脚。 最新的迹象是SAP收购CallidusClou […]
-
API设计如龙生九子 各不相同
IT咨询管理公司CA Technologies对API产业做了个问卷调查,问卷内容涉及API设计风格以及管理部署的新动向。调查结果表明,JSON与XML可谓两分天下。
-
API设计:如何正确开发应用程序接口
在交互组件化软件的世界里,没有比让组件之间以及组件与移动设备和浏览器之间进行连接的应用程序接口(API)更重要的东西了。
-
IBM投资12亿美元用于扩大其全球云的部署
1月17日,IBM宣布计划投入超过12亿美元大规模拓展其全球云的部署。这项投资包括建立旨在为客户带来更大灵活性和透明度的数据中心网络。