Using the MQ Series system layer
MQI is supported by three primary classes implemented at the system layer:
• AbtMQqm represents an MQ Series queue manager
• AbtMQqueue represents an MQ Series queue
• AbtMQMessage represents an MQ Series message
In addition, if an error occurs, then an instance of the AbtMQError class will be returned.
If you need to access MQ Series function that VAST Platform does not provide, the AbtMQCall class has a private class method for each of the external functions in the MQ Series DLLs.
The following sections discuss how you use these classes to establish a connection between your application and an MQ Series queue.
Defining and connecting to a queue manager
The AbtMQqm object represents the queue manager that your application is going to communicate with. To define a particular queue manager you create an instance of AbtMQqm and send it the name: message. After the queue manager is defined you can connect to it by sending the instance of AbtMQqm the connect message as illustrated in the following example code:
| aQueueManager rc |
"Connect to queue manager"
(aQueueManager := AbtMQqm new) name: 'MYQMGR'.
(rc := aQueueManager connect) isAbtError
ifTrue: [
Transcript cr; show: 'Connect request failed'.
^Transcript cr; show: 'Return code: ',
(aQueueManager lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Connect is ok'].
The usual API to connect to the MQ Queue manager is via the AbtMQqm>>Mconnect API which uses the MQCONN call. The AbtMQqm>>connectXTo:with: API (MQCONNX call) can be used to customize the connection parameters using an AbtMQCNOStruct. MQCONNX is similar to MQCONN except that it allows options to be specified that controls the way the call works. Refer to MQSeries documentation for further information about these functions and structures
Defining and opening a queue
The AbtMQqueue object represents the queue that your application uses to place or retrieve messages. To define a particular queue you create an instance of AbtMQqueue and send it the name:queueManager: message. After you have connected to the queue manager, and the queue is defined, you can open it by sending it the openWithOptions: message as illustrated in the following example code:
| aQueue aQueueManager rc |
"Connect to queue manager"
(aQueueManager := AbtMQqm new) name: 'MYQMGR'.
(rc := aQueueManager connect) isAbtError
ifTrue: [
Transcript cr; show: 'Connect request failed'.
^Transcript cr; show: 'Return code: ',
(aQueueManager lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Connect is ok'].
(aQueue := AbtMQqueue new)
name: 'MYQMGR.MYQUEUE';
queueManager: aQueueManager.
(rc := aQueue openWithOptions:
(AbtMQConstants::MqooInputShared |
AbtMQConstants::MqooOutput |
AbtMQConstants::MqooInquire |
AbtMQConstants::MqooSet)) isAbtError
ifTrue: [
Transcript cr; show: 'Open of queue request failed'.
^Transcript show: 'Return code: ',
(aQueue lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Open of queue is ok'].
Browse the openWithOptions: method of the AbtMQqueue class for all the options you can specify when opening a queue. To view all the constants available for working with MQ Series from VAST, browse the AbtMQConstants pool dictionary.
Querying the queue type
To query the type of a particular queue, you send the inquireQueueType message to an instance of AbtMQqueue . The inquireQueueType message returns one of the Mqqt* constants defined in AbtMQConstants. After you have connected to the queue manager, and the queue is defined, you can send it the inquireQueueType: message as illustrated in the following example code:
| aQueueManager aQueue rc |
"Connect to queue manager"
(aQueueManager := AbtMQqm new) name: 'MYQMGR'.
(rc := aQueueManager connect) isAbtError
ifTrue: [
Transcript cr; show: 'Connect request failed'.
^Transcript cr; show: 'Return code: ',
(aQueueManager lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Connect is ok'].
(aQueue := AbtMQqueue new)
descriptorObjectName: 'MYQMGR.MYQUEUE';
queueManager: aQueueManager.
(rc := aQueue inquireQueueType) isAbtError
ifTrue: [
Transcript cr; show: 'Inquire request failed'.
Transcript cr; show: 'Return code: ',
(aQueue lastError codesAsString); cr]
ifFalse: [Transcript cr;
show: 'Inquire request returned: ', rc printString].
(rc := aQueueManager disconnect) isAbtError ifTrue: [self halt].
Browse the inquireQueueType: method of the AbtMQqueue class for all the constants that can be returned when querying a queue. To view all the constants available for working with MQ Series from VAST, browse the AbtMQConstants pool dictionary.
Defining a Distribution List
AbtMQDistributionList maintains an OrderedCollection of instances of AbtMQDistributionListQueueInfo; each member of the OrderedCollection corresponds to one destination for the distribution list. You must initialize each instance of AbtMQDistributionListQueueInfo with the queue name and information about the queue manager (which you can initialize either by passing the name of the queue manager or by passing an instance of AbtMQqm). The instances may optionally contain any information that would normally go into an MQPMR structure.
You may build the OrderedCollection in AbtMQDistributionList in one of two ways. You could build each instance of AbtMQDistributionListQueueInfo yourself, passing the instances to the AbtMQDistributionList through the method addDestination:. Alternatively, you could use the method AbtMqDistributionList >> addQueue:queueManger: and allow this method to automatically build the AbtMQDistributionList instances for you.
We have added the classes AbtMQORStruct and AbtMQPmrStruct to support the new structures for MQOR and MQPMR. We have also updated the classes AbtMQPMOStruct and AbtMQODStruct to contain the optional fields used with distribution lists. Note that if you are using any of the fields in the MQPMR structure, you must use the method AbtMQDistributionList >> pmoPutMsgRecFields: to set the MQPMO structure's putsgRecFields value.
With distribution lists, it is now possible to get multiple errors back from one command. We have added the class AbtMQMultipleErrors where you would normally receive an AbtMQError.
Sending and receiving messages
After you have properly opened a queue you can place messages on the queue or retrieve messages from the queue. The queue must be opened with the proper options for the activity you wish to perform.
To place a message on the queue, do the following:
| aQueue aQueueManager rc |
"Connect to queue manager"
(aQueueManager := AbtMQqm new) name: 'MYQMGR'.
(rc := aQueueManager connect) isAbtError
ifTrue: [
Transcript cr; show: 'Connect request failed'.
^Transcript cr; show: 'Return code: ',
(aQueueManager lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Connect is ok'].
(aQueue := AbtMQqueue new)
name: 'MYQMGR.MYQUEUE';
queueManager: aQueueManager.
(rc := aQueue openWithOptions:
(AbtMQConstants::MqooInputShared |
AbtMQConstants::MqooOutput |
AbtMQConstants::MqooInquire |
AbtMQConstants::MqooSet)) isAbtError
ifTrue: [
Transcript cr; show: 'Open of queue request failed'.
^Transcript show: 'Return code: ',
(aQueue lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Open of queue is ok'].
aMessage := AbtMQMessage
fromBytes: ('This is message 1' asByteArray)
msgId: ('Dave1' asByteArray);
msgType: AbtMQConstants::MqmtDatagram;
replyToQ: 'MYQMGR.MYQUEUE'.
(rc := aQueue putMessageWithDefaultOptions: aMessage) isAbtError
ifTrue: [
Transcript cr; show: 'Put to queue request failed'.
Transcript show: ' Return code: ',
(aQueue lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Put to queue is ok'].
Browse the msgType: method of the AbtMQMessage class for all the options you can specify when opening a queue
To receive a message, do the following:
| aQueue aQueueManager rc |
"Connect to queue manager"
(aQueueManager := AbtMQqm new) name: 'MYQMGR'.
(rc := aQueueManager connect) isAbtError
ifTrue: [
Transcript cr; show: 'Connect request failed'.
^Transcript cr; show: 'Return code: ',
(aQueueManager lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Connect is ok'].
(aQueue := AbtMQqueue new)
name: 'MYQMGR.MYQUEUE';
queueManager: aQueueManager.
(rc := aQueue openWithOptions:
(AbtMQConstants::MqooInputShared |
AbtMQConstants::MqooOutput |
AbtMQConstants::MqooInquire |
AbtMQConstants::MqooSet)) isAbtError
ifTrue: [
Transcript cr; show: 'Open of queue request failed'.
^Transcript show: 'Return code: ',
(aQueue lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Open of queue is ok'].
(rc := aQueue getMessage) isAbtError
ifTrue: [
Transcript cr; show: 'Get from queue request failed'.
Transcript show: ' Return code: ',
(aQueue lastError codesAsString); cr]
ifFalse: [
Transcript cr; show: 'Get from queue is ok'.
Transcript cr; show: 'Message id is: ', rc msgId.
Transcript cr; show: 'Message data is: ', rc contentsAsString].
Closing the queue
To close the queue, send the instance the close message, as illustrated in the following code example:
| aQueue rc |
(rc := aQueue close) isAbtError
ifTrue: [
Transcript cr; show: 'Close of queue request failed'.
^Transcript show: ' Return code: ',
(aQueue lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Close of queue is ok'].
Disconnecting from the queue manager
After all queues are close, you can disconnect from the queue manager, send the instance the disconnect message, as illustrated in the following code example:
| aQueueManager rc |
(rc := aQueueManager disconnect) isAbtError
ifTrue: [
Transcript cr; show: 'Disconnect request failed'.
Transcript show: ' Return code: ',
(aQueueManager lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Disconnect is ok'].
MQ Series client and server support
MQI provides two types of support on Windows, AIX, Solaris, and Linux client support and server support. Server applications can put and get messages by directly accessing message queues, while client applications send MQ requests to the server (via APPC, or TCP) in order to put and get messages.
Each type of support is provided by a different runtime library (DLL). To change the type of support you are using, execute one of the following statements in the Transcript window:
| | |
Windows 2000 / XP / 7 / 10 | PlatformLibrary mapLogicalName: 'MQSERIESDLL' toPhysicalName: 'MQIC32' (Default) | PlatformLibrary mapLogicalName: 'MQSERIESDLL' toPhysicalName: 'MQM' |
Using the AbtMQConnection class
The AbtMQConnection class is a higher level abstraction of the AbtMQqueue and AbtMQqm classes. The AbtMQConnection class is used in conjunction with the AbtMQConnectionSpec class. The AbtMQConnectionSpec provides the necessary information used by the AbtMQConnection class allowing it to both connect to the queue manager and access its input and output queues. The following sections discuss how you use these classes to establish a connection between your application and an MQ Series queue.
Defining an AbtMQConnectionSpec
An
AbtMQConnectionSpec is used to provide all the information necessary to connect a queue manager and open input and output queues. You must create a new instance of AbtMQConnectionSpec and specify values for the
queueManagerName,
replyQueueName and
requestQueueName prior to attempting to connect. If you neglect to specify names for the input or output queue none will be opened for you by the instance of the class AbtMQConnection. By setting the
server attribute of the of the AbtMQConnectionSpec to True or False you specify whether the request queue will be used for input or output of MQ messages. Refer to
Setting up an MQI conversation for additional information about the server attribute setting.
In the following example we set the server attribute to False so that the request queue will be used for output and the reply queue will be used as input. In other words the AbtMQConnectionSpec will specify information for an MQ client configuration. You can set the syncPoint attribute to True if you want to commit or rollback a series of MQ gets and/or puts that define your Logical Unit of Work.
Note:
For a detailed description of the Logical Unit of Work, see the IBM publication Transaction Processing:Concepts and Products (GC33-0754).
| aConnectionSpec |
aConnectionSpec := AbtMQSeriesConnectionSpec new
queueManagerName: 'TEST';
requestQueueName: 'TEST.VAQUEUE1';
replyQueueName:'TEST.VAQUEUE2';
syncPoint: false;
server: false
yourself.
Connecting to a queue manager and opening input and output queues
The AbtMQConnection class uses the AbtMQSeriesConnectionSpec to connect to the queue manager and open its input and output queues. The following example shows the use of the connection spec to connect and open the queues:
| aConnectionSpec aConnection rc |
aConnectionSpec := AbtMQSeriesConnectionSpec new
queueManagerName: 'TEST';
requestQueueName: 'TEST.VAQUEUE1';
replyQueueName: 'TEST.VAQUEUE2';
syncPoint: false;
server: false
yourself.
aConnection := AbtMQConnection new.
(rc := aConnection connectUsing: aConnectionSpec)
isAbtError ifTrue: [
Transcript cr; show: 'Connect request failed, '.
^Transcript show: 'Return Code: ',
(aConnection lastError codesAsString); cr]
ifFalse: [Transcript cr; show: 'Connect request is ok'].
Putting a message to the output queue
The VAST MQ classes provide the user with the flexibility to define their own MQ messages and control the message descriptor contents. The user may also allow VAST MQ support to define a default message descriptor for them. In the first of two examples to follow we use the default message descriptor. In the second example we show how to define your own.
Example one using default message descriptor
| aConnectionSpec aConnection rc aMessage |
"Define a connection spec, connect to a queue manager and open queues
as illustrated in previous example"
(rc := aConnection putRequest: 'This is a test string to be written
to our message queue ') isAbtError;
ifTrue: [Transcript cr; show: 'Error writing to queue '.
Transcript show: 'Return code: ';
show: aConnection lastError codesAsString; cr]
ifFalse: [Transcript cr; show: 'Write to queue was ok'].
Example two shows user defined message descriptor
| aConnectionSpec aConnection rc aMessage |
"Define a connection spec, connect to a queue manager and open queues
as illustrated in previous example"
aMessage := AbtMQMessage
fromBytes: 'This is a test message ' asByteArray
msgId: 'VA Msg' asByteArray;
msgType: AbtMQConstants::MqmtRequest;
replyToQ: 'TEST.VAQUEUE2';
yourself.
(rc := aConnection putMQMessage aMessage) isAbtError;
ifTrue: [Transcript cr; show: 'Error writing to queue '.
Transcript show: 'Return code: ';
show: aConnection lastError codesAsString; cr]
ifFalse: [Transcript cr; show: 'Write to queue was ok'].
Reading a message from the input queue
The VAST AbtMQConnection class asks MQ to return the first available message from the queue. If the user wants to get a message with a specific message or correlation ID then they need to use the AbtMQqueue class.
| aConnectionSpec aConnection rc aMessage |
"Define a connection spec, connect to a queue manager and open queues
as illustrated in previous example"
(rc := aConnection get) isAbtError;
ifTrue: [Transcript cr;
show: 'Get from queue failed, return code = ';
show: aConnection lastError codesAsString]
ifFalse: [Transcript cr; show: 'The message id = ';
show: rc msgId printstring; cr;
show: 'The message data is: ';
show: rc contentsAsString].
Defining a unit of work
Applications may use the AbtMQqm>>begin API (MQBEGIN function call) to start a unit of work. The AbtMQBOStruct allows the application to specify options relating to the creation of a unit of work. The structure is an input/output parameter on the MQBEGIN call. The AbtMQBOStruct is not available for MQ clients. Refer to MQSeries documentation for further information about these functions and structures.
Disconnecting from the queue manager and closing the queues
To close the queues and disconnect from the queue manager pass the disconnect message to the connection.
| aConnectionSpec aConnection rc aMessage |
(rc := aConnection disconnect) isAbtError;
ifTrue: [Transcript cr; show: 'Error disconnecting rc = ';
show: aConnection lastError codesAsString]
ifFalse: [Transcript cr; show: 'Disconnect was successful'].