getting 2110 MQRC format error from Mainframe when sending request and getting reply from IBM MQ using JMS

194 views Asked by At

Due to the IBM migration, the previously utilized connection pool manager is no longer supported. Consequently, I am in the process of identifying an alternative approach for sending messages. It's important to note that the existing code used to send messages as shown below. I have attempted to convert it into equivalent JMS code. However, I'm uncertain whether this conversion is in the correct format or not. When testing on the mainframe side, it results in a '2110 MQRC FORMAT ERROR.' Could you please review and verify the accuracy of this conversion?"


OLD CODE:
   MQMessage reqMsg = new MQMessage();
      reqMsg.messageId        = CMQC.MQMI_NONE;
      reqMsg.correlationId    = CMQC.MQCI_NEW_SESSION;
      reqMsg.userId           = racfUserid;
      reqMsg.characterSet     = CHARSET_IBM500;

      reqMsg.persistence      = persistence;
      //  ---- create request message
      String result = "";

         byte blanks[] = new byte[8];
         for (int i=0; i<blanks.length; i++)
            blanks[i] = (byte)' ';
         reqMsg.clearMessage();
         // ---- write MQCIH
         reqMsg.writeString ("CIH ");              // MQCHAR4   StrucId;
         reqMsg.writeInt (2);                      // MQLONG    Version;
         reqMsg.writeInt (180);                      // MQLONG    StrucLength;
         reqMsg.writeInt (reqMsg.encoding);        // MQLONG    Encoding;
      MQPutMessageOptions pmo = new MQPutMessageOptions();
         pmo.options = CMQC.MQPMO_NEW_MSG_ID |
                                              CMQC.MQPMO_SET_IDENTITY_CONTEXT |
                                              CMQC.MQPMO_FAIL_IF_QUIESCING;
         requestQueue.put (reqMsg, pmo);

//JMS Code

      Hashtable<String, String> environment = new Hashtable<String, String>();

      environment.put(Context.INITIAL_CONTEXT_FACTORY,
          "com.ibm.websphere.naming.WsnInitialContextFactory");

      Context context = new InitialContext(environment);

      ConnectionFactory connectionFactory = (ConnectionFactory) context
          .lookup("name");

      Destination requestQueue = (Destination) context
          .lookup(requestQueueName);
      Connection connection = connectionFactory.createConnection();
      Session session = connection.createSession(false,
          Session.AUTO_ACKNOWLEDGE);
     Destination replyQueue = (Destination) context
          .lookup(replyToQueueName);
      context.close();
      MessageProducer producer = session.createProducer(requestQueue);


      BytesMessage message = session.createBytesMessage();

      message.setJMSMessageID(MQConstants.MQMI_NONE.toString());
         message.setJMSCorrelationIDAsBytes(MQConstants.MQCI_NEW_SESSION);
      message.setJMSReplyTo(replyQueue);
      message.setStringProperty("JMS_IBM_MQMD_UserIdentifier", racfUserid);
      message.setIntProperty("JMS_IBM_MQMD_CodedCharSetId",

      byte blanks[] = new byte[8];
      for (int i = 0; i < blanks.length; i++)
        blanks[i] = (byte) ' ';

      // Construct the CIH header as a byte array
      ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
      DataOutputStream outData = new DataOutputStream(outBytes);

      outData.writeBytes("CIH "); // MQCHAR strucId
      outData.writeInt(2); // MQLONG version
      outData.writeInt(180); // MQLONG strucLength
      outData.writeInt(messageEncoding); // MQLONG encoding
      outData.writeInt(CHARSET_IBM500); // MQLONG CodedCharSetId;


      StringBuffer pgmName = new StringBuffer(progName);
      for (int i = pgmName.length(); i < 8; i++)
        pgmName.append(' ');

      outData.writeBytes(pgmName.substring(0, 8)); 
      outData.writeBytes(commArea);

      byte[] cihRequestMessage = outBytes.toByteArray();
      message.writeBytes(cihRequestMessage);
      producer.send(message);

        MessageConsumer consumer = session.createConsumer(replyQueue);

      Message replyMessage = consumer.receive(replyTimeout * 1000);

1

There are 1 answers

6
Roger On

I'm confused by what you are doing. Secondly, there is an MQ class called MQCIH that handles CICS messages.

Here's the proper way of doing it:

MQMessage sendMsg = new MQMessage();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutput dataOutput = new DataOutputStream(baos);

MQCIH cih = new MQCIH();

cih.setVersion(version);
cih.setEncoding(encoding);
cih.setCodedCharSetId(CCSID);
cih.setFlags(flags);
cih.setReturnCode(returnCode);
cih.setCompCode(compCode);
cih.setReason(reason);
cih.setUOWControl(UOWControl);
cih.setGetWaitInterval(getWaitInterval);
cih.setLinkType(linkType);
cih.setOutputDataLength(outputDataLength);
cih.setFacilityKeepTime(facilityKeepTime);
cih.setADSDescriptor(aDSDescriptor);
cih.setConversationalTask(conversationalTask);
cih.setTaskEndStatus(taskEndStatus);
cih.setCursorPosition(cursorPosition);
cih.setErrorOffset(errorOffset);
cih.setInputItem(inputItem);
cih.setFormat(format);
cih.setFacility(tempFacility)
cih.setFunction(function);
cih.setAbendCode(abendCode);
cih.setAuthenticator(authenticator);
cih.setReplyToFormat(replyToFormat);
cih.setRemoteSysId(remoteSysId);
cih.setRemoteTransId(remoteTransId);
cih.setTransactionId(transactionId);
cih.setFacilityLike(facilityLike);
cih.setAttentionId(attentionId);
cih.setStartCode(startCode);
cih.setCancelCode(cancelCode);
cih.setNextTransactionId(nextTransactionId);

cih.write(dataOutput);

sendMsg.write(baos.toByteArray());

sendMsg.writeString("This is a test message");

sendMsg.format = CMQC.MQFMT_CICS;
sendMsg.messageType = CMQC.MQMT_DATAGRAM;
sendMsg.messageId = CMQC.MQMI_NONE;
sendMsg.correlationId = CMQC.MQCI_NONE;

queue.put(sendMsg, new MQPutMessageOptions());

Update: August 30

You are going down a path very few have gone. I have tried to get IMS/CICS messages to work with JMS but have failed. A JMS message is internally known as an MQRFH2 header.

MQRFH2 and MQCIH headers are called embedded headers. Meaning they exist in front of the message payload and not in a separate structure. So, basically, you are chaining together several embedded headers.

{MQRFH2}{MQCIH}{message payload}

First, you have to set the "format" field of each chained embedded message. MQ/JMS library will set the correct format for the JMS message. But you need to set the format of the MQCIH in the MQRFH2 header. i.e. So MQ knows what to expect in the next part of the chain. And in the MQCIH, you need to set the format of the message payload. i.e. NONE, STRING, etc..

i.e. something like this.

outData.setStringProperty(WMQConstants.JMS_IBM_MQMD_FORMAT, "MQCICS");
outData.setStringProperty(WMQConstants.JMS_IBM_MQMD_Encoding, MQC.MQENC_INTEGER_NORMAL);
outData.setStringProperty(WMQConstants.JMS_IBM_MQMD_CodedCharSetId, 819);

Or possibly this:

outData.setStringProperty("JMS_IBM_Format", "MQCICS");
outData.setIntProperty("JMS_IBM_Encoding", MQC.MQENC_INTEGER_NORMAL);
outData.setIntProperty("JMS_IBM_Character_Set", 819);

Then, you create the MQCIH header:

//write MQCIH struct into message buffer

outData.writeString("CIH ");           /* Structure identifier */
outData.writeInt(1);                   /* Structure version number 1 or 2 */
outData.writeInt(164);                 /* Length of MQCIH structure V1=164 V2=180 */
outData.writeInt(putMsg.encoding);     /* Reserved */
outData.writeInt(putMsg.characterSet); /* Reserved */
outData.writeString(MQC.MQFMT_NONE);   /* MQ Format name */
outData.writeInt(0);                   /* Reserved */
outData.writeInt(0);                   /* Return code from bridge */
outData.writeInt(0);                   /* MQ completion code or CICS
                                              EIBRESP */
outData.writeInt(0);                   /* MQ reason or feedback code, or CICS
                                              EIBRESP2 */
outData.writeInt(273);                 /* Unit-of-work control */
outData.writeInt(-2);                  /* Wait interval for MQGET call issued
                                              by bridge */
outData.writeInt(1);                   /* Link type */
outData.writeInt(-1);                  /* Output commarea data length */
outData.writeInt(0);                   /* Bridge facility release time */
outData.writeInt(0);                   /* Send/receive ADS descriptor */
outData.writeInt(0);                   /* Whether task can be
                                              conversational */
outData.writeInt(0);                   /* Status at end of task */
//     byte [] temp = new byte[8];
//outData.writeFully(temp);               /* BVT token value */
outData.writeInt(0);   // need 8 use 4 * 2
outData.writeInt(0);

outData.writeString("    ");           /* MQ call name or CICS EIBFN function
                                              name */
outData.writeString("    ");           /* Abend code */
outData.writeString("Password");       /* Password or passticket */
outData.writeString("        ");       /* Reserved */
//   putMsg.writeString(MQC.MQFMT_NONE);   /* MQ format name of reply message */
outData.writeString("ABCD1234");   /* MQ format name of reply message */
outData.writeString("    ");           /* Remote sysid to use */
outData.writeString("    ");           /* Remote transid to attach */
outData.writeString("    ");           /* Transaction to attach */
outData.writeString("    ");           /* Terminal emulated attributes */
outData.writeString("    ");           /* AID key */
outData.writeString("    ");           /* Transaction start code */
outData.writeString("    ");           /* Abend transaction code */
outData.writeString("MMMM");           /* Next transaction to attach */
outData.writeString("        ");       /* Reserved */
outData.writeString("        ");       /* Reserved */

     //Version 2 fields
outData.writeInt(0);                   /* Cursor position */
outData.writeInt(0);                   /* Error offset */
outData.writeInt(0);                   /* Input item */
outData.writeInt(0);                   /* Reserved */

Finally, you can go down this path but I wouldn't recommend it unless you are extremely knowledgeable of MQ. Personally, I would write the code in Java (not JMS) because it is so much simpler.