一.概述 3
二.Web Service和Service Oriented Architecture(SOA) 3
三.Tuxedo Service 4
四.将Tuxedo Service发布为Web Service的架构和实施步骤 5
五.给相关项目所带来的益处 15
六.参考文献 16
一.概述
BEA公司的WebLogic Workshop集成开发环境可将其交易中间件Tuxedo后台运行的Service暴露成Web Service,供其它系统调用。
本文对Tuxedo Service和Web Service的理论和架构进行了阐述,并通过两个实例介绍了将Tuxedo Service发布为Web Service的架构和实施步骤,以及总结了这样会给相关项目所带来的益处。
二.Web Service和Service Oriented Architecture(SOA)
面向服务的体系结构(Service Oriented Architecture)是设计和构建松散耦合的软件解决方案的方法,这个解决方案能够以程序化的可访问的软件服务的形式公开业务功能,以使其他应用程序可以通过已发布的和可发现的接口来使用这些服务。通过应用 SOA,一个企业可以使用一组分布式服务来构成并组织应用程序;这样,他们就能通过重用他们自己的资产和他们伙伴的业务功能来构造新的应用程序和修改现有的应用程序参考。
(1)下面我们来看一下SOA的组成:
图1
从图1可以看出,SOA结构中共有三种角色:
① Service provider:发布自己的服务,并且对使用自身服务的请求进行响应
② Service broker:注册已经发布的Service provider,对其进行分类,并提供搜索服务
③ Service requester:利用Service broker查找所需的服务,然后使用该服务
SOA体系结构中的组件必须具有上述一种或多种角色。
在这些角色之间使用了三种操作:
① publish操作:使Service provider可以向Service broker注册自己的功能及访问接口
② find操作:使Service requester可以通过Service broker查找特定种类的服务
③ bind操作:使Service requester能够真正使用Service provider
为支持结构中的三种操作(publish、find和bind),SOA需要对服务进行一定的描述,这种服务描述(Service Description)应具有下面几个重要特点:首先,它要声明Service provider的语义特征。Service broker使用语义特征将Service provider进行分类,以帮助具体服务的查找。Service requester根据语义特征来匹配那些满足要求的Service provider。(因此,语义特征中重要的一点就是对Service provider的分类。)其次,服务描述应该声明接口特征,以访问特定的服务。最后,服务描述还应声明各种非功能特征,如安全要求,事务要求,使用Service provider的费用等等。接口特征和非功能特征也可以用来帮助Service requester对Service provider的查找。
注意,服务描述和服务实现是分离的,这使得Service requester可以在Service provider的一个具体实现(implementation)正处于开发阶段、部署阶段或完成(execution)阶段时,对其(具体实现)进行绑定。
(2)Web Service代表了SOA的一种实现(但并不能认为所有的SOA应用程序都是Web Service)。另外,因为SOA中的组件相互之间必须能够进行交互,才能进行上述三种操作,所以Web Services的实现使用了标准的技术,包括服务描述(UDDI, WSDL)、通讯协议(HTTP, SOAP)以及数据格式(XML)等。这样一来,开发者就可以开发出平台独立、编程语言独立的Web Services,从而能够充分利用现有的软硬件资源和人力资源。
我们将Web Service定义为:通过SOAP在Web上提供的软件服务,使用WSDL文件进行说明,并通过UDDI进行注册(3)。SOAP/WSDL/UDDI等协议皆以XML为数据格式。图2展示了这几个组件之间的交互关系:

图2
SOAP
即简单对象访问协议(Simple Object Access Protocol),它是用于交换XML编码信息的轻量级协议。它有三个主要方面:XML-envelope为描述信息内容和如何处理内容定义了框架;将程序对象编码成为XML对象的规则;执行远程过程调用(RPC)的约定。
WSDL
WSDL是用来描述网络(network)服务或终端(endpoint)的一种XML语言,它用于定义Web Services以及如何调用它们(描述Web服务的属性,例如它做什么,它位于哪里和怎样调用它)。WSDL文档可用于动态发布Web Services、查找已发布的Web Services以及绑定Web Services。
UDDI
即Universal Description, Discovery and Integration。它提供了在Web上描述并发现商业服务的框架。UDDI通过服务注册,以及使用SOAP访问这些注册信息的约定来实现上述目标。(2)
有关更详细的Web Service的技术内容市面上有很多,在此不再赘述,有兴趣的读者可自行查阅。
三.Tuxedo Service
一个Tuxedo Service是一个可供客户调用的一个Service函数。
Tuxedo Service函数具有下列3特性:
1) 一个Service是一个C函数,用于完成一项业务任务。
2) 一个Service函数有一个逻辑名,客户程序或其他Service程序通过这个逻辑名访问此Service。
3) 一个Service函数具有清晰的输入输出定义。
从客户程序的观点来看,这三个特性定义了一个协议,包括:
1) Service名字
2) Service要求的输入参数
3) 对那些输入的特定处理
4) 输出值或错误列表,将作为处理结果返回给客户程序。(4)
一个Tuxedo 应用可以分成3部分:
1) 发布交易请求的客户端
2) 运行响应请求交易的服务
3) 描述应用机器和服务信息的配置文件
其交互关系如图3所示:

图3
有关更详细的Tuxedo的技术内容在此不再赘述,有兴趣的读者可到BEA的相关主页http://e-docs.bea.com/tuxedo/tux81/index.htm上查阅。
这里所要提上一笔的是Tuxedo Service实际上从较宽泛的意义上来说也是SOA的一种实现:
1) Tuxedo Server是Tuxedo Service的provider
2) Tuxedo Client是Tuxedo Service的requester
3) Tuxedo的Bulletin Board是Tuxedo Service的broker
唯一有可能不符合SOA条件的理由是Tuxedo Service的协议并非一种流行的标准协议。
四.将Tuxedo Service发布为Web Service的架构和实施步骤
BEA公司的WebLogic Workshop(WebLogic Platform中的一部份)可将Tuxedo的Service暴露成Web Service。
以下通过2个实例介绍了如何通过WebLogic Workshop 7.0将Tuxedo Service发布为Web Service。这两个实例分别代表了用WebLogic Workshop 7.0将Tuxedo Service发布为Web Service的2种架构。
环境说明:2个实例都是在WebLogic Platform 7.0.1.0和Tuxedo 8.1的环境下实施的。
架构1:通过WebLogic Tuxedo Connector将Tuxedo Service发布为Web Service
此架构利用了WebLogic Server的Web Service Container,让WebLogic Server通过WTC模拟Tuxedo TDomain和Tuxedo通信,从而将Tuxedo Service发布为Web Service,如图4所示:

图4
在本实例中,具体的Server端流程链如下:
Java Web Service <-->stateless session bean <-->WTC ?à Tuxedo Service
以下是实施步骤:
(1) Tuxedo端的配置和编码
(i) ubbconfig的配置:
*RESOURCES
IPCKEY 50000
DOMAINID Tuxedo
MASTER SITE1
MODEL SHM
*MACHINES
"FIGURE-NOTEBOOK" LMID=SITE1
TUXDIR = "C:\bea\tuxedo8.1"
APPDIR = "D:\TuxedoDomain"
TUXCONFIG = "D:\TuxedoDomain\tuxconfig"
*GROUPS
GROUP1 LMID=SITE1 GRPNO=1
GROUP2 LMID=SITE1 GRPNO=2
*SERVERS
simpserv SRVGRP=GROUP1 SRVID=1
DMADM SRVGRP=GROUP2 SRVID=10
GWADM SRVGRP=GROUP2 SRVID=20
GWTDOMAIN SRVGRP=GROUP2 SRVID=30
*SERVICES
TOUPPER
(ii) dmconfig的配置:
*DM_LOCAL_DOMAINS
Tuxedo GWGRP=GROUP2 TYPE=TDOMAIN DOMAINID="Tuxedo"
*DM_REMOTE_DOMAINS
WebLogic TYPE=TDOMAIN DOMAINID="WebLogic"
*DM_TDOMAIN
Tuxedo NWADDR="//127.0.0.1:12345"
WebLogic NWADDR="//127.0.0.1:12346"
*DM_LOCAL_SERVICES
TOUPPER LDOM=Tuxedo
(iii) Tuxedo Server端代码:
#include
#include
#include "atmi.h"
void TOUPPER (TPSVCINFO *rqst)
{
int i;
for(i = 0; i < rqst->len-1; i++)
rqst->data[i] = toupper(rqst->data[i]);
tpreturn(TPSUCCESS, 0, rqst->data, 0L, 0);
}
此实例的Tuxedo Service是经典的TOUPPER,即将传入的字符串转换为大写再返回。并且TOUPPER Service暴露成TDomain的Service。
tmboot Tuxedo实例。
(2) 创建WebLogic Domain
点击"开始菜单à程序àBEA WebLogic Platform 7.0"中的 "Domain Configuration Wizard",启动WebLogic Platform 7.0.2.0的Domain Configuration Wizard,Domain Type选择WebLogic Workshop。其他选项选择默认值即可,这里我们将创建的Domain起名为TuxedoWebService。可以看到,Domain创建好之后,会在user_projects目录下生成一个TuxedoWebService目录,其中包含了TuxedoWebService域所含的所有文件。

图5
(3) 配置WTC
运行TuxedoWebService域下的startWebLogic.cmd脚本,从而启动相应的WebLogic Server,如图6:

图6
可以看到在WebLogic Server进程启动时,会同时启动WebLogic Workshop Debugger进程,这主要是因为启动WebLogic Server时设置了debugFlag=true。
通过http://localhost:7001/console登陆WebLogic Server的Web Console。在Service --> WebLogic Tuxedo Connector中点击 "Configure a new WTCServer...",如图7所示:
图7
所配置的WTCServer的内容如下:
Local WLS Domains à
Access Point: WebLogic
Access Point Id: WebLogic
Network Address: //127.0.0.1:12346
Remote Tuxedo Domains à
Access Point: Tuxedo
Access Point Id: Tuxedo
Local Access Point: WebLogic
Network Address: //127.0.0.1:12345
Imported Services à
Resource Name: TOUPPER
Local Access Point: WebLogic
Remote Access Point List: Tuxedo
(4) 编写和发布调用WTC接口的stateless session bean(ToupperSLBean)
(i) ToupperSLBean代码
package ToupperSLBean;
import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import weblogic.wtc.jatmi.TPException;
import weblogic.wtc.jatmi.TPReplyException;
import weblogic.wtc.jatmi.TypedString;
import weblogic.wtc.jatmi.Reply;
import weblogic.wtc.gwt.TuxedoConnectionFactory;
import weblogic.wtc.gwt.TuxedoConnection;
public class ToupperBean implements SessionBean
{
static final boolean VERBOSE = true;
private SessionContext ctx;
public void setSessionContext(SessionContext ctx) {
log("setSessionContext called");
this.ctx = ctx;
}
public void ejbActivate() {log("ejbActivate called");}
public void ejbPassivate() {log("ejbPassivate called");}
public void ejbRemove() {log("ejbRemove called");}
public void ejbCreate() throws CreateException {log("ejbCreate called");}
public String Toupper(String toConvert) throws TPException, TPReplyException {
Context ctx;
TuxedoConnectionFactory tcf;
TuxedoConnection myTux;
TypedString myData;
Reply myRtn;
int status;
log("toupper called, converting " + toConvert);
try {
ctx = new InitialContext();
tcf = (TuxedoConnectionFactory) ctx.lookup("tuxedo.services.TuxedoConnection");
} catch (NamingException ne) {
throw new TPException(TPException.TPENOENT,
"Could not get TuxedoConnectionFactory : " + ne);
}
myTux = tcf.getTuxedoConnection();
myData = new TypedString(toConvert);
log("About to call tpcall");
try {myRtn = myTux.tpcall("TOUPPER", myData, 0);}
catch (TPReplyException tre) {log("tpcall threw TPReplyExcption " + tre); throw tre;} catch (TPException te) {log("tpcall threw TPException " + te); throw te;}
catch (Exception ee) {
log("tpcall threw exception: " + ee);
throw new TPException(TPException.TPESYSTEM, "Exception: " + ee);
}
log("tpcall successfull!");
myData = (TypedString) myRtn.getReplyBuffer();
myTux.tpterm();
return (myData.toString());
}
private void log(String s) {if (VERBOSE) {System.out.println(s);}}
}
(ii) ejb-jar.xml的配置
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>Toupper</ejb-name>
<home>ToupperSLBean.ToupperHome</home>
<remote>ToupperSLBean.Toupper</remote>
<ejb-class>ToupperSLBean.ToupperBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>Toupper</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>NotSupported</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
(iii) weblogic-ejb-jar.xml的配置
<weblogic-ejb-jar>
<weblogic-enterprise-bean>
<ejb-name>Toupper</ejb-name>
<jndi-name>tuxedo.services.ToupperHome</jndi-name>
</weblogic-enterprise-bean>
</weblogic-ejb-jar>
(5) 将stateless session bean(ToupperSLBean)暴露成Web Service
点击"开始菜单à程序àBEA WebLogic Platform 7.0à WebLogic Workshop"中的 "WebLogic Workshop",启动WebLogic Workshop 7.0.2.0。
在Workshop的File菜单中点击 "New Project…",弹出对话框后将Project的名字起为TuxedoWebService,点击OK将新建一名为TuxedoWebService的Project。实质上该操作是在 \TuxedoWebService\applications下创建了一个名为TuxedoWebService的子目录,该目录所包含的内容实际上是一个开放目录式的Web App。所以Workshop的project在运行时即为Web App。
接下来弹出的对话框要你Create New File,选择创建Web service类型的文件。这里Web service类型的文件以 .jws作为后缀名。它其实是一个Java源文件,只不过要在源代码的注视中插入一些用于识别Web service相关内容的特殊的javadoc标记。将新Create的Web service文件起名为TuxedoWebService则生成TuxedoWebService.jws文件。
在TuxedoWebService.jws的Design View中的Add Operation下拉框中选择Add Method,把新添加的Method起名为callTuxedoService,如图8:
右键点击callTuxedoService,选择Edit Maps and Interface。在弹出的对话框的Java: 框中修改callTuxedoService的输入参数和返回值:
public String callTuxedoService(String toConvert)
如图9:

点击OK后再打开callTuxedoService方法的Edit Maps and Interface对话框,可以看到在XML: 框中callTuxedoService的输入参数和返回值的SOAP Envelope Body皆已经生成,如图10和图11:

图10

图11
此时我们已经生成了一个名为callTuxedoService的Web Service。
在TuxedoWebService.jws的Design View中的Add Control下拉框中选择Add EJB Control,弹出对话框中参数填写如图12:

图12
如果相应的WebLogic Server正处于运行状态的话,jndi-name可以通过点击Browse来选取。这里jndi-name填为tuxedo.services.ToupperHome,即(4)中stateless session bean(ToupperSLBean)的weblogic-ejb-jar.xml文件中填写的值。点击Create之后,会生成一个名为callToupperControl.ctrl的控件文件,其内容如下:
import weblogic.jws.*;
import weblogic.jws.control.*;
/**
* @jws:ejb home-jndi-name="tuxedo.services.ToupperHome"
* @editor-info:ejb
*/
public interface callToupperControl
extends ToupperSLBean.ToupperHome, // home interface
ToupperSLBean.Toupper, // bean interface
weblogic.jws.control.SessionEJBControl // control interface
{
}
这样通过callToupperControl控件,callTuxedoService Web Service就可以调用ToupperSLBean stateless session bean了。
在TuxedoWebService.jws的Source View中补充其实现代码。最终的TuxedoWebService.jws源代码如下:
import weblogic.jws.control.JwsContext;
import ToupperSLBean.*;
import java.rmi.RemoteException;
import weblogic.wtc.jatmi.TPException;
import weblogic.wtc.jatmi.TPReplyException;
import weblogic.wtc.jatmi.TypedString;
public class TuxedoWebService
{
/**
* @jws:control
*/
private callToupperControl callToupper;
/** @jws:context */
JwsContext context;
/**
* @jws:operation
*/
public String callTuxedoService(String toConvert)
throws RemoteException, TPReplyException, TPException
{
return callToupper.Toupper(toConvert);
}
}
(6) 测试callTuxedoService Web Service
点击Workshop的Debug菜单下的Start项进行测试。此时会启动IE并显示出一组测试页面。测试页面包含了5个标签页,分别为Overview / Console / Test Form / Test XML / Warnings。点击Test Form标签页,在其string toConvert: 栏中填入要进行转换的小写字符串,这里我们填入 "tuxedo web service",如图13:

图13
点击callTuxedoService按钮,返回页面如图14:

图14
可以看到返回了大写字符串 "TUXEDO WEB SERVICE"。
(7) 注意事项
(i) 在 .jws代码中不可直接调用WTC的API;
(ii) 只能将stateless session bean发布成Web Service,不可将stateful session bean发布成Web Service;
(iii) 并且被发布的stateless session bean的ejb-jar.xml中的
值必须设为NotSupported,否则会报错。
架构2:通过Jolt将Tuxedo Service发布为Web Service
此架构利用了WebLogic Server的Web Service Container,让WebLogic Server通过调用Jolt接口连接到Tuxedo Jolt Server,从而将Tuxedo Service发布为Web Service,如图15所示:

图15
在本实例中,具体的Server端流程链如下:
Java Web Service <--> Jolt <-->Tuxedo Service
以下是实施步骤:
(1) Tuxedo端的配置和编码
(i) ubbconfig的配置:
*RESOURCES
IPCKEY 50000
MASTER SITE1
MODEL SHM
*MACHINES
"FIGURE-NOTEBOOK" LMID=SITE1
TUXDIR = "C:\bea\tuxedo8.1"
APPDIR = "D:\JoltDomain"
TUXCONFIG = "D:\JoltDomain\tuxconfig"
MAXWSCLIENTS = 10
*GROUPS
GROUP1 LMID=SITE1 GRPNO=1
ADMINGRP LMID=SITE1 GRPNO=2
*SERVERS
simpserv SRVGRP=GROUP1 SRVID=1
JSL SRVGRP=ADMINGRP SRVID=500 RESTART=Y MAXGEN=5 CLOPT="-- -n //127.0.0.1:12345"
JREPSVR SRVGRP=ADMINGRP SRVID=501 RESTART=Y MAXGEN=5 CLOPT="-A -- -W -P C:\bea\tuxedo8.1\udataobj\jolt\repository\jrepository"
*SERVICES
TOUPPER
(ii) Tuxedo Server端代码:
同架构1中的Tuxedo Server端代码。所以此实例的Tuxedo Service也是经典的TOUPPER,即将传入的字符串转换为大写再返回。
tmboot Tuxedo实例。
(2) 创建WebLogic Domain
创建名为JoltWebService的Domain。
(3) 在 .jws中调用Jolt接口
在Workshop中新建名为JoltWebService的project。在此project中新建JoltWebService.jws文件。在JoltWebService.jws中添加名为callJolt的Method。修改callJolt的输入参数和返回值:
public String callJolt(String toConvert)
至此名为callJolt的Web Service已经生成。JoltWebService.jws源代码如下:
import weblogic.jws.control.JwsContext;
import bea.jolt.*;
public class JoltWebService
{
/** @jws:context */
JwsContext context;
/**
* @jws:operation
*/
public String callJolt(String toConvert)
{
JoltSession session;
JoltSessionAttributes sattr;
JoltRemoteService toupper;
sattr = new JoltSessionAttributes();
sattr.setString(sattr.APPADDRESS, "//127.0.0.1:12345");
session = new JoltSession(sattr, null, null, null, null);
toupper = new JoltRemoteService("TOUPPER", session);
toupper.addString("STRING", toConvert);
toupper.call(null);
String result = toupper.getStringDef("STRING", null);
System.out.println(result);
session.endSession();
return result;
}
}
(4) 测试callJolt Web Service
在测试页面的Test Form标签页的string toConvert: 栏中填入要进行转换的小写字符串,这里我们填入 "tuxedo web service",如图16:

图16
点击callJolt按钮,返回页面如图17:

图17
可以看到返回了大写字符串 "TUXEDO WEB SERVICE"。
五.给相关项目所带来的益处
概括地说,将Tuxedo Service发布成Web Service会给相关项目带来以下益处:
(1) 保留了Tuxedo的现有投资,并将其架构延伸至了J2EE和Web Service;
(2) 更充分地利用了WebLogic和Tuxedo这两个平台的各自所长:Tuxedo在后端处理的极其优异的性能和WebLogic对标准强有力的支持和其十分先进的的架构设计;
(3) 利用Web Service能使项目能得到更高的投资回报率,它可以优化项目实施的生命周期;
(4) Web Service的实施使代码模块具有更强的灵活性;
(5) Web Service的实施更好地区分了开发人员的角色;
(6) Web Service的实施独立了客户端层和Service层的安全机制;
(7) 利用Web Service能更方便模块化地进行功能和性能测试;
(8) Web Service的客户端类型无关性;
(9) Web Service可以聚集;
(10) Web Service的实施增强了系统的易维护性;
(11) Web Service的实施增强了模块的可重用性;
(12) 利用Web Service可使开发的并行度更高;
(13) Web Service的实施让系统的可扩展性更强;
(14) Web Service的实施可使系统的可用性更高。
六.参考文献
(1) 《Web服务的最佳实践》
(2) 《Web Services概述》
(3) 《XML Web Service基础》
(4) 《Tuxedo应用系统设计规范》
|