引言
Prolifics 公司开发的 XMLink 是一种专门用于对基于 BEA Tuxedo 交易中间件技术开发的应用系统的数据、业务整合的适配器产品。该适配器全称为 XMLink Tuxedo Adapter。它可以将 J2EE 应用程序连接到基于 BEA Tuxedo 开发的服务上,特别适用于基于IBM WebSphere Application Server 开发的 EJB, Servlet 和 JSP,以及基于 WebSphere Business Integration Family 开发的相应流程、服务等。但是,XMLink 的使用比较复杂,编程难度也较大。XMLink Wrapper 合理地抽取出 XMLink 中与 Tuxedo 相关的底层操作细节,将其封装成可复用的、接口简易的组件,从而大大降低了 WebSphere Application Server 和 Tuxedo 之间应用整合的难度。
一、XMLink简介
XMLink的架构是完全符合J2C/J2EE架构规范的,它是针对Tuxedo专门实现的J2C连接器。因此可以方便的跟其它Java应用进行互联互通。
图1 XMLink体系结构示意图

XMLink提供了一个资源适配器并且支持两种情形的部署场景。J2EE资源适配器不但能够在有应用服务器(比如IBM WebSphere Application Server)的环境中运行,而且能够在独立的Java应用程序中被调用执行。就像J2C架构一样,XMLink架构也同样提供了相应的访问方式:JavaBean、Servlet、JSPs和EJB。
XMLink Tuxedo Adapter允许用户将任何已有的BEA Tuxedo应用无缝地集成到一个Java应用中,无论该应用是否部署在应用服务器上。XMLink只需要标准的Tuxedo配置就能完成相关功能。这使得用户可以方便快捷地访问Tuxedo标准层中的相关服务。
在Tuxedo中,使用IPC(Inter-Process Communication)消息队列等方式实现了在客户端和服务器端之间服务请求的传递。这些消息被封装在相应的缓冲区中。XMLink使用已有的IPC等配置方式,来跟相应的数据缓冲区交互数据,从而连接到Tuxedo的指定服务。
在这个过程中,XMLink就像其它Tuxedo客户端一样,使用ATMI (Application to Transaction Monitor Interface) 层来连接到Tuxedo。相应的,ATMI接口来控制信息交互、事务处理、数据缓冲区管理等功能。
根据XMLink在前图的J2C连接器架构中所处的位置,我们把它进一步细化,如下图所示:
图2 XMLink体系结构示意图
图2 XMLink体系结构示意图
如上图所示,XMLink可以实现以下操作:
- 1. XMLink是一个J2EE/JCX实现。通过它的Tuxedo适配器,将J2EE调用行为转换成为Tuxedo API调用行为。
- 2. XMLink的适配器层处于J2EE/JCX和Tuxedo之间。该适配器层的职责是将Java输入流转换成Tuxedo本地缓冲区的流(反之亦然),并且通过Tuxedo的链接池进行相应调用。
- 3. XML parser验证从客户端提交Java流并转换成为XML流,同时也验证反向的XML流并转换成为Java流。
XMLink提供了一个无状态会话Bean的组件,它可以读取外部的XML格式的配置文件,从而实现指定的用户业务服务调用。
二、XMLink Wrapper整体架构设计
XMLink Wrapper处于用户的DataBean和XMLink之间,一方面,它封装了XMLink的绝大部分功能,简化了用户的调用接口;另一方面,它使用统一的配置文件来管理Tuxedo以及XMLink相关的环境设置,从而当Tuxedo端或XMLink端发生变更时,客户端可以不用做任何修改也能够很好地运行。下图表示XMLink Wrapper与其他模块之间的关系。
图3 XMLink Wrapper与其它模块的联系
XMLink Wrapper包含三个部分:
- 1、Schema生成器:Schema Generator
- 2、数据转换器:Data Exchanger
- 3、XMLink功能调用包装器:XMLink Tool
它们在XMLink Wrapper中的位置如下图所示:
图4 XMLink Wrapper总体结构图
下面分别予以介绍:
Schema生成器(Schema Generator):在XMLink Wrapper中有一个Schema生成器,它能够从Tuxedo的Field Table File (*.fld文件,定义FML/FML32字段信息)生成格式定义良好的XML Schema。然后,通过利用XMLBeans,我们又能够从XML Schema文件生成FML/FML32字段信息的对象模型,这些对象模型在用户看来就是一些普通的Java Bean。整个过程如下图所示:
图5 使用Schema Generator和XMLBeans来生成FML/FML32数据对应的对象模型
数据转换器(Data Exchanger):XMLink Wrapper中包含一个数据转换器。一方面,我们在调用XMLink相关功能之前,需要使用Data Exchanger for Input将FML/FML32数据对应的对象模型转换成XMLink能够识别的数据格式(XMLink XML Call Input Data Format);另一方面,我们在得到XMLink返回的输出数据(XMLink XML Call Output Data Format)之后,需要使用Data Exchanger for Output将其转化成为用户能够读懂的FML/FML32数据对应的对象模型。整个过程的流程如下图所示:
图6 使用Data Exchanger来进行FML/FML32数据对象模型与XMLink XML Call Data之间的转换
XMLink功能调用包装器(XMLink Tool):XMLink Wrapper中包含一个XMLink功能调用包装器。该包装器能够读取XMLink配置文件中的相关信息,判断出XMLink的安装环境,然后使用该环境下对应的XMLink的接口来调用Tuxedo服务。
图7 封装两种类型的XMLink安装方式,使其在用户看来都是透明的

图4 XMLink Wrapper总体结构图
下面分别予以介绍:
Schema生成器(Schema Generator):在XMLink Wrapper中有一个Schema生成器,它能够从Tuxedo的Field Table File (*.fld文件,定义FML/FML32字段信息)生成格式定义良好的XML Schema。然后,通过利用XMLBeans,我们又能够从XML Schema文件生成FML/FML32字段信息的对象模型,这些对象模型在用户看来就是一些普通的Java Bean。整个过程如下图所示:
图5 使用Schema Generator和XMLBeans来生成FML/FML32数据对应的对象模型
数据转换器(Data Exchanger):XMLink Wrapper中包含一个数据转换器。一方面,我们在调用XMLink相关功能之前,需要使用Data Exchanger for Input将FML/FML32数据对应的对象模型转换成XMLink能够识别的数据格式(XMLink XML Call Input Data Format);另一方面,我们在得到XMLink返回的输出数据(XMLink XML Call Output Data Format)之后,需要使用Data Exchanger for Output将其转化成为用户能够读懂的FML/FML32数据对应的对象模型。整个过程的流程如下图所示:
图6 使用Data Exchanger来进行FML/FML32数据对象模型与XMLink XML Call Data之间的转换
XMLink功能调用包装器(XMLink Tool):XMLink Wrapper中包含一个XMLink功能调用包装器。该包装器能够读取XMLink配置文件中的相关信息,判断出XMLink的安装环境,然后使用该环境下对应的XMLink的接口来调用Tuxedo服务。
图7 封装两种类型的XMLink安装方式,使其在用户看来都是透明的

三、 几种XMLink 开发模式的对比
1、未封装前的XMLink的开发模式
XMLink默认的开发模式包括以下几个步骤:
1)初始化连接池
2)建立Tuxedo连接
3)建立一个和Tuxedo服务交互的实例
4)建立一个交互实例的配置属性对象
5)设置调用的Tuxedo服务名
6)设置调用方式:1-同步/0-异步
7)设置超时时间-毫秒
8)定义记录工厂--缓冲区
9)定义输入、输出参数
10)往缓冲区压入业务输入参数
11)调用Tuxedo服务,得到输出结果
12)调整输出结果的字符集格式
13)关闭与Tuxedo服务交互的实例
14)关闭Tuxedo连接
其实例代码如下:
2、经过第一级封装后的XMLink的开发模式(使用Schema Generator 和XMLink Tool之后的开发模式)
经过第一级封装以后,我们把Tuxedo服务调用相关的配置信息放到配置文件中,而客户端仅仅需要以下几行代码就能完成上面代码的类似功能:
1、未封装前的XMLink的开发模式
XMLink默认的开发模式包括以下几个步骤:
1)初始化连接池
2)建立Tuxedo连接
3)建立一个和Tuxedo服务交互的实例
4)建立一个交互实例的配置属性对象
5)设置调用的Tuxedo服务名
6)设置调用方式:1-同步/0-异步
7)设置超时时间-毫秒
8)定义记录工厂--缓冲区
9)定义输入、输出参数
10)往缓冲区压入业务输入参数
11)调用Tuxedo服务,得到输出结果
12)调整输出结果的字符集格式
13)关闭与Tuxedo服务交互的实例
14)关闭Tuxedo连接
其实例代码如下:
|
代码:/**初始化连接池**/ Context initctx = new InitialContext(); ConnectionFactory connectionFactory = (ConnectionFactory) initctx.lookup("jca/xmlink"); /**建立连接**/ Connection conn = connectionFactory.getConnection(); /**建立一个和tuxedo服务交互的实例**/ Interaction interaction = conn.createInteraction(); /**建立一个交互实例的配置属性对象**/ TuxInteractionSpec tux1 = new TuxInteractionSpec(); /**设置调用的tuxedo服务名**/ tux1.setFunctionName("GETDETAIL"); /**设置调用方式:1-同步/0-异步**/ tux1.setInteractionVerb(1); /**设置超时时间-毫秒**/ tux1.setExecutionTimeout(300); /**定义记录工厂--缓冲区**/ RecordFactoryImpl rdf = (RecordFactoryImpl) connectionFactory.getRecordFactory(); /**定义输入、输出参数**/ /**定义传输类型为FML32类型**/ FML32Record rc = (FML32Record) rdf.createMappedRecord("FML32"); /**往缓冲区压入业务输入参数*/ rc.addIn("COUNT",count); rc.addIn("SATIME",satime); /**获取输出结果*/ System.out.println("step 1......"); FML32Record ret = (FML32Record) interaction.execute(tux1, rc); System.out.println("step 2......"); /**中文字符集转换*/ ret.setEncoding("GB2312"); ret.processOutput(0); System.out.println("返回参数个数为:" + ret.size()); System.out.println("用户姓名:" + ret.getField("USRNAME").get(0)); System.out.println("用户卡号:" + ret.getField("COUNT").get(0)); System.out.println("用户存款记录:"); /*取得用户所有存款记录*/ Iterator it = ret.getField("SAID").listIterator(); Iterator it1 = ret.getField("SAADDR").listIterator(); Iterator it2 = ret.getField("SATIME").listIterator(); List all=new ArrayList(); while(it.hasNext()) { Sale use=new Sale(); use.setSaid((String)(it.next())); use.setSaaddr((String)(it1.next())); use.setSatime((String)(it2.next())); all.add(use); } interaction.close(); conn.close(); |
2、经过第一级封装后的XMLink的开发模式(使用Schema Generator 和XMLink Tool之后的开发模式)
经过第一级封装以后,我们把Tuxedo服务调用相关的配置信息放到配置文件中,而客户端仅仅需要以下几行代码就能完成上面代码的类似功能:
|
代码: /**指定调用的Tuxedo服务名:GETDETAIL*/ TranInDataBean ccx = new TranInDataBean("GETDETAIL"); /**压入输入参数:COUNT,1*/ ccx.setField("COUNT", "1"); /**压入输入参数:SATIME,2001/03/19*/ ccx.setField("SATIME", "2001/03/19"); /*调用Tuxedo服务,得到服务结果*/ TranOutDataBean ut = dd.callSyncService(ccx); /*从服务结果读取所需数据*/ List flds=out.getFields(); for (int i = 0; i < flds.size(); i++) { CommonField cf=(CommonField)flds.get(i); String fldName = cf.getFldName(); String fldValue =cf.getFldValue(); System.out.println( "fldName:" + fldName + "\t" + "fldValue:" + fldValue); } |
我们定义的配置文件callprops.properties格式如下:
|
代码:#calltype:0表示容器环境,无须配置其他属性;1表示非容器环境,需要配置其他属性 calltype=1 #calltype=0时需要配置的其他属性如下: namecontxtfac=com.ibm.websphere.naming.WsnInitialContextFactory contxturl=iiop://localhost:2809 xmlinkjndi=jca/xmlink #calltype=1时需要配置的其他属性如下: WSNADDR=//192.168.102.1:7898 TUXCONFIG=D:\\simpappFML\\tuxconfig FLDTBLDIR= FLDTBLDIR32=D:\\simpappFML FIELDTBLS= FIELDTBLS32=user.fld |
3、经过第二级封装后的XMLink的开发模式(使用Schema Generator ,XMLink Tool和Data Exchanger之后的开发模式)
第二级封装是在第一级封装的基础上再加上用户数据转换器Data Exchanger。Data Exchanger允许用户可以以更加直观的方式处理将要压入FML/FML32缓冲区的数据以及将要从FML/FML32缓冲区读出的数据。其使用效果图如下:
使用第二级封装后,XMLink的编程模式如下:
|
代码:OBJLISTDocument d = OBJLISTDocument.Factory.newInstance(); OBJLISTDocument.OBJLIST bj = od.addNewOBJLIST(); /*设定Tuxedo服务名*/ obj.setService("GETDETAIL"); /*增加新的COUNT字段值*/ Fldtype ft = obj.addNewCOUNT(); ft.setStringValue("2"); /*增加新的SATIME字段值*/ ft = obj.addNewSATIME(); ft.setStringValue("2001/03/19"); /*将用户可以识别的DataBean转化为Tuxedo可以识别的Bean*/ TranInDataBean ccx = AutoFormat.xmlTransIn(od); /*调用Tuxedo服务*/ String input = ccx.getDocumentString(); String utput = CallTuxService.getXmlinkService(input); /*从Tuxedo服务结果抽取自己所需的数据,这里是USRNAME*/ Document doc = AutoFormat.xmlTransOut(output); XmlOptions xo = new XmlOptions(); Map ns = new HashMap(); ns.put("", "http://xmlbeans.lan.org/myuser"); xo.setLoadSubstituteNamespaces(ns); OBJLISTDocument obj1 = OBJLISTDocument.Factory.parse(doc, xo); System.out.println(obj1.getOBJLIST().getUSRNAME().getStringValue()); |
如何在J2EE架构下整合Tuxedo应用是一个很值得关注的话题。XMLink是一个遵循J2C标准的、性能良好Tuxedo适配器。然而它配置复杂,封装层次太低,因此我们有必要开发自己的包装器来对其进行封装。使用XMLink Wrapper之后,我们既简化了用户接口,又实现了用户应用程序与XMLink的松散耦合,从而达到了运行时可变更配置的目的,提升了系统的灵活性。

