Java 17 Released

Oracle has just released Java 17.

Java Platform, Standard Edition (Java SE) lets you develop and deploy Java applications on desktops and servers, as well as in today’s demanding embedded environments. Java offers the rich user interface, performance, versatility, portability, and security that today’s applicationsrequire.

Regards,
Roger Lacroix
Capitalware Inc.

IBM i (OS/400), Java, JMS, Linux, macOS (Mac OS X), Programming, Raspberry Pi, Unix, Windows, z/OS Comments Off on Java 17 Released

IBM MQ Fix Pack 9.1.0.9 Released

IBM has just released Fix Pack 9.1.0.9 for IBM MQ V9.1 LTS:
https://www.ibm.com/support/pages/downloading-ibm-mq-9109

Regards,
Roger Lacroix
Capitalware Inc.

Fix Packs for MQ, IBM i (OS/400), IBM MQ, IBM MQ Appliance, Linux, Unix, Windows Comments Off on IBM MQ Fix Pack 9.1.0.9 Released

IBM Announces IBM Semeru Runtimes

IBM has introduced no-cost IBM Semeru Runtimes to develop and run Java applications.
https://developer.ibm.com/blogs/introducing-the-ibm-semeru-runtimes/
https://developer.ibm.com/languages/java/semeru-runtimes/

IBM Semeru Runtimes use the class libraries from OpenJDK, along with the Eclipse OpenJ9 Java Virtual Machine to enable developers to build and deploy Java applications that will start quickly, deliver great performance, all while using less memory.

    Key highlights of these runtimes include:

  • Provides a stable, no-cost environment for developing Java workloads
  • Available across a wide variety of hardware and software platforms, including on-premises, in public cloud, or on container orchestrators like Kubernetes and OpenShift
  • Includes commonly used JDK releases like the JDK 8 and JDK 11 Long Term Support (LTS) releases
  • Performance benefits from deep technology investment in Eclipse OpenJ9
  • Zero usage restrictions, so you can use these runtimes for development or in production

You can review the performance overview at: https://www.eclipse.org/openj9/performance/. It looks pretty impressive.

Regards,
Roger Lacroix
Capitalware Inc.

Java, JMS, Linux, macOS (Mac OS X), Programming, Unix, Windows Comments Off on IBM Announces IBM Semeru Runtimes

How Long it Takes for a Hacker to Crack Your Password

Over at Komando’s web site, they have an article called: Use this chart to see how long it’ll take to crack your passwords.

A general rule is that your password should be at least 11 characters and use numbers, along with upper and lowercase letters. That combination will take hackers 41 years to crack.

Here’s the chart of password lengths, contents of password and how long it will take to crack it using brute force method:

Time it takes a hacker to brute force your password.

Regards,
Roger Lacroix
Capitalware Inc.

Education, Security Comments Off on How Long it Takes for a Hacker to Crack Your Password

IBM MQ Fix Pack 8.1.0.8 for HP NonStop Server Released

IBM has just released Fix Pack 8.1.0.8 for IBM MQ for HP NonStop Server:
https://www.ibm.com/support/pages/fix-list-ibm-mq-hpe-nonstop-version-81#8108

Regards,
Roger Lacroix
Capitalware Inc.

Fix Packs for MQ, HPE NonStop, IBM MQ Comments Off on IBM MQ Fix Pack 8.1.0.8 for HP NonStop Server Released

IBM MQ Fix Pack 9.2.0.3 Released

IBM has just released Fix Pack 9.2.0.3 for IBM MQ V9.2 LTS:
https://www.ibm.com/support/pages/node/6474635

Regards,
Roger Lacroix
Capitalware Inc.

Fix Packs for MQ, IBM i (OS/400), IBM MQ, IBM MQ Appliance, Linux, Unix, Windows Comments Off on IBM MQ Fix Pack 9.2.0.3 Released

IBM MQ V9.2.3 Announced

IBM has announced IBM MQ V9.2.3:
https://www.ibm.com/common/ssi/ShowDoc.wss?docURL=/common/ssi/rep_ca/1/877/ENUSZP21-0231/index.html

Highlights:

MQ 9.2.3:

  • – Streaming queues to make message data from existing flows available to Apache Kafka streaming applications, artificial intelligence (AI), and analytics applications, with zero impact to the existing applications or their messages and without a need for rearchitecting your message flows
  • – Broadened uniform cluster support for improved fault tolerance
  • – MQ Console remote queue manager support, enabling clients to manage their entire MQ estate
  • – Security enhancements
  • – A dead-letter queue (DLQ) handler included in the MQ client package to enable processing of messages on remote queue managers
  • – Additional channel attributes for Advanced Message Queueing Protocol (AMQP)
  • MQ Advanced 9.2.3:

  • – Native high availability (HA), delivered in 9.2.2 under an Early Access license, becomes generally available in 9.2.3. Native HA is for clients deploying container-based queue managers to IBM Cloud Pak® for Integration on Red Hat® OpenShift® using the MQ certified container.
  • – Replicated Data Queue Manager (RDQM) kernel module serviceability enhancements.
  • MQ Appliance 9.2.3 firmware:

  • – Streaming queues
  • – Broadened uniform cluster support
  • – Additional channel attributes for AMQP.
  • Planned availability for IBM MQ V9.2.3 is July 22, 2021 for Electronic software delivery.

    IBM MQ (aka WebSphere MQ) homepage
    https://www.ibm.com/products/mq

    Regards,
    Roger Lacroix
    Capitalware Inc.

    IBM MQ, IBM MQ Appliance, Linux, Unix, Windows, z/OS Comments Off on IBM MQ V9.2.3 Announced

    Time Warp – AIX and MQ v6

    Last week, a customer emailed an interesting request. They have 2 AIX hub servers running WebSphere MQ V6.0 and they want to determine what applications are using the 2 MQ hub servers, so that they can upgrade to a newer release of MQ. That made me clean my glasses because MQ v6 went out of support in September 2012 (almost 9 years ago).

    They asked if either MQ Auditor and/or MQ Channel Connection Inspector (MQCCI) could obtain the IP address of the incoming MQ connection. I said yes, both can get the IP address and if they didn’t want any other information (i.e. queue names, MQ headers, message data, etc) then MQCCI would be the best/easiest solution.

    Yesterday, I drove over to my offsite facility to search for backup DVDs of MQ v6. I have 2 boxes of DVD backups, it took about 30 minutes to find 2 backup DVDs with MQ v6 for AIX. I figured at least one of them should be ok.

    So, I created a reservation on IBM’s CECC portal for AIX v7.1, uploaded and installed MQ v6 and, of course, I had to install IBM’s XLC compiler because for some strange reason, CECC does not include it for AIX (but they do for Linux on Power and IBM i).

    MQCCI was created and launched in May 2018, long, long after MQ v6 went out of support. So, when I tried to do a build, I got several errors about unknown defines (i.e. MQCD_VERSION_9). So, I added a bunch of “#ifdefs” to the code and bam, it compiled and linked successfully.

    I created a queue manager and I did a bunch of tests with MQCCI. Everything went smoothly, so I let the customer know that I have a build for them to test out.

    At this point in my life, I’m never surprised by the odd requests I get. 🙂

    Regards,
    Roger Lacroix
    Capitalware Inc.

    Capitalware, IBM MQ, MQ Auditor, MQ Channel Connection Inspector, Unix Comments Off on Time Warp – AIX and MQ v6

    MQ Request/Reply Scenario with Async Getter Thread

    Ok. Continuing on with the previous blog posting here, the StackOverflow user says that s/he wants the getter component to be run in a separate thread.

    To me, the request does not really make a lot of sense. If the user wants to do a Get with CorrelId then they should be coding for synchronous processing and not Asynchronous.

    So, I have created a fully functioning Java/MQ application that will perform the request/response as an asynchronous process. The code uses Java’s Blocking Queue to communicate between the 2 threads. It will put 10 messages on the queue and then pass 3 random numbers as CorrelId to the Getter thread to perform a Get by CorrelId and a 4th invalid random number on the blocking queue to show how a failure would work.

    You can download the source code from here.

    import java.io.IOException;
    import java.text.DecimalFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Hashtable;
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    
    import com.ibm.mq.MQException;
    import com.ibm.mq.MQGetMessageOptions;
    import com.ibm.mq.MQMessage;
    import com.ibm.mq.MQPutMessageOptions;
    import com.ibm.mq.MQQueue;
    import com.ibm.mq.MQQueueManager;
    import com.ibm.mq.constants.CMQC;
    
    /**
     * Program Name
     *  MQTest11Async
     *
     * Description
     *  This java class will connect to a remote queue manager with the
     *  MQ setting stored in a HashTable, 
     *  
     *  Functionality:
     *  - Parse input parameters
     *  - Start a child thread for retrieving messages by CorrelId
     *  - Connect and open queue 
     *  - Put 10 message on a queue with unique CorrelIds
     *  - Pass the CorrelId to the child thread via the Blocking Queue
     *  - Close and disconnect
     *  
     *  Child thread:
     *  - Connect and open queue
     *  - Waiting on Blocking Queue 
     *  - Retrieve the message by CorrelId
     *  - When the QUIT message is received exit loop
     *  - Close and disconnect
     *
     * Sample Command Line Parameters
     *  -m MQA1 -h 127.0.0.1 -p 1414 -c TEST.CHL -q TEST.Q1 -u UserID -x Password
     *
     * @author Roger Lacroix
     */
    public class MQTest11Async
    {
       private static final SimpleDateFormat  LOGGER_TIMESTAMP = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
       private static final String            QUIT_MSG = "QUIT";
       private Hashtable<String,String>       params = new Hashtable<String,String>();
       private Hashtable<String,Object>       mqht = new Hashtable<String,Object>();
    
       /**
        * The constructor
        */
       public MQTest11Async()
       {
          super();
       }
    
       /**
        * Make sure the required parameters are present.
        * @return true/false
        */
       private boolean allParamsPresent()
       {
          boolean b = params.containsKey("-h") && params.containsKey("-p") &&
                      params.containsKey("-c") && params.containsKey("-m") &&
                      params.containsKey("-q") &&
                      params.containsKey("-u") && params.containsKey("-x");
          if (b)
          {
             try
             {
                Integer.parseInt((String) params.get("-p"));
             }
             catch (NumberFormatException e)
             {
                b = false;
             }
          }
    
          return b;
       }
    
       /**
        * Extract the command-line parameters and initialize the MQ HashTable.
        * @param args
        * @throws IllegalArgumentException
        */
       private void init(String[] args) throws IllegalArgumentException
       {
          int port = 1414;
          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())
          {
    
             try
             {
                port = Integer.parseInt((String) params.get("-p"));
             }
             catch (NumberFormatException e)
             {
                port = 1414;
             }
             
             mqht.put(CMQC.CHANNEL_PROPERTY, params.get("-c"));
             mqht.put(CMQC.HOST_NAME_PROPERTY, params.get("-h"));
             mqht.put(CMQC.PORT_PROPERTY, new Integer(port));
             mqht.put(CMQC.USER_ID_PROPERTY, params.get("-u"));
             mqht.put(CMQC.PASSWORD_PROPERTY, params.get("-x"));
    
             // I don't want to see MQ exceptions at the console.
             MQException.log = null;
          }
          else
          {
             throw new IllegalArgumentException();
          }
       }
    
       /**
        * Connect, open queue, write 10 messages, close queue and disconnect.
        */
       private void testSend()
       {
          MQPutMessageOptions     pmo = new MQPutMessageOptions();
          pmo.options = CMQC.MQPMO_NO_SYNCPOINT | CMQC.MQPMO_FAIL_IF_QUIESCING;
          MQQueueManager          qMgr = null;
          MQQueue                 queue = null;
          MQMessage               sendmsg;
          String                  msgData;
          DecimalFormat           df = new DecimalFormat("0000");
          BlockingQueue<Object>   toGetter_BQ = new ArrayBlockingQueue<Object>(100);
          String                  qMgrName = (String) params.get("-m");;
          String                  outputQName = (String) params.get("-q");
    
          /**
           * Start up child "getter" thread.
           */
          Thread t1 = new Thread(new Getter(toGetter_BQ, qMgrName, outputQName));
          t1.start();
    
          try
          {
             qMgr = new MQQueueManager(qMgrName, mqht);
             logger("successfully connected to "+ qMgrName);
    
             queue = qMgr.accessQueue(outputQName, CMQC.MQOO_OUTPUT | CMQC.MQOO_FAIL_IF_QUIESCING);
             logger("successfully opened "+ outputQName);
             
             /*
              * Code to send 10 messages with a specific CorrelId.  i.e. 0001, 0002, etc.
              */
             for (int i=0; i < 10; i++)
             {
                // Define a simple MQ message, and write some text
                sendmsg = new MQMessage();
                sendmsg.format = CMQC.MQFMT_STRING;
                sendmsg.messageId = CMQC.MQMI_NONE;
                sendmsg.correlationId = df.format(i+1).getBytes();
    
                // Write message data
                msgData = "This is a test message from MQTest11Async. CorrelID is "+new String(sendmsg.correlationId);
                sendmsg.writeString(msgData);
    
                // put the message on the queue
                queue.put(sendmsg, pmo);
                logger("Sent: Message Data>>>" + msgData);
             }
             
             try
             {
                // Put 3 random numbers on the blocking queue to be used as CorrelId by the child thread. 
                toGetter_BQ.put(df.format(5).getBytes());
                toGetter_BQ.put(df.format(3).getBytes());
                toGetter_BQ.put(df.format(7).getBytes());
    
                // Put on unknown CorrelId
                toGetter_BQ.put(df.format(99).getBytes());
    
                // Ok, tell child we are done.
                toGetter_BQ.put(QUIT_MSG);
             }
             catch (InterruptedException ie)
             {
                logger("InterruptedException: "+ie.getMessage());
             }
          }
          catch (MQException e)
          {
             logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
          }
          catch (IOException e)
          {
             logger("IOException:" +e.getLocalizedMessage());
          }
          finally
          {
             try
             {
                if (queue != null)
                {
                   queue.close();
                   logger("closed: "+ outputQName);
                }
             }
             catch (MQException e)
             {
                logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
             }
             try
             {
                if (qMgr != null)
                {
                   qMgr.disconnect();
                   logger("disconnected from "+ qMgrName);
                }
             }
             catch (MQException e)
             {
                logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
             }
          }
          
          try
          {
             // Wait for child thread to be done.
             t1.join();
          }
          catch (InterruptedException ie)
          {
             logger("InterruptedException: "+ie.getMessage());
          }
       }
    
       /**
        * Getter class to be run as a separate thread to retrieve messages from a queue. 
        * Connect, open queue, wait on blocking queue for instructions on what to do.  
        * Loop until we get the QUIT message then close queue and disconnect. 
        */
       class Getter implements Runnable 
       {
          private BlockingQueue<Object> toGetter_BQ;
          private String                qMgrName;
          private String                replyQName;
          private boolean               working = true;
    
          /**
           * The constructor
           * @param toGetter_BQ Blocking Queue
           * @param qMgrName Queue Manager name
           * @param replyQName Reply queue name
           */
          public Getter(BlockingQueue<Object> toGetter_BQ, String qMgrName, String replyQName)
          {
             super();
             this.toGetter_BQ = toGetter_BQ;
             this.qMgrName = qMgrName;
             this.replyQName = replyQName;
          }
          
          @Override
          public void run() 
          {
             Object         o;
             MQQueueManager qMgr = null;
             MQQueue        queue = null;
    
             try
             {
                qMgr = new MQQueueManager(qMgrName, mqht);
                logger("successfully connected to "+ qMgrName);
    
                queue = qMgr.accessQueue(replyQName, CMQC.MQOO_INPUT_SHARED | CMQC.MQOO_FAIL_IF_QUIESCING);
                logger("successfully opened "+ replyQName);
                
                while (working)
                {
                   // poll returns immediately with either an object or null
                   o = toGetter_BQ.poll();
    
                   /*
                    * Check what we got off the blocking queue.
                    */
                   if (o == null)
                   {
                      try
                      {
                         // Nothing to do! Put a slight pause in the loop. 
                         if (working)
                            Thread.sleep(50); // time in milliseconds
                      }
                      catch (InterruptedException ie)
                      {}
                   }
                   else if (o instanceof byte[])
                   {
                      logger("Retrieve the next CorrelId: " + new String((byte[])o));
                      getMessage((byte[])o, queue);
                   }
                   else if (o instanceof String)
                   {
                      if (QUIT_MSG.equals((String)o))
                      {
                         logger("quitting time. ");
                         working = false;
                      }
                      else
                      {
                         logger("Error: unknown string command: " + (String)o);
                      }
                   }
                   else
                   {
                      logger("Error: unknown object passed into BlockingQueue.");
                   }
                }
             }
             catch (MQException e)
             {
                logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
             }
             finally
             {
                try
                {
                   if (queue != null)
                   {
                      queue.close();
                      logger("closed: "+ replyQName);
                   }
                }
                catch (MQException e)
                {
                   logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
                }
                try
                {
                   if (qMgr != null)
                   {
                      qMgr.disconnect();
                      logger("disconnected from "+ qMgrName);
                   }
                }
                catch (MQException e)
                {
                   logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
                }
             }
          }
    
          /**
           * Retrieve a message by specific CorrelId
           * @param correlId
           * @param queue
           */
          private void getMessage(byte[] correlId, MQQueue queue)
          {
             logger("Attempting to get message from queue.");
             
             MQGetMessageOptions gmo = new MQGetMessageOptions();
             gmo.options = CMQC.MQGMO_NO_SYNCPOINT | CMQC.MQGMO_WAIT | CMQC.MQGMO_CONVERT | CMQC.MQGMO_FAIL_IF_QUIESCING;
             gmo.matchOptions = CMQC.MQMO_MATCH_CORREL_ID;
             gmo.waitInterval = 5000; // 5 seconds or you can use CMQC.MQWI_UNLIMITED
             
             // Define a simple MQ message, and write some text
             MQMessage receiveMsg = new MQMessage();
             receiveMsg.messageId = CMQC.MQMI_NONE;
             receiveMsg.correlationId = correlId;
    
             try
             {
                // get the message on the queue
                queue.get(receiveMsg, gmo);
    
                if (CMQC.MQFMT_STRING.equals(receiveMsg.format))
                {
                   String msgStr = receiveMsg.readStringOfByteLength(receiveMsg.getMessageLength());
                   logger("Received: Message Data>>>" + msgStr);
                }
                else
                {
                   byte[] b = new byte[receiveMsg.getMessageLength()];
                   receiveMsg.readFully(b);
                   logger("Received: Message Data>>>" + new String(b));
                }
             }
             catch (MQException e)
             {
                logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
             }
             catch (IOException e)
             {
                logger("IOException:" +e.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)
       {
          MQTest11Async mqta = new MQTest11Async();
    
          try
          {
             mqta.init(args);
             mqta.testSend();
             
             logger("exiting.");
          }
          catch (IllegalArgumentException e)
          {
             logger("Usage: java MQTest11Async -m QueueManagerName -h host -p port -c channel -q QueueName -u UserID -x Password");
             System.exit(1);
          }
    
          System.exit(0);
       }
    }

    And the output will look like:

    2021/07/08 13:27:04.684 MQTest11Async: testSend: successfully connected to MQA1
    2021/07/08 13:27:04.684 MQTest11Async$Getter: run: successfully connected to MQA1
    2021/07/08 13:27:04.700 MQTest11Async: testSend: successfully opened TEST.Q1
    2021/07/08 13:27:04.700 MQTest11Async$Getter: run: successfully opened TEST.Q1
    2021/07/08 13:27:04.700 MQTest11Async: testSend: Sent: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0001
    2021/07/08 13:27:04.700 MQTest11Async: testSend: Sent: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0002
    2021/07/08 13:27:04.700 MQTest11Async: testSend: Sent: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0003
    2021/07/08 13:27:04.700 MQTest11Async: testSend: Sent: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0004
    2021/07/08 13:27:04.700 MQTest11Async: testSend: Sent: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0005
    2021/07/08 13:27:04.700 MQTest11Async: testSend: Sent: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0006
    2021/07/08 13:27:04.700 MQTest11Async: testSend: Sent: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0007
    2021/07/08 13:27:04.700 MQTest11Async: testSend: Sent: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0008
    2021/07/08 13:27:04.700 MQTest11Async: testSend: Sent: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0009
    2021/07/08 13:27:04.700 MQTest11Async: testSend: Sent: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0010
    2021/07/08 13:27:04.700 MQTest11Async: testSend: closed: TEST.Q1
    2021/07/08 13:27:04.715 MQTest11Async: testSend: disconnected from MQA1
    2021/07/08 13:27:04.762 MQTest11Async$Getter: run: Retrieve the next CorrelId: 0005
    2021/07/08 13:27:04.762 MQTest11Async$Getter: getMessage: Attempting to get message from queue.
    2021/07/08 13:27:04.769 MQTest11Async$Getter: getMessage: Received: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0005
    2021/07/08 13:27:04.769 MQTest11Async$Getter: run: Retrieve the next CorrelId: 0003
    2021/07/08 13:27:04.769 MQTest11Async$Getter: getMessage: Attempting to get message from queue.
    2021/07/08 13:27:04.769 MQTest11Async$Getter: getMessage: Received: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0003
    2021/07/08 13:27:04.769 MQTest11Async$Getter: run: Retrieve the next CorrelId: 0007
    2021/07/08 13:27:04.769 MQTest11Async$Getter: getMessage: Attempting to get message from queue.
    2021/07/08 13:27:04.769 MQTest11Async$Getter: getMessage: Received: Message Data>>>This is a test message from MQTest11Async. CorrelID is 0007
    2021/07/08 13:27:04.769 MQTest11Async$Getter: run: Retrieve the next CorrelId: 0099
    2021/07/08 13:27:04.769 MQTest11Async$Getter: getMessage: Attempting to get message from queue.
    2021/07/08 13:27:09.774 MQTest11Async$Getter: getMessage: CC=2 : RC=2033
    2021/07/08 13:27:09.774 MQTest11Async$Getter: run: quitting time.
    2021/07/08 13:27:09.774 MQTest11Async$Getter: run: closed: TEST.Q1
    2021/07/08 13:27:09.774 MQTest11Async$Getter: run: disconnected from MQA1
    2021/07/08 13:27:09.774 MQTest11Async: main: exiting.

    Regards,
    Roger Lacroix
    Capitalware Inc.

    HPE NonStop, IBM i (OS/400), IBM MQ, IBM MQ Appliance, Java, Linux, macOS (Mac OS X), Open Source, Programming, Raspberry Pi, Unix, Windows Comments Off on MQ Request/Reply Scenario with Async Getter Thread

    Put 2 Messages with Unique CorrelId and Get 1 Message by CorrelId

    On StackOverflow, someone asked a question about putting 2 messages on a queue with unique correlation ids and then retrieve a message with a particular correlation id.

    Here is a fully functioning Java/MQ program that will put 2 messages on a queue with unique correlation ids and then retrieve a message with a particular correlation id (i.e. “0002”).

    You can download the source code from here.

    import java.io.IOException;
    import java.text.DecimalFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Hashtable;
    
    import com.ibm.mq.MQException;
    import com.ibm.mq.MQGetMessageOptions;
    import com.ibm.mq.MQMessage;
    import com.ibm.mq.MQPutMessageOptions;
    import com.ibm.mq.MQQueue;
    import com.ibm.mq.MQQueueManager;
    import com.ibm.mq.constants.CMQC;
    
    /**
     * Program Name
     *  MQTest11B
     *
     * Description
     *  This java class will connect to a remote queue manager with the
     *  MQ setting stored in a HashTable, put 2 message on a queue with unique CorrelIds
     *  and then retrieve the message with a  CorrelId of "0002".
     *
     * Sample Command Line Parameters
     *  -m MQA1 -h 127.0.0.1 -p 1414 -c TEST.CHL -q TEST.Q1 -u UserID -x Password
     *
     * @author Roger Lacroix
     */
    public class MQTest11B
    {
       private static final SimpleDateFormat  LOGGER_TIMESTAMP = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
    
       private Hashtable<String,String> params;
       private Hashtable<String,Object> mqht;
       private String qMgrName;
       private String outputQName;
    
       /**
        * The constructor
        */
       public MQTest11B()
       {
          super();
          params = new Hashtable<String,String>();
          mqht = new Hashtable<String,Object>();
       }
    
       /**
        * Make sure the required parameters are present.
        * @return true/false
        */
       private boolean allParamsPresent()
       {
          boolean b = params.containsKey("-h") && params.containsKey("-p") &&
                      params.containsKey("-c") && params.containsKey("-m") &&
                      params.containsKey("-q") &&
                      params.containsKey("-u") && params.containsKey("-x");
          if (b)
          {
             try
             {
                Integer.parseInt((String) params.get("-p"));
             }
             catch (NumberFormatException e)
             {
                b = false;
             }
          }
    
          return b;
       }
    
       /**
        * Extract the command-line parameters and initialize the MQ HashTable.
        * @param args
        * @throws IllegalArgumentException
        */
       private void init(String[] args) throws IllegalArgumentException
       {
          int port = 1414;
          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())
          {
             qMgrName = (String) params.get("-m");
             outputQName = (String) params.get("-q");
    
             try
             {
                port = Integer.parseInt((String) params.get("-p"));
             }
             catch (NumberFormatException e)
             {
                port = 1414;
             }
             
             mqht.put(CMQC.CHANNEL_PROPERTY, params.get("-c"));
             mqht.put(CMQC.HOST_NAME_PROPERTY, params.get("-h"));
             mqht.put(CMQC.PORT_PROPERTY, new Integer(port));
             mqht.put(CMQC.USER_ID_PROPERTY, params.get("-u"));
             mqht.put(CMQC.PASSWORD_PROPERTY, params.get("-x"));
    
             // I don't want to see MQ exceptions at the console.
             MQException.log = null;
          }
          else
          {
             throw new IllegalArgumentException();
          }
       }
    
       /**
        * Connect, open queue, write a message, close queue and disconnect.
        *
        */
       private void testSendAndReceive()
       {
          MQQueueManager qMgr = null;
          MQQueue queue = null;
          int openOptions = CMQC.MQOO_INPUT_SHARED | CMQC.MQOO_OUTPUT | CMQC.MQOO_FAIL_IF_QUIESCING;
          MQPutMessageOptions pmo = new MQPutMessageOptions();
          pmo.options = CMQC.MQPMO_NO_SYNCPOINT | CMQC.MQPMO_FAIL_IF_QUIESCING;
          MQGetMessageOptions gmo = new MQGetMessageOptions();
          gmo.options = CMQC.MQGMO_NO_SYNCPOINT | CMQC.MQGMO_WAIT | CMQC.MQGMO_CONVERT | CMQC.MQGMO_FAIL_IF_QUIESCING;
          gmo.matchOptions = CMQC.MQMO_MATCH_CORREL_ID;
          gmo.waitInterval = CMQC.MQWI_UNLIMITED;
          MQMessage sendmsg;
          String msgData;
          DecimalFormat df = new DecimalFormat("0000");
    
          try
          {
             qMgr = new MQQueueManager(qMgrName, mqht);
             logger("successfully connected to "+ qMgrName);
    
             queue = qMgr.accessQueue(outputQName, openOptions);
             logger("successfully opened "+ outputQName);
             
             /*
              * Code to send 2 messages with a specific CorrelId.  i.e. 0001 and 0002
              */
             for (int i=0; i < 2; i++)
             {
                // Define a simple MQ message, and write some text
                sendmsg = new MQMessage();
                sendmsg.format = CMQC.MQFMT_STRING;
                sendmsg.messageId = CMQC.MQMI_NONE;
                sendmsg.correlationId = df.format(i+1).getBytes();
    
                // Write message data
                msgData = "This is a test message from MQTest11B. CorrelID is "+new String(sendmsg.correlationId);
                sendmsg.writeString(msgData);
    
                // put the message on the queue
                queue.put(sendmsg, pmo);
                logger("Sent: Message Data>>>" + msgData);
             }
             
             /*
              * Code to receive a message with a specific CorrelId.  i.e. 0002
              */
             
             // Define a simple MQ message, and write some text
             MQMessage receiveMsg = new MQMessage();
             receiveMsg.messageId = CMQC.MQMI_NONE;
             receiveMsg.correlationId = "0002".getBytes();
    
             // get the message on the queue
             queue.get(receiveMsg, gmo);
    
             if (CMQC.MQFMT_STRING.equals(receiveMsg.format))
             {
                String msgStr = receiveMsg.readStringOfByteLength(receiveMsg.getMessageLength());
                logger("Received: Message Data>>>" + msgStr);
             }
             else
             {
                byte[] b = new byte[receiveMsg.getMessageLength()];
                receiveMsg.readFully(b);
                logger("Received: Message Data>>>" + new String(b));
             }
          }
          catch (MQException e)
          {
             logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
          }
          catch (IOException e)
          {
             logger("IOException:" +e.getLocalizedMessage());
          }
          finally
          {
             try
             {
                if (queue != null)
                {
                   queue.close();
                   logger("closed: "+ outputQName);
                }
             }
             catch (MQException e)
             {
                logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
             }
             try
             {
                if (qMgr != null)
                {
                   qMgr.disconnect();
                   logger("disconnected from "+ qMgrName);
                }
             }
             catch (MQException e)
             {
                logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
             }
          }
       }
    
       /**
        * 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)
       {
          MQTest11B write = new MQTest11B();
    
          try
          {
             write.init(args);
             write.testSendAndReceive();
          }
          catch (IllegalArgumentException e)
          {
             logger("Usage: java MQTest11B -m QueueManagerName -h host -p port -c channel -q QueueName -u UserID -x Password");
             System.exit(1);
          }
    
          System.exit(0);
       }
    }

    And the output will look like:

    2021/07/02 14:01:59.316 MQTest11B: testSendAndReceive: successfully connected to MQA1
    2021/07/02 14:01:59.332 MQTest11B: testSendAndReceive: successfully opened TEST.Q1
    2021/07/02 14:01:59.332 MQTest11B: testSendAndReceive: Sent: Message Data>>>This is a test message from MQTest11B. CorrelID is 0001
    2021/07/02 14:01:59.347 MQTest11B: testSendAndReceive: Sent: Message Data>>>This is a test message from MQTest11B. CorrelID is 0002
    2021/07/02 14:01:59.347 MQTest11B: testSendAndReceive: Received: Message Data>>>This is a test message from MQTest11B. CorrelID is 0002
    2021/07/02 14:01:59.347 MQTest11B: testSendAndReceive: closed: TEST.Q1
    2021/07/02 14:01:59.347 MQTest11B: testSendAndReceive: disconnected from MQA1

    Regards,
    Roger Lacroix
    Capitalware Inc.

    HPE NonStop, IBM i (OS/400), IBM MQ, IBM MQ Appliance, Java, Linux, macOS (Mac OS X), Open Source, Programming, Raspberry Pi, Unix, Windows Comments Off on Put 2 Messages with Unique CorrelId and Get 1 Message by CorrelId