Coding the Java Application

There are seven steps that are involved in developing this part of the application:

To provide the connection to an MQSeries queue manager, we have created a Java class MQCommunicator. It looks like this:

public class MQCommunicator {.......}

The full code is on the accompanying CD in the directory called \mqseries-java client\MQCommunicator.class.

MQSeries provides a number of Java classes, which we can access on Windows NT by importing the package com.ibm.mq.*. In order to make a connection to the relevant queue manager we need to supply the following information:

  • The IP address of the host machine on which the OS/390 queue manager that we are going to use is located

  • The name of the Windows NT queue manager

  • The name of the MQI channel that makes the connection from the MQSeries client to the Windows NT queue manager (named in the previous bullet)

  • The request queue where we put the MQSeries message containing details of the customer account number

  • The reply-to queue onto which we get the response message containing the customer details supplied by the NACT02 application

The code looks like this:

// Setup MQ object

MQComms=newMQCommunictaor(hostname,qManager,channel,requestQueue,replyQueue);

Using the MQSeries supplied environment class MQEnvironment, we set the variables for the host name, queue manager, and the communications port to use:

MQEnvironment.hostname = hostname;            // ARG#1
MQEnvironment.channel  = channel;             // ARG#2
MQEnvironment.port = 1414;                    // Hard code port

The communications port in this case has the system default value of 1414. When no value is set for the port, this value will normally be assumed. This is important if you are using more than one port.

Connection to the selected queue manager is then made by creating an instance of the MQSeries supplied object MQQueueManager:

qMgr = new MQQueueManager(qManager);

Once we have established the connection, we can open the MQSeries queues for use. requestQueue and replyQueue are instances of the MQSeries supplied object MQQueue.

To enable the request queue so that we can place messages on it, we set the relevant open option:

openOptions = MQC.MQOO_OUTPUT ;          // Open queue to perform MQPUTs

This information is then supplied with the open request:

requestQueue = qMgr.accessQueue(aRequestQueue, openOptions,
                   null,           // queue manager on which the queue is defined
                   null,           // no dynamic queue name
                   null);         // no alternate user id

The use of null for the queue manager name denotes that the queue is defined to the queue manager to which this MQQueueManager object is connected.

Similarly, we enable the reply-to queue so that we can get the response message:

openOptions = MQC.MQOO_INPUT_AS_Q_DEF ;
replyQueue = qMgr.accessQueue(aReplyQueue, openOptions,
                   null,            // queue manager on which the queue is defined
                   null,             // no dynamic queue name
                   null);           // no alternate user id

To create an instance of the MQSeries object MQMessage:

sendMessage = new MQMessage();

Default values for the message can be used for most of the message options. The following changes need to be made:

Add the COMMAREA fields to the message buffer:

MQMessage.WriteString
.
Add COMMAREA structure

Under certain circumstances, the message format required for the MQSeries CICS DPL bridge contains an additional structure compared with standard MQSeries messages.

For our simple example (which only starts one program), this MQCIH structure is not required. The MQCIH is required when you want to do one of the following:

The MQCIH header is placed at the start of the message buffer.

The contents of the request COMMAREA for this application always contain the same supplied values apart from the customer account number keyfield. We have chosen to store the COMMAREA fields before the customer account number key-field in the string bufferFront. The fields following the customer account number keyfield are stored in the string bufferEnd.

The bufferFront string is composed as follows:

bufferFront = "NACT02" +   // Program name
         "V1A"+            // Version
         "E"+              // Request type
         "    "+           //
         "    "+
         "     "

We need to supply the remainder of the COMMAREA after the customer account number. It consists of only spaces. As a result, bufferEnd is a string of 378 spaces.

These values are now used to create the message buffer string:

String buffer = new String(bufferFront + customerNumber + bufferEnd);

The customerNumber field is a 5-character string holding the customer account number value.

This is then written to the MQSeries message instance sendMessage:

sendMessage.writeString(buffer);

MQSeries provides an object to specify options for the message being put onto a queue. In most cases the default options are acceptable. We create an instance of this MQPutMessageOptions object pmo:

// Specify the message options...(default)
MQPutMessageOptions pmo = new MQPutMessageOptions();

The message can now be placed on the appropriate queue:

requestQueue.put(sendMessage, pmo);

The response message is recognized by its correlation ID (CorrelId), which matches the original message ID (msgId) passed with the request message. The application copies the global: message ID of the request message into the correlation ID of a new MQMessage object, in this case, the response message.

In a similar way to which we built the request message, we first create an instance of the MQSeries object MQGetMessageOptions, which is used to set the options for getting the response message:

MQGetMessageOptions gmo = new MQGetMessageOptions();

You can modify the default values of this new instance gmo as follows:

We already have the required MQSeries message object in the instance StoredMessage which is supplied as the parameter replyMessage. The code to get the message is:

ReplyQueue.get(replyMessage,gmo);

The COMMAREA returned by NACT02 within the response message contains a response code and reason code. These need to be checked in order to determine whether the request to retrieve the customer details was successful or whether some error was encountered. For a non-zero return code, the following need to be checked:

Example 15-1. Sample Code for CICS-Related Errors

//informUser("Message received!");
//print("Message is: "+messageReturned);
//Check that inquire has been successful
CICSresponseCode = messageReturned.substring(12,16);
print(">CICS response code" +CICSresponseCode+"#");

CICSreasonCode=messageReturned.substring(16,20);
print(">CICS reason code" + CICSreasonCode+"#");
if (CICSresponseCOde.equals("0000")){
    //Strip off the fields preceding the customer record
    customerDetails = messageReturned.substring(25,408);
    AccountRecord retrieved=new AccountRecord(customerDetails);
    displayRecord(retreived);
    return;
}
//No valid record to display so clear fields
clearDisplay();
    //Check out error response returned by CICS
    if(CICSresponseCode.equals("0013")){
        informUser("No record can be found for the custimer number given.")
        return;
    }
    if(CICSresponseCode.equals("LOCK")){
        informUser("The requested record is currently unavailable, possibly being
            updated."
                     + "\nPlease try again later.");
         return;
    }
    if(CICSresponseCode.equals("ABND")){
        informUser("Please inform the systems administrator the the CICS system has"
            +"\nabnormally ended with code" + CICSreasonCode + "Severe Error");
        return;
    }
    if((CICSresponseCode.equals("FRMT")) & (CICSreasonCode.equals("LENE")){
        informUser("Please inform the systems administrator that the call to the CICS
            program" + "\nhas failed due to an error in the length of the data
            supplied.");
    }
    if((CICSresponseCode.equals("FRMT")) & (CICSreasonCode.equals("REQE"))){
        informUser("Please inform the systems administrator that the call to the CICS
             program + "\nhas failed due to an error in the type of request made.");
    }
    informUser("Please inform the systems administrator that the call to the CICS
         program + "\nhas failed with the following error" + "\
         nEIBRESP="CICSresponseCode+"EIBRESP2=" CICSreasonCode);
    }finally{
        enableDisableListitems(true);
    }

The next step is to create retrieved, a new instance of AccountRecord and pass the appropriate portion of the response message string as a parameter. The constructor class for this instance of AccountRecord uses the supplied string held in customerDetails to construct the various fields that make up the customer information returned within the COMMAREA from the NACT02 program. The basic method is to assign substrings based on position to the various declared fields of the AccountRecord structure. A getfieldname method is provided for each record field so that the fields can be easily retrieved by other Java classes. The code looks like:

AccountRecord retrieved = new AccountRecord(customerDetails);

The MQClient method displayRecord can then be used to populate the various fields displayed on our main panel:

displayRecord(retrieved);