使用 WebSphere ESB 实现协议转换和数据转换概要

发布时间:2018-10-27 09:43:47   来源:文档文库   
字号:

使用 WebSphere ESB 实现协议转换和数据转换

李兆全目前就职于软通动力信息技术有限公司,工作重点是 SOA 方面的相关主题,担任 IBM WebSphere 产品的架构、开发工作。专长 Web ServiceESBMB MQ 技术。擅长于应用层的数据交换技术。

简介: 本文主要介绍如何通过 WebSphere ESB 实现协议转换和数据转换功能:通过 Websphere ESB 实现 SOAP/HTTP JMS 之间的协议转换;实现 JMS Object Message Business Object 之间、以及 Business Object Java Object 的数据转换;实现客户端与 ESB 之间 request/response 的交互方式,客户端向 ESB 发送带有数据对象的请求,ESB 请求 Web 服务后,将结果以数据对象的形式返回给客户端。

引言

已有许多文章介绍了如何将 xml message 传入 ESB 进行协议转换和数据转换,而在实际的应用环境中,面向对象的设计会显得更实用些。本文主要介绍如何基于 JMS WebSphere ESB 构建企业服务总线,实现 SOAP/HTTP JMS 之间的协议转换;实现 JMS Object MessageBusiness Object Java Object 之间的数据转换;以及如何实现通过 ESB 来实现 request/response 的交互方式。

示例场景



1:示例场景

1 示例展示了一个典型的端到端的 SOA 场景:

1Service Provider SOAP/HTTP 方式发布 Web Service,该 Web Service 输入和返回都是 Java Object

2)客户端以 JMS 方式去调用这个 Web Service,需要经过 WehSphere ESB 进行协议转换,WehSphere ESB 将客户端的 JMS 协议转换为服务端需要的 SOAP/HTTP 协议;

3)客户端将 JMS Object Message 发送给 WehSphere ESBWehSphere ESB 通过 SOAP/HTTP 方式请求 Web Service。在服务请求的过程中,WehSphere ESB 将客户端传入的 JMS Object Message 转换为 Business Object,又将 Business Object 转换为服务端需要的 Java Object;在服务返回的过程中,WehSphere ESB 将服务端返回的 Java Object 转换为 Business Object,又将 Business Object 转换为客户端能识别的 JMS Object Message

4)客户端向 WebSphere ESB 发送请求和接收返回数据分别在两个队列上进行,客户端只需关注如何将请求的数据转化为 JMS Object Message 并放入 WehSphere ESB 的接收队列,以及如何从 WehSphere ESB 的发送队列里取出 JMS Object Message 并解析所需的结果即可。

本示例是基于 WID6.0.2 ESB6.0.2 实现的,下面来详细介绍如何实现这一示例场景。

创建 Service provider

建立工程 BookOrderService,来担任 Service Provider。该 service 提供了一个接口方法 order(),其输入和输出分别是 java objectOrderRequest OrderResponse,将此方法发布成 Web Service,如下:

1.建立一个 Dynamic Web ProjectBookOrderService

2.添加对象类、接口和实现类

对象类:

Address.java

包含属性:

private String street;

private String city;

OrderRequest.java

包含属性:

private String name;

private int count;

private Address address;

OrderResponse.java

包含属性:

private double totalPrice;

接口类:

BookOrderIf.java

public interface BookOrderIf {

public OrderResponse order(OrderRequest req);

}

实现类:

BookOrderImpl.java

实现了一个简单的业务逻辑。

public OrderResponse order(OrderRequest req) {

double totalPrice = 10.0 * req.getCount();

OrderResponse resp = new OrderResponse();

resp.setTotalPrice(totalPrice);

System.out.println("Service Provider: The book is " + req.getName()+

", the city is "+req.getAddress().getCity()+", total price is "+totalPrice);

return resp;

}

3.将 BookOrderImpl 发布为 SOAP/HTTP Web service,产生 WSDL 文件 BookOrderImpl.wsdl

创建 WebSphere ESB

WebSphere ESB 的数据转换和协议转换功能通过 Mediation Module 工程来实现,Mediation Module 工程包含三个重要组件:Mediation FlowImport Export 组件。Mediation Flow 组件实现数据转换功能;Import 组件负责对 Service Provider Web Service 进行调用;Export 组件是外界(JMS Client)访问 Mediation Module 的接口。

创建新的 Mediation Module

建立新的 Mediation ModuleSOAPHTTP2JMSBinding

建立 Mediation Module 的同时,会自动创建名称为 Mediation1 Mediation Flow 的组件。

Mediation Module 需要访问刚刚创建的 Service Provider,就需要导入 BookOrderImpl.wsdl 文件。从 BookOrderService Porject 里找到 BookOrderImpl.wsdl,复制到 SOAPHTTP2JMSBinding ProjectWebSphere ESB 就是通过 BookOrderImpl.wsdl 来建立对 Service Provider 调用的。

添加 Import 组件

Import 组件负责完成对 Service Provider Web Service 进行调用。

打开 SOAPHTTP2JMSBinding Assemble Diagram,添加 Import,更名为:SOAPHTTPImport。选择 SOAPHTTPImport,添加接口“Add Interface”,选择 BookOrderImpl,这正是 BookOrderImpl.wsdl 提供的接口。

Import 组件有几种方式可以访问 Mediation Module 之外的 service provider

Messaging Binding 方式,包括 JMS BindingMQ Binding JMS MQBinding;

Web Service Binding 方式。

因为我们刚才建立的 service provider 的接口是 SOAP/HTTP Web Service,所以 Import 组件需要选用 Web Service Binding 方式。

SOAPHTTPImport 添加绑定:“Generate Binding”,选择 Web Service Binding,如图 2



2Web Service Binding

在接下来的对话框中选择“Use an existing web service port”,并“Browse”选择 service portsBookOrderImpl(因为之前已经导入了 BookOrderImpl.wsdl 文件,该文件提供了访问 service provider web service port)。

新建 Business Object

Mediation Module 要进行数据对象的转换,就需要建立内部的数据对象 Business Object,来担任数据转换的中间者。

SOAPHTTP2JMSBinding 建立新的 Business Object

OrderBO

添加属性:booknamecountcity street

RespBO

添加属性:totalPrice

新建接口

建立新的 WebSphere ESB 接口,为 service provider 提供新的展现方式,以便向外界提供各种接口方式(各种 Binding 方式,见“添加 Export 组件”)。

SOAPHTTP2JMSBinding 新建 InterfaceBookOrderIF

添加“Request Response Operation”,修改 operation name 为:order

修改参数,如图 3

Input

NameorderBOTypeOrderBO

OutPut

NamerespBOTypeRespBO



3New Interface

添加 Export 组件

为了使外界(JMS Client)访问到 Mediation Module,需要添加 Export 组件。

添加 Export,更名为 JMSExport。为 JMSExport 添加接口,“Add Interface”,选择“BookOrderIF”(注意是新建的接口,不是 BookOrderImpl.wsdl 提供的接口)。

Mediation Module 可以向外界提供几种方式的接口:

Messaging Binding:包括 JMS BindingMQ Binding MQ JMS Binding

SCA BindingSCA 方式提供给其他 Mediation Module 来访问;

Web Service Binding:提供外界 Web Service 的访问方式。

这里,我们提供 JMS 的访问方式。

JMSExport 添加绑定: Generate Binding,选择“JMS Binding”,如图 4



4JMS Binding

弹出对话框,JMS Export Binding 需要复杂的资源设置,如图 5



5JMS Export Binding Configuration

因为 JMS 协议要求访问者(JMS Client JMSExport 都是 ESB 资源的访问者)通过 JNDI 来访问队列、队列工厂等 ESB 资源的,因此需要在 ESB 上设置各资源的 JNDI(参见 WAS 配置 ESB)。在此处需要为 JMSExport 指定各资源的 JNDI

选择“use pre-configured messaging provider resources”,设置激活规范、接收目标和发送目标:

JNDI name for activation specification: jms/JMSBindingAS4Export

这个 JNDI JMSExport 访问队列的激活规范(参见 WAS 配置 ESB);

JNDI name for receive destination: jms/JMSBingQExportRecv

这个 JNDI 指向 ESB 的接收队列(参见 WAS 配置 ESB);

JNDI name for send destination: jms/JMSBingQExportSend

这个 JNDI 指向 ESB 的发送队列(参见 WAS 配置 ESB);

选择 serialization type: Serialized Business Object using JMSObjectMessage”。因为 ESB 队列接收和返回的数据都是 JMSObjectMessage 对象,因此需要选择此项。如果接收到数据是 XML,可选择“Business Object XML using JMSTextMessage”。

为了使 WebSphere ESB 能将数据返回给客户端,还需要设置 CallBack Desitination Managed Connection Factory。如图 6 和图 7



6CallBack Desitination

JMSExport Properties Binding / End-point configuration 窗口,设置:

JMS Destinations/Callback Destination Propertiesjms/JMSBindingQ



7Managed Connection Factory Properties

JMSExport Properties Binding / End-point configuration 窗口,设置:

Response Connection/ Managed Connection Factory Properties: jms/JMSBindingQCF

Callback Destination Managed Connection Factory 是为 JMSExport 返回数据而设置的,如果 JMS 客户端不需要返回数据,则此两项可以不设置。

创建 JMSExport 的自定义实现类

为实现 JMS 客户端的 JMSObjectMessage 对象与 Service Provider 端的纯 Java 对象进行数据转换,就需要建立 JMSExport 的自定义实现类,通过该类先实现 JMSObjectMessage Business Object 的转换。

SOAPHTTP2JMSBinding 新建 JMSExport 自定义实现类:JMSObjectBindingImpl.java

接口选择 com.ibm.websphere.sca.jms.data.JMSObjectBinding。此接口提供了一些数据转换的方法。

添加 JMSExport 自定义实现类的代码:

首先新建 java 类:

SOAPHTTP2JMSBinding 新建普通的 java 数据对象,以承载从 JMSExport 传入的 JMSObjectMessage 对象,该类也可以作为 JMS 客户端的业务对象,客户端在访问 ESB 队列时,将此业务对象与 JMSObjectMessag 对象进行转换(详见客户端 Servlet ServiceConsumer 的代码):

JMSDataObject.java

实现接口:java.io.Serializable

添加以下属性到该类:

private String bookname;

private int count;

private String city;

private String street;

private double totalPrice;

打开实现类 JMSObjectBindingImpl,添加下列代码:

public class JMSObjectBindingImpl implements JMSObjectBinding {

private JMSDataObject jmsdata;

private DataObject bo;

public void setObject(Object arg0) throws DataBindingException {

System.out.println("set JMS Object.");

jmsdata = (JMSDataObject)arg0;

}

public Object getObject() throws DataBindingException {

return jmsdata;

}

public boolean isObjectType() {

return false;

}

public void setObjectType(boolean arg0) {

}

public int getMessageType() {

return JMSObjectDataBinding.OBJECT_MESSAGE;

}

public void read(Message arg0) throws JMSException {

System.out.println("read JMS Message...");

jmsdata = (JMSDataObject)((ObjectMessage)arg0).getObject();

com.ibm.websphere.sca.ServiceManager serviceManager =

new com.ibm.websphere.sca.ServiceManager();

com.ibm.websphere.bo.BOFactory factory = (com.ibm.websphere.bo.BOFactory)

serviceManager.locateService("com/ibm/websphere/bo/BOFactory");

DataObject orderBO = factory.create("http://SOAPHTTP2JMSBinding","OrderBO");

orderBO.setString("bookname",jmsdata.getBookname());

orderBO.setString("city",jmsdata.getCity());

orderBO.setString("street",jmsdata.getStreet());

orderBO.setInt("count",jmsdata.getCount());

try {

setDataObject(orderBO);

} catch (DataBindingException e) {

throw new JMSException(e.getLocalizedMessage());

}

}

public void write(Message arg0) throws JMSException {

System.out.println("write JMS Message...");

try {

DataObject bo = getDataObject();

JMSDataObject jmsobj = new JMSDataObject();

jmsobj.setTotalPrice(bo.getDouble("totalPrice"));

((ObjectMessage) arg0).setObject(jmsobj);

} catch (DataBindingException e) {

throw new JMSException(e.getLocalizedMessage());

}

}

public boolean isBusinessException() {

return false;

}

public void setBusinessException(boolean arg0) {

}

public DataObject getDataObject() throws DataBindingException {

return bo;

}

public void setDataObject(DataObject arg0) throws DataBindingException {

System.out.println("set Service Data Object.");

bo = arg0;

}

该类实现了以下功能:

当客户端向 JMSExport 发出请求时,该类负责将外部传入的 JMSObjectMessage 转变为内部的 Business Object,转变过程依次经过以下方法:

1readmessage

2getDataObject()

JMSExport 向客户端返回数据时,该类负责将内部的 Business Object 转变为外部的 JMS Object Message,转变过程依次经过以下方法:

1setDataObject()

2getMessageType()

3writemessage

设置 JMSExport 的自定义实现类

JMSExport Method Bindings 设置为自定义的实现类:JMSObjectBindingImpl

返回 Assembly Diagram,选择 JMSExport,选择 Method bindings,如图 8



8Method Bindings

选择“Show Advanced”,设置以下属性,选择刚刚定义的实现类。如图 9

Input data binding format

Serialization type: User Supplied

Input data binding class name: order.JMSObjectBindingImpl

Output data binding format

Serialization type: User Supplied

Input data binding class name: order.JMSObjectBindingImpl



9Data Binding Format

连接 ExportMediation Import

选择 JMSExport Add Wire,拖拽到 Mediation1;选择 Mediation1 Add Wire,拖拽到 SOAPHTTPImport 上。将 ExportMediation Import 连接起来,如图 10



10Add Wire

配置 Mediation Flow,做数据对象转换

因为 Service Provider service 有输入对象和返回对象,因此需要作输入对象和返回对象分别做转换:

一是 Business Object Service Provider 的输入对象的转换;

二是 Service Provider 的返回对象与 Business Object 的转换。

Mediation1 的菜单里选择“Generate Implementation”,进入 Mediation Flow Editor 窗口,连接两个 order 方法,如图 11



11Mediation Flow

先为请求的数据对象作 mapping

在“Requestorder”的窗口里,添加 XML Transformation,命名为 XML Transformation1,并将 XML Transformation1order:BookOrderIF order:BookOrderImpl 连接起来,如图 12



12XML Transformation

创建 Mapping file。选择 XML Transformation1,选择 Properties Details,如图 13



13Create Mapping File

选择 New…,跳过 New XSLT Mapping 窗口,显示 Mapping 窗口,展开所有属性,将属性一一做 mapping。这样,通过 XSLT Mapping,就将 Business Object 转换为 Service Provider 的输入对象,如图 14



14Data Mapping 1

同样,为返回的数据对象作 Mapping

在“Responseorder”窗口,添加 XML Transformation,命名为 XML Transformation2。将 Service Provider 的返回数据对象和 Business Object 属性一一作 Mapping。如图 15



15Data Mapping 2

WAS 配置 ESB

Mediation Module 提供给客户端 JMS 的访问方式。因此需要在 ESB 上建立队列以及 JMS JNDI 访问对象,以实现客户端和 ESB JMS 访问。

建立总线目标

打开 admin console,选择服务集成 -> 总线,选择“SCA.SYSTEM.widCell.Bus”。

新建队列目标,建立以下三个队列目标:

JMSBingQ

JMSBingQExportRecv

JMSBingQExportSend

建立 JMS 队列

选择资源 ->JMS 提供程序 -> 缺省消息传递。

新建 JMS 队列,建立下面三个 JMS 队列:

1JMSBindingQ

JNDI 名称:jms/JMSBindingQ

队列名:JMSBingQ

总线名:SCA.SYSTEM.widCell.Bus

2JMSBingQExportRecv

JNDI 名称:jms/ JMSBingQExportRecv

队列名:JMSBingQExportRecv

总线名:SCA.SYSTEM.widCell.Bus

3JMSBingQExportSend

JNDI 名称:jms/ JMSBingQExportSend

队列名:JMSBingQExportSend

总线名:SCA.SYSTEM.widCell.Bus

建立 JMS 队列连接工厂

选择资源 ->JMS 提供程序 -> 缺省消息传递

新建 JMS 队列连接工厂:

JMSBindingQCF

JNDI 名称:jms/JMSBindingQCF

总线名:SCA.SYSTEM.widCell.Bus

建立激活规范

选择资源 ->JMS 提供程序 -> 缺省消息传递

新建“JMS 激活规范”:

JMSBindingAS4Export

JNDI 名称:jms/JMSBindingAS4Export

目标类型:队列

目标 JNDI 名称:jms/JMSBingQExportRecv

总线名:SCA.SYSTEM.widCell.Bus

创建 Service Consumer

Business Integration Perspective 切换到 J2EE Perspective。创建客户端的访问程序。

创建 web 工程 ServiceConsumerWeb

创建新的 Web 工程 ServiceConsumerWebEAR project ServiceConsumerWebEAR

客户端将使用 JMSDataObject.java 类作为其业务对象类(见“创建 JMSExport 的自定义实现类”)。因此,需要将 SOAPHTTP2JMSBinding 工程 export SOAPHTTP2JMSBinding.jar 包,并将 jar 包输出到 ServiceConsumerWebEAR\ 目录下。

并且设置 ServiceConsumerWeb 的属性:

SOAPHTTP2JMSBinding.jar 加入到“java Build Path/Libraries”;

选择 java JAR Dependencies,选择 SOAPHTTP2JMSBinding.jar

创建 ServiceConsumer

ServiceConsumerWeb 工程新建 java 类:ServiceConsumer,实现客户端请求的逻辑。

public class ServiceConsumer {

private String QCF ="jms/JMSBindingQCF";

private String jndi_recvfrom_esb = "jms/JMSBingQExportSend";

private String jndi_sendto_esb ="jms/JMSBingQExportRecv";

public String sendMes(Object mes) {//throws ISSXException {

QueueConnectionFactory qcf = null;

QueueConnection connection = null;

QueueSession session = null;

QueueSender sender = null;

try {

InitialContext ic = new InitialContext();

qcf = (QueueConnectionFactory) ic.lookup(QCF);

// Create a connection

connection = qcf.createQueueConnection();

connection.start();

session = connection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);

Queue outQueue = (Queue) ic.lookup(jndi_sendto_esb);

// Create a QueueSender

sender = session.createSender(outQueue);

sender.setTimeToLive(0);

Message message = null;

if(mes instanceof Object){

System.out.println("Service consumer: send request to ESB.");

message = (ObjectMessage)session.createObjectMessage((JMSDataObject)mes);

}

message.setStringProperty("TargetFunctionName","order");

message.setJMSType("order");

sender.send(message);

// Close the connection

sender.close();

session.close();

connection.close();

sender = null;

session = null;

connection = null;

} catch (JMSException je) {

je.printStackTrace();

Exception le = je.getLinkedException();

if (le != null){

le.printStackTrace();

}

} catch (Exception e) {

e.printStackTrace();

} finally {

}

return "OK";

}

public String receiveMes(){

QueueConnectionFactory qcf = null;

QueueConnection connection = null;

QueueSession session = null;

QueueReceiver receiver = null;

String ret = null;

try {

InitialContext ic = new InitialContext();

qcf = (QueueConnectionFactory) ic.lookup(QCF);

// Create a connection

connection = qcf.createQueueConnection();

connection.start();

sessio = connection.createQueueSession(true,Session.AUTO_ACKNOWLEDGE);

// Obtain the Destination object from JNDI

Queue inQueue = (Queue) ic.lookup(jndi_recvfrom_esb);

// Create a QueueSender

receiver = session.createReceiver(inQueue);

Message message = receiver.receive(5000);

if(message instanceof ObjectMessage){

ObjectMessage omes = (ObjectMessage)message;

JMSDataObject obj = (JMSDataObject)omes.getObject();

System.out.println("Service consumer: get response from ESB.TotalPrice="

+obj.getTotalPrice());

}else{

System.out.println("Service consumer: receive other message.");

}

session.commit();

receiver.close();

session.close();

connection.close();

receiver = null;

session = null;

connection = null;

} catch (JMSException je) {//Log,save,sendmail,throw exception

je.printStackTrace();

Exception le = je.getLinkedException();

if (le != null){

le.printStackTrace();

}

} catch (Exception e) {

e.printStackTrace();

} finally {

}

return ret;

}

}

ServiceConsumer 类主要实现两个方法:

sendMesObject)方法,将传入的业务数据对象转化为 JMSObjectMessage,发送到 ESB 的接收队列里;

receiveMes()方法,将结果从 ESB 的发送队列里取出,然后将 JMSObjectMessage 解析为业务数据对象。

创建测试的 servlet

ServiceConsumerWeb 工程创建 servletTestServlet

protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1)

throws ServletException, IOException {

ServiceConsumer consumer = new ServiceConsumer();

JMSDataObject data = new JMSDataObject();

data.setBookname("abc");

data.setCount(10);

data.setCity("beijing");

data.setStreet("zhongguancun");

consumer.sendMes(data);

try {

Thread.sleep(5000);

} catch (InterruptedException e) {

e.printStackTrace();

}

consumer.receiveMes();

Servlet 主要实现的功能是:

建立业务对象类,调用 ServiceConsumer 的发送请求和接收返回的方法。

测试

BookOrderServiceSOAPHTTP2JMSBinding ServiceConsumerWeb 三个工程发布运行。

IE 浏览器地址栏输入以下地址:

http://localhost:9080/ServiceConsumerWeb/TestServlet

测试结果,控制台输出以下结果:

1SystemOut O Service consumer: send request to ESB.

2SystemOut O ESB: read JMS Message.

3SystemOut O Service Provider: The book is abc, the city is beijing, total price is 100.0

4SystemOut O ESB: write JMS Message.

5SystemOut O Service consumer: get response from ESB. TotalPrice=100.0

结果分析:

1)客户端向 ESB 发出请求,将 JMS Object Message 发送给 ESB

2ESB 读取 JMS Object Message,转化为 ESB 内部的 Business ObjectESB Business Object 通过 XML Transformation1 转化为 BookOrderService 所需要的数据对象,并向 BookOrderService 发出请求;

3BookOrderService 得到请求,进行处理,向 ESB 返回数据对象;

4ESB 获得 BookOrderService 的返回对象,通过 XML Transformation2 转化为内部的 Business Object,然后再转化为 JMS Object Message,返回给客户端;

5)客户端得到 ESB 的返回的 JMS Object Message,解析到 BookOrderService 返回的结果。

总结

从整个过程来看,WebSphere ESB 在数据转换过程实现了两种数据类型的 4 次转换,这两种数据类型分别是 Service Consumer 端传入的 JMSObjectMessage 对象和 Service Provider 端的 Web Service 输入对象和返回对象。在 ESB 内部,JMSExport 的自定义实现类和 Module Flow XML Transformation 承担了数据转换的任务。4 次转换包括:

数据请求过程:

1. 客户端传入 JMSObjectMessage 对象,JMSExport 的自定义实现类将 JMSObjectMessage 对象转换为 ESB 内部的 Business Object

2. Module Flow XML Transformation Business Object 转换成 Web Service 的输入对象,去调用 Service Provider Web Service

数据返回过程:

1. Service Provider 返回结果数据对象,Module Flow XML Transformation 将返回的对象转换成 Business Object

2. JMSExport 的自定义实现类又将 Business Object 转换成客户端的 JMSObjectMessage 对象。

由于有了 JMSExport SOAPHTTPImport 以及它们不同的绑定实现(JMS Binding Web Service Binding),因此也就实现了 JMS 协议到 SOAP/HTTP 协议的转换。

本文来源:https://www.2haoxitong.net/k/doc/f850fd6b42323968011ca300a6c30c225801f050.html

《使用 WebSphere ESB 实现协议转换和数据转换概要.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式