MQI is supported by three primary classes implemented at the system layer:
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 VisualAge 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.
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 | "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 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 | "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: (MqooInputShared | MqooOutput | MqooInquire | 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'].
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].
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 AbtMQDistributionListQueueInfowith 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 MQPMRstructure.
You may build the OrderedCollectionin AbtMQDistributionListin one of two ways. You could build each instance of AbtMQDistributionListQueueInfoyourself, passing the instances to the AbtMQDistributionListthrough the method addDestination:. Alternatively, you could use the method AbtMqDistributionList>> addQueue:queueManger: and allow this method to automatically build the AbtMQDistributionListinstances for you.
We have added the classes AbtMQORStructand AbtMQPmrStructto support the new structures for MQORand MQPMR. We have also updated the classes AbtMQPMOStructand AbtMQODStructto contain the optional fields used with distribution lists. Note that if you are using any of the fields in the MQPMRstructure, you must use the method AbtMQDistributionList >> pmoPutMsgRecFields: to set the MQPMOstructure's putsgRecFieldsvalue.
With distribution lists, it is now possible to get multiple errors back from one command. We have added the class AbtMQMultipleErrorswhere you would normally receive an AbtMQError.
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 | "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: (MqooInputShared | MqooOutput | MqooInquire | 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: 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'].
To receive a message, do the following:
| aQueue aQueueManager | "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: (MqooInputShared | MqooOutput | MqooInquire | 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].
To close the queue, send the instance the close message, as illustrated in the following code example:
| aQueue | (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'].
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 := 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'].
MQI provides two types of support on OS/2, Windows, AIX, and Solaris: 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:
Platform | Client | Server | |
---|---|---|---|
Windows 95 | (No client on Windows 95)
|
PlatformLibrary mapLogicalName: 'MQSERIESDLL' toPhysicalName: 'MQM' (Default)
| |
Windows NT |
PlatformLibrary mapLogicalName: 'MQSERIESDLL' toPhysicalName: 'MQIC32' (Default)
|
PlatformLibrary mapLogicalName: 'MQSERIESDLL' toPhysicalName: 'MQM' | |
OS/2 |
PlatformLibrary mapLogicalName: 'MQSERIESDLL' toPhysicalName: 'MQIC' (Default)
|
PlatformLibrary mapLogicalName: 'MQSERIESDLL' toPhysicalName: 'MQM' | |
Solaris |
AbtMQSeriesBaseUnixSubApp client |
AbtMQSeriesBaseUnixSubApp server (Default)
| |
AIX | threaded |
AbtMQSeriesBaseUnixSubApp client; threaded |
AbtMQSeriesBaseUnixSubApp server; threaded |
unthreaded |
AbtMQSeriesBaseUnixSubApp client; unThreaded |
AbtMQSeriesBaseUnixSubApp server; unThreaded (Default)
|
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.
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.
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'].
The VisualAge Smalltalk 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 VisualAge Smalltalk 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: 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'].
The VisualAge Smalltalk 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].
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'].