New: MQ Auditor v3.1.0

Capitalware Inc. would like to announce the official release of MQ Auditor v3.1.0. This is a FREE upgrade for ALL licensed users of MQ Auditor. MQ Auditor is a solution that allows a company to audit/track all MQ API calls performed by MQ applications that are connected to a queue manager.

For more information about MQ Auditor go to:
https://www.capitalware.com/mqa_overview.html

    Changes for MQ Auditor v3.1.0:

  • Added code to make sure AuditPath and AuditArchivePath have a trailing slash.
  • Updated code so that when ArchiveCleanup is Yes, only ‘*.csv’ files are deleted.
  • Added code to allocate ResObjectString on MQOPEN if application did not provide it.
  • Erase ExitUserArea field on on exiting.
  • Added code to append trailing slash for ExitPath if it is missing.
  • Added code to append trailing slash for AuditPath if it is missing.
  • Added code to append trailing slash for AuditArchivePath if it is missing.
  • Fixed issue with UserIDFormatting
  • Tuned the logging code

Regards,
Roger Lacroix
Capitalware Inc.

Capitalware, IBM i (OS/400), IBM MQ, Linux, MQ Auditor, Unix, Windows Comments Off on New: MQ Auditor v3.1.0

WebSphere MQ V5.3 for HP NonStop Server End of Service Date

The end of service date for WebSphere MQ V5.3 for HP NonStop Server is April 30, 2020. The official announcement can be found here:
https://www.ibm.com/support/docview.wss?uid=ibm10957081

Regards,
Roger Lacroix
Capitalware Inc.

HPE NonStop, IBM MQ Comments Off on WebSphere MQ V5.3 for HP NonStop Server End of Service Date

New Raspberry Pi 4 Model B Released

Raspberry Pi Foundation has just released a new Raspberry Pi 4 Model B.
https://www.raspberrypi.org/blog/raspberry-pi-4-on-sale-now-from-35/

Everything is bigger, faster & better.

    Specifications:

  • A 1.5GHz quad-core 64-bit ARM Cortex-A72 CPU (~3× performance)
  • 1GB, 2GB, or 4GB of LPDDR4 SDRAM
  • Full-throughput Gigabit Ethernet
  • Dual-band 802.11ac wireless networking
  • Bluetooth 5.0
  • Two USB 3.0 and two USB 2.0 ports
  • Dual monitor support, at resolutions up to 4K
  • VideoCore VI graphics, supporting OpenGL ES 3.x
  • 4Kp60 hardware decode of HEVC video

Regards,
Roger Lacroix
Capitalware Inc.

Education, Linux, Open Source, Operating Systems, Programming, Raspberry Pi Comments Off on New Raspberry Pi 4 Model B Released

Updates to MessageSelector Class

In the blog posting, Java MQ Code to Retrieve Messages from a Queue Based on a Filter, I posted code for a Java MessageSelector class.

I have updated the setFilter method to catch any invalid values that may be passed to the MessageSelector class on the setFilter call.

You can download the source code for the test driver program called MQTest12MS from here which includes the MessageSelector class. If you just want the MessageSelector class, you can download from here.

Note: I have updated the original blog posting with the updated code.

Regards,
Roger Lacroix
Capitalware Inc.

IBM i (OS/400), IBM MQ, Java, Linux, macOS (Mac OS X), Programming, Unix, Windows Comments Off on Updates to MessageSelector Class

Java MQ Code to Retrieve Messages from a Queue Based on a Filter

There is a misconception regarding MQ/JMS message based filtering. Some people think that the IBM MQ queue manager does something special for JMS applications that is not done for plain Java or C/C++/C#/COBOL applications. It is just NOT true. Note: For C/C++/C#/COBOL applications, they can use the SelectionString from MQOD structure to perform message selection.

Sometimes when you quickly read a paragraph, you may miss the subtle nuances of the paragraph. See the first paragraph of the Message selectors in JMS in the Knowledge Center. It says:

Messages can contain application-defined property values. An application can use message selectors to have a JMS provider filter messages.

It doesn’t say the queue manager will filter the messages but rather, it says “JMS provider”. The JMS provider, aka the JMS client library, will perform the filtering of the messages.

So, I decided to create a simple POJO (Plain Old Java Object) class which can be used as a simple message selector with your POJO MQ application. There is nothing complicated about the code. It browses the messages on the queue, checks the message property for a matching value. If found then the message is removed from the queue and returned to the application, otherwise it continues to the next message. This is done until all messages have been checked (RC of 2033 – MQRC_NO_MSG_AVAILABLE).

I could have just as easily created it in C but I decided to do it in Java because I have seen people want a message selector in POJO.

You can download the source code for the test driver program called MQTest12MS from here which includes the MessageSelector class. If you just want the MessageSelector class, you can download from here.

Here is a snippet of the MQTest12MS that shows you how to use the MessageSelector class.

ms = new MessageSelector(qMgr);
ms.openQueue(inputQName);
ms.setFilter("SomeNum", MessageSelector.Conditions.GREATER_THAN_EQUAL, 123);

while (true)
{
   receiveMsg = ms.getMessage(startAtBeginning);

   // got the message, now go and do something with it.

   // set flag to continue rather than restart at the beginning.
   startAtBeginning = false;
}
ms.closeQueue();

Here is the MessageSelector class.

import java.io.IOException;

import com.ibm.mq.MQException;
import com.ibm.mq.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.CMQC;

/**
 * Class Name
 *  MessageSelector
 *
 * Description
 *  This java class will retrieve messages from a queue based on a filter.
 *
 * @author Roger Lacroix
 * @version 1.0.0
 * @license Apache 2 License
 */
public class MessageSelector
{
   public enum Conditions
   {
      EQUAL, NOT_EQUAL, LESS_THAN, LESS_THAN_EQUAL, GREATER_THAN, GREATER_THAN_EQUAL;
   }
   
   private MQQueueManager  qMgr = null;
   private MQQueue         inQ = null;
   private String          filterName = null;
   private Conditions      filterCondition;
   private Object          filterValue = null;

   /**
    * The constructor
    * @param qMgr - must have a valid/active connection to the queue manager 
    */
   public MessageSelector(MQQueueManager qMgr)
   {
      super();
      this.qMgr = qMgr;
   }
   
   /**
    * Open the queue for both browsing and destructive gets.
    * @param qName
    * @throws MQException
    */
   public void openQueue(String qName) throws MQException
   {
      inQ = qMgr.accessQueue(qName, CMQC.MQOO_INQUIRE + CMQC.MQOO_BROWSE + CMQC.MQOO_FAIL_IF_QUIESCING + CMQC.MQOO_INPUT_SHARED);
   }
   
   /**
    * Close the queue.
    * @throws MQException
    */
   public void closeQueue() throws MQException 
   {
      if (inQ != null)
         inQ.close();
   }
   
   /**
    * Set the filter name, condition and value. 
    * @param name
    * @param condition
    * @param value
    * @throws IllegalArgumentException
    */
   public void setFilter(String name, Conditions condition, Object value) throws IllegalArgumentException
   {
      if (name == null)
         throw new IllegalArgumentException("Filter name cannot be null.");
      else if ("".equals(name))
         throw new IllegalArgumentException("Filter name cannot be blank.");
      else if (value == null)
         throw new IllegalArgumentException("Filter value cannot be null.");
      
      if ( (value instanceof String) || (value instanceof Boolean) ||
           (value instanceof Byte)   || (value instanceof Byte[])  )
       {
          if ( (Conditions.EQUAL != condition) && (Conditions.NOT_EQUAL != condition) )
          {
             throw new IllegalArgumentException("Filter condition can only be EQUAL or NOT_EQUAL.");
          }
       }
       else if ( (value instanceof Integer) || (value instanceof Long) ||
                 (value instanceof Double)  || (value instanceof Float) )
       {
          if ( (Conditions.EQUAL != condition) && (Conditions.NOT_EQUAL != condition) &&
               (Conditions.LESS_THAN != condition) && (Conditions.LESS_THAN_EQUAL != condition) &&
               (Conditions.GREATER_THAN != condition) && (Conditions.GREATER_THAN_EQUAL != condition) )
          {
             throw new IllegalArgumentException("Filter condition must be one of the following: EQUAL, NOT_EQUAL, LESS_THAN, LESS_THAN_EQUAL, GREATER_THAN, GREATER_THAN_EQUAL.");
          }
       }
       else
       {
          throw new IllegalArgumentException("Unknown Object type for Filter value.");
       }

      /**
       * Pass the checks, save the values
       */
      this.filterName = name;
      this.filterCondition = condition;
      this.filterValue = value;
   }

   /**
    * Retrieve the next matching message from the queue.
    * @param reset - Start over from the beginning of the queue.
    * @return
    * @throws MQException
    * @throws IOException
    */
   public MQMessage getMessage(boolean reset) throws MQException, IOException
   {
      MQGetMessageOptions gmo = new MQGetMessageOptions();
      if (reset)
         gmo.options = CMQC.MQGMO_BROWSE_FIRST + CMQC.MQGMO_NO_WAIT + CMQC.MQGMO_FAIL_IF_QUIESCING;
      else
         gmo.options = CMQC.MQGMO_BROWSE_NEXT + CMQC.MQGMO_NO_WAIT + CMQC.MQGMO_FAIL_IF_QUIESCING;
      MQMessage getMsg = null;

      while (true)
      {
         getMsg = new MQMessage();

         inQ.get(getMsg, gmo);

         if (performConditionalTest(getMsg))
         {
            deleteMessage();
            break;
         }

         gmo.options = CMQC.MQGMO_BROWSE_NEXT + CMQC.MQGMO_NO_WAIT + CMQC.MQGMO_FAIL_IF_QUIESCING;
      }
      
      return getMsg;
   }
   
   /**
    * Handle the conditional testing of the value.
    * @param getMsg
    * @return true/false
    */
   private boolean performConditionalTest(MQMessage getMsg)
   {
      boolean flag = false;

      try
      {
         if (filterValue instanceof String)
         {
            String value = getMsg.getStringProperty(filterName);
            if (value != null) 
            {
               if ( (Conditions.EQUAL == filterCondition) && (((String)filterValue).equals(value)) )
                  flag = true;
               else if ( (Conditions.NOT_EQUAL == filterCondition) && (!(((String)filterValue).equals(value))) )
                  flag = true;
            }
         }
         else if (filterValue instanceof Integer)
         {
            int value = getMsg.getIntProperty(filterName);
            
            if ( (Conditions.EQUAL == filterCondition) && (value == (Integer)filterValue) ) 
               flag = true;
            else if ( (Conditions.NOT_EQUAL == filterCondition) && (value != (Integer)filterValue) ) 
               flag = true;
            else if ( (Conditions.LESS_THAN == filterCondition) && (value < (Integer)filterValue) ) 
               flag = true;
            else if ( (Conditions.LESS_THAN_EQUAL == filterCondition) && (value <= (Integer)filterValue) ) 
               flag = true;
            else if ( (Conditions.GREATER_THAN == filterCondition) && (value > (Integer)filterValue) ) 
               flag = true;
            else if ( (Conditions.GREATER_THAN_EQUAL == filterCondition) && (value >= (Integer)filterValue) ) 
               flag = true;
         }
         else if (filterValue instanceof Long)
         {
            long value = getMsg.getLongProperty(filterName);
            
            if ( (Conditions.EQUAL == filterCondition) && (value == (Long)filterValue) ) 
               flag = true;
            else if ( (Conditions.NOT_EQUAL == filterCondition) && (value != (Long)filterValue) ) 
               flag = true;
            else if ( (Conditions.LESS_THAN == filterCondition) && (value < (Long)filterValue) ) 
               flag = true;
            else if ( (Conditions.LESS_THAN_EQUAL == filterCondition) && (value <= (Long)filterValue) ) 
               flag = true;
            else if ( (Conditions.GREATER_THAN == filterCondition) && (value > (Long)filterValue) ) 
               flag = true;
            else if ( (Conditions.GREATER_THAN_EQUAL == filterCondition) && (value >= (Long)filterValue) ) 
               flag = true;
         }
         else if (filterValue instanceof Double)
         {
            double value = getMsg.getDoubleProperty(filterName);
            
            if ( (Conditions.EQUAL == filterCondition) && (value == (Double)filterValue) ) 
               flag = true;
            else if ( (Conditions.NOT_EQUAL == filterCondition) && (value != (Double)filterValue) ) 
               flag = true;
            else if ( (Conditions.LESS_THAN == filterCondition) && (value < (Double)filterValue) ) 
               flag = true;
            else if ( (Conditions.LESS_THAN_EQUAL == filterCondition) && (value <= (Double)filterValue) ) 
               flag = true;
            else if ( (Conditions.GREATER_THAN == filterCondition) && (value > (Double)filterValue) ) 
               flag = true;
            else if ( (Conditions.GREATER_THAN_EQUAL == filterCondition) && (value >= (Double)filterValue) ) 
               flag = true;
         }
         else if (filterValue instanceof Float)
         {
            float value = getMsg.getFloatProperty(filterName);

            if ( (Conditions.EQUAL == filterCondition) && (value == (Float)filterValue) ) 
               flag = true;
            else if ( (Conditions.NOT_EQUAL == filterCondition) && (value != (Float)filterValue) ) 
               flag = true;
            else if ( (Conditions.LESS_THAN == filterCondition) && (value < (Float)filterValue) ) 
               flag = true;
            else if ( (Conditions.LESS_THAN_EQUAL == filterCondition) && (value <= (Float)filterValue) ) 
               flag = true;
            else if ( (Conditions.GREATER_THAN == filterCondition) && (value > (Float)filterValue) ) 
               flag = true;
            else if ( (Conditions.GREATER_THAN_EQUAL == filterCondition) && (value >= (Float)filterValue) ) 
               flag = true;
         }
         else if (filterValue instanceof Boolean)
         {
            Boolean value = getMsg.getBooleanProperty(filterName);
            if ( (value != null) && ((Boolean)filterValue == value) ) 
               flag = true;
         }
         else if (filterValue instanceof Byte)
         {
            byte value = getMsg.getByteProperty(filterName);
            if ((Byte)filterValue == value)  
               flag = true;
         }
         else if (filterValue instanceof Byte[])
         {
            byte[] value = getMsg.getBytesProperty(filterName);
            if ( (value != null) && (java.util.Arrays.equals((byte[])filterValue, value)) ) 
               flag = true;
         }
      }
      catch (Exception e)
      {}

      return flag;
   }
   
   /**
    * Delete the message that the cursor is pointing to. 
    */
   private void deleteMessage()
   {
      MQMessage deleteMsg = new MQMessage();
      MQGetMessageOptions gmo = new MQGetMessageOptions();
      gmo.options = CMQC.MQGMO_MSG_UNDER_CURSOR + CMQC.MQGMO_NO_WAIT + CMQC.MQGMO_FAIL_IF_QUIESCING + CMQC.MQGMO_ACCEPT_TRUNCATED_MSG;

      /** 
       * don't need it - because we already have the message
       * just delete it.
       */
      try
      {
         inQ.get(deleteMsg, gmo, 1);  // only get 1 byte - who cares right!!  
      }
      catch (MQException e)
      {}
   }
}

Regards,
Roger Lacroix
Capitalware Inc.

IBM i (OS/400), IBM MQ, Java, Linux, macOS (Mac OS X), Programming, Unix, Windows 5 Comments

IBM MQ Fix Pack 9.0.0.7 Released

IBM has just released Fix Pack 9.0.0.7 for IBM MQ V9.0 LTS
https://www.ibm.com/support/docview.wss?uid=ibm10887223

Regards,
Roger Lacroix
Capitalware Inc.

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

RFE – IBM MQ support for AdoptOpenJDK

Please review and vote for this RFE if you think it’s a good idea. The link below will take you directly there.

Headline:
Add support for AdoptOpenJDK in IBM MQ

URL to review the RFE and Vote for it if you like:
http://www.ibm.com/developerworks/rfe/execute?use_case=viewRfe&CR_ID=133991

Description:
Currently, IBM MQ supports 2 JDKs/JREs: IBM and Oracle. It would be extremely useful if IBM MQ supported a 3rd JDK/JRE called AdoptOpenJDK. IBM is a backer of AdoptOpenJDK, so it would seem logical that IBM MQ supports it.

Use case:
For those customers who want to move from using Oracle JDK/JRE to another option besides IBM’s JDK/JRE.

Business justification:
Starting in 2019, Oracle has implemented high monthly fees for the use of the Oracle JDK/JRE whereas previously the usage of the Oracle JDK/JRE was free.

Regards,
Roger Lacroix
Capitalware Inc.

IBM MQ, Java, JMS, Linux, Programming, Unix, Windows Comments Off on RFE – IBM MQ support for AdoptOpenJDK

IBM MQ and OpenJDKs

On Monday, Peter Potkay asked a simple question on the MQ List Server:

Does IBM support any version of OpenJDK, from any vendor, for use with IBM MQ Clients, specifically the Resource Adapter?

Tim McCormick of IBM responded with:

The full list of supported JREs are listed in the MQ system requirements here: https://www.ibm.com/support/docview.wss?uid=swg27006467

Specific link for 9.1 LTS: https://www.ibm.com/software/reports/compatibility/clarity-reports/report/html/softwareReqsForProduct?deliverableId=B560B760819A11E6B5854315721876AE&duComponentIds=A006

At this time we only support IBM and Oracle implementations.

Now that is the official line from IBM because they have not gone through the selection and testing of an OpenJDK implementation but since Oracle JDK and OpenJDK are 99% the same, I think IBM may give companies some leeway.

Here was my response to Peter’s question (and yes, you can say, Roger tell us how you REALLY feel).

Your question, although a clear answer should be simple, there are so many moving parts, you just end up banging your head against the wall.

Right off the top, I would like to thank Oracle for their greed which created this problem!!!!!!

Sun Microsystem said 13 years ago that they would open source Java and it would be free. When Oracle purchased Sun Microsystem, they said they would honor Sun’s promise to the Java community. Well, that last about 8 years. Last Summer, Oracle said f-u to the world and said if you want to use Oracle’s JRE and/or JDK, you need to pay (for both desktops and servers). Period. No exceptions.

Now Oracle’s JRE & JDK are 99% the same as OpenJDK. I haven’t found any differences between the 2 JDK’s (or JREs) but I write desktop applications and not Java back-end servers. See here: https://jaxenter.com/oracle-jdk-builds-openjdk-builds-difference-149318.html

I switched to AdoptOpenJDK. The primary reason I switched to it is because IBM is behind it!!!

A Java Enterprise Edition (Java EE) is built on top of a JDK. The current version of Java EE is 8. For a Java server to be considered to be a Java EE server, it has to implement a bunch of specifications. A Java server can be Java EE certified for 1 specification or all specifications for Java EE. If you go to wiki page on Java EE and scroll down to “Certified referencing runtimes”, you will see that JBoss is fully certified for Java EE 8 (and Java EE 7 too).

And now back to the “MQ Resource Adapter”. IBM’s web page on MQ Resource Adapter, says that the Java server you use must be certified for JCA v1.7 and JMS 2.0. For MQ v8 and v9, the Java server must be Java EE 7 certified.

So, as long as the version of the JBoss server you are running is Java EE 7 or 8 certified and you are using OpenJDK 8 or higher (which is the same as Oracle JDK 8 or higher), then you should be on a supported footing.

So, that’s my 2 cents.

Oh yeah, Oracle, here’s another 2 cents, you are a greedy, greedy, greedy, ………………. company.

Here is more that I did not put in my response to Peter’s question, Oracle not only screwed over Java users/customers but I know of 1 company that was forced to close!!!!

Excelsior LLC is (was) a 20 year old company that created and sold Excelsior Jet. Excelsior Jet is a compiler that compiles Java code to native code (executable). Excelsior LLC officially licensed the JDK/JRE from Oracle. Excelsior Jet was available for Windows, Linux, macOS and ARM (Linux & Windows).

Last year, Oracle changed the licensing of the Oracle JDK & JRE that would take effect in 2019. Monthly fee of $25.00 per server processor and $2.50 per desktop. Greedy, Greedy, greedy!!!

Now, if Excelsior LLC wanted to keep using the licensed Oracle JDK/JRE code then they would need to collect those monthly fees from the end-customers which are really the customers of their customers. i.e. Capitalware being a customer of Excelsior Jet would have to collect those monthly fees from all of our customers and give that money to Excelsior LLC, who then would give it to Oracle. What a lovely process.

Knowing how greedy Oracle is, I would even guess that they probably increased the licensing fees that Excelsior LLC had to pay them. Note: That is only a guess on my part but probably a reasonable guess.

Last October 31, 2018, announced a beta of Excelsior Jet 15.3 (officially released in November 2018) and the switchover to OpenJDK. That was great news, now Excelsior LLC customers (i.e. Capitalware) wouldn’t have to worry about chasing our customers for Oracle’s new licensing fees.

But the good news was short lived. On May 15, 2019, I received an email from Excelsior LLC saying that they were exiting the JVM business and shutting down.

There is a lot of speculation on Reddit, forums, etc. on why Excelsior LLC decided to shutdown. Most of it centers on Oracle’s GraalVM. While it could be the case, I seriously doubt it for 2 reasons:

  • Before GraalVM there was GCJ (GNU Compiler for Java). Excelsior LLC survived and thrived when GCJ existed, so Excelsior LLC should do the same with the existence of GraalVM.
  • Follow the money or more specifically, follow the licensing!!

    What do I mean by “follow the licensing”? Before Excelsior Jet 15.3, Excelsior LLC licensed the Oracle JDK/JRE from Oracle (Sun Microsystems before that). Last fall, Excelsior Jet switched to OpenJDK for Excelsior Jet 15.3. OpenJDK is licensed under GPL with the classpath exception. So, if Excelsior LLC wanted to stay on the right side of the law, they would have to publish their code when OpenJDK was included in Excelsior Jet 15.3 but they did not.

    So, I’m guessing that someone or company (probably Oracle) served Excelsior LLC with a legal notice that they are in violation of the terms of GPL.

    I do not know why Excelsior LLC did not just simply go the open source subscription route and publish their code. Maybe they were using proprietary code that could not be open sourced or just did not like the concept, I do not know. All I know is that this REALLY sucks!!!! I’ve been using Excelsior Jet for more than 7 years and have been a very happy user.

    The Laurel & Hardy quote is running through my head about Oracle:

    Well, here’s another nice mess you’ve gotten me into.

    In case I didn’t mention it before, Oracle is a greedy, greedy, greedy, …… company.

    Finally, I’ll check IBM MQ RFEs and if nobody has opened one for the support of OpenJDK then I’ll open it and request that AdoptOpenJDK be supported, since IBM is a backer of it.

    Regards,
    Roger Lacroix
    Capitalware Inc.

  • IBM MQ, Java, Linux, macOS (Mac OS X), Programming, Unix, Windows 1 Comment

    Oh Error Messages, Why Can’t You Say What You Mean?

    Talk about spending several days chasing my tail. 🙁

    I have a customer who build a brand new Windows 2016 Server and install IBM MQ v9.1 then applied Fix Pack 2. So, they were at MQ v9.1.0.2.

    Next, they installed MQAUSX and applied their generic definitions to it. So far, so good.

    But when they went to do a test, the channel was closed and the following error messages were found in the queue manager’s log file:

    ----- amqrimna.c : 866 --------------------------------------------------------
    6/10/2019 10:43:05 - Process(2156.3) User(MUSR_MQADMIN) Program(amqrmppa.exe)
                          Host(SERVER001) Installation(Installation1)
                          VRMF(9.1.0.2) QMgr(MQA1)
                          Time(2019-06-10T15:43:05.208Z)
                          ArithInsert1(24948) ArithInsert2(126)
                          CommentInsert1(d:\Capitalware\MQAUSX\mqausx.dll)
                          CommentInsert2(The specified module could not be found.)
                          CommentInsert3(64)
    
    AMQ6174I: The library 'd:\Capitalware\MQAUSX\mqausx.dll' was not found.
    
    EXPLANATION:
    The dynamically loadable library 'd:\Capitalware\MQAUSX\mqausx.dll' was not
    found. Possible reasons for the error:
    (a) Library is not present in the specified path.
    (b) Library is present but the architecture of the library does not match the
      process's architecture which is '64' bit.
    (c) Library is present but it has a dependency on other libraries which are not
      present in the same directory.
    ACTION:
    Check that the file exists and is either fully qualified or is in the
    appropriate directory. Check the architecture of the library and process match.
    Also check if the library has dependency on any other libraries.
    ----- amqxufnn.c : 706 --------------------------------------------------------
    6/10/2019 10:43:05 - Process(2156.3) User(MUSR_MQADMIN) Program(amqrmppa.exe)
                          Host(SERVER001) Installation(Installation1)
                          VRMF(9.1.0.2) QMgr(MQA1)
                          Time(2019-06-10T15:43:05.210Z)
                          ArithInsert1(24948)
                          CommentInsert1(TEST.CHL)
                          CommentInsert2(d:\Capitalware\MQAUSX\mqausx(SecExit))
                          CommentInsert3(64)
    
    AMQ9535E: User exit not valid.
    
    EXPLANATION:
    Channel program 'TEST.CHL' ended because user exit
    'd:\Capitalware\MQAUSX\mqausx(SecExit)' is not valid.
    Architecture of the exit library does not match the process's architecture
      which is '64' bit.
    ACTION:
    Ensure that the user exit is specified correctly in the channel definition, and
    that the user exit program is correct and available.

    The first error message was AMQ6174I which says “not found”. So, I worked with the customer to make sure the MQAUSX install directory and the SCYEXIT parameter for channel were correct and they were (directory listings, screenshots, etc.). So, that was a red herring.

    The second error message was AMQ9535E which says the “user exit is not valid”. Had the customer triple check what they had installed and used is32or64 program to verify that indeed they were using the 64-bit release of MQAUSX. Again, another red herring.

    I already had IBM MQ v9.1 installed on a 64-bit Windows Server, so I applied Fix Pack 2 and installed MQAUSX 64-bit on the D: drive, just as the customer did. Hence, I was at the same MQ level and MQAUSX setup as the customer’s queue manager and MQAUSX installation. Everything worked perfectly for me. 🙁

    We spent so much time going over everything with a fine-toothed comb but nothing was incorrect. Just banging my head against the wall.

    The customer asked if they require any Redistributable packages, since it is a brand new server, it doesn’t have any installed. I said if you don’t have “Microsoft Visual C++ 2010 Redistributable x64” installed then yes download and install it. After it was installed and the server was rebooted, everything worked as expected.

    Sometimes, I really hate Windows. I don’t know if this was MQ misinterpreting the Windows error message or Windows returning a bad error message to MQ. But it sure wasted a lot of my time. If this was an MQ misinterpreting the error message, then IBM please update your code to better reflect the “actual” issue.

    I have had a similar issues on Linux/Unix. On Linux/Unix, when an MQ exit (aka shared library) has a dependency on another shared library, the error message that is outputted to the queue manager’s error log file actually has useful information about the issue. It does not send you off on wild goose chases that have nothing to do with the issue.

    Regards,
    Roger Lacroix
    Capitalware Inc.

    C, Capitalware, IBM MQ, MQ Authenticate User Security Exit, Windows 3 Comments

    Windows: Is the exe or DLL 32-bit or 64-bit?

    Every so often, I have a customer send me an email with a IBM MQ message like the following:

    Channel program ‘TEST.CHL’ ended because user exit ‘C:\Capitalware\MQAUSX\mqausx(SecExit)’ is not valid.
    Architecture of the exit library does not match the process’s architecture which is ’64’ bit.

    MQAUSX is just an example, as it could happen with any other Capitalware product.

    For Windows, MQAUSX has 2 installers:

  • mqausx-server-setup.exe for 32-bit version of MQAUSX
  • mqausx-server-64-setup-MQv8.exe for 64-bit version of MQAUSX
  • It is easy for someone to select and run the wrong installer. Or sometimes, a user will simply copy the DLLs from one server to another server and not realize that the platform architecture (32 vs 64-bit) is different. If the user does then MQ will output the above error message.

    Windows does not include a program like “file” for Linux/Unix. Yes, there are several options that users can install:

  • “dumpbin” included with Visual Studio
  • Dependency Walker
  • Process Explorer
  • But sometimes you just want a simple command line tool. Hence, I decided to create a Windows command line program called is32or64 that will take file name(s), either executable (“exe”) or DLL, as parameter(s) and output if the named file is 32-bit or 64-bit.

    You can download is32or64 from here. The download archive contains 3 files:

  • bin32\is32or64.exe (32-bit release)
  • bin64\is32or64.exe (64-bit release)
  • ReadMe.txt
  • Example:

    C:\>is32or64.exe C:\Windows\regedit.exe C:\Windows\difxapi.dll
    C:\Windows\regedit.exe: 64-bit
    C:\Windows\difxapi.dll: 64-bit

    Enjoy.
    Regards,
    Roger Lacroix
    Capitalware Inc.

    Capitalware, Licensed As Free, MQ Authenticate User Security Exit, Operating Systems, Windows Comments Off on Windows: Is the exe or DLL 32-bit or 64-bit?