ibmMQ-第十四章

来源:互联网 发布:淘宝助手收费吗 编辑:程序博客网 时间:2024/04/29 19:07
第十四章 用AMI编程目标学习使用WebSphere MQ AMI 编程。14.1 概述应用程序消息接口(AMI)是对现有WebSphere MQ API 的最新补充。其可向程序员提供一种可以用于处理队列管理器对象非常简单的接口。利用AMI,程序员不必深入了解所有MQI 调用,他们只要专注于应用程序的商业逻辑即可。这就意味着在编程时出现的错误更少,具有更高的处理业务及技术改变的灵活性。AMI 减少了编写新应用程序所需的代码数量。每种编程模式都有不同的调用。举例说来,如果程序员希望编写发布/预订应用程序代码,那么他将必须采用不同于编写请求/回复应用程序的程序员所采用的调用。单个函数之中的结构更少,但是动词会更多。许多函数现在都是中间件层的一部分,在中间件层,企业确立的一系列策略代表应用程序得以应用。AMI包括了Java、C 和C++等在内的标准编程语言的接口。AMI允许中央集中式控制和灵活的改变管理,为点到点模型提供高级接口,可以进行发布/预订工作。AMI 的重要特点是,其是独立于运输和消息发送基础设施的。可采用以下方式发送和接收消息AMI:发送-遗忘,不需要回复。分配表,将消息发送到多个目的地。请求/回复,发送消息的应用程序需要请求消息的回复。发布/预订,由代理管理消息的分配。利用AMI,程序员通常需要处理三个概念:消息,或者说交换的是“什么”。消息包括:- 标题信息,确定消息及其属性。- 消息主体,包含应用程序数据。应用程序数据可以由应用程序生成,也可以由消息服务API 生成。在采用MQI 的WebSphere MQ 应用程序中,消息属性是用MQI 显示设定的,因此应用程序设计人员必须理解其目的是什么。利用AMI 工作时,消息属性包括在消息对象中,或由系统管理员设定的策略所定义,因此程序员就不必再关心这些细节。策略,或者说将要“如何”处理消息。其包含优先级或交付确认等信息。任何数量的应用程序都可以利用相同的策略,而且任何应用程序都可以利用超过一个的策略。IBM 提供了一套通用或默认策略,此外,其也提供了开放式策略处理器框架,该框架允许第三方软件销售商创建更多策略。如果必须修改策略的话,那么通常来说,我们不必修改应用该策略的应用程序。服务,或者说消息将被发送到“何处”或应从“何处”接收消息。就WebSphere MQ 而言,这是指队列、分配表等。服务可以是指由单个应用程序提供服务的单个目的地,也可以是指目的地列表或消息代理。服务通常定义在储存库(REPOSITORY)中,其可指定到消息发送网络中真实资源的映射。储存库可以定义不同类型的服务。服务由AMI 暗示打开和关闭。储存库可为服务及策略提供定义。如果服务名或策略名在储存库中找不到,或者AMI应用程序没有储存库,那么就可采用集成在AMI 中的定义。将储存库定义保存在XML格式的储存库文件中。这些定义可以通过管理工具进行更改,但只能在Windows 平台上才可获得该管理工具。利用标准文件共享工具或者简单的文件发送,我们可以在不同的平台上共享储存库文件。重要的是要明确AMI 应用程序不管具备或不具备储存库时都可以运行。如果没有储存库,那么就将使用默认值。在管理工具中,被称为“服务点”(service point)的单个定义可代表储存库中发送者和接收者的定义。利用管理工具,我们可以界定义如下对象:服务点分配表发布者预订者策略不管有无相对应的储存库定义,我们都可以创建策略以及除分配表之外的服务。只有在创建服务点之后才可创建分配表。利用储存库创建服务或策略时,必须包含专用类型的定义,其命名应与应用程序所指定的名称相对应。举例来说,创建名为“ORDERS”的发送者对象时,储存库必须有一个名为“ORDERS”的服务点定义。利用储存库创建的策略和服务,其内容由称为命名储存库定义进行初始化。无储存库的策略和服务,其内容由在默认系统定义中定义的值进行初始化。管理工具只是WebSphere MQ AMI SupportPac (MA0F)for Windows NT 的一部分,并只能安装在运行Windows NT 4.0 或Windows 2000 的机器上。启动管理工具时,应选择IBM WebSphere MQAMI->IBM WebSphere MQ AMI Administration Tool,或者从Windows 资源管理器中双击文件\amt\AMITool\amitool.bat。下图显示了AMI 管理工具。 图,AMI 管理工具AMI 具有两个不同的角色:管理角色和开发角色。在开发作用中,开发者专注于利用管理员提供的资源发送信息。这一作用不需要深入了解WebSphere MQ。管理作用则负责创建和定义储存库中的服务和策略。换言之,管理员定义信息将被发送到“哪里”以及“如何”发送信息。这一作用要求深入了解WebSphere MQ。利用AMI,简化连接代码以便在发送或接收消息时确定服务或策略。利用管理工具在储存库中定义策略和服务,因此管理员可以修改它们而不会对应用程序造成任何影响。利用AMI,我们可以在下面一种或更多种情况中交换消息:1,与另一个使用AMI 的应用程序交换。2,与使用任何不同WebSphere MQ API (MQI、WebSphere MQ Classes for Java、ActiveX 等)的应用程序交换。3,与消息代理交换(WebSphere MQ 发布/预订或WebSphere MQ Integrator)。AMI 简化了发布/预订应用程序的创建。发布/预订环境中的许多配置都存在储存库中,应用程序从中获取参照。如果程序员希望寻找简单的、毋需深入了解WebSphere MQ 的API,那么我们就会推荐AMI。AMI 可以通过SupportPac (MA0F)获得,也可以从下面的IBM 网站地址中下载:http://www.ibm.com/software/ts/WebSphere MQ/txppacs/;提示:在尝试采用AMI 的发布/预订功能前,必须先安装WebSphere MQ Publish/SubscribeSupportPac (MA0C)。14.2 平台和语言AMI 适用于C、C++和Java 语言。其可应用于以下平台上:Windows NT 和Windows 2000AIX 版本4.3 或更高版本Sun Solaris 2.6 或2.7HP-UX 版本11.0AS/400 版本4R4 或更高版本AMI 也适用于COBOL,但仅限于OS/390 版本2R6 或更高,以及CICS 版本4.1 和IMS版本5.1。AMI 的过程应用程序编程有两个级别:高级:程序C 和COBOL(在OS/390 接口上)。由于操作是隐式的,因此AMI 函数数量减少。对象级:Java 和C++类接口/对象风格C 接口。提示:C 高级接口包括适应大多数应用程序要求的功能。但是,如果我们需要更多的功能的话,那么可以采用C 对象接口和高级接口的组合。AMI 除了可提供简单的接口来处理队列管理器对象外,其对每种编程语言都有一个自然的风格。下例显示了采用C API 的发送-遗忘应用程序。#include <stdio.h>#include <stdlib.h>#include <string.h>#include <amtc.h>#include <time.h>int main(void){/* 创建会话*/hSession = amSesCreate( SAMPLE_SESSION_NAME, &compCode, &reason);hPol = amSesCreatePolicy( hSession, SAMPLE_POLICY_NAME, &compCode, &reason);hSender = amSesCreateSender( hSession, SAMPLE_SENDER_NAME, &compCode, &reason);success = amSesOpen( hSession, hPol, &compCode, &reason);success = amSndOpen( hSender, hPol, &compCode, &reason);success = amSndSend( hSender, hPol, AMH_NULL_HANDLE, AMH_NULL_HANDLE,strlen(sampleMsg), (unsigned char *)sampleMsg, AMH_NULL_HANDLE, &compCode,&reason );success = amSesDelete( &hSession, &compCode, &reason );endSample(EXIT_SUCCESS);}下例中出现的应用程序与上例中的发送-遗忘应用程序相同,不过这回它是用Java API 编写的。请注意,这两种编程语言的每一种都具有自然的风格。例,用Java 编写的简单发送- 遗忘应用程序import java.util.*;import com.ibm.mq.amt.*;. . .public void main(){mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(SAMPLE_SESSION_NAME);myPolicy = mySession.createPolicy(SAMPLE_POLICY_NAME);mySender = mySession.createSender(SAMPLE_SENDER_NAME);mySendMSG = mySession.createMessage(SAMPLE_MESSAGE_NAME);mySession.open(myPolicy);mySender.open(myPolicy);String sampleMessage = new String("Sample message");mySendMSG.writeBytes(sampleMessage.getBytes());mySender.send(mySendMSG);mySender.close(myPolicy);mySession.close(myPolicy);}14.3 库和包现在,我们已经了解了可以用来编写AMI 应用程序的不同编程语言,接下来,我们就必须了解用于编写AMI 应用程序的不同的库。如果利用C 语言来编写应用程序的话,那么AMI 会提供头文件,称为amtc.h。该文件包括AMI 所用的所有函数、结构和常量。该头文件必须包含在应用程序中,我们可以用下面的语句来做到这一点:#include <amtc.h>下图显示了在支持AMI 的不同平台上amtc.h 文件所处的位置。表, AMI C 头文件的位置操作系统平台位置AS400QMQAMI/HUNIX(包括AIX, HP-UX 和Solaris){WebSphere MQ 目录}/amt/incWindows{WebSphere MQ 目录}\amt\includeOS/390hlq.SCSQC370提示:在编译时间内,程序必须能够访问amtc.h 文件。就C++而言,AMI 还可提供另一个头文件,称为amtcpp.hpp。该头文件包括C++的函数、结构和常量,与C 语言的头文件完全一样。同样,amtcpp.hpp 也必须包含在应用程序中。我们同样也可以用下面的语句来实现这一目的:#include<amtcpp.hpp>下表显示了amtcpp.hpp 文件在支持AMI 的不同平台上的位置。表,AMI C++ 头文件的位置操作系统平台位置AS/400(包括AIX、HP-UX 和Solaris)QMQAMI/HUNIX{WebSphere MQ 基目录}/amt/incWindows{WebSphere MQ 基目录}\amt\include提示:在编译时间内,即便amtcpp.hpp 是唯一在使用中的头文件,程序也必须可以访问amtc.h 和amtcpp.hpp 这两个文件。如果开发人员希望使用Java API 的话,那么AMI 可提供包括构成AMI package for Java所有类的JAR 文件。Java 包:com.ibm.mq.amtJava JAR 文件:com.ibm.mq.amt.jar为了使用AMI package for Java,我们必须利用导入语句将其导入Java 应用程序:import com.ibm.mq.amt.*;提示:JAR 文件必须是CLASSPATH 环境变量的一部分(这必须在编译和运行Java 应用程序的环境中完成)。下表显示了AMI JAR 文件在支持AMI 不同平台上所处的位置。表, AMI Java JAR 文件的位置操作系统平台位置AS/400/QIBM/ProdData/mqm/amt/Java/libUNIX(包括AIX、HP-UX 和Solaris){WebSphere MQ 基目录}/java/libWindows{WebSphere MQ 基目录}\java\lib下表显示了由AMI 支持的C、COBOL、C++,以及Java 语言编译程序:表,语言编译器操作系统平台所支持的编译器AIX用于C++ 5.0 版本的VisualAgeJDK 1.1.7 和更高OS/400用于Java(5769JV1)的AS/400 Developer Kit用于AS/400(5769CX2)的ILE C用于AS/400(5799GDW)的ILE C++用于C++ for 0S/400(5716CX4)的Visual AgeHP-UXHP aC++ B3910B A.03.10HP aC++ B3910B A.03.04(970930)支持库JDK 1.1.7 和更高OS/390OS/390 C/C++ 版本2(第6 次发行)或更高用于OS/390 & VM 版本2(第1 次发行)或更高的IBM COBOL用于MVS 和VM 版本1(第2 次发行)或更高的IBM COBOLSun SolarisWorkshop Compiler 4.2(带Solaris 2.6)Workshop Compiler 5.0(带Solaris 7)JDK 1.1.7 或更高WindowsMicrosoft Visual C++ Version 6JDK 1.1.7 或更高如欲了解如何在所有支持的语言中准备并运行AMI 应用程序的更多信息,请参见WebSphere MQ 应用程序消息发送接口文档。14.4 体系结构模型AMI 可提供以下对象:会话:用以创建新的AMI 会话,并用以控制事务处理支持。这是在创建和管理所有其他对象(消息、策略、接收者等)前第一个需要初始化的对象。消息:该对象包含消息数据以及发送或接受消息时用到的消息描述符结构。发送者:代表消息发送目的地的一项服务。MQOD 结构包含在该对象中。接收者:代表消息接收来源的一项服务。MQOD 结构也包含在该类中。分配表:包含发送者服务列表,提供目的地列表。发布者:包含发送者服务,其中目的地是一个发布/预订代理。预订者:包含发送者服务,将预订和取消预订消息发送至发布/预订代理,也包括一个接收者服务,接收来自代理的发布内容。策略:定义应当如何处理消息,包括优先级、持久性,以及其是否应包括在工作单元中等项目。发送者、接收者、分配表、发布者和预订者都是服务。直接连接到消息传输层的唯一对象是发送者和接收者。因此,分配表和发布者对象包含发送者,而预订者对象包含发送者和接收者。下图显示了AMI 体系结构模型,并反映了每个对象如何与其他各个对象进行互动。 图, AMI 体系结构模型消息、服务和策略对象是由会话对象创建和管理的。会话对象也提供工作单元的范围。连接、发送者和接收者对象的组合可提供消息的传输。程序员可以利用系统默认提供的消息属性、服务和策略对象,也可以利用管理员定义的、储存在储存库中的属性。除了以上提到的对象之外,AMI 还为C++和Java 提供了更多的对象定义。这些对像包括:会话库:该对象用以创建会话对象。没有会话库,就不能创建会话对象。协助对象和异常对象(Helper and Exception objects)。14.5 用AMI编程本节所用的实例是采用Java接口编写的。如欲了解如何采用其他支持AMI 的编程语言发出调用,请参考应用程序消息发送接口文档。14.5.1 连接到队列管理器正如在其他WebSphere MQ API 中一样,在尝试访问任何队列服务器对象之前,我们都必须连接到队列服务器。我们可以利用两个AMI Java 调用实现这一目的。首先,需要创建新的会话库对象。在此应记住,为了创建会话对象,必须至少有一个会话库对象(这只适用于C++和Java)。用来创建会话库的命令是:SessionFactoryObject = new AmSessionFactory(String factoryName)FactoryName 是一个可选参数。该字符串实际上就是储存库和主文件所在的目录,其也可以是完全指定的目录,包括文件所在的路径,例如:C:\Program Files\WebSphere MQ\amt。如果该参数没有指定,那么我们将使用AMT_DATA_PATH 环境变量所指定的值。该环境变量通常是在WebSphere MQ AMI SupportPac(MA0F)安装时设定的。创建会话库对象之后,我们可以定义新的会话对象。通过利用AmSessionFactory 类的createSession()方法来进行这一工作。mySessionFactory.createSession(String sessionName)sessionName 参数是我们可以用来确定会话对象的名。一旦会话库初始化且创建了会话对象,应用程序就可以处理WebSphere MQ 对象了。在AMI 中,队列管理器名是从位于{WebSphere MQ 基目录}/amt 的主文件(默认情况下是amthost.xml)中读取的。下面显示了用来连接到称为ITSOH 队列管理器的主文件样例。如果defaultConnection 标签没有指定队列管理器的话,那么将采用默认的队列管理器。例, 主文件样例<?xml version=”1.0” encoding=”UTF-8” ?><queueManagersNames defaultConnection=”ITSOH”connectionName1=”queueManagerName1” connectionName2=”queueManagerName2” />下例显示了如何创建AmSessionFactory 对象,以及名为ITSO 的AmSession 对象。例,创建新对象private AmSessionFactory mySessionFactory = null;private AmSession mySession = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO”);一旦创建了会话,我们在创建其他AMI对象时所采用的顺序就并不重要了。但是,我们建议您以如下顺序对对象进行初始化:1. 会话2. 策略3. 发送者/接收者/发布者/预订者/分配表4. 消息14.5.2 打开WebSphere MQ对象创建会话库和会话对象之后,下一步应创建/初始化其他AMI 对象。14.5.2.1创建策略首先,我们需要创建策略对象。我们可以利用AmSession 类的createPolicy()方法来达到这一目的。sessionObject.createPolicy(String policyName)如果我们所指定的policyName 与储存库中已经存在的策略名相匹配,那么将会采用储存库定义来创建策略。如果储存库中不存在这种策略名,则将采用默认值创建策略。在下例中,我们可以看到如何创建AMT.SAMPLE.POLICY。由于储存库已经定义了AMT.SAMPLE.POLICY,因此该策略将用储存库已定义的值进行创建。例,创建策略对象public static void main(){AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);}创建策略之后,下一步就是根据应用程序要采用的设计模式来创建对象模式。对象类型可以是:发送者和/或接收者(也称服务点)发布者预订者分配表14.5.2.2创建发送者为了创建发送者对象,我们要用到会话对象的createSender()方法。sessionObject.createSender(String senderName);如果指定的senderName 与储存器中已存在的相匹配,那么将采用储存器中的定义来创建发送者对象。如果不存在的话,那么将采用默认值来创建发送者。下例显示了如何创建一个称为AMT.SENDER.NAME 的发送者。例,创建发送者AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);mySender = mySession.createSender(“AMT.SENDER.NAME”);14.5.2.3创建接收者为了创建接收者对象,我们要用到会话对象的createReceiver()方法。sessionObject.createReceiver(String receiverName);如果我们指定的receiverName 与储存器中已经存在的相匹配,那么将采用储存器中的定义来创建接收者对象。如果不存在的话,将采用默认值来创建接收者。下例显示了如何创建一个称为MT.RECEIVER.NAME 的接收者。例, 创建接收者AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;AmReceiver myReceiver = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);myReceiver = mySession.createReceiver(“AMT.RECEIVER.NAME”);14.5.2.4创建发布者为了创建发布者对象,我们要用到会话对象的createPublisher()方法。sessionObject.createPublisher(String publisherName);如果我们指定的publisherName 与储存器中已经存在的相匹配,那么将采用储存器中的定义来创建发布者对象。如果不存在的话,那么将采用默认值来创建发送者。发布者和预订者所用的发送者和接收者点的服务类型必须在储存库中定义为MQRFH。这就会产生MQRFH 标题,包含发送/预订名/值等因素,这些将在消息发送时被加到消息中。如欲了解更多信息,请参见应用程序消息发送接口文档。下例显示了如何创建称为AMT.PUBLISHER.NAME 的发布者。例,创建发布者AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;AmPublisher myPublisher = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);myPublisher = mySession.createPublisher(“AMT.PUBLISHER.NAME”);14.5.2.5创建预订者为了创建预订者,我们要用到会话对象的createSubscriber()方法。sessionObject.createSubscriber(String subscriberName);如果我们指定的subscriberName 与储存器中已经存在的名称相匹配,那么将采用储存器中的定义来创建预订者对象。如果不存在,将采用默认值进行创建。下例显示了如何创建一个称为AMT.SAMPLE.SUBSCRIBER 的预订者。例, 创建预订者public static void main(){ . . .AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);mySubscriber = mySession.createSubscriber(“AMT.SAMPLE.SUBSCRIBER”);}14.5.2.6创建分配表为了创建分配表对象,我们要用到会话对象的createDistributionList()方法。sessionObject.createDistributionList(String distributionlistName);如果我们指定的分配表名与储存器中已经存在的相同,那么将采用储存器中的定义创建对象。如果不存在,将采用默认值创建分配表。在我们能使用分配表之前,管理员必须首先定义发送者服务,再将这些服务定义为分配表的一部分。下例显示了应当如何创建分配表。例,创建分配表public static void main(){AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);mySender = mySession.createDistributionList(“AMT.DISTRIBUTION.LIST”);}14.5.2.7创建消息为了创建消息对象,我们要用到以下AmSession 类的createMessage()方法。AmSession.createMessage(String messageName)对应用程序而言,MessageName 是具有意义的名称。下例显示了一段代码样例,告诉我们如何创建称为ITSO.SAMPLE.MESSAGE.NAME 的消息。例, 创建消息对象public static void main(){AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;AmPolicy myPolicy = null;AmMessage mySendMSG = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);mySender = mySession.createSender(“AMT.SENDER_NAME”);mySendMSG = mySession.createMessage(“ITSO.SAMPLE.MESSAGE.NAME”);}现在我们已经创建了对象,那么下一步就要打开这些已被定义的对象。利用open()方法来进行这一工作。举例来说,如果需要打开发送者对象,那么就要用到该发送者对象的open()方法。所有的打开调用都分享一个共同的参数,这就是策略对象,open()方法的语法如下:AmSession.open(AmPolicy policyObject);AmSender.open(AmPolicy policyObject);AmReceiver.open (AmPolicy policyObject);AmPublisher.open(AmPolicy policyObject);AmSubscriber.open(AmPolicy policyObject);下例显示了如何打开会话、发布者和接收者对象。例,打开不同类型的对象myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);mySession.open(myPolicy);myPublisher.open(myPolicy);myRespReceiver.open(myPolicy);14.5.3 基本操作下面讨论可对这些WebSphere MQ 对象进行哪些基本操作。这些基本操作包括获取消息、发送消息、发布和预订消息。可以在MQI 中发送或接收消息之前,我们必须先打开队列,以获得输入或输出。在MQI中,这被称为打开选项(MQOO_INPUT_SHARED, MQOO_OUTPUT)。在AMI 中,由管理员给出这些定义,并将其保存在储存库中,因此在队列管理器对象打开或作为一部分调用的时候,程序员不必对其做明确的定义。发送消息为了发送消息,我们要用到发送者类的send()方法。请记住,在尝试发送消息之前,必须创建至少四个对象(会话、策略、消息和发送者)。如果我们需要获得回复的话,那么还必须创建接收者对象和另外的消息对象。消息内容总是以字节形式发送的(Java 的本身形式),因此我们建议您在发送消息前用getBytes()方法(Java 的本身方法)将消息转化成字节数组。一旦转化消息,接下来就应当利用发送者类的writeBytes()方法将其写入消息对象中。senderObject.send(AmMessage messageObject, AmReceiver receiverObject/AmMessagereceivedMessage, AmPolicy policyObject)另外,我们可以指定策略对象和/或接收者或另一消息对象。请记住,策略是指“如何”处理消息。换言之,我们利用策略可以指定优先级,或者说如果送达消息时出现错误的话,那么应当采取哪些行动,等等。如果我们要求某种类型的回复,比如送达报告确认或远程应用程序的确认,那么我们就必须根据希望如何处理回复而指定接收者对象或消息对象。下例显示了发送消息样例方法。例,发送消息样例public static void main(){AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;AmSender mySender = null;AmMessage mySendMSG = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);mySender = mySession.createSender(“AMT.SENDER_NAME”);mySendMSG = mySession.createMessage(“ITSO.SAMPLE.MESSAGE.NAME”);String sampleMessage = new String("Sample message");mySendMSG.writeBytes(sampleMessage.getBytes());mySender.send(mySendMSG);}我们也可以同时将消息发送到多个目的地。我们可以利用distributionList 对象的send()方法做到这一点。下例显示了将消息样例发送到多个目的地的实例的方法。例, 将一条消息发送到多个目的地public static void main(){AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;AmDistributionList myDistributionLst = null;AmMessage mySendMSG = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);myDistributionLst = mySession.createDistributionList(“ITSO.DISTRIBUTION.LIST”);mySendMSG = mySession.createMessage(“ITSO.SAMPLE.MESSAGE.NAME”);String sampleMessage = new String("Sample message");mySendMSG.writeBytes(sampleMessage.getBytes());myDistributionList.send(mySendMSG);}获取消息为了获取消息,我们要用到接收者类的receive()方法。amReceiver.receive(AmMessage messageObject, AmSender senderObject, AmMessageselectionmessageObject, AmPolicy policyObject);要该调用中有4 个参数,但其中只有messageObject 是始终需要的。接收的消息将被储存在此参数中。如果发送应用程序请求回复的话,那么就必须指定senderObject。PolicyObject 用来指定等待时间间隔,或是否要求数据转换等。如果我们需要根据关联性ID(correlation ID)获得某个特定消息的话,那么就必须指定selectionmessageObject。下例显示了如何接收消息。例,接收消息public static void main(){AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;AmReceiver myReceiver = null;AmMessage myReceiveMSG = null;AmMessage mySendMSG = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“ITSO.SAMPLE.POLICY”);myReceiveMSG = mySession.createMessage(“ITSO.SAMPLE.MESSAGE.NAME”);myReceiver.receive(MyReceiveMSG);String sampleMessage = newString(MyReceiveMSG.readbytes(myReceiveMSG.getDataLength()));}发布消息发布消息时,应当遵从以下几个步骤。一旦打开消息和发布者对象,就需要为消息创建新主题。该主题就是描述将要发布数据的词。我们用消息类的addTopic()方法创建主题。messageObject.addTopic(String topicName)唯一所需的参数就是topicName,正如我们前面谈到的那样,其为描述将要发布数据的词。添加主题之后,我们就可以发布消息了。为了发布消息,要用到发布者类的publish()方法。publisherObject.publish(AmMessage messageObject, AmReceiverreceiverObject, AmPolicy policyObject)messageObject 是包含将发布消息的对象。只有在策略不指定发布者的隐式注册(implicit registration)的情况下,才可以省略receiverObject。总是应当指定MessageObject。如果没有指定policyObject,将采用默认定义。下例显示了如何发布消息的样例代码。在该例中,没有指定policyObject;因此我们将采用默认定义。默认定义不要求发布者的隐式注册,因此不要求receiverObject。例, 发布一条消息string pubMessage=”SUNNY”;mySendMSG.addTopic(“Weather”);mySendMSG.writeBytes(pubMessage.getBytes());myPublisher.publish(mySendMSG);预订消息为了预订消息,应用程序应当就感兴趣的信息发送请求。我们通过在请求中包含主题来实现这一目的。一旦请求完成,预订者就可以接收来自许多不同发布者的信息,而且也可以将接收到信息发送给其他的预订者。为了在请求中包括主题,我们可以使用消息类的addTopic()方法。messageObject.addTopic(String topicName)topicName 是确认数据的一个名,该数据对预订者应用程序有用。对应用程序希望预订的每个主题,都必须使用该调用。一旦应用程序定义了所有主题,就用预订者类的subscribe()方法发送预订请求。subscriberObject.subscribe(AmMessage messageObject, AmReceiverreceiverObject, AmPolicy policyObject)messageObject 是我们利用addTopic()方法向其添加主题的对象。该参数是可选的。将匹配预订请求的发布内容发送到receiverObject。但是,该参数并不总是需要的。另一种接收匹配请求的发布信息的方法就是发出预订类的receive()方法。可以确定,也可以不指确定PolicyObject。如确定,那么策略就包含匿名注册、仅接收新发布内容等选项。如果未确定的话,那么将采用默认策略。如果receiverObject 在预订请求中未确定的话,那么可以利用receive()方法接收发布内容。subscriberObject.receive(AmMessage messageObject, AmMessageselectionmessageObject, AmPolicy policyObjectmessageObject 将包含所有已发布的消息,并在消息接收前进行隐式重置。只有在我们希望根据关联性ID 选择某个特定消息时才采用selectionMessageObject。如果未确定的话,那么就接收第一个可用的信息。可以确定PolicyObject,也可以不确定。一旦我们接收了符合预订请求所确定标准的所有消息,或者说我们不需要更多的消息了,那么应用程序就可以取消预订,换言之,应用程序此时可以发出请求,这样就不会再发送更多的消息了。应用程序可以发送一个请求,取消预订其最初请求的所有主题,也可仅取消预订某个特定主题。通过发出预订类的unsubscribe()方法,我们可实现这一目的。subscribeObject.unsubscribe(AmMessage messageObject, AmReceiverreceiverObject, AmPolicy policyObject)messageObject 包含取消预订请求所应用的主题。如需要获得取消预订请求的确认,那么必须发出receiverObject。正如前面的调用一样,可以确定策略,也可以不确定。下例显示了如何应用我们在本节所讨论的这些调用。例,预订消息int iCounter = 0;String topic = ”Weather”;mySendMSG.addTopic(“Weather”);mySubscriber.subscribe(mySendMSG, myPolicy);// Only 5 messages are expectedfor (iCounter = 0; iCounter < 5; iCounter++)mySubscriber.receive(myReceiveMSG, myPolicy);String myRequest = newString(myReceiveMSG.readBytes(myReceiveMSG.getDataLength()));System.out.println(myRequest);// The application has received all the messages that it wanted so it proceeds// to send an unsubscribe request.mySubscriber.unsubscribe(mySendMSG, myPolicy);14.5.4 删除会话并关闭连接我们对队列管理器应用程序的工作完成之后,接下来就可关闭对象了。我们利用每个被用对象的close()方法来实现这一目的。另一种方法就是仅关闭会话对象。一旦关闭该对象,其他对象也将关闭。但是,我们强烈建议您隐式关闭所有已打开的对象。subscriberObject.close(AmPolicy policy Object);sessionObject.close(AmPolicy policy Object);receiverObject.close(AmPolicy policy Object);publisherObject.close(AmPolicy policy Object);distributionlistObject.close(AmPolicy policy Object);所有这些close()方法需要的唯一一个参数就是policyObject。请记住,policyObject也包含关闭选项,如关闭时删除动态队列等。如欲了解更多信息,请参见WebSphere MQ 应用程序消息发送接口文档。提示:最后一个必须关闭的对象是sessionObject。一旦关闭sessionObject,其他参照都会无效。14.6 AMI和MQI的比较我们已经讨论了WebSphere MQ 所提供的不同API,现在,我们可以谈谈它们彼此之间的比较。在这一节中,我们将对AMI 和MQI 进行比较。利用MQI,消息目的地和消息的发送/接收选项均由应用程序管理,而利用AMI,则由策略管理。MQI 提供全部WebSphere MQ 函数支持,只考虑消息传输。AMI 提供较少的WebSphere MQ 函数,但提供更多的功能性。MQI 的编程接口属低级的(动词较少,但有很多结构),对不同语言(C、C++、Java和COBOL)来说,其API 都是相似的。AMI 具有高级编程接口,这意味着其动词更多,而结构更少,而且其API 对每种不同的编程语言都有各自自然的风格。MQI 根据传输而不同,AMI 则独立于传输。MQI 是IBM 的所有,而AMI 的子集符合开放应用程序组/开放应用程序中间件API 标准(C++和Java)。14.7 事务处理管理为了使AMI 发送和接收的消息成为事务处理工作单元的一部分,管理员必须利用AMI管理工具指定策略的同步点属性。在默认情况下,将同步点属性设为关闭。我们可以在策略定义的General 标签中找到该属性。控制事务处理的API 调用取决于正被使用的事务处理类型。此处有两种不同的情况:当唯一的资源是WebSphere MQ 消息时:在这种情况中,根据策略中就发送或接收对象所确定的那样,事务处理由同步点控制下第一个发送或接收的消息来启动。多个消息可以包括在同一工作单元中。可以用会话对象的commit()方法提交事务处理,或者也可以用会话对象的rollback()方法取消事务处理。下例显示了WebSphere MQ 消息作为唯一资源的同步点控制实例。例,同步点控制public static void main(){AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;AmReceiver myReceiver = null;AmMessage myReceiveMSG = null;AmMessage mySendMSG = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“ITSO.SAMPLE.POLICY”);myReceiveMSG = mySession.createMessage(“ITSO.SAMPLE.MESSAGE.NAME”);myReceiver.receive(MyReceiveMSG);// If no failures were found commit the actionmySession.commit(myPolicy);String sampleMessage = newString(MyReceiveMSG.readbytes(myReceiveMSG.getDataLength()));// If some problems were found, don’t retrieve the messagemySession.rollback(myPolicy);}WebSphere MQ 作为XA 事务处理协调器(XA transaction coordinator)在可恢复资源(如关系数据库)发生改变之前,须用AmSession 类的begin()方法显式启动事务处理。而后,可以用AmSession 类的commit()方法提交工作单元,或者用AmSession 类的rollback()方法予以取消。下例显示了WebSphere MQ作为XA 事务处理协调器的实例。例,WebSphere MQ 作为XA 事务处理协调器public static void main(){AmSessionFactory mySessionFactory = null;AmSession mySession = null;AmPolicy myPolicy = null;AmSender mySender = null;AmMessage mySendMSG = null;mySessionFactory = new AmSessionFactory();mySession = mySessionFactory.createSession(“ITSO.SESSION.NAME”);myPolicy = mySession.createPolicy(“AMT.SAMPLE.POLICY”);mySender = mySession.createSender(“AMT.SENDER_NAME”);mySendMSG = mySession.createMessage(“ITSO.SAMPLE.MESSAGE.NAME”);mySession.Begin(myPolicy);// Update a table.// If the update was successful then commit the action and send a message to// another applicationString sampleMessage = new String("Sample message");mySendMSG.writeBytes(sampleMessage.getBytes());mySender.send(mySendMSG);mySession.commit(myPolicy);// If problems occurred during the update, backout the changesmySession.rollback(myPolicy);}提示:如果使用外部事务处理协调器(如Tuxedo),就可能出现另一种情况。在这种情况下,我们利用外部事务处理协调器的API 调用来控制事务处理。尽管没有使用AMI调用,但同步点属性仍必须在调用使用的策略中确定。14.8 分组AMI 允许将一系列相关消息包含在消息组中或作为消息组发送。组上下文信息(group context information)随每个消息发送,以使消息系列得以保存,并可由接收程序获得。为了将消息包含在消息组中,组中第一个和后续消息的组状态信息(group status information)必须进行如下设定:第一条消息设为AMGRP_FIRST_MSG_IN_GROUP除第一和最后一条消息外,所有消息均设为AMGRP_MIDDLEMSG_IN_GROUP最后一条消息设为AMGRP_LAST_MSG_IN_GRP我们可以利用消息类的setGroupStatus()实现上述目的。messageObject.setGroupStatus(int groupStatus)groupStatus 可以为下面任何值:AMGRP_MSG_NOT_IN_GROUPAMGRP_FIRST_MSG_IN_GRPAMGRP_MIDDLE_MSG_IN_GRPAMGRP_LAST_MSG_IN_GROUPAMGRP_ONLY_MSG_IN_GROUP如果AMGRP_FIRST_MSG_IN_GROUP 在序列外, 那么该消息的行为与AMGRP_MIDDLE_MSG_IN_GRP 相同。提示:一旦应用程序开始发送在组中的消息,那么在尝试发送不在该组内的任何其他消息之前,必须先发送完该组的消息。14.9本章小结本章概括介绍了应用程序消息接口,讲解什么是AMI 以及如何应用AMI。14.10本章练习1.使用WebSphere MQ AMI 编写文件的发送程序。2.使用WebSphere MQ AMI编写文件的接收程序。