使用 WebSphere MQ 和 WebSphere Enterprise Service Bus 调用 Web 服务

使用 WebSphere Integration Developer 构建解决方案

了解如何使用 IBM WebSphere Enterprise Service Bus (ESB) 和 IBM WebSphere Integration Developer 来通过 IBM® WebSphere® MQ 客户端调用 Web 服务。您将创建一个 MQ Java™ 客户端,为 WebSphere ESB 编写一个自定义 WebSphere MQ 数据绑定和一个自定义功能选择器,并配置 WebSphere ESB 以接收来自 MQ 队列的消息。

Philip Norton (nortonp@uk.ibm.com), WebSphere ESB 开发团队软件工程师, IBM

Philip Norton photoPhilip Norton 是 IBM Hursley Lab 的一位软件工程师。他在 WebSphere ESB Development 团队工作。他的专业领域包括 Java 和 JMS for Websphere MQ。他是认证 Java 程序员,拥有坎特伯雷大学计算机科学方面的学位。



2007 年 6 月 25 日

开始之前

关于本教程

WebSphere Enterprise Service Bus (ESB) 支持应用程序和服务的连接,这些应用程序和服务在许多情况下是在不同的时间使用不同的编程语言、接口和标准来开发的。本教程演示如何使用现有的 WebSphere MQ 系统来调用 WebSphere ESB 上承载的服务。

目标

您将使用 WebSphere Integration Developer 所提供的可视工具来构建一个端到端解决方案。

先决条件

本教程假设 WebSphere Integration Developer 已经与 WebSphere ESB Integrated Test Environment 安装在一起,并且已将服务器缺省主机配置到端口 9080。需要 WebSphere MQ V5.3 FixPack12 或更高版本。完成本教程需要 WebSphere ESB Version 6.0.2 或更高版本。

系统要求

要运行本教程中的示例,计算机将至少需要有 500MB 的内存。


创建 MQ 客户端

首先,我们必须创建一个将向队列发送消息的 WebSphere MQ 客户端。在本教程中,我们将使用 Java,但是通常可以使用任何受支持的编程语言来编写该客户端。我们将在消息中使用自定义数据类型,以演示如何使现有的系统能够与 WebSphere ESB 通信。我们打算使用的 Web 服务将接受一个客户,并返回表明该客户详细信息已被存储的确认信息。

首先打开 WebSphere Integration Developer 并关闭欢迎窗格,以进入 Business Integration 透视图。如果碰巧关闭了此透视图,可以通过选择 Window > Open Perspective > Other > Business Integration 来重新打开它。对于第一个任务,我们需要使用 Physical Resources 视图。选择 Window > Show View > Physical Resources:

  1. 右键单击 Physical Resources 视图,并选择 New > Other...
  2. 选择项目类型 Java > Java Project。这将打开 New Java Project 对话框。
  3. 输入 MQClient 作为项目名称。
  4. 单击 Finish。如果提示切换到 Java Perspctive 透视图时,请单击 No
  5. 展开 MQClient Java 项目。单击右键,并选择 New > Other...
  6. 选择 Java > Class,然后单击 Next
  7. 输入 com.ibm.demo 作为包,输入 CustomerClient 作为类名称,如图 1 所示。
  8. 单击 Finish
图 1. 创建 CustomerClient 类
新的 Java 类
  1. 此时将打开 CustomerClient.java。将内容替换为清单 1 所示的内容。
清单 1. CustomerClient.java 的代码
package com.ibm.demo;

 import com.ibm.mq.MQC;
 import com.ibm.mq.MQEnvironment;
 import com.ibm.mq.MQException;
 import com.ibm.mq.MQGetMessageOptions;
 import com.ibm.mq.MQMessage;
 import com.ibm.mq.MQPutMessageOptions;
 import com.ibm.mq.MQQueue;
 import com.ibm.mq.MQQueueManager;

 public class CustomerClient {
  Arguments args; //Command line aruments
   private MQQueueManager qmgr; //Connection to Queue Manager
    /*
    * Constructor
    */
     public CustomerClient(String[] arguments) {
     args = new Arguments(arguments);
    }
    /*
     * Create a new Queue Manager connection if one doesn't exist
     */
private MQQueueManager getQueueManager() throws MQException {
MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY, args.transport);
MQEnvironment.hostname = args.hostname;
MQEnvironment.port = args.port;
MQEnvironment.channel = args.channel;
if (qmgr == null || !qmgr.isConnected()) qmgr = new MQQueueManager(args.queueManager);
 return qmgr;
 }
 /*
  * Send an MQ message
  */
public void sendMessage(MQMessage message) throws MQException {
  MQQueue mqQueue = getQueueManager().accessQueue
  (args.requestQueue, MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_OUTPUT);
  MQPutMessageOptions pmo = new MQPutMessageOptions();
  mqQueue.put(message, pmo);
  mqQueue.close();
  disconnect();
    }
    /*
     * Receive an MQ message
     */
public MQMessage receiveMessage(int wait) throws MQException {
  MQQueue mqQueue = getQueueManager().accessQueue
  (args.responseQueue, MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_OUTPUT);
  MQGetMessageOptions gmo = new MQGetMessageOptions();
  gmo.options = MQC.MQGMO_WAIT;
  gmo.waitInterval = wait;
   MQMessage message = new MQMessage();
   mqQueue.get(message, gmo);
   mqQueue.close();
   disconnect();
   return message;
    }
    /*
     * Disconnect from the Queue Manager
     */
private void disconnect() {
 try {
 if (qmgr != null && qmgr.isConnected()) qmgr.disconnect();
 } catch (MQException e) {
 qmgr = null;
    }
}    
/*
* Class used to gather arguments from the command line in the form of 
* -name value -name value ...
*/
private class Arguments {
  int index = 0;
  private String hostname;
  private String channel;
  private int port;
  private String queueManager;
  private String requestQueue;
  private String responseQueue;
  private String transport;

  public Arguments(String[] args) {
   process(args);
   }

  private void process(String[] args) {
   while (index < args.length) {
     String arg = args[index++];
     String value = args[index++];
     if (value.startsWith("-")) {
     value = null;
     index--;
     }
   if (value != null) {
   if (arg.startsWith("-hostname")) this.hostname = value;
   else if (arg.startsWith("-channel")) this.channel = value;
   else if (arg.startsWith("-port")) this.port = Integer.parseInt(value);
   else if (arg.startsWith("-queueManager")) this.queueManager = value;
   else if (arg.startsWith("-requestQueue")) this.requestQueue = value;
   else if (arg.startsWith("-responseQueue")) this.responseQueue = value;
   else if (arg.startsWith("-transport")) {
   if (value.equals("bindings")) this.transport = MQC.TRANSPORT_MQSERIES_BINDINGS;
   else this.transport = MQC.TRANSPORT_MQSERIES_CLIENT;
    }
   }
  }
 }
}

 public static void main(String[] args) {
  CustomerClient client = new CustomerClient(args);
   try {
    MQMessage request = new MQMessage();
    //Build a customer
    request.writeInt(1234);              //CustomerId   MQINT
    request.writeString("Fred        "); //First Name   MQCHAR12
    request.writeString("Flintstone  "); //Last Name    MQCHAR12
    request.writeInt(25);                //Age          MQINT
    request.writeString("Bedrock     "); //Address      MQCHAR12
            
     //Send the message
     client.sendMessage(request);
            
    //Wait for response
    MQMessage response = client.receiveMessage(5000);                        
    System.out.println("Response from Web Service");
    System.out.println("Customer Id "+response.readInt());
    boolean success = false;
    if (response.readInt() == 1) success = true;
    System.out.println("Success     "+success);
            
    } catch (Exception e) {            
    e.printStackTrace();
   }
  }
}

现在还存在编译错误,因为 MQ Java 类不在类路径上。

  1. 右键单击 MQClient 项目并选择 Properties
  2. 选择 Java Build Path,然后选择Libraries 选项卡。
  3. 单击 Add External JARs...
  4. 定位到您的 WebSphere MQ Java/lib 目录并选择 com.ibm.mq.jar
  5. 单击 Open
  6. 单击 OK

这就完成了该 MQ 客户端的创建工作。


编写自定义 MQ 数据绑定

WebSphere ESB 如何知道怎样理解我们的客户消息?此刻它还不知道,因此我们将创建一个自定义数据绑定。这向 WebSphere ESB 描述如何从 MQ 消息的内容构建一个业务对象。让我们执行以下操作:

  1. 在 Physical Resources 视图中,右键单击 MQModule 并选择 New > Other...
  2. 选择 Java > Class,然后单击 Next
  3. 输入 com.ibm.demo.data.binding 作为包,输入 CustomerDataBinding 作为类名称,并添加接口 MQBodyDataBinding,如图 2 所示。
  4. 单击 Finish
图 2. 客户数据绑定
客户数据绑定

CustomerDataBinding.java 在创建时具有几个空方法。下面是那些方法的用途摘要。

read 用于读取消息的内容并构建一个 DataObject。

write 用于写入来自 DataObject 的消息内容。

setBusinessException 未使用。

isBusinessException 未使用。

setFormat 用于消息格式的 Setter。

getFormat 用于消息格式的 Getter。

getDataObject 在数据绑定中需要某个 DataObject 时调用。

setDataObject 在将新的 DataObject 传递给数据绑定时调用。

  1. 将 CustomerDataBinding.java 的内容替换为清单 2 中的实现并保存。
清单 2. CustomerDataBinding.java 的代码
package com.ibm.demo.data.binding;

import java.io.IOException;
import java.util.List;
import com.ibm.mq.data.MQDataInputStream;
import com.ibm.mq.data.MQDataOutputStream;
import com.ibm.websphere.sca.mq.data.MQBodyDataBinding;
import com.ibm.websphere.sca.mq.structures.MQMD;
import com.ibm.websphere.sca.sdo.DataFactory;
import commonj.connector.runtime.DataBindingException;
import commonj.sdo.DataObject;

public class CustomerDataBinding implements MQBodyDataBinding {
  //This is the namespace of the expected request type.
  private static String REQUEST_TYPE_NAMESPACE = "http://MQModule";
  //This is the request type expected
  private static String REQUEST_TYPE_NAME = "Customer";
  //The QName built from the namespace and type
  private static String REQUEST_TYPE_QNAME = 
  "{" + REQUEST_TYPE_NAMESPACE + "}" + REQUEST_TYPE_NAME;
  //This is the namespace of the expected response type
  private static String RESPONSE_TYPE_NAMESPACE = "http://MQModule";
  //This is the response type expected
  private static String RESPONSE_TYPE_NAME = "Confirmation";
  //The QName built from the namespace and type
  private static String RESPONSE_TYPE_QNAME = 
  "{" + RESPONSE_TYPE_NAMESPACE + "}" + RESPONSE_TYPE_NAME;
  //Format
  public String format;
  //DataObject that is built from the request message
  //It is also used to build the response messages
  public DataObject dataObject;

  public void read(MQMD mqmd, List headers, 
  MQDataInputStream input) throws IOException {
    if (dataObject == null) {
     //If the Data Object we received is null create a new request
     dataObject = DataFactory.INSTANCE.create
     (REQUEST_TYPE_NAMESPACE, REQUEST_TYPE_NAME);
    }
   if (dataObject.getType().getURI().equals
   (REQUEST_TYPE_NAMESPACE) && 
   dataObject.getType().getName().equals(REQUEST_TYPE_NAME)) {
  //If the Data Object is a request build a Customer data object
  //by reading the known structure from the input stream
  dataObject.setInt("customerId", input.readInt());
  dataObject.setString("firstName", input.readMQCHAR12().trim());
  dataObject.setString("lastName", input.readMQCHAR12().trim());
  dataObject.setInt("age", input.readInt());
   dataObject.setString("address", input.readMQCHAR12().trim());
    } else if (dataObject.getType().getURI().equals(RESPONSE_TYPE_NAMESPACE) 
    && dataObject.getType().getName().equals(RESPONSE_TYPE_NAME)) {
    //If the Data Object is a response build a Confirmation data object
    //by reading the known structure from the input stream
    dataObject = DataFactory.INSTANCE.create
    (RESPONSE_TYPE_NAMESPACE, RESPONSE_TYPE_NAME);
    dataObject.setInt("customerId", input.readInt());
    if (input.readInt() == 1) {
     dataObject.setBoolean("success", true);
      } else {
      dataObject.setBoolean("success", false);
     }
    }
   }

public void write(MQMD mqmd, List headers, 
MQDataOutputStream output) throws IOException {
 if (dataObject == null) {
   //If the Data Object is null create a new response
   dataObject = DataFactory.INSTANCE.create
   (RESPONSE_TYPE_NAMESPACE, RESPONSE_TYPE_NAME);
  }
 if (dataObject.getType().getURI().equals
 (REQUEST_TYPE_NAMESPACE) && 
 dataObject.getType().getName().equals(REQUEST_TYPE_NAME)) {
  //If the Data Object is a request write the Customer
  //to the message output stream
  output.writeInt(dataObject.getInt("customerId"));
  output.writeMQCHAR12(dataObject.getString("firstName"));
  output.writeMQCHAR12(dataObject.getString("lastName"));
  output.writeInt(dataObject.getInt("age"));
  output.writeMQCHAR12(dataObject.getString("address"));
 } else if (dataObject.getType().getURI().equals(RESPONSE_TYPE_NAMESPACE)
 &&  dataObject.getType().getName().equals(RESPONSE_TYPE_NAME)) {
  //If the Data Object is a response write the confirmation
  //to the message output stream                        
  output.writeInt(dataObject.getInt("customerId"));
  if (dataObject.getBoolean("success") == true) {
  output.writeInt(1);
  } else {
  output.writeInt(0);
  }
 }
}

public void setBusinessException(boolean arg0) {
}

public boolean isBusinessException() {
 return false;
}

public void setFormat(String arg0) {
  format = arg0;
}

public String getFormat() {
  return format;
}

public DataObject getDataObject() throws DataBindingException {
 return dataObject;
}

public void setDataObject(DataObject dObj) throws DataBindingException {
  if (dObj == null) dataObject = null;
   else if ((dObj.getType().getURI().equals(REQUEST_TYPE_NAMESPACE) &&
      dObj.getType().getName().equals(REQUEST_TYPE_NAME))
   || (dObj.getType().getURI().equals(RESPONSE_TYPE_NAMESPACE) &&
      Obj.getType().getName().equals(RESPONSE_TYPE_NAME))) {
  // Check the DataObject is the correct type
  dataObject = dObj;
  } else {
  throw new DataBindingException();
  }
}
}

数据绑定检查它是在处理某个请求消息还是响应消息。这允许在 MQ 导出组件和 MQ 导入组件上使用它。现在该自定义数据绑定已经完成。


构建一个使用 MQ 绑定的模块

下一步是创建一个接口,该接口接受一个客户对象并返回一个确认信息。

  1. 返回 Business Integration 视图。
  2. 选择 File > New > Project...
  3. 选择 Mediation Module 并单击 Next
  4. 输入 MQModule 作为模块名称,并取消选中 Create mediation flow component 复选框,如图 3 所示。
图 3. 新的中介模块
新的中介模块

下面让我们创建业务对象,用于描述客户和 MQ 客户端中使用的确认信息。

  1. 单击 Finish。这样就创建了一个新模块。
  2. 在 MQModule中右键单击 Data Types,并选择 New > Business Object
  3. 输入 Customer 作为业务对象名称。
  4. 单击 Finish。此时将打开 Business Object Editor。
  5. 向 Customer 添加所需属性,如图 4 所示。
图 4. Customer 业务对象
Customer 业务对象
  1. 创建另一个名为 Confirmation 的业务对象,它具有所需的属性,如图 5 所示。
图 5. Confirmation 业务对象
Confirmation 业务对象

现在我们将创建接口,用于接受一个客户对象并返回确认信息:

  1. 在 Business Integration 视图中,在 MQModule 中右键单击 Interfaces
  2. 选择 New > Interface
  3. 将该接口命名为 CustomerInterface
  4. 单击 Finish。此时会打开接口编辑器。
  5. 添加一个名为 handleMessage 的双向操作。
  6. 将输入类型设置为 Customer,将输出类型设置为 Confirmation,如图 6 所示。
图 6. Customer 接口
Customer 接口

下一步,我们将创建 MQ Module。我们将在此场景中使用一个 Java 组件来模拟 Web 服务。

  1. 打开 MQModule 的组装编辑器。
  2. CustomerInterface 拖放到编辑器上,选择 Export with no binding 并单击 Ok
  3. 现在将一个 Java 组件添加到编辑器,并将其连接到该导出组件,如图 7 所示。
图 7. MQModule
MQModule
  1. 右键单击该 Java 组件,并选择 Generate Implementation
  2. 选择缺省包并单击 OK
  3. 将实现替换为清单 3 中的实现。
清单 3. Java 组件的代码
package sca.component.java.impl;

import java.util.HashMap;
import java.util.Map;
import commonj.sdo.DataObject;
import com.ibm.websphere.bo.BOFactory;
import com.ibm.websphere.sca.ServiceManager;

public class Component1Impl {

  static Map customers = new HashMap();
    
  public Component1Impl() {
   super();
  }

private Object getMyService() {
  return (Object) ServiceManager.INSTANCE.locateService("self");
 }

public DataObject handleMessage(DataObject input) {
  boolean success = false;
  //Get the customer id
  int id = input.getInt("customerId");        
  //Create the customer from the request
  Customer customer = new Customer();        
  customer.fName = input.getString("firstName");
  customer.lName = input.getString("lastName");
  customer.age = input.getInt("age");
  customer.address = input.getString("address");  
  //Check whether the customer is already stored
  if(customers.get(new Integer(id)) == null)
    {                   
	  //Store the customer if they don't currently exist
	  customers.put(new Integer(id), customer);
	  success = true; 
    }
  //Build the confirmation response
  ServiceManager serviceManager = new ServiceManager();
  BOFactory bofactory = 
  (BOFactory) serviceManager.locateService("com/ibm/websphere/bo/BOFactory");
  DataObject response = 
  bofactory.createByElement("http://MQModule/CustomerInterface", "handleMessageResponse");
  DataObject confirmation = response.createDataObject("output1");
  confirmation.setInt("customerId", id);
  confirmation.setBoolean("success", success);
  return confirmation;
    }
    
 private class Customer {
   String fName;
   String lName;
   int age;
   String address;
 } 
}

下一步,我们需要生成导出组件上的 MQ 绑定。由于本教程集中于配置 WebSphere ESB,我们将假设有一个 MQ 队列管理器 QM 在该计算机上可用,并且已创建了两个队列 REQUESTQRESPONSEQ。若要使用不同的配置,只需在创建数据绑定时填入您的 MQ 配置。

  1. 右键单击 Export1 并选择 Generate Binding...-> Messaging Binding...-> MQ Binding
  2. 此时会打开 MQ Export Binding 属性面板。
  3. 使用您的 MQ 属性填写 End-point Configuration 文本框,如图 9 所示。
  4. Request Serialization type 下面的 Data Format 部分,选择 User supplied 并单击 Browse
  5. 从 Select Type 对话框中选择您的 CustomerDataBinding,如图 8 所示,并单击 OK
图 8. 选择数据绑定
选择数据绑定
  1. Response Serialization Type 选择同一个数据绑定,现在该面板应该与图 9 类似。
图 9. MQ 导出绑定
MQ 导出绑定
  1. 单击 OK 并保存。该模块现在已完成。

测试 MQ 绑定

在运行该客户端之前,我们需要部署该模块。

  1. 打开服务器视图,右键单击您的服务器并选择 Start
  2. 在服务器启动以后,再次右键单击它并选择 Add and Remove projects...
  3. 选择 MQModule,单击 Add,然后单击 OK
  4. 等待项目完成部署并成功启动。

现在让我们尝试向队列发送一个 MQ 消息,并确定我们是否会获得应答。

  1. 右键单击 CustomerClient.java 并选择 Run > Run...
  2. 单击 Arguments 选项卡。
  3. 在 Program Arguments 文本框中,输入 -hostname localhost -channel SYSTEM.DEF.SVRCONN -port 1414 -queueManager QM -requestQueue REQUESTQ -responseQueue RESPONSEQ -transport client,如图 10 所示。
  4. 单击 Run
图 10. 运行 MQ 客户端
运行 MQ 客户端

在控制台中,您应该看到客户端的输出确认已成功添加了该客户。尝试再次运行该客户端以添加同一个客户,您应该看到响应,但这次 success 字段将为 false。您可以编辑 MQClient 以添加具有不同 ID 的客户。


结束语

在本教程中,我们使用 WebSphere Integration Developer 和 WebSphere ESB 来开发并测试了以下内容:

  1. 一个 MQ 客户端,它可以发送包含自定义数据类型的 MQ 消息
  2. 一个使用 Java 组件来实现的 Java 服务
  3. 一个自定义数据绑定,它允许将消息格式转换为服务所需要的格式

本教程还演示了如何使用 WebSphere MQ 来调用 Web 服务。然而,同样的自定义数据绑定还可用于将 MQ 应用程序公开为 Web 服务。利用我们的自定义数据绑定,通过 Web 服务绑定来将导出组件连接到 MQ 导入组件,我们可以使用 Web 服务调用来调用 MQ 应用程序。但愿本文能让您对如何使用这两个产品来将 WebSphere MQ 和 WebSphere MQ 应用程序与 Web 服务集成有个基本的了解。


下载

描述名字大小
Project Interchange for mediation moduleMQModule.zip7KB
MQ ClientMQClient.zip3KB

参考资料

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services, WebSphere
ArticleID=236152
ArticleTitle=使用 WebSphere MQ 和 WebSphere Enterprise Service Bus 调用 Web 服务
publish-date=06252007