四MQI的主要调用

更新时间:2023-12-20 15:26:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

WebSphere MQ Solution Designer 认证考试 996 准备: 第 4 部分,主要 MQI 调用 Willy Farrell, 高级软件工程师, IBM Developer Skills Program

2007 年 5 月 29 日

准备 IBM 认证考试 996:WebSphere MQ Solution Designer。本教程讨论 Message Queuing Interface (MQI) 中的主要调用,MQI 是用于开发 WebSphere MQ 应用程序的应用程序编程接口 (API)。这是有关 WebSphere MQ Solution Designer 的包括五个教程的系列中的第四个教程。 开始之前

关于本系列

WebSphere? MQ Version 6.0 以一致的、可靠的和易于管理的方式来连接应用程序,并为跨部门、企业范围的集成提供了可靠的基础。通过提供重要消息和事务可靠的“一次且仅一次”的传递,WebSphere MQ 解决了通信协议的复杂性,并在可用资源之间动态分配消息工作负载。这个包括五个教程的系列帮助您准备参加 IBM 认证考试 996:IBM WebSphere MQ V6.0, Solution Design。该认证针对了解异步消息的概念并且能够规划、架构和设计基于 WebSphere MQ 的解决方案的中级设计人员。

关于本教程

本教程是旨在帮助您准备 IBM 认证考试 996:WebSphere MQ V6.0, Solution Design 的系列中的第四个教程。本教程介绍 Message Queuing Interface (MQI) 中的主要调用,包括常规事务调用和用于放置及获取消息的调用。其中还将讨论打开队列、消息描述符和用于控制消息检索的技术。完成本教程后,请继续学习第五个教程,其中介绍了其他 MQI 主题。 目标

完成本教程后,您应该熟悉:

MQI 的常规事务调用:MQCONN、MQOPEN、MQCLOSE 和 MQDISC。 MQPUT 谓词 (verb)。 打开队列。 消息描述符。 MQGET 谓词。 MQPUT1 谓词。 控制消息检索。

先决条件

本教程是为具有应用程序和解决方案设计和实现方面的中级经验的开发人员和架构师编写的。它假设您具有以下几个方面的中级知识和技能:

事务管理和数据库产品 系统管理 基本编程概念 数据通信和网络 信息技术安全概念

系统要求

本教程中的示例使用 WebSphere MQ V6.0 for Windows? 和 Rational? Application Developer V6.0 for Windows 开发。

本教程中使用的产品的系统要求可通过以下链接找到: WebSphere MQ

Rational Application Developer

搜索更多相关主题的帖子: Solution Designer MQI WebSphere 考试 Solution Designer MQI WebSphere 考试

查看详细资料 TOP

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 2# 大 中 小 发表于 2008-7-7 16:46 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 引言

本部分介绍 Message Queue Interface (MQI)。其中列出 MQI 调用,并讨论 MQI 使用的数据类型、结构和常量。本部分还将描述受支持的编程语言,以及如何构建应用程序,并研究可用于消息应用程序的 Java API。

MQI 调用

MQI 是一个简单的高级编程接口,由十三个调用组成。这些调用可划分为主要和次要调用。主要调用是业务应用程序中最常用的调用。次要调用是不太常用的调用。这个区别是非常随意的。

主要调用及其功能包括:

次要调用及其功能包括:

基本数据类型

WebSphere MQ 为 MQI 调用中使用的参数定义了基本数据类型。这些类型被定义为非特定于编程语言的,并为每种受支持的编程语言提供了特定于编程语言的对应定义。

一些较常用的基本数据类型包括:

2008-7-7 16:46

有关基本数据类型以及从 MQI 类型到特定于编程语言的类型的映射的更多信息,请参见 WebSphere MQ 文档库中的 WebSphere MQ Application Programming Reference(请参见参考资料)。

MQI 中使用的结构

有些 MQI 调用参数是包含多个数据字段的数据结构。所有结构都是按照基本数据类型来定义的。

最常用的结构包括:

2008-7-7 16:46

有关数据结构的更多信息,请参见 WebSphere MQ 文档库中的 WebSphere MQ Application Programming Reference(请参见参考资料)。

MQI 常量

WebSphere MQ 还定义了在 MQI 编程中使用的常量。这些常量定义了 MQI 调用中使用的输入和输出参数的有效值。这些符号常量在 MQI 程序中得到广泛使用,并显著改进了那些程序的可读性。大多数常量名称都以一个前缀开头,用于标识其使用场合。例如,以 MQRC_ 开头的常量定义原因代码,以 MQOO_ 开头的常量定义打开选项。

受支持的编程语言

WebSphere MQ 提供了对大量编程语言的支持,包括 C、C++、COBOL、.Net、PL/I、Assembler

和 RPG。有些语言在多种平台上受支持;而诸如 Assembler 和 RPG 等语言则仅在一种平台上受支持(分别为 System z 和 System i)。诸如 REXX 等其他编程语言支持则通过 SupportPac 来提供。

构建 WebSphere MQ 应用程序

由于有如此多的语言和编译器跨许多 WebSphere MQ 平台受到支持,成功的编译和链接过程不仅在平台之间存在差异,而且在语言之间甚至在使用同一语言的不同编译器之间也存在差异。

程序员务必知道要使用哪个编译器,因为编译和链接可能是独特的。有关编译和链接 WebSphere MQ 应用程序的详细信息,请参见 WebSphere MQ 文档库中的 WebSphere MQ Application Programming Guide(请参见参考资料)。

Java API

WebSphere MQ 提供了两个用于构建应用程序的 Java API。

第一个是 WebSphere MQ classes for Java,有时称为 WebSphere MQ base Java。此 API 紧密模仿 MQI,但是由于 Java 的面向对象性质而存在微妙的区别。例如,连接到队列管理器并不涉及到可容易地识别为 MQCONN 调用的调用。相反,将创建一个 MQQueueManager 实例。后续 MQI 调用,例如通常传递将由 MQCONN 返回的连接句柄的 MQOPEN 或 MQCLOSE,将改为使用 MQQueueManager 实例上的方法来发出。

本教程中提供的示例程序使用 WebSphere MQ classes for Java,您将在其中看到 MQI 调用和参数如何映射到 Java 方法和类。

第二个 Java API 是 WebSphere MQ classes for Java Message Service,也称为 WebSphere MQ JMS。此 API 提供了 Java Message Service (JMS) 规范的一种实现。JMS 提供了用于访问任何企业消息系统的标准 API,允许程序员集中于消息应用程序的业务逻辑,并隐藏了基础的实现细节。

当使用 WebSphere MQ JMS 来与非 JMS 的程序通信时,要注意 WebSphere MQ JMS 消息在缺省情况下会携带一个附加标头,非 JMS 程序可能无法处理该标头。当您知道是要将消息发送到非 JMS 程序时,可以省略这个附加标头。 查看详细资料 TOP

在这里,您可以IBM 软件产品下载、Demo下载、试用版下载、红皮书下载、白皮书下载

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 3# 大 中 小 发表于 2008-7-7 16:52 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 MQCONN

概述

在发出任何其他的 MQI 调用之前,应用程序必须首先使用 MQCONN 调用连接到队列管理器。应用程序所连接到的队列管理器是本地 队列管理器。通常,您可以连接到特定的队列管理器或缺省的队列管理器。应用程序通常需要具有相应的权限以连接到队列管理器。

MQCONN 调用的语法如下: 复制内容到剪贴板代码:

MQCONN (QMgrName, Hconn, CompCode, Reason)

MQCONN 调用具有一个输入参数和三个输出参数,如下所示:

队列管理器名称——QMgrName(输入) 应用程序希望连接到的队列管理器的名称。

连接句柄——Hconn(输出) 连接句柄表示到队列管理器的连接,并且对该队列管理器进行的后续 MQI 调用必须指定它作为参数。

完成代码——CompCode(输出) 每个 MQI 调用都会返回一个完成代码,以便应用程序可以快速地判断该次调用是成功完成、部分完成还是失败。

原因代码——Reason(输出) 每个 MQI 调用都会返回一个原因代码,以便在调用部分完成或失败的情况下,为应用程序提供更多的信息。

连接句柄

在连接时返回给应用程序的连接句柄将在所有后续 MQI 调用上使用。应用程序一定不能更改它。有效的句柄是连接成功并且应用程序已被授权使用该队列管理器的指示。

MQCONN 完成和原因代码

所有调用都会产生三个原因代码之一:

2008-7-7 16:52

程序需要在每个调用后检查完成代码,如果出现警告或失败,程序需要检查原因代码,以确定程序是否应该继续。

在尝试 MQCONN 调用时可能出现的一些最常见原因代码包括:

2008-7-7 16:52

不成功的 MQCONN 尝试还可能会返回其他许多可能的原因代码。WebSphere MQ Application Programming Reference(请参见参考资料)中的 MQCONN 调用描述包括了完整的原因代码列表。

在所有调用上,程序员都应该测试三类状态:

一切正常,未报告特殊条件(MQCC_OK 和 MQRC_NONE)。

可能在各个调用上发生的预期特殊条件,它们特定于应用程序;例如,MQGET 上的 MQRC_NO_MSG_AVAILABLE。

意外条件,例如 MQCONNECT 或 MQOPEN 上的 MQRC_NOT_AUTHORIZED。

CICS 连接

CICS (z/OS) 程序不需要发出 MQCONN 调用。CICS 会负责执行连接,因此不存在队列管理器选择。一个 CICS 区域中只能有一个队列管理器。

虽然并不要求这样做,但是在 CICS 程序中包括 MQCONN 可能有助于您通过最少的重新编码来将应用程序移植到非 CICS 环境。请注意,MQCONN 在 CICS 环境中始终成功完成。

批处理连接

大型机环境中的批处理程序必须 发出一个 MQCONN 命令。但是与 CICS 不同,批处理程序可以选择要连接到哪个队列管理器(如果已在系统上设置了多个队列管理器)。务必注意的是,一个批处理程序一般一次只能连接到一个队列管理器。这是大多数其他队列管理器所共有的行为类型。通过向批处理应用程序附加额外的任务控制块 (TCB),可以同时连接到其他队列管理器。然而,WebSphere MQ 不会在 TCB 之间协调同步点操作或资源共享。

IMS 连接

Information Management System (IMS) 提供了连接到多个队列管理器的特殊情况。IMS 程序可以 同时连接到多个队列管理器。只要队列管理器对 IMS 控制区域是已知的,运行于与 IMS 无关的区域中的程序就能连接到该队列管理器,而不管程序是否已经连接到其他的队列管理器。

连接句柄的范围

连接句柄代表到队列管理器的连接。它将在应用程序与队列管理器交互时发出的所有后续调用上使用,直到发出 MQDISC 调用时才不再有效。当定义连接句柄范围的处理单元终止时,连接句柄也不再有效。

连接句柄的范围仅限于所涉及环境中的最小并行处理单元。例如,UNIX、Linux 或 Windows 上的某个线程、某个 CICS 任务、某个 IMS 任务(截止到同步点)、某个批处理任务或 z/OS 下的某个 TSO 任务。在该范围之外使用连接句柄无效。

连接到多个队列管理器

通常,应用程序一次只能连接到一个队列管理器。但是存在一些例外: 在 z/OS 上,批处理、TSO 和 IMS 允许多个并发连接。 在 Windows 上,每个线程可以连接到不同的队列管理器。 客户端应用程序可以在一个线程中连接到多个队列管理器。

用于连接到多个队列管理器的规则在不同的受支持平台和环境之间是不同的,因此它是编写应用程序时的一个重要注意事项。如果存在将来希望移植应用程序的可能性,您需要考虑最受限制的环境,您将在其中针对该环境进行运行和设计。

访问控制

运行在特定用户 ID 下的应用程序可能不允许连接到某个队列管理器。如果访问被拒绝(MQCC_FAILED 和 MQRC_NOT_AUTHORIZED),则应用程序除了向 WebSphere MQ 管理员报告问题外,其他什么事情也做不了。可能需要更改配置文件或访问控制列表。在任何情况下,都不会返回连接句柄,并且让应用程序继续运行是无意义的。

MQCONNX

尽管本教程的主题是 MQI 中的主要调用,而 MQCONNX 调用被视为次要调用,我们还是简要讨论一下它,因为它实际上只是 MQCONN 的变体。

MQCONNX 调用是连接到某些平台上的队列管理器的另一种方法。除了在 MQCONN 调用中传递的那些参数之外,它还提供了另一个参数。此附加参数称为连接选项。

MQCONNX 调用的语法如下: 复制内容到剪贴板代码:

MQCONNX (QMgrName, ConnectOpts, Hconn, CompCode, Reason)

连接选项的用途之一是控制程序连接的方式。当应用程序使用 MQCONN 调用连接到队列管理器时,为每个后续 MCI 调用提供服务而执行的队列管理器代码作为与该应用程序独立的执行单元运行。但是,当应用程序使用 MQCONNX 调用连接到队列管理器时,它可以在调用中指定 fastpath binding 选项。通过使用这个选项,为每个后续 MCI 调用提供服务而执行的队列管理器代码与该应用程序运行于相同的执行单元中。这种安排方式的优点在于,运行应用程序仅需要更少的系统资源。其缺点是,队列管理器的完整性受到损害,因为无法保护其存储空间不会被覆盖。这种应用程序称为受信任的应用程序。

连接选项的另一种用途是客户端使用它来指定希望连接到的特定服务器,从而改写控制服务器连接的任何定义或其他设置。

MQCONNX 还允许您创建共享(与线程无关)的连接,可由某个进程中的所有线程使用。

MQCONN 伪代码

下面的清单 1 是使用 MQCONN 的伪代码 示例。我们将在本教程和下一个教程中使用伪代码,以提供与语言无关的代码用法和技术演示。虽然伪代码显然不是真实的编程语言,但是它允许我们看到代码结构和顺序,而不必束缚于某种特定的语言。

清单 1. MQCONN 示例 复制内容到剪贴板代码:

DEFINE DEFAULT_QMGR AS CONSTANT ' '

DEFINE QMGR AS MQCHAR48

DEFINE CONN_HANDLE AS MQHCONN DEFINE COMP_CODE AS MQLONG DEFINE REASON_CODE AS MQLONG

QMGR = DEFAULT_QMGR

CALL MQCONN(QMGR, CONN_HANDLE, COMP_CODE, REASON_CODE)

IF COMP_CODE NOT = MQCC_OK

write an error message detailing the REASON_CODE terminate the program STOP END-IF

该代码首先将一个用于缺省队列管理器名称的常量定义为一个空字符串。在 MQCONN 中为队列管理器名称传递空字符串将导致连接到系统上的缺省队列管理器。

然后是定义用于保存队列管理器名称、连接句柄、完成代码和原因代码的变量。

然后是将缺省队列管理器名称常量赋值给队列管理器名称变量,并发出 MQCONN 调用。

调用完成后,该代码检查完成代码,如果完成代码不是 MQCC_OK,则写入错误消息并终止程序。

查看详细资料 TOP

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 4# 大 中 小 发表于 2008-7-7 16:58 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 MQOPEN 概述

在应用程序能够将消息放置到队列上或从队列获取消息之前,它必须首先通过发出 MQOPEN 调用来打开队列。

MQOPEN 调用的语法如下: 复制内容到剪贴板代码:

MQOPEN (HConn, ObjDesc, Options, Hobj, CompCode, Reason)

MQOPEN 调用的有些参数在前面没有描述,它们分别是:

对象描述符——ObjDesc (输入/输出) MQI 中定义的结构之一。它的用途是标识打开的对象。它包含许多字段,其中有些字段可以指定所打开的对象的名称和对象的类型。

选项——Options(输入) 由应用程序用于指定它希望在所打开的对象上执行哪些操作,或用于控制 MQOPEN 的操作。示例包括打开队列以便放入消息,打开队列浏览消息,以及打开队列查询其部分或所有属性。通过将多个选项加在一起,或者通过使用按位 OR 操作来组合它们,应用程序可以指定多个选项。

对象句柄——Hobj(输出) 表示已建立的到对象的访问,并且必须在操作该对象的所有后续 MQI 调用上将其指定为参数。

对象句柄

与从 MQCONN 返回的连接句柄一样,对象句柄由 MQOPEN 返回,并表示已建立的到该队

MQPUT 调用的语法如下: 复制内容到剪贴板代码:

MQPUT (Hconn, Hobj, MsgDesc, PutMsgOpts, BufferLength, Buffer, CompCode, Reason)

可以看到,在这个调用上传递的参数数量大于常规事务调用(MQCONN、MQOPEN、MQCLOSE、MQDISC)的参数数量。其中有些参数应该是很熟悉的,例如 Hconn、Hobj、CompCode 和 Reason,因为常规事务调用中已使用过它们。

Buffer 和 BufferLength 参数分别包含应用程序数据(消息)和应用程序数据的长度。

下面讨论消息描述符 (MsgDesc) 和放置消息选项 (PutMsgOpts)。

消息描述符

消息描述符(MQMD 结构)封装了消息的属性。它可由应用程序或由队列管理器更新。在许多情况下,应用程序允许队列管理器在发出 MQPUT 时简单地提供缺省值(例如取自队列定义)。

消息描述符中的一些更重要字段包括:

放置消息选项

放置消息选项(MQPMO 结构)控制如何将消息放置到队列上。放置消息选项的一些字段如下:

MQPUT 原因代码

MQPUT 返回的一些原因代码如下:

MQPUT 伪代码

下面的清单 5 包含了 MQPUT 调用的伪代码。

清单 5. MQPUT 示例 复制内容到剪贴板代码:

DEFINE DEFAULT_QMGR AS CONSTANT ' '

DEFINE QMGR AS MQCHAR48

DEFINE CONN_HANDLE AS MQHCONN DEFINE COMP_CODE AS MQLONG DEFINE REASON_CODE AS MQLONG DEFINE OBJ_DESC AS MQOD

DEFINE MYQUEUE_HANDLE AS MQHOBJ DEFINE OPEN_OPTIONS AS MQLONG DEFINE CLOSE_OPTIONS AS MQLONG DEFINE MESSAGE_DESCRIPTOR AS MQMD DEFINE PUT_OPTIONS AS MQPMO

DEFINE MESSAGE_LENGTH AS MQLONG DEFINE MESSAGE AS CHAR100

QMGR = DEFAULT_QMGR

CALL MQCONN(QMGR, CONN_HANDLE, COMP_CODE, REASON_CODE)

IF COMP_CODE NOT = MQCC_OK

write an error message detailing the REASON_CODE terminate the program STOP END-IF

OBJ_DESC.ObjectType = MQOT_Q OBJ_DESC.ObjectName = 'MYQUEUE'

OBJ_DESC.ObjectQMgrName = DEFAULT_QMGR

OPEN_OPTIONS = MQOO_OUTPUT + MQ00_FAIL_IF_QUIESCING

CALL MQOPEN(CONN_HANDLE, OBJ_DESC,

OPEN_OPTIONS, MYQUEUE_HANDLE, COMP_CODE, REASON_CODE)

IF COMP_CODE NOT = MQCC_OK

write an error message detailing the REASON_CODE terminate the program STOP END-IF

MESSAGE_LENGTH = 11

MESSAGE = 'Hello World'

CALL MQPUT(CONN_HANDLE, MYQUEUE_HANDLE, MESSAGE_DESCRIPTOR, PUT_OPTIONS, MESSAGE_LENGTH, MESSAGE, COMP_CODE,

REASON)

IF COMP_CODE NOT = MQCC_OK

write an error message detailing the REASON_CODE terminate the program STOP END-IF

CLOSE_OPTIONS = MQCO_NONE

CALL MQCLOSE(CONN_HANDLE, MYQUEUE_HANDLE, CLOSE_OPTIONS, COMP_CODE, REASON_CODE)

IF COMP_CODE NOT = MQCC_OK

write an error message detailing the REASON_CODE terminate the program STOP END-IF

CALL MQDISC(CONN_HANDLE, COMP_CODE, REASON_CODE)

IF COMP_CODE NOT = MQCC_OK

write an error message detailing the REASON_CODE terminate the program STOP END-IF

请注意为 MQPUT 调用定义的变量(MESSAGE_DESCRIPTOR、PUT_OPTIONS、MESSAGE_LENGTH 和 MESSAGE)。该伪代码没有设置消息描述符的任何字段,也没有设置放置消息选项,而是接受那些结构的缺省值。 查看详细资料 TOP

在这里,您可以IBM 软件产品下载、Demo下载、试用版下载、红皮书下载、白皮书下载

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当

前离线 7# 大 中 小 发表于 2008-7-7 17:20 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 消息创建示例代码

清单 5 提供了一个完整(尽管不是相当有用)程序的伪代码。它连接到一个队列管理器,打开一个队列,在该队列上放置一个消息,然后关闭该队列,并断开与队列管理器的连接。在本部分中,您将研究一些用 Java 编写的实际代码,并运行该代码以查看其实际工作情况。

在继续之前,您需要安装 IBM Rational Application Developer v6.0 (Application Developer)。请参见参考资料以获得指向 Application Developer 试用版的链接。在下载试用版时,您只需下载标记为必需的文件;您不需要任何标记为可选的文件。在安装 Application Developer 时接受所有缺省设置。

下载示例代码

将包含示例代码和配置文件的 .zip 文件 wes-cert9964samples.zip 下载到系统上(请参见 samples02.zip (9.97 KB) samples02.zip (9.97 KB)

下载次数: 1

2008-8-27 16:20下载)。将该文件的内容提取到系统上的某个文件夹中。提取之后,您将拥有四个文件:MQMajor.zip、setup01.txt、setup02.txt 和 setup03.txt。

将三个设置文件复制到您的用户目录,即打开命令提示符时的缺省目录。通常,该目录为 \\Documents and Settings\\Administrator or \\Documents and Settings\\

导入示例代码

若要将示例代码导入 Application Developer:

1.从“开始”菜单中启动 Application Developer。

2.在提示选择工作区时接受缺省工作区,然后单击 OK。 3.从主菜单中,单击 Window >Open Perspective > Java。 4.从主菜单中选择 File > Import...。

5.选择 Project Interchange 并单击 Next。您的屏幕应该与图 1 类似。您系统上的 Project location root: 字段可能不同;这没有问题。

图 1. Import Project Interchange Contents

6.单击 From zip file: 字段旁边的 Browse...,导航到您解压缩下载的示例代码的文件夹,选择 MQMajor.zip。您的屏幕应该与图 2 类似。(在我的系统上,我将该文件解压缩到一个名为 wes-cert9964samples 的文件夹;如果您使用不同的文件夹,那没有问题)。

图 2. 选择 MQMajor.zip 以打开用于导入

7.单击 Open。

8.选择 Select All,然后选择 Finish。

9.在 Package Explorer 视图中展开 MQMajor,再展开 com.ibm.cert996,以显示示例代码类。您的屏幕显示应该与图 3 类似。

图 3. 展开的 MQMajor 项目

10.双击 MQPUT.java。

检查示例代码

让我们研究一下该示例代码,看看它在做什么。我们将分成很小的部分来逐一仔细检查该代码,并讨论每个部分在做什么。类声明以及一些已声明的常量和 main() 方法如下面的清单

6 所示。

清单 6. MQPut.java 类声明 复制内容到剪贴板代码:

public class MQPut { private static final String qManager = \private static final String qName = \

此代码定义了两个常量字符串来指定队列管理器和队列。main() 方法不过就是创建该类的实例,并调用其 run() 方法。run() 方法是该类中唯一的其他方法,我们将在此检查过程的其余部分研究它。

看一下清单 7 中的 run() 方法的前几行。

清单 7. run() 方法的开头 复制内容到剪贴板代码:

public void run() { System.out.println(\MQPut\try { MQQueueManager qMgr = new MQQueueManager(qManager); int openOptions = MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING; MQQueue queue = qMgr.accessQueue(qName, openOptions); MQPutMessageOptions putOptions = new MQPutMessageOptions(); putOptions.options = MQC.MQPMO_NO_SYNCPOINT + MQC.MQPMO_FAIL_IF_QUIESCING;

首先,此代码将一条指示程序已启动的消息打印到控制台上。

然后它创建一个 MQQueueManager 对象,并传入队列管理器的名称。这提供了到队列管理器的连接,并提供了与 MQOPEN 调用相同的功能。

然后它将值 MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING 赋值给一个整数。此整数将在打开队列时用作打开选项。WebSphere MQ base Java 提供了一个类 MQC,其中包含了在 WebSphere MQ 编程中使用的符号常量。这些常量名称与 WebSphere MQ 手册所记录的常量名称相同。

然后调用 qMgr 对象的 accessQueue() 方法,并将队列名称和打开选项作为参数来传递。accessQueue() 提供了与 MQOPEN 相同的功能。

此程序在连接到队列管理器以后和打开队列以后都不检查完成代码和原因代码。WebSphere MQ base Java 不会在每个调用后返回这些代码。相反,如果出现错误,则会引发一个异常 (MQException)。如果遇到错误,程序员必须捕获此异常,其中包含完成代码和原因代码。

接下来是创建并初始化一个 MQPutMessageOptions 对象,以便消息在放置时不处于同步点的控制之下,并且在队列管理器正在关闭时使放置消息操作失败。

如清单 8 所示的下几行代码是此程序的核心。

清单 8. 读取文件和放置消息 复制内容到剪贴板代码:

BufferedReader br = new BufferedReader(new FileReader( \String line = null; while ((line = br.readLine()) != null) { MQMessage msg = new MQMessage(); msg.messageType = MQC.MQMT_DATAGRAM; msg.writeUTF(line); msg.messageId = MQC.MQMI_NONE; msg.correlationId = MQC.MQCI_NONE; queue.put(msg, putOptions); }

这里打开了一个文件 testdata.txt 来进行读取。然后声明了一个变量 (line) 来包含从该文件读取的每一行内容,之后进入一个循环,此循环读取该文件的每一行,并在没有其他行可供读取时终止。

在此循环中,代码创建并初始化了一个 MQMessage 对象:消息类型设置为数据报,消息 ID 和相关性 ID 设置为无。而且,从该文件读取的行的内容还作为应用程序数据“写入”消息中。(WebSphere MQ base Java 分别使用“写入”和“读取”来将应用程序数据分配给消息和从消息获取应用程序数据。)最后,此代码将消息放置到队列上。与前面一样,这可能与您从简单的 MQI 过程转换中预期看到的结果并不完全相同。然而,它遵循了与清单 5 中的伪代码相同的基本步骤,只不过采用了最适合 Java 语言的面向对象方式。

从该文件读取所有的行并将其放置到队列上以后,队列被关闭,应用程序断开与队列管理器的连接,如清单 9 所示。

清单 9. 关闭队列并断开与队列管理器的连接 复制内容到剪贴板代码:

queue.closeOptions = MQC.MQCO_NONE; queue.close(); qMgr.disconnect();

下面的清单 10 显示了在其中捕获并显示 MQException 的 catch 块。最后,在程序完成后,向控制台打印一条关于该异常的消息。

清单 10. 异常处理和程序结束 复制内容到剪贴板代码:

} catch (MQException mqex) { System.out .println(\Code \catch (FileNotFoundException fnfex) { fnfex.printStackTrace(); } catch (IOException ioe) { ioe.printStackTrace(); } System.out.println(\ 运行示例代码

现在让我们运行此代码!这里的说明假设您已经遵循了本系列第 2 部分中的说明。

1.打开一个 Windows 命令提示符。 2.输入 strmqm 并按 Enter。 3.队列管理器启动以后,键入 runmqsc < setup01.txt 并按 Enter。您的屏幕显示应该与图 4 类似。

图 4. 队列管理器已启动和配置

4.可以看到,setup01.txt 包含 MQSC 命令,以创建一个其名称与 MQPUT.java 中使用名称匹配的队列。

5.关闭 Windows 命令提示符。

6.在 Application Developer,从主菜单上选择 Window > Show View > Console。

7.在 Package Explorer 视图中,右键单击 MQPut.java,并选择 Run > Java Application。 8.您应该在控制台中看到指示程序已启动和结束的消息。

9.现在让我们使用一个以前还没有使用过的工具来查看队列上的消息。从 Windows“开始”菜单启动 WebSphere MQ Explorer。

10.在 WebSphere MQ Explorer - Navigator 视图中,展开 Queue Managers,然后展开 QMC1,并选择 Queues。您的屏幕显示应该与图 5 类似。

图 5. 显示队列的 WebSphere MQ Explorer

11.在 WebSphere MQ Explorer – Content 视图中右键单击 CERT.TARGET,并选择 Browse Messages...。您应该看到队列上的消息。

12.在 Application Developer 中双击 testdata.txt,并将其内容与队列中的消息进行比较。 13.让 WebSphere MQ Explorer 和 Application Developer 保持运行。

[ 本帖最后由 艾依然 于 2008-8-27 16:20 编辑 ] 查看详细资料 TOP

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 8# 大 中 小 发表于 2008-7-7 17:23 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 打开队列

本部分讨论打开不同队列类型的队列的一些方面。

队列独立性

当程序发出 MQOPEN 时,它始终将所打开的对象视为本地的。队列管理器将解析所打开的对象的名称。

如果所打开的队列名称已定义为另一个系统上某个队列的远程定义,则队列管理器将负责使用管理员创建的定义来确保将消息放在正确的传输队列上,并确保消息中包含必要的路由信息以支持在远程端传递。此讨论仅与放置信息有关;您无法从远程队列获取消息。

如果所打开的队列名称是别名,同样是队列管理器负责将该名称解析为本地或远程队列的定义,并正确地传递该消息。

程序确实不知道所打开的队列是本地队列、别名队列还是另一个系统上的队列的远程定义。

别名队列

别名队列只是一个定义。它允许通过另一个名称来引用某个本地或远程队列。别名队列可以具有与它所指向的基础队列不同的属性。例如:

DEFINE QLOCAL(REALQ) GET(ENABLED) PUT(ENABLED

DEFINE QALIAS(MYNAME) TARGQ(REALQ) GET(DISABLED)

允许访问名为 REALQ 的队列的程序的 GET 和 PUT 消息。然而,如果程序打开名为 MYNAME 的队列,则只允许 PUT 消息。GET 将被禁用,尽管两个程序实际上使用的是同一个队列 (REALQ)。

务必要理解的是,程序的行为就像名为 MYNAME 的队列是实际队列而不只是指向另一个队列的指针。

队列名称解析

当程序打开队列时,对象描述符包含对象名称,并可选地包含队列管理器的名称。在大多数情况下,对象描述符中的 ObjectQueueManagerName 字段包含空白。如果它的确包含内容,或者包含应用程序所连接到的队列管理器名称,则会搜索本地定义以解析该队列名称。

如果队列管理器名称字段包含另一个队列管理器的名称,则假设此队列管理器是远程的,并搜寻一个可在其中放置 MQPUT 消息的同名传输队列。 模型队列

当管理员定义模型队列时,该定义只是一个模板。当在某个 MQOPEN 的对象描述符中指定模型队列的名称时,将会动态创建一个具有该模型属性的队列。模型本身没有其他用途。在显示新队列的特征时,该队列作为本地队列出现。

临时动态队列 仅持续至创建它的程序执行结束(正常或异常结束),或持续至创建程序关闭它。不存在将临时动态队列保留到该时间点以后的方法。

临时动态队列不能包含持久消息。

持久动态队列 完全以相同的方式创建,但是不会自动删除它们。它们必须通过某个删除关闭选项或由管理员使用删除命令来明确删除。创建之后,WebSphere MQ 并不执行任何特殊操作来跟踪动态创建的永久动态队列。

所选的动态队列类型是应用程序设计的事情。

动态队列名称

对象描述符中的 DynamicQueueName 字段用于控制所创建的动态队列名称。当星号出现在队列名称最后一个位置时,则会在生成的名称中将其替换为保证对本地队列管理器唯一的字符串。DynamicQueueName 字段存在多种选择:

缺省值(对于 z/OS 是 CSQ.*,对于其他环境是 AMQ.*)。 结尾没有星号的名称,如 MYQUEUE。此类名称可能不唯一。

名称,如 MYQUEUE.*。出于管理和安全性的考虑,可以对其名称以共同字符串开头的队列分组。

单独的星号(不推荐使用)。

在 MQOPEN 成功完成后,新队列的名称在 ObjectName 字段中可用。

动态应答队列伪代码

下面的清单 11 所示的伪代码用于打开一个动态队列,并将该名称作为一个应答队列保存在

消息描述符中以供以后使用。为简化该示例和集中于动态队列的打开和使用,MQCONN 调用的详细信息和某些变量定义已省去了。

清单 11. 动态应答队列示例 复制内容到剪贴板代码:

DEFINE DYN_OBJ AS MQOD DEFINE A_MQMD AS MQMD CALL MQCONN(.....) DYN_OBJ.DynamicQName = 'MYQUEUE.*' DYN_OBJ.ObjectName = 'MODEL1' CALL MQOPEN(CONN_HANDLE, DYN_OBJ, OPEN_OPTIONS, MYQUEUE_HANDLE, COMP_CODE, REASON_CODE) IF COMP_CODE NOT = MQCC_OK /* error handling*/ ELSE /* save name assigned to created dynamic queue for later use */ /* typically in the MQMD reply-to queue name field */ A_MQMD.ReplyToQ = DYN_OBJ.ObjectName END-IF

查看详细资料 TOP

在这里,您可以IBM 软件产品下载、Demo下载、试用版下载、红皮书下载、白皮书下载

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 9# 大 中 小 发表于 2008-7-7 17:28 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 消息描述符

本部分详细查看一下消息描述符 (MQMD) 中的字段,其中有些字段已在前面描述过了。

持久性

消息的持久性属性确定消息在队列管理器重新启动或重新构建受损队列之后是否可以恢复。持久消息 将进行日志记录以支持恢复,并且该日志记录具有性能影响。

非持久消息 不作日志记录,并且在队列管理器重新启动或重新构建受损队列后不会继续存在。

MQMD 持久性字段可由应用程序设置为以下值之一:

当将消息放在具有持久性的队列上时,队列管理器会在重新启动时通过重播其日志来恢复消息。同时,作为非持久消息来放置的消息会在重新启动时明确地删除。

如果消息非常重要,并且不存在重新创建它的简单方法,则程序员应该将消息描述符持久性明确设置为 MQPER_PERSISTENT,或者如果已使用 DEFPSIST(YES) 来定义队列,则程序可以安全地允许使用为该队列定义的缺省持久性。

优先级

消息描述符中的优先级字段用于在将消息放置到队列上时设置消息优先级。此值可在 0 – 9 的范围内,或者为 -1,后者导致继承队列的缺省优先级。

由管理员设置的消息传递顺序属性确定队列管理器如何实际将消息存储在队列上。如果此属性的值为 MQMDS_FIFO,则使用队列的缺省优先级来对消息排队,而与应用程序设置的优先级无关。如果此属性为 MQMDS_PRIORITY,则在对消息排队时考虑消息描述符中的优先级值。

在构造应答时的一个约定是使用传入请求中的优先值。

消息类型

WebSphere MQ 提供了四种预定义的消息类型,由消息描述符中的消息类型字段来标识。 请求 当应用程序创建一个预期从目标应用程序获得响应的消息时,应该将消息类型设置为请求。 响应 来自目标应用程序的特定于应用程序的响应。 报告 通常由目标队列管理器作为发生某个特定条件(例如无法传递)的结果而生成。 数据报 缺省消息类型,不需要响应。 应用程序还可以在 MQMT_APPL_FIRST 和 MQMT_APPL_LAST 范围内定义它们自己的消息。

应答队列

当程序发送请求消息(通过将消息类型字段设置为 MQMT_REQUEST)时,它告诉接收其请求的应用程序它需要应答。请求应用程序还必须在消息描述符的应答队列名称字段中放入队列名称。如果消息类型设置为请求而没有提供应答队列名称,则 MQPUT 将会失败。

当应答队列名称由于多个请求者在发送消息而可能不同时,或者如果单个请求者程序在每次启动时创建一个新的动态应答队列,则在消息描述符中使用应答队列非常有用。

由于异步处理的性质,不存在关于应答将在何时发回的隐含计时。稍后我们将研究设置时间限制以等待应答的方法。 报告

应用程序设置消息描述符的报告字段来指示它希望接收报告,这些报告基于在处理消息时可能发生的某些事件。报告字段的一些最常用值包括:

如果将报告字段设置为 MQRO_NONE 以外的任何值,则还必须设置应答队列名称字段。

可以对报告选项进行组合。例如,如果设置了传递确认报告选项和其中一个异常报告选项,那么如果消息未能传递,您将接收到异常报告消息。然而,如果仅选择传递确认报告选项,而消息未能传递,则不会接收到异常报告消息。

常报告

当本地队列存在问题(队列已满、不存在,等等)时,队列管理器可以使用一个完成代码和原因代码来立即和同步地通知应用程序。

对于远程队列,满意的完成代码或原因代码只是意味着消息已放置到传输队列上。如果接收队列管理器随后遇到问题,就无法使用完成代码/原因代码机制:时间独立性意味着发送程序可能不再是活动的。在此情况下,如果消息描述符报告字段已指示应该在无法传递消息的情况下发送异常报告,则目标队列管理器将构造一个异常报告,并将其返回给消息描述符中指定的应答队列。

存在三个异常报告选项:

反馈

报告消息(异常报告除外)的反馈字段标识消息所表示的报告类型。例如,确认传递报告消息将在反馈字段中包含 MQFB_COD。

对于异常报告,反馈字段包含描述该异常的原因代码。 编码

当将浮点数、小数或整数数据放在消息的应用程序数据部分的字段中时,将会存在问题,因为数据在不同的平台上可能以不同的方式表示。此问题可通过消息描述符中的编码字段来避免。使用缺省值 MQENC_NATIVE 将使队列管理器能够在消息为 PUT 时,根据程序运行所在的平台和用于编写程序的语言,将正确的值放到编码字段中。目标队列管理器可以检查传入消息描述符中的编码字段,并应邀根据情况转换数字字段。

CodedCharSetId

数据可能使用多种语言,并且可能使用 ASCII 或 EBCDIC 字符集。因此,在将消息放在队列上时,务必标识所使用的编码字符集。同样,通过对编码字符集 ID 字段使用缺省值 (MQCCSI_Q_MGR),该字段的正确值可由队列管理器在 MQPUT 时提供。实际值将是该特定语言或平台的 ISO 代码页编号。

WebSphere MQ Application Programming Reference(请参见参考资料)的附录中提供了一组所有受支持代码页的表。 格式

传入消息中的编码和编码字符集 ID 字段使接收队列管理器能够转换消息描述符。该队列管理器知道数字字段(如消息类型)和字符字段(如应答队列名称)的位置。

然而,接收队列管理器不清楚消息的应用程序数据部分是如何设计的;它仅看到数据流。 如果还需要转换消息的应用程序数据部分,您有三种选择:

创建一个消息,其中应用程序数据全都是字符格式,包括数字字段。如果将消息描述符的格式字段设置为 MQFMT_STRING,则会在逐个字符的基础上转换应用程序数据。 编写一个消息转换出口,并将其名称放在格式字段中。

使用某个其他产品(例如 WebSphere Message Broker)来执行数据转换。

查看详细资料 TOP

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 10# 大 中 小 发表于 2008-7-7 17:34 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 MQGET 概述

MQGET 用于从先前使用某个 MQOO_INPUT 选项来打开的队列检索消息。除非使用 MQOO_BROWSE 选项,否则会将消息破坏性地从队列中删除并将其返回应用程序缓冲区。

MQGET 调用的语法如下: 复制内容到剪贴板代码:

MQGET (HConn, Hobj, MsgDesc, GetMsgOpts, BufferLength,

Buffer, DataLength, CompCode, Reason)

同样,连接句柄和对象句柄是传递的前两个参数。

消息描述符同样既是输入又是输出结构,与获取消息选项结构一样。

在 MQGET 的情况下,缓冲区为一个输出字段。缓冲区长度告诉队列管理器,将返回的消息应用程序部分要在缓冲区中占据多长的位置。

队列管理器使用数据长度参数来返回实际长度的所检索消息数据。通过这种方式,程序可以利用通用缓冲区,其中可以包含或大或小的消息。它可以通过数据长度值了解所检索的每个消息的实际大小。

获取消息选项

获取消息选项结构允许定义将在发出 MQGET 时使用的选项。获取消息选项的一些字段如下:

缓冲区长度

用于缓冲区长度的值一定不能 大于程序中的实际缓冲区。否则,MQGET 可能返回大于您已建立的工作区的消息,从而会覆盖非缓冲区存储。

最安全的方法是确保该缓冲区长度与程序中的缓冲区就长度达成一致。但是,可以将长度参数设置为小于缓冲区的实际大小。如果消息不比声明的缓冲区长度大,则将其放到缓冲区中。务必要记住,可能仍然存在来自前一次获取的数据超出了当前缓冲区长度。

如果消息大于指定的缓冲区长度,通过使用 MQGMO_ACCEPT_TRUNCATED_MESSAGE 选项,

可以检索能够装入缓冲区的消息部分,并丢弃超出缓冲区长度的任何内容。在此情况下,会将消息从队列中删除。如果未作此指定,则 MQGET 会在遇到大于缓冲区的消息时失败。然而,缓冲区将包含所能装入的消息部分,尽管消息仍然保留在队列上。在这两种情况下,都会在数据长度字段中返回消息的完整应用程序数据部分的长度。

MQGET 原因代码

MQGET 返回的一些原因代码如下:

MQGET 伪代码

清单 12 包含了 MQGET 调用的伪代码。

清单 12. MQGET 示例 复制内容到剪贴板代码:

DEFINE DEFAULT_QMGR AS CONSTANT ' ' DEFINE QMGR AS MQCHAR48 DEFINE CONN_HANDLE AS MQHCONN DEFINE COMP_CODE AS MQLONG DEFINE REASON_CODE AS MQLONG DEFINE OBJ_DESC AS MQOD DEFINE MYQUEUE_HANDLE AS MQHOBJ DEFINE OPEN_OPTIONS AS MQLONG DEFINE CLOSE_OPTIONS AS MQLONG DEFINE MESSAGE_DESCRIPTOR AS MQMD DEFINE GET_OPTIONS AS MQGMO DEFINE MESSAGE_LENGTH AS MQLONG DEFINE MESSAGE AS CHAR100 DEFINE LENGTH_OF_MESSAGE AS MQLONG QMGR = DEFAULT_QMGR CALL MQCONN(QMGR, CONN_HANDLE, COMP_CODE, REASON_CODE) IF COMP_CODE NOT = MQCC_OK write an error message detailing the REASON_CODE terminate the program STOP END-IF OBJ_DESC.ObjectType = MQOT_Q OBJ_DESC.ObjectName = 'MYQUEUE' OBJ_DESC.ObjectQMgrName = DEFAULT_QMGR OPEN_OPTIONS = MQOO_INPUT_SHARED + MQ00_FAIL_IF_QUIESCING CALL MQOPEN(CONN_HANDLE, OBJ_DESC, OPEN_OPTIONS, MYQUEUE_HANDLE, COMP_CODE, REASON_CODE) IF COMP_CODE NOT = MQCC_OK write an error message detailing the REASON_CODE terminate the program STOP END-IF GET_OPTIONS.Options = MQGMO_NO_WAIT + MQGMO_NO_SYNCPOINT MESSAGE_LENGTH = 100 DO MESSAGE_DESCRIPTOR.MsgId = MQMI_NONE MESSAGE_DESCRIPTOR.CorrelId = MQCI_NONE CALL MQGET(CONN_HANDLE, MYQUEUE_HANDLE, MESSAGE_DESCRIPTOR, GET_OPTIONS, MESSAGE_LENGTH, MESSAGE, LENGTH_OF_MESSAGE COMP_CODE, REASON)

UNTIL REASON_CODE NOT = MQRC_NO_MSG_AVAILABLE IF COMP_CODE NOT = MQCC_OK write an error message detailing the REASON_CODE terminate the program STOP END-IF CLOSE_OPTIONS = MQCO_NONE CALL MQCLOSE(CONN_HANDLE, MYQUEUE_HANDLE, CLOSE_OPTIONS, COMP_CODE, REASON_CODE) IF COMP_CODE NOT = MQCC_OK write an error message detailing the REASON_CODE terminate the program STOP END-IF CALL MQDISC(CONN_HANDLE, COMP_CODE, REASON_CODE) IF COMP_CODE NOT = MQCC_OK write an error message detailing the REASON_CODE terminate the program STOP END-IF

在上面的伪代码中,程序在一个循环中获取消息,该循环在没有更多消息可用时终止。消息 ID 和相关性 ID 字段分别在每个 MQGET 前设置为 MQMI_NONE 和 MQCI_NONE。此调用的原因代码将在控制消息检索中讨论。 将应答发送到正确的应答队列

当程序发出 MQGET 时,它可能旨在查询消息描述符消息类型字段,以验证该消息是否为一个请求。如不是,则可能在响应应用程序始终预期请求类型的消息时调用某个错误处理过程。

一旦验证了消息类型并完成业务处理,就可以将应答消息构造到应答队列管理器上的应答队列。

如果接收响应的队列不在本地队列管理器上,则应答队列管理器就非常重要了。该队列管理器寻找与应答队列管理器具有相同名称的传输队列,并将消息放到其上(附带正确的传输标头,其中包含路由信息),从而通过该通道继续传输消息。

应答伪代码

下面的清单 13 包含的伪代码显示了构建和发送应答消息的步骤。这些步骤之外的详细信息已省去,以简化代码和集中于应答处理。

清单 13. 应答示例 复制内容到剪贴板代码:

... DEFINE IN_MSG_DESC AS MQMD DEFINE OUT_MSG_DESC AS MQMD CALL MQGET(..., ..., IN_MSG_DESC, ...) IF IN_MSG_DESC.MsgType = MQMT_REQUEST formulate reply OUT_MSG_DESC.MsgType = MQMT_REPLY OBJ_DESC.ObjectName = IN_MSG_DESC.ReplyToQ OBJ_DESC.ObjectQMgrName = IN_MSG_DESC.ReplyToQMgr CALL MQPUT1(...., OBJ_DESC, OUT_MSG_DESC, ...) END-IF ...

查看详细资料 TOP

在这里,您可以IBM 软件产品下载、Demo下载、试用版下载、红皮书下载、白皮书下载

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 11# 大 中 小 发表于 2008-7-7 17:37 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 MQPUT1 概述

与 MQPUT 一样,MQPUT1 用于将消息放置到队列上。但是对于 MQPUT1,不需要关联的 MQOPEN 和 MQCLOSE 调用,因为 MQPUT1 中已隐含了这两个常规事务调用。当服务器程序为来自许多不同用户的请求提供服务,并且每个请求的消息描述符指定了不同的应答队列时,则通常使用 MQPUT1。使用 MQPUT1 可以避免多个 MQOPEN 和 MQPUT 调用的开销。

MQPUT1 调用的语法如下: 复制内容到剪贴板代码:

MQPUT1 (Hconn, ObjDesc, MsgDesc, PutMsgOpts, BufferLength, Buffer, CompCode, Reason)

MQPUT1 参数是用于 MQOPEN 的参数(对象描述符)和用于 MQPUT(消息描述符和放置消息选项)的参数的组合,但是不包括用于 MQPUT 的对象句柄。由于打开、放置和关闭全都用一个调用完成,所以不需要分配对象句柄。 MQPUT1 不能用于模型队列。

MQPUT1 安全性

若要成功执行 MQPUT1,用户必须拥有允许打开队列以便输入的正确访问权限。由于没有明确执行 MQOPEN,在执行 MQPUT1 时,必须完成在运行程序的平台上可用的访问控制检查。因此,在 MQPUT 从不返回原因代码 MQRC_NOT_AUTHORIZED 的场合,MQPUT1 可能会返回该原因代码。

MQPUT1 伪代码

下面的清单 14 包含了 MQPUT1 调用的伪代码。

清单 14. MQPUT1 示例

复制内容到剪贴板代码:

DEFINE DEFAULT_QMGR AS CONSTANT ' ' DEFINE QMGR AS MQCHAR48 DEFINE CONN_HANDLE AS MQHCONN DEFINE COMP_CODE AS MQLONG DEFINE REASON_CODE AS MQLONG DEFINE OBJ_DESC AS MQOD DEFINE MESSAGE_DESCRIPTOR AS MQMD DEFINE PUT_OPTIONS AS MQPMO DEFINE MESSAGE_LENGTH AS MQLONG DEFINE MESSAGE AS CHAR100 QMGR = DEFAULT_QMGR CALL MQCONN(QMGR, CONN_HANDLE, COMP_CODE, REASON_CODE) IF COMP_CODE NOT = MQCC_OK write an error message detailing the REASON_CODE terminate the program STOP END-IF OBJ_DESC.ObjectType = MQOT_Q OBJ_DESC.ObjectName =

'MYQUEUE' OBJ_DESC.ObjectQMgrName = DEFAULT_QMGR MESSAGE_LENGTH = 11 MESSAGE = 'Hello World' CALL MQPUT1(CONN_HANDLE, OBJ_DESC, MESSAGE_DESCRIPTOR, PUT_OPTIONS, MESSAGE_LENGTH, MESSAGE, COMP_CODE, REASON) IF COMP_CODE NOT = MQCC_OK write an error message detailing the REASON_CODE terminate the program STOP END-IF CALL MQDISC(CONN_HANDLE, COMP_CODE, REASON_CODE) IF COMP_CODE NOT = MQCC_OK write an error message detailing the REASON_CODE terminate the program STOP END-IF

请将此伪代码与清单 5 所示的 MQPUT 调用伪代码进行比较。请注意,不存在用于对象句柄、打开选项或关闭选项的变量,因为不需要这些内容。 查看详细资料 TOP

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 12# 大 中 小 发表于 2008-7-7 17:41 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 使用消息示例代码

在本部分,您将查看并运行一个演示 MQPUT 和 MQPUT1 调用的示例程序。

Transfer 程序从一个输入队列 MQGET 消息,并尝试将它们 MQPUT 到一个输出队列上。并非所有消息都能成功地 MQPUT,消息太长就会失败(已设置了输出队列的 MAXMSGL 属性以引发这种情况)。对于无法放置到输出队列上的消息,Transfer 使用 MQPUT1 来将消息发送到一个应答队列。

我还编写了另一个程序 FeedTran,它从一个文件读取行,将它们放置到一个队列上,非常类似于第一个程序 MQPut。FeedTran 在其上放置消息的队列是 Transfer 使用的输入队列。FeedTran 还创建应答队列,Transfer 将无法放置到输出队列上的消息返回到该应答队列。FeedTran 监视应答队列并将所返回的消息打印到控制台上。

由于本示例的重点是 MQPUT 和 MQPUT1,我就不再讨论 FeedTran 程序了。建议您大致看一下它,并了解它是如何工作的。我们将在动态队列和管理消息示例代码中研究一个与它类似的示例程序。

检查示例代码

您已经将示例代码 samples03.zip (9.97 KB) samples03.zip (9.97 KB) 下载次数: 0

2008-8-27 16:18下载并导入了 Application Developer,因此您可以直接开始研究该代码。与

前面一样,您将分成很小的部分来逐一查看该代码和每个部分所做的工作。让我们首先查看类声明,以及所声明的一些常量和 main() 方法,如清单 15 所示。

清单 15. Transfer.java 类声明 复制内容到剪贴板代码:

public class Transfer { private static final String qManager = \private static final String inputQName = \static void main(String[] args) { new Transfer().run(); }

此代码定义了三个常量字符串来指定队列管理器和输入及输出队列。main() 方法不过就是创建该类的实例,并调用其 run() 方法。run() 方法是该类中唯一的其他方法。 现在让我们看一下清单 16 中的 run() 方法的前几行。

清单16. run() 方法的开头 复制内容到剪贴板代码:

public void run() { try { MQQueueManager qMgr = new MQQueueManager(qManager); int openOptions = MQC.MQOO_INPUT_SHARED + MQC.MQOO_FAIL_IF_QUIESCING; MQQueue inputQueue = qMgr.accessQueue(inputQName, openOptions); openOptions = MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING; MQQueue outputQueue = qMgr.accessQueue(outputQName, openOptions); MQGetMessageOptions getOptions = new MQGetMessageOptions(); getOptions.waitInterval = 10000;

首先,它建立到队列管理器的连接,并打开输入队列和输出队列。然后是创建一个 MQGetMessageOptions 对象,并将等待间隔字段设置为 10000(10 秒)。

清单 17 显示了该程序的核心部分。

清单 17. 获取和放置消息 复制内容到剪贴板代码:

boolean msgsAvailable = true; while (msgsAvailable) { try { getOptions.options = MQC.MQGMO_WAIT + MQC.MQGMO_NO_SYNCPOINT + MQC.MQGMO_FAIL_IF_QUIESCING + +MQC.MQGMO_ACCEPT_TRUNCATED_MSG; MQMessage msg = new MQMessage(); msg.messageId = MQC.MQMI_NONE; msg.correlationId = MQC.MQCI_NONE; inputQueue.get(msg, getOptions); String replyQName = msg.replyToQueueName; MQPutMessageOptions putOptions = new MQPutMessageOptions(); putOptions.options = MQC.MQPMO_NO_SYNCPOINT + MQC.MQPMO_FAIL_IF_QUIESCING; try { outputQueue.put(msg, putOptions); } catch (MQException mqex) { msg.messageType = MQC.MQMT_REPORT; msg.feedback = mqex.reasonCode; msg.messageId = MQC.MQMI_NONE; msg.correlationId = MQC.MQCI_NONE; msg.report = MQC.MQRO_NONE; qMgr.put(replyQName, msg, putOptions); }

此部分首先声明一个 Boolean 变量并将其初始化为 true,然后进入一个循环,该循环在 Boolean 变量为 false 时终止。

然后是设置获取选项,创建并初始化一个新消息,并执行获取操作。

请注意被声明为循环中第一行的 try 块。这是该程序中声明的第二个 try 块。第一个 try 块被声明为 run() 方法中的第一行,它将捕获在连接到队列管理器和打开队列期间发生的错误。如果其中任何操作失败,则无法完成任何进一步的处理,程序将终止。此第二个 try 旨在捕获获取操作期间发生的错误。特别是,您希望确定任何异常所返回的原因代码是否为 MQRC_NO_MSG_AVAILABLE。稍后您将看到该代码。

一旦执行了获取,则将应答队列名称保存在一个变量中以便以后使用。然后对输出队列执行一个放置操作。

请注意这里的第三个 try 块。您只希望捕获在放置期间发生的错误。如果确实发生某个错误,则会调用该 catch 块。它将消息类型设置为报告,使用来自该异常的原因代码来填充反馈字段,初始化消息 ID 和相关性 ID 字段,将报告字段设置为 MQRO_NONE,然后对应答队列执行一个 MQPUT1。

此时,您或许在想“MQPUT1 呢?我没有看到 MQPUT1。”请仔细看一下对应答队列的放置和对输出队列的放置。对输出队列的放置使用了队列对象上的 put() 方法。它对应于一个 MQPUT。对应答队列的放置使用了队列管理器对象上的 put() 方法。它就是 MQPUT1。如果您考虑到这点,一切就清楚了。您通过调用队列管理器上的方法 (accessQueue()) 来打开了一个队列。由于 MQPUT1 在单个操作中执行了打开、放置和关闭,因此必须具有 MQPUT1 功能的是队列管理器。

关于清单 17,还要注意另一点。如果对应答队列的放置失败,由于该放置操作是在与第三个 try 关联的 catch 中执行的,因此该异常将在所声明的第二个 try 块中捕获。

现在您可以看一下第二个 try 的 catch 块,如清单 18 所示。

清单 18. 第二个 catch 块 复制内容到剪贴板代码:

} catch (MQException mqex) { msgsAvailable = false; switch (mqex.reasonCode) { case MQException.MQRC_NO_MSG_AVAILABLE: System.out.println(\more input messages\break; default: System.out .println(\WebSphere MQ Error occured : Completion Code \+ mqex.completionCode + \Reason Code \+ mqex.reasonCode); mqex.printStackTrace(); break; } } }

这里将控制循环的 Boolean 变量设置为 false。然后检查原因代码。如果没有更多消息可用,则向控制台打印一条消息来表明这一点。如果发生任何其他错误,则显示该错误。

下面的清单 19 显示了该程序的结尾:关闭队列,程序断开与队列管理器的连接,并向控制台打印一条指示程序结束的消息。清单 19 还显示了最外层 try 块中的 catch。

清单 19. 异常处理和程序结束 复制内容到剪贴板代码:

inputQueue.closeOptions = MQC.MQCO_NONE; inputQueue.close(); outputQueue.closeOptions = MQC.MQCO_NONE; outputQueue.close(); qMgr.disconnect(); System.out.println(\

Transfer\Completion Code \+ mqex.completionCode + \Reason Code \+ mqex.reasonCode); mqex.printStackTrace(); } } } 运行示例代码

现在您可以运行该代码了。 创建输入队列、输出队列和 FeedTran 将用于创建应答队列的模型队列。打开一个 Windows 命令提示符。

输入 runmqsc < setup02.txt 并按 Enter。

请注意,输出队列的 MAXMSGL 属性已设置为 25。 关闭 Windows 命令提示符。

运行 FeedTrans 程序来将消息放置到 Transfer 的队列上。在 Application Developer 中,在 Package Explorer 视图中右键单击 FeedTran.java,并选择 Run > Java Application。 在 Package Explorer 视图中右键单击 Transfer.java,并选择 Run > Java Application。 每个程序将在自己的控制台中显示消息。通过选择 Display Selected Console 来在控制台之间切换,如图 6 中的红色框所示。

图 6. “显示所选控制台”按钮

一旦程序完成,Transfer 的控制台应该与图 7 类似。红色的行是 WebSphere MQ base Java 打印到 System.err 的消息。有五条消息对于输出队列来说太长了(原因代码 2030)。

图 7. 程序结束后的 Transfer 控制台

FeedTran 的控制台应该与图 8 类似。请注意那五条显示了反馈 2030 的消息。

图 8. 程序结束后的 FeedTran 控制台

使用 WebSphere MQ Explorer 来浏览 CERT.OUTPUT 队列中的消息。

[ 本帖最后由 艾依然 于 2008-8-27 16:18 编辑 ] 查看详细资料 TOP

在这里,您可以IBM 软件产品下载、Demo下载、试用版下载、红皮书下载、白皮书下载

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 13# 大 中 小 发表于 2008-7-7 17:52 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 控制消息检索

本部分探索用于控制消息检索的技术。

MsgId 和 CorrelId

消息描述符的 MsgId 和 CorrelId 字段用于提供消息的唯一标识 (MsgId),以及用于将应答消息与先前发送的请求相关联 (CorrelId)。当应用程序发送消息时,它可以设置 MsgId,或者让队列管理器生成唯一的 MsgId(通过将 MsgId 设置为 MQMI_NONE)。在任一种情况下,都会在将消息放置到队列上之后将 MsgId 字段的实际值返回给应用程序。在大多数情况下,队列管理器将 CorrelId 保留为应用程序分配的值。

处理传入消息并构建应答消息的应用程序可以将原始消息中的 MsgId 字段复制到应答消息

的 CorrelId 字段。一旦将应答消息发回到请求程序,它就可以将应答的 CorrelId 与原始请求消息的 MsgId 作比较,以确保所收到的应答是针对所发送的请求。

稍后您将看到,还可以指定 MQGET 仅检索具有特定 MsgId、CorrelId 或这两者的消息。

MsgId 和 CorrelId 被定义为 MQBYTE24,并且不进行转换。应该将这些字段视为字节序列,而不是视为字符串。

生成 MsgId 和 CorrelId

正如前面讨论过的,应用程序可以创建自己的消息 MsgId,或者通过将 MsgId 设置为 MQMI_NONE,从而让队列管理器生成唯一的 MsgId。而且,队列管理器通常将 CorrelId 字段保留不变。

在大多数系统上,还有另一种设置 MsgId 的方法。可以在放置消息选项中设置 MQPMO_NEW_MSG_ID,以指示队列管理器应该为 MsgId 生成唯一标识符,从而改写应用程序放在该字段中的任何值。

此外,还可以在放置消息选项中设置 MQPMO_NEW_CORREL_ID,以指示队列管理器应该为 CorrelId 生成唯一标识符,同样改写应用程序放在该字段中的任何值。这是让队列管理器生成 CorrelId 的唯一方法。

使用 MQPMO_NEW_MSG_ID 和 MQPMO_NEW_CORREL_ID 可以使得应用程序设置 MsgId 和 CorrelId 的任务更加容易。

按 MsgId 和 CorrelId 检索消息

在执行 MQGET 时,应用程序可以指定仅返回具有特定 MsgId 或特定 CorrelId 或这两者的特定组合的消息。应用程序在发出 MQGET 前,设置消息描述符中的这其中任一个字段或同时设置这两个字段。然后队列管理器扫描队列中与应用程序设置的 MsgId 或 CorrelId 匹配的消息。

如果队列上有许多消息,将 MQGET 与 MsgId 或 CorrelId 一起使用会影响性能;在设计应用程序期间应该考虑到这个注意事项。

检索每个消息

若要检索队列上的第一个可用消息而不管 MsgId 和 CorrelId 为何值,应用程序应该将这些字段分别设置为 MQMI_NONE 和 MQCI_NONE。然而,一旦 MQGET 返回一个消息,这些字段就包含刚检索的消息的值。因此,应用程序必须在发出另一个 MQGET 前,将这些字段设置回 MQMI_NONE 和 MQCI_NONE,以确保检索下一个可用消息而不管 MsgId 和 CorrelId 为何值。返回去看一下清单 12,可以看到在该程序中,这是在每次通过循环以 MQGET 消息时完成的。

请求/应答队列注意事项

在多个应用程序使用同一队列来接收应答的情况下,将应答消息的 CorrelId 设置为先前发送的消息的 MsgId 是最有用的。通过仅检索具有与先前发送的请求 MsgId 匹配的 CorrelId 的消息,应用程序不会从属于共享该队列的另一个应用程序的应答队列删除消息。

在设计 WebSphere MQ 解决方案时,务必要考虑应用程序应该共享某个应答队列,还是每个应用程序应该拥有自己的队列。使用单独的应答队列(通常是动态队列以便简化管理)会限制按 CorrelId 来检索消息。然而,如果请求应用程序在开始接收任何应答消息前发送了多个请求,按 CorrelId 的检索在这种情况下仍然是必要的。

MatchOptions

在大多数平台上,可以在获取消息选项结构中使用一个名为 MatchOptions 的字段。此字段可设置为 MQMO_NONE 以指示应该检索的下一个可用消息,而不管 MsgId 和 CorrelId 为何值。这消除了在下一个 MQGET 前重设 MsgId 和 CorrelId 的需要。

MatchOptions 还可以设置为 MQMO_MATCH_MSG_ID 或 MQMO_MATCH_CORREL_ID,以指示按 MsgId 或 CorrelId 检索消息。MatchOptions 的缺省设置是同时设置为这两个选项。设置这些选项后,MQGET 使用 MsgId 或 CorrelId 中的值来检索适当的消息。然而,即使设置了这些选项,将 MsgId 设置为 MQMI_NONE 和将 CorrelId 设置为 MQCI_NONE 也会返回下一个可用消息,而不管 MsgId 或 CorrelId 为何值。 索引

在 z/OS 上,WebSphere MQ 管理员可以将 MsgId 或 CorrelId 定义为索引。例如,如果队列上的 IndexType 为 MsgId,则会维护队列上所有 MsgId 的索引,并且按 MsgId 检索消息会更快,即使队列上存在许多消息。然而在这种情况下,按 CorrelId 的检索会导致处理更慢,因为无法同时指定两者的 IndexType。 浏览

如果应用程序希望查看某个消息而不从队列中删除它,MQGMO_Options 字段可以包括 MQGMO_BROWSE_FIRST 或 MQGMO_BROWSE_NEXT。浏览是单向的;没有办法在队列中向后浏览。

为了浏览,必须使用 MQOO_BROWSE 打开选项来打开队列。然后,当应用程序使用 MQGMO_BROWSE_... 选项而不是破坏性的消息删除时,应用程序只是沿着队列中的消息移动,并将下一个可用消息的副本检索到其缓冲区中。

当使用了用于浏览的打开选项时,队列管理器创建一个与该对象句柄关联的唯一指针。此指针称为浏览游标。正是浏览游标监视应用程序当前正指向哪一个消息。除了通过使用 MQGMO_BROWSE_... 选项之一来发出 MQGET 外,程序无法操作浏览器游标。

可以将 MQGMO_WAIT 选项与浏览结合使用。如果计划使用此选项,强烈建议指定等待间隔。

由于浏览是单向的,应用程序可以浏览具有消息传递优先级顺序的队列上的消息,并在具有更高优先级的消息被放置到该队列上的同时到达可用消息的结尾 (MQRC_NO_MSG_AVAILABLE)。在这种情况下,使用 MQGMO_BROWSE_FIRST 选项发出 MQGET 可以将浏览游标重新定位到队列开头。

当发现应用程序希望从队列中删除的消息时,必须使用选项 MQGMO_MSG_UNDER_CURSOR 来另外发出一个 MQGET。这将导致从队列中破坏性地删除浏览游标所指向的消息。 查看详细资料 TOP

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 14# 大 中 小 发表于 2008-7-7 17:52 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 浏览同一消息

如果应用程序在打开队列时组合了 MQOO_BROWSE 和 MQOO_INPUT_SHARED 选项,则其他程序也可以浏览并从该队列中删除消息。

两个应用程序可以同时浏览同一个消息。然后任一个程序都可以决定使用 MQGMO_MSG_UNDER_CURSOR 选项来删除该消息。如果第二个程序随后也尝试删除该消息,则调用将失败,并产生错误代码 MQRC_NO_MSG_UNDER_CURSOR。实际上,游标正指向队列中的一个空 Slot。

您可以将 MQGMO_LOCK 选项与 MQGMO_BROWSE_... 组合使用以避免此问题。这将使得所浏览的消息对其他可能也在浏览和从该队列获取消息的应用程序不可见和不可用。有一个 MQGMO_UNLOCK 选项允许明确解锁某个先前锁定的消息。队列上成功的 MQCLOSE 也会对消息解锁。

浏览伪代码

清单 20 显示了用于浏览队列中消息的伪代码。为简化代码和集中于浏览功能,常规事务调用已省去了。

清单 20. 浏览示例

复制内容到剪贴板代码:

DEFINE COMP_CODE AS MQLONG DEFINE REASON_CODE AS MQLONG DEFINE GET_OPTIONS AS MQGMO CALL MQCONN(....) CALL MQOPEN(....) GET_OPTIONS.Options = MQGMO_BROWSE_FIRST + MQGMO_LOCK CALL MQGET(....) DO WHILE COMP_CODE = MQCC_OK IF you need to process this message GET_oPTIONS.Options = MQGMO_MSG_UNDER_CURSOR CALL MQGET(....) IF COMP_CODE NOT = MQCC_OK IF REASON_CODE NOT = MQRC_NO_MSG_UNDER_CURSOR /* investigate what went wrong */ END-IF ELSE /* process the message */ END-IF END-IF GET_OPTIONS.Options = MQGMO_BROWSE_NEXT + MQGMO_LOCK CALL MQGET(....) END-DO /* find out why we terminated the loop */ /* and take the appropriate action */ 等待

由于 WebSphere MQ 应用程序经常通过网络通信或等待来自触发程序的响应,应答总是无法在放置请求消息后立即可用。在这些情况下,如果应用程序是设计为同步的,则 MQGMO_WAIT 选项会非常有用。

如果应用程序使用 MQGMO_WAIT,建议同时还使用 MQGMO_FAIL_IF_QUIESCING 选项。这允许队列管理器正在关闭时终止调用,并返回 MQRC_Q_MGR_QUIESCING。

在有关队列消息传递能力的条件发生变化时,也可以终止等待。例如,如果 WebSphere MQ 管理员将队列的获取属性从允许更改为禁止,则调用会失败并返回 MQRC_GET_INHIBITED。

使用 WaitInterval 的等待

获取消息选项结构中有一个名为 WaitInterval 的字段,用于设置等待的有效持续时间(以毫秒为单位)。如果在发出 MQGET 时消息可用,则等待从不生效。如果当时消息不可用,则 MQGMO_WAIT 选项连同 WaitInterval 字段中的值一起,将允许程序确定等待某个消息的合理时间。如果在该时间内没有消息到达,则 MQGET 将完成并返回完成代码 MQCC_FAILED 和原因代码 MQRC_NO_MSG_AVAILABLE。在等待间隔期间,如果某个消息到达,则等待立即结束。

请注意,缺省等待间隔为 MQWI_UNLIMITED(永远)。对此缺省选项的使用应该极其慎重,并且始终与 MQGMO_FAIL_IF_QUIESCING 一起使用。

使用 WaitInterval 的等待伪代码

下面的清单 21 显示了使用等待间隔来等待消息的伪代码。为简化代码和集中于等待功能,常规事务调用已省去了。

清单 21. 等待示例 复制内容到剪贴板代码:

DEFINE COMP_CODE AS MQLONG DEFINE REASON_CODE AS MQLONG DEFINE MESSAGE_DESCRIPTOR AS MQMD DEFINE GET_OPTIONS AS MQGMO CALL MQCONN(....) CALL MQOPEN(....) MESSAGE_DESCRIPTOR.MsgId = SomeValue MESSAGE_DESCRIPTOR.CorrelId = SomeOtherValue GET_OPTIONS.Options = MQGMO_WAIT + MQGMO_FAIL_IF_QUIESCING

GET_OPTIONS.WaitInterval = 300000 CALL MQGET(....) IF COMP_CODE NOT = MQCC_OK IF REASON_CODE = MQRC_NO_MSG_AVAILABLE /* we were woken up but there was no */ /* message available - timeout expired */ END-IF IF REASON_CODE = MQRC_GET_INHIBITED /* we were woken up but we are not */ /* now allowed to get a message */ END-IF ELSE /* we got the message OK, now process it */ END-IF

WAIT 和多个应用程序

如果多个程序在处理某个用于输入的队列,已结束等待的消息可能由另一个程序删除,后者或许只是从队列获取任何可用消息。在这种情况下,哪个应用程序实际从队列检索消息是不可预测的;它取决于竞争任务的相对操作系统优先级。

因此,即使所设置的等待没有等待间隔,设计应用程序时也始终应该考虑到接收 MQRC_NO_MSG_AVAILABLE 的可能性。

使用 SET_SIGNAL 的 MQGET

有些 WebSphere MQ 实现上的一个 MQGET 选项允许操作系统在预期消息到达队列上时通知程序(或向其发送信号)。您不能将 MQGMO_SET_SIGNAL 选项与 MQGMO_WAIT 选项结合使用。然而,等待间隔是允许的,并且在 IMS 的情况下,建议将等待间隔与 SET_SIGNAL 选项结合使用。

MQGMO_SET_SIGNAL 的优点在于将应用程序线程解放出来完成其他处理,并在消息到达时依赖操作系统来通知程序。

程序可以同时在多个队列句柄上设置未完成信号。当操作系统通知应用程序某个针对未完成信号请求的消息已到达时,MQGET 必须实际检索该消息。

到达通知特定于操作系统。例如在 z/OS 上,完成代码将被返回给获取消息选项结构的 Signal1 字段中标识的地址处的事件控制块 (ECB)。完成代码可以通知程序: 消息已到达队列。

等待间隔已过期并且没有消息到达。 信号已取消(例如,队列已禁止获取)。

过期

消息描述符中的过期字段值就是消息生存期。这是一个以十分之一秒为单位表示的时间,由放置消息的应用程序设置。如果在此时间段过去后还没有从目标队列删除消息,则该消息就变得适合丢弃了。当发生了应该已经返回还未过期的消息的 MQGET 调用(无论是浏览还是非浏览)时,该消息就会被丢弃。

缺省值为 MQEI_UNLIMITED,表示无限的生存期。

过期值通常与等待间隔结合使用。您应该将过期值设置为等待间隔的值,因为您不希望等待得比该时间更久。 查看详细资料

TOP

在这里,您可以IBM 软件产品下载、Demo下载、试用版下载、红皮书下载、白皮书下载

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 15# 大 中 小 发表于 2008-7-7 17:54 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 动态队列和管理消息示例代码

在本部分,您将查看并运行一个示例程序来演示: 发送请求消息

创建一个将接收应答的动态队列 等待应答被发送

使用 MsgId 和 CorrelId 来验证所检索的消息的确是对请求消息的应答

Request 程序从一个文件中读取行,并将它们作为请求消息放置到一个队列上。发送每个请求消息以后,它等待自己创建的动态队列接收到应答消息。如果在超过等待间隔之前接收到应答消息,则它检索该消息并将其内容打印到控制台,从而指示应答消息是否与先前发送的请求消息相关。

我还编写了另一个程序 EchoRequest,它获取 Request 发送的请求消息,并将应答消息发送到 Request 创建的动态队列。EchoRequest 向 Request 发送的应答数量与请求消息第一个字节中找到的数字对应。如果该第一个字节中为 1,则它发送 1 个应答;如果其中为 5,则它发送 5 个应答;如果其中为 9,则它发送 9 个应答,以此类推。如果该第一个字节中为 0(零),则它不发送任何应答。

由于本示例的重点针对发送请求和等待应答,我就不再讨论 EchoRequest 程序了。不过,建议您大致看一下它,并了解它是如何工作的。

检查示例代码

与前面一样,我们将分成很小的部分来逐一查看该代码并解释每个部分所做的工作。让我们首先查看类声明,以及所声明的一些常量和 main() 方法,如清单 22 所示。

清单 22. Request.java 类声明 复制内容到剪贴板代码:

public class Request { private static final String qManager = \private static final String requestQName = \static final String dynamicQName = \public static void main(String[] args) { new Request().run(); }

此代码定义了四个常量字符串来指定队列管理器、请求和应答队列以及动态队列。main() 方法不过就是创建该类的实例,并调用其 run() 方法。run() 方法是该类中唯一的其他方法。 现在让我们看一下 run() 方法的前几行,如清单 23 所示。

清单 23. run() 方法的开头 复制内容到剪贴板代码:

public void run() { System.out.println(\Request\try { MQQueueManager qMgr = new MQQueueManager(qManager); int openOptions = MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING; MQQueue requestQueue = qMgr.accessQueue(requestQName, openOptions); openOptions = MQC.MQOO_INPUT_SHARED + MQC.MQOO_FAIL_IF_QUIESCING; MQQueue replyQueue = qMgr.accessQueue(replyQName, openOptions, qManager, dynamicQName, null); System.out.println(\queue is \+ replyQueue.name); MQPutMessageOptions putOptions = new MQPutMessageOptions(); putOptions.options = MQC.MQPMO_NO_SYNCPOINT + MQC.MQPMO_FAIL_IF_QUIESCING;

此代码首先建立到队列管理器的连接,并打开请求和应答队列。应答队列是动态队列,并且由于在打开队列时提供的应答队列名称以星号结尾,队列管理器创建该动态队列并生成一个唯一标识符来替换星号。应用程序在打开队列后将队列名称打印到控制台。然后是创建并初始化一个 MQPutMessageOptions 对象。

清单 24 显示了从文件读取行并将消息放置到请求队列的过程。

清单 24. 读取文件和放置消息 复制内容到剪贴板代码:

BufferedReader br = new BufferedReader(new FileReader( \String line = null; while ((line = br.readLine()) != null) { MQMessage msg = new MQMessage(); msg.messageType = MQC.MQMT_REQUEST; msg.report = MQC.MQRO_EXCEPTION_WITH_DATA; msg.replyToQueueName = replyQueue.name; msg.format = MQC.MQFMT_STRING; msg.writeUTF(line); requestQueue.put(msg, putOptions); byte[] msgID = msg.messageId; MQGetMessageOptions getOptions = new MQGetMessageOptions(); getOptions.waitInterval = 10000;

此代码与 MQPut.java 中的代码类似。请注意,此代码将消息类型设置为 MQMT_REQUEST,在发生异常时请求一个报告,提供一个应答队列,并将格式设置为 MQFMT_STRING。 一旦将消息放置到请求队列上,则将消息 ID 保存到一个变量以便以后参考。然后是创建一个 MQGetMessageOptions 对象,并将等待间隔设置为 10 秒。

清单 25 显示了应答消息的处理。

清单 25. 等待和接收应答 复制内容到剪贴板代码:

boolean msgsAvailable = true; while (msgsAvailable) { try { getOptions.options = MQC.MQGMO_WAIT + MQC.MQGMO_NO_SYNCPOINT + MQC.MQGMO_CONVERT + MQC.MQGMO_FAIL_IF_QUIESCING + MQC.MQGMO_ACCEPT_TRUNCATED_MSG; MQMessage reply = new MQMessage(); reply.encoding = MQC.MQENC_NATIVE; reply.characterSet = MQC.MQCCSI_Q_MGR; reply.messageId = MQC.MQMI_NONE; reply.correlationId =

MQC.MQCI_NONE; replyQueue.get(reply, getOptions); getOptions.waitInterval = 1000; if (Arrays.equals(msgID, reply.correlationId)){ System.out.println(\else { System.out.println(\\+ reply.readUTF()); } if (reply.messageType == MQC.MQMT_REPORT) { System.out.println(\ 此代码声明了一个 Boolean 变量并将其初始化为 true,然后进入一个循环,该循环在 Boolean 变量为 false 时终止。然后是设置获取选项,创建并初始化一个新消息,并执行获取操作。

循环中的代码在一个 try 块中。与 Transfer.java 中的第二个 try 块一样,这个 try 块旨在捕获获取期间发生的错误,尤其是检查 MQRC_NO_MSG_AVAILABLE 以指示没有更多的应答可用。

在获取之后,将等待间隔减至 1 秒。然后将前面保存的消息 ID 与应答消息的相关性 ID 作比较,并将应答消息打印到控制台,从而指示它是否与该请求消息相关。如果应答消息不是报告消息,则还将反馈字段打印到控制台。

收到所有应答后,程序将循环回去读取文件中的一行并发送另一个请求。

下面的清单 26 显示了程序中的第二个 catch 块,该块与 Transfer.java 中的第二个 catch 块完全相同。

清单 26. 第二个 catch 块 复制内容到剪贴板代码:

} catch (MQException mqex) { msgsAvailable = false; switch (mqex.reasonCode) { case MQException.MQRC_NO_MSG_AVAILABLE: System.out.println(\System.out .println(\WebSphere MQ Error occured : Completion Code \+ mqex.completionCode + \Reason Code \+ mqex.reasonCode); mqex.printStackTrace(); break; } } } }

在发送该文件中的所有行并收到所有应答之后,程序通过关闭队列并断开与队列管理器的连接来结束,如下面的清单 27 所示。此清单还显示了最外层 try 块中的 catch 块。

清单 27. 异常处理和程序结束

复制内容到剪贴板代码:

requestQueue.closeOptions = MQC.MQCO_NONE; requestQueue.close(); if (replyQueue.isOpen()) {

replyQueue.closeOptions = MQC.MQCO_DELETE; replyQueue.close(); }

qMgr.disconnect();

System.out.println(\

} catch (MQException mqex) { System.out

.println(\ + mqex.completionCode + \ + mqex.reasonCode); mqex.printStackTrace();

} catch (FileNotFoundException fnfex) { fnfex.printStackTrace(); } catch (IOException ioex) { ioex.printStackTrace(); } } }

运行示例代码

首先创建请求队列。使用已经为应答队列创建的模型队列。

打开一个 Windows 命令提示符。

输入 runmqsc < setup03.txt 并按 Enter。 关闭 Windows 命令提示符。 启动 Request 程序。

在 Application Developer 中,在 Package Explorer 视图中右键单击 Request.java,并选择 Run > Java Application。

在 Package Explorer 视图中右键单击 EchoRequest.java,并选择 Run > Java Application。 每个程序将在自己的控制台中显示消息。通过选择 Display Selected Console,您可以在控制台之间切换。 在程序执行期间,Request 似乎不时地暂停。此暂停发生在所发送消息的第一个字节为 0(零)并且没有发送应答的时候。Request 在发送请求后等待 10 秒钟以便应答到达。 一旦程序完成,Request 的控制台应该如图 9 所示。(只有部分消息打印到了控制台,如图 9 所示。)

图 9. 程序结束后的 Request 控制台

[ 本帖最后由 艾依然 于 2008-8-21 18:53 编辑 ] 查看详细资料 TOP

阳春三月 版主

帖子141 积分1311 金钱1000 W币 注册时间2008-7-7 个人空间 发短消息 加为好友 当前离线 16# 大 中 小 发表于 2008-7-7 17:55 只看该作者

WebSphere入门开窍班第6期:剪不断理还乱的Portal问题汇总 | 谁是未来存储架构师?成就下一代信息架构 | 《WebSphere中国》杂志免费领取 总结

本教程介绍了 MQI 中的主要调用,包括常规事务调用或用于放置及获取消息的调用。其中还讨论了打开队列、消息描述符和用于控制消息检索的技术。完成本系列中的五个教程可以帮助您获得所需的知识以准备考试 996:IBM WebSphere MQ V6.0, Solution Design,但是决不取代您通过使用产品和学习文档所获得的经验和知识。

但愿您会发现本教程是有帮助的,并祝您在准备认证考试时获得好运。

本文来源:https://www.bwwdw.com/article/n9b5.html

Top