How to resolve Unable to put message to reply queue. MQRC=2110?

281 Views Asked by At

I am encountering an issue when sending the message in this following manner. I am sending the message using CICS via JMS. I receive the error "Unable to put message to reply queue" with an MQRC=2110 error code on the mainframe side, and I also receive a null response. Can you help me resolve this issues.

Version : IBM MQ 9.1 I am sending the code like this...

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

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

            // Setup JNDI context
            Context context = new InitialContext(environment);

            // Look up connection factory and destination queue
            ConnectionFactory connectionFactory = (ConnectionFactory) context
                    .lookup("jms/xyz");
            
            // creating request Queue
            Destination requestQueue = (Destination) context
                    .lookup(requestQueueName);

            Connection connection = connectionFactory.createConnection();
            Session session = connection.createSession(false,
                    Session.AUTO_ACKNOWLEDGE);
            logger.info("getJMSConnection:: JMS connections  created ...");
1

There are 1 best solutions below

3
Roger On

You didn't follow any tips I gave you in the other post on the same subject. There is a lot wrong with your code so I decided to play around with my own code because I was bored today.

I don't think you are understanding how MQ handles the chaining of embedded structures:

This sets the CCSID of the MQMD header:

message.setIntProperty("JMS_IBM_MQMD_CodedCharSetId",819);

Whereas this sets the CCSID of the first embedded structure:

message.setIntProperty("JMS_IBM_Character_Set", 819);

Next, why are you setting the MQMD UserId field? There is really no purpose to it.

And your setting of the MQMD format field is not correct.

Finally, is the message payload or any of the structures going to be in EBCDIC? If not, then do NOT attempt to set the CCSID, because it will just break or generate an error.

Here is a fully functioning JMS application that puts a CICS message to a queue.

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;

import javax.jms.BytesMessage;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.ibm.msg.client.jms.JmsDestination;

import com.ibm.mq.MQException;
import com.ibm.mq.constants.MQConstants;

/**
 * Program Name
 *  MQTestJMS03
 *
 * Description
 *  This java JMS class will connect to a remote queue manager using JNDI and put a message to a queue.
 *
 * Sample Command Line Parameters
 *  -c myQCF -q dev.test.q -f C:\JNDI-Directory\roger\mqjndi -u UserID -x Password
 *
 *  Sample MQ JNDI Commands:
 *    DEFINE QCF(myQCF) QMANAGER(MQA1) CHANNEL(TEST.CHL) HOSTNAME(127.0.0.1) PORT(1414) TRANSPORT(CLIENT) FAILIFQUIESCE(YES)
 *    DEFINE Q(dev.test.q) QUEUE(TEST.Q1) QMANAGER(MQA1) TARGCLIENT(JMS) FAILIFQUIESCE(YES)
 *    DEFINE Q(dev.test.q.reply) QUEUE(TEST.REPLY.Q) QMANAGER(MQA1) TARGCLIENT(JMS) FAILIFQUIESCE(YES)
 *
 * @author Roger Lacroix
 */
public class MQTestJMS03
{
   private static final SimpleDateFormat  LOGGER_TIMESTAMP = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
   private final String BLANK4 = "    ";
   private final String BLANK8 = "        ";

   private QueueConnectionFactory cf;
   private String qName;
   private Destination destination = null;
   private Queue replyQ;
   private Hashtable<String,String> params;

   public MQTestJMS03() throws NamingException
   {
      super();
      params = new Hashtable<String,String>();
   }

   /**
    * Make sure the required parameters are present.
    * @return true/false
    */
   private boolean allParamsPresent()
   {
      boolean b = params.containsKey("-c") && params.containsKey("-q") &&
                  params.containsKey("-f") &&
                  params.containsKey("-u") && params.containsKey("-x");

      return b;
   }

   /**
    * Extract the command-line parameters and initialize the MQ variables.
    * @param args
    * @throws IllegalArgumentException
    */
   private void init(String[] args) throws IllegalArgumentException
   {
      if (args.length > 0 && (args.length % 2) == 0)
      {
         for (int i = 0; i < args.length; i += 2)
         {
            params.put(args[i], args[i + 1]);
         }
      }
      else
      {
         throw new IllegalArgumentException();
      }

      if (allParamsPresent())
      {
         Hashtable<String,String> env = new Hashtable<String,String>();
         env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
         env.put(Context.PROVIDER_URL, "file:/"+(String) params.get("-f"));

         try
         {
            Context ctx = new InitialContext(env);

            cf = (QueueConnectionFactory) ctx.lookup((String) params.get("-c"));
            qName = ((Queue) ctx.lookup((String) params.get("-q"))).getQueueName();
            replyQ = (Queue) ctx.lookup((String) params.get("-q") + ".reply");
         }
         catch (NamingException e)
         {
            MQTestJMS03.logger(e.getLocalizedMessage());
            e.printStackTrace();
            throw new IllegalArgumentException();
         }
         catch (JMSException e)
         {
            MQTestJMS03.logger(e.getLocalizedMessage());
            e.printStackTrace();
         }
      }
      else
      {
         throw new IllegalArgumentException();
      }
   }

   /**
    * Test the connection to the queue manager.
    * @throws MQException
    */
   private void testConn() throws JMSException
   {
      QueueConnection conn = null;
      QueueSession session = null;

      try
      {
         conn = cf.createQueueConnection((String) params.get("-u"), (String) params.get("-x"));
         conn.start();

         session = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
         MQTestJMS03.logger("successfully connected.");

         sendMsg(session);
      }
      catch (JMSException e)
      {
         MQTestJMS03.logger("getLinkedException()=" + e.getLinkedException());
         MQTestJMS03.logger(e.getLocalizedMessage());
         e.printStackTrace();
      }
      finally
      {
         try
         {
            if (session != null)
               session.close();
         }
         catch (Exception ex)
         {
            MQTestJMS03.logger("session.close() : " + ex.getLocalizedMessage());
         }

         try
         {
            if (conn != null)
               conn.stop();
         }
         catch (Exception ex)
         {
            MQTestJMS03.logger("connection.stop() : " + ex.getLocalizedMessage());
         }

         try
         {
            if (conn != null)
               conn.close();
         }
         catch (Exception ex)
         {
            MQTestJMS03.logger("connection.close() : " + ex.getLocalizedMessage());
         }
      }
   }

   /**
    * Send a message to a queue.
    * @throws MQException
    */
   private void sendMsg(QueueSession session) throws JMSException
   {
      QueueSender sender = null;

      try
      {
         destination = session.createQueue(qName);

         ((JmsDestination) destination).setIntProperty(MQConstants.WMQ_MQMD_MESSAGE_CONTEXT,MQConstants.WMQ_MDCTX_SET_IDENTITY_CONTEXT);

         // Enable write of MQMD fields. See documentation for further details.
         ((JmsDestination) destination).setBooleanProperty(MQConstants.WMQ_MQMD_WRITE_ENABLED, true);

         sender = session.createSender((Queue) destination);

         BytesMessage message = session.createBytesMessage();

         // Request Headers
         message.setStringProperty("JMS_IBM_MQMD_UserIdentifier", "RECFUSER");
//         message.setIntProperty("JMS_IBM_MQMD_CodedCharSetId",819);
         message.setJMSReplyTo(replyQ);

         /* Set the format value in the MQRFH2 header to CICS because that is the next embedded message. */
         message.setStringProperty("JMS_IBM_Format", "MQCICS");
//         message.setIntProperty("JMS_IBM_Character_Set", 819);

         // 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(MQConstants.MQENC_INTEGER_NORMAL); // MQLONG encoding

         // Only set this to 500 if your comm area aka message data is EBCDIC
         outData.writeInt(500);          // MQLONG CodedCharSetId;
         outData.writeBytes(MQConstants.MQFMT_STRING); // MQCHAR8 Format;
         outData.writeInt(4);            // MQLONG Flags;
         outData.writeInt(0);            // MQLONG ReturnCode;
         outData.writeInt(0);            // MQLONG CompCode; Completion code
         outData.writeInt(0);            // MQLONG Reason; MQ reason code
         outData.writeInt(0x111);        // MQCUOWC_ONLY // MQLONG UOWControl; Unit of work control

         outData.writeInt(-2);       // MQCGWI_DEFAULT // MQLONG GetWaitInterval;
         outData.writeInt(1);        // MQCLT_PROGRAM // MQLONG LinkType;
         outData.writeInt(-1);       // MQLONG OutputDataLength;
         outData.writeInt(0);        // MQLONG FacilityKeepTime;
         outData.writeInt(0);        // MQLONG ADSDescriptor;
         outData.writeInt(0);        // MQLONG ConversationalTask;
         outData.writeInt(0);        // MQLONG TaskEndStatus;
         outData.write(BLANK8.getBytes()); // MQBYTE Facility[8];
         outData.writeBytes(BLANK4); // MQCHAR4 Function;
         outData.writeBytes(BLANK4); // MQCHAR4 `    ;
         outData.writeBytes(BLANK8); // MQCHAR8 Authenticator;
         outData.writeBytes(BLANK8); // MQCHAR8 Reserved1;
         outData.writeBytes(MQConstants.MQFMT_STRING); // MQCHAR8
         outData.writeBytes(BLANK4); // MQCHAR4 RemoteSysId;
         outData.writeBytes(BLANK4); // MQCHAR4 RemoteTrans Id;
         outData.writeBytes("ABCD"); // MQCHAR4 TransactionId;;
         outData.writeBytes(BLANK4); // MQCHAR4 FacilityLike;
         outData.writeBytes(BLANK4); // MQCHAR4 AttentionId;
         outData.writeBytes(BLANK4); // MQCHAR4 StartCode;
         outData.writeBytes(BLANK4); // MQCHAR4 CancelCode;
         outData.writeBytes(BLANK4); // MQCHAR4 NextTransactionId;
         outData.writeBytes(BLANK8); // MQCHAR8 Reserved2;
         outData.writeBytes(BLANK8); // MQCHAR8 Reserved3;
         outData.writeInt(0);        // MQLONG CursorPosition;
         outData.writeInt(0);        // MQLONG ErrorOffset;
         outData.writeInt(0);        // MQLONG InputItem;
         outData.writeInt(0);        // MQLONG Reserved4;
         // ---- make sure progName is exactly 8 characters
         StringBuffer pgmName = new StringBuffer("TESTPGM");
         for (int i = pgmName.length(); i < 8; i++)
             pgmName.append(' ');
         // ---- write program name followed by commarea
         outData.writeBytes(pgmName.substring(0, 8));
         outData.writeBytes("commArea 012356789");

         message.writeBytes(outBytes.toByteArray());

         sender.send(message);

         MQTestJMS03.logger("Message sent.");
      }
      catch (JMSException e)
      {
         MQTestJMS03.logger("getLinkedException()=" + e.getLinkedException());
         MQTestJMS03.logger(e.getLocalizedMessage());
         e.printStackTrace();
      }
      catch (IOException e)
      {
         MQTestJMS03.logger(e.getLocalizedMessage());
         e.printStackTrace();
      }
      finally
      {
         try
         {
            if (sender != null)
               sender.close();
         }
         catch (Exception ex)
         {
            MQTestJMS03.logger("sender.close() : " + ex.getLocalizedMessage());
         }
      }
   }

   /**
    * A simple logger method
    * @param data
    */
   public static void logger(String data)
   {
      String className = Thread.currentThread().getStackTrace()[2].getClassName();

      // Remove the package info.
      if ( (className != null) && (className.lastIndexOf('.') != -1) )
         className = className.substring(className.lastIndexOf('.')+1);

      System.out.println(LOGGER_TIMESTAMP.format(new Date())+" "+className+": "+Thread.currentThread().getStackTrace()[2].getMethodName()+": "+data);
   }

   /**
    * main line
    * @param args
    */
   public static void main(String[] args)
   {
      try
      {
         MQTestJMS03 tj = new MQTestJMS03();
         tj.init(args);
         tj.testConn();
         MQTestJMS03.logger("finished.");
      }
      catch (IllegalArgumentException e)
      {
         MQTestJMS03.logger("Usage: java MQTestJMS03 -c QueueConnectionFactoryName -q JMS_Queue_Name -f path_to_MQ_JNDI -u UserID -x Password");
         System.exit(1);
      }
      catch (NamingException ex)
      {
         MQTestJMS03.logger(ex.getLocalizedMessage());
         ex.printStackTrace();

      }
      catch (JMSException e)
      {
         MQTestJMS03.logger("getLinkedException()=" + e.getLinkedException());
         MQTestJMS03.logger(e.getLocalizedMessage());
         e.printStackTrace();
      }
      catch (Exception ex)
      {
         MQTestJMS03.logger(ex.getLocalizedMessage());
         ex.printStackTrace();
      }
   }
}

Here is a HEX dump of the message sent from my code showing the 2 embedded structures:

enter image description here

The message's MQMD Format field is shown here:

enter image description here

And the MQRFH2 header, JMS properties and the correctly set CICS format is shown here:

enter image description here

Now, I don't currently have a CICS region to test your actual formatting CICS header and message payload. But if its not correct, just refer to the MQCIH structure in the cmqc.h file.

Or you could just use the MQCIH class from the MQ Java base classes.