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?

    Java MQ Code to List All Local Queues Filtering by Current Depth

    If you have done the following runmqsc command to display all local queues filtering by current queue depth of a queue manager:

    DIS QL(*) WHERE (CURDEPTH GT 0)

    And you wanted to do the same thing via a program, here is a fully functioning Java MQ example that will connect to a remote queue manager, issue a PCF “Inquire Queue” command filtering the current queue depth (CURDEPTH), get the PCF response messages, loop through the PCF responses and output the information. You can download the source code from here.

    For more information about the PCF “Inquire Queue” command, go to MQ KnowLedge Center here.

    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Hashtable;
    
    import com.ibm.mq.MQException;
    import com.ibm.mq.MQQueueManager;
    import com.ibm.mq.constants.CMQC;
    import com.ibm.mq.constants.CMQCFC;
    import com.ibm.mq.headers.MQDataException;
    import com.ibm.mq.headers.pcf.PCFMessage;
    import com.ibm.mq.headers.pcf.PCFMessageAgent;
    
    /**
     * Program Name
     *  MQListQueueWithFilter01
     *
     * Description
     *  This java class issues a PCF "inquire queue" request message for all ("*") local queues 
     *  with a queue depth greater than 0 (zero) of a remote queue manager. 
     *  
     *  This PCF code is equivalent to issuing the runmqsc command of:
     *     DIS QL(*) WHERE (CURDEPTH GT 0) 
     *
     * Sample Command Line Parameters
     *  -m MQA1 -h 127.0.0.1 -p 1414 -c TEST.CHL -u UserID -x Password
     *
     * @author Roger Lacroix
     */
    public class MQListQueueWithFilter01
    {
       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;
    
       public MQListQueueWithFilter01()
       {
          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("-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");
             
             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();
          }
       }
       
       /**
        * Handle connecting to the queue manager, issuing PCF command then 
        * looping through PCF response messages and disconnecting from 
        * the queue manager. 
        */
       private void doPCF()
       {
          MQQueueManager qMgr = null;
          PCFMessageAgent agent = null;
          PCFMessage   request = null;
          PCFMessage[] responses = null;
          
          try
          {
             qMgr = new MQQueueManager(qMgrName, mqht);
             MQListQueueWithFilter01.logger("successfully connected to "+ qMgrName);
    
             agent = new PCFMessageAgent(qMgr);
             MQListQueueWithFilter01.logger("successfully created agent");
          
             // https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.1.0/com.ibm.mq.ref.adm.doc/q087800_.htm
             request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q);
             
             /**
              * You can explicitly set a queue name like "TEST.Q1" or
              * use a wild card like "TEST.*"
              */
             request.addParameter(CMQC.MQCA_Q_NAME, "*");
             
             // Add parameter to request only local queues
             request.addParameter(CMQC.MQIA_Q_TYPE, CMQC.MQQT_LOCAL);
             
             // Add parameter to request only queue name and current depth
             request.addParameter(CMQCFC.MQIACF_Q_ATTRS, new int [] { 
                                                                      CMQC.MQCA_Q_NAME,
                                                                      CMQC.MQIA_CURRENT_Q_DEPTH
                                                                    });
    
             // Add filter to only return responses with a queue depth greater than 0 (zero)  i.e. non-zero queue depth
             request.addFilterParameter(CMQC.MQIA_CURRENT_Q_DEPTH, CMQCFC.MQCFOP_GREATER, 0);
    
             responses = agent.send(request);
             
             MQListQueueWithFilter01.logger("responses.length="+responses.length);
             
             for (int i = 0; i < responses.length; i++)
             {
                if ( ((responses[i]).getCompCode() == CMQC.MQCC_OK) &&
                     ((responses[i]).getParameterValue(CMQC.MQCA_Q_NAME) != null) )
                {
                   String name = responses[i].getStringParameterValue(CMQC.MQCA_Q_NAME);
                   if (name != null)
                      name = name.trim();
    
                   int depth = responses[i].getIntParameterValue(CMQC.MQIA_CURRENT_Q_DEPTH);
                   
                   MQListQueueWithFilter01.logger("Name="+name + " : depth="+depth);
                }
             }
          }
          catch (MQException e)
          {
             MQListQueueWithFilter01.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
          }
          catch (IOException e)
          {
             MQListQueueWithFilter01.logger("IOException:" +e.getLocalizedMessage());
          }
          catch (MQDataException e)
          {
             MQListQueueWithFilter01.logger("MQDataException:" +e.getLocalizedMessage());
          }
          finally
          {
             try
             {
                if (agent != null)
                {
                   agent.disconnect();
                   MQListQueueWithFilter01.logger("disconnected from agent");
                }
             }
             catch (MQDataException e)
             {
                MQListQueueWithFilter01.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
             }
    
             try
             {
                if (qMgr != null)
                {
                   qMgr.disconnect();
                   MQListQueueWithFilter01.logger("disconnected from "+ qMgrName);
                }
             }
             catch (MQException e)
             {
                MQListQueueWithFilter01.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);
       }
    
       public static void main(String[] args)
       {
          MQListQueueWithFilter01 mqlqs = new MQListQueueWithFilter01();
          
          try
          {
             mqlqs.init(args);
             mqlqs.doPCF();
          }
          catch (IllegalArgumentException e)
          {
             MQListQueueWithFilter01.logger("Usage: java MQListQueueWithFilter01 -m QueueManagerName -h host -p port -c channel -u UserID -x Password");
             System.exit(1);
          }
    
          System.exit(0);
       }
    }

    Regards,
    Roger Lacroix
    Capitalware Inc.

    Capitalware, HPE NonStop, IBM i (OS/400), IBM MQ, Java, Linux, macOS (Mac OS X), Open Source, PCF, Programming, Unix, Windows Comments Off on Java MQ Code to List All Local Queues Filtering by Current Depth

    Excelsior Jet and macOS Mojave

    Well, here’s a little oddity that Excelsior Jet users should know about.

    On Friday, I decided to upgrade my MacBook Pro from High Sierra (v10.13) to Mojave (v10.14). Everything went smoothly. I checked the version level and it said I was running v10.14.2.

    Note: I have Excelsior Jet 15.3 Professional installed on my MacBook Pro.

    I played around with a bunch of stuff and tested my applications, life was good. When I started Excelsior Jet’s Control Panel (or Jet Pack II), the window showed it was loading (progress bar) but locked up when it went to display the main screen and would never complete (transparent/ghost window frame). I killed it and try again (and again) – always the same results, a locked application.

    On the bright-side, at least the non-GUI versions of Excelsior Jet’s Control Panel and Jet Pack II worked.

    After a whole lot of swearing, I sent Excelsior Jet’s support an email but of course it was late Friday afternoon, so you know what that means – talk to you on Monday. 🙁

    On Sunday, I was fooling around with my MacBook Pro and when I was in the App Store, it said there were updates, so I applied them. My MacBook Pro was upgraded to v10.14.5. After it was rebooted, both Jet Control Panel and Jet Pack worked perfectly. I was a happy camper! 🙂

    First off, what the hell is Apple doing? On Friday, why did it only upgrade my MacBook Pro to v10.14.2 if v10.14.5 was already available? Dumb, really dumb.

    Secondly, what screw-up did Apple do to the OS such that it would cause issues with an application which they clearly fixed in either v10.14.3 or v10.14.4 or v10.14.5.

    Early Monday morning, I received an email from Excelsior Jet support. The email contained a hotfix #4 for Excelsior Jet 15.3 and instructions for installing it. I said I was good to go and would wait for the maintenance release. In a follow up email, they said to apply either the hotfix or maintenance before distributing my application(s) because other users might be running macOS v10.14.2.

    So, this is an FYI to Excelsior Jet users. Be forewarned.

    Regards,
    Roger Lacroix
    Capitalware Inc.

    Java, macOS (Mac OS X), Programming Comments Off on Excelsior Jet and macOS Mojave

    Java MQ Code to List All Local Queues and their Attributes

    If you have done the following runmqsc command to display all local queues with attributes of a queue manager:

    DIS QL(*) ALL

    And you wanted to do the same thing via a program, here is a fully functioning Java MQ example that will connect to a remote queue manager, issue a PCF “Inquire Queue” command, get the PCF response messages, loop through the PCF responses and output the information. You can download the source code from here.

    For more information about the PCF “Inquire Queue” command, go to MQ KnowLedge Center here.

    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Hashtable;
    
    import com.ibm.mq.MQException;
    import com.ibm.mq.MQQueueManager;
    import com.ibm.mq.constants.CMQC;
    import com.ibm.mq.constants.CMQCFC;
    import com.ibm.mq.headers.MQDataException;
    import com.ibm.mq.headers.pcf.PCFMessage;
    import com.ibm.mq.headers.pcf.PCFMessageAgent;
    
    /**
     * Program Name
     *  MQListQueueAttributes01
     *
     * Description
     *  This java class issues a PCF "inquire queue" request message for all ("*") local queues 
     *  of a remote queue manager. 
     *  
     *  This PCF code is equivalent to issuing the runmqsc command of:
     *     DIS QL(*) ALL 
     *
     * Sample Command Line Parameters
     *  -m MQA1 -h 127.0.0.1 -p 1414 -c TEST.CHL -u UserID -x Password
     *
     * @author Roger Lacroix
     */
    public class MQListQueueAttributes01
    {
       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;
    
       public MQListQueueAttributes01()
       {
          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("-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");
             
             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();
          }
       }
       
       /**
        * Handle connecting to the queue manager, issuing PCF command then 
        * looping through PCF response messages and disconnecting from 
        * the queue manager. 
        */
       private void doPCF()
       {
          MQQueueManager qMgr = null;
          PCFMessageAgent agent = null;
          PCFMessage   request = null;
          PCFMessage[] responses = null;
          
          try
          {
             qMgr = new MQQueueManager(qMgrName, mqht);
             MQListQueueAttributes01.logger("successfully connected to "+ qMgrName);
    
             agent = new PCFMessageAgent(qMgr);
             MQListQueueAttributes01.logger("successfully created agent");
          
             // https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.1.0/com.ibm.mq.ref.adm.doc/q087800_.htm
             request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q);
             
             /**
              * You can explicitly set a queue name like "TEST.Q1" or
              * use a wild card like "TEST.*"
              */
             request.addParameter(CMQC.MQCA_Q_NAME, "*");
             
             // Add parameter to request only local queues
             request.addParameter(CMQC.MQIA_Q_TYPE, CMQC.MQQT_LOCAL);
    
             // Add parameter to request all of the attributes of the queue
             request.addParameter(CMQCFC.MQIACF_Q_ATTRS, new int [] { CMQCFC.MQIACF_ALL });
    
             responses = agent.send(request);
             
             MQListQueueAttributes01.logger("responses.length="+responses.length);
             
             for (int i = 0; i < responses.length; i++)
             {
                if ( ((responses[i]).getCompCode() == CMQC.MQCC_OK) &&
                     ((responses[i]).getParameterValue(CMQC.MQCA_Q_NAME) != null) )
                {
                   String name = responses[i].getStringParameterValue(CMQC.MQCA_Q_NAME);
                   if (name != null)
                      name = name.trim();
    
                   int depth = responses[i].getIntParameterValue(CMQC.MQIA_CURRENT_Q_DEPTH);
                   int maxDepth = responses[i].getIntParameterValue(CMQC.MQIA_MAX_Q_DEPTH);
                   
                   // many, many attributes can be listed - see web page mentioned above.
                   
                   MQListQueueAttributes01.logger("Name="+name + " : depth="+depth + " : max_depth="+maxDepth);
                }
             }
          }
          catch (MQException e)
          {
             MQListQueueAttributes01.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
          }
          catch (IOException e)
          {
             MQListQueueAttributes01.logger("IOException:" +e.getLocalizedMessage());
          }
          catch (MQDataException e)
          {
             MQListQueueAttributes01.logger("MQDataException:" +e.getLocalizedMessage());
          }
          finally
          {
             try
             {
                if (agent != null)
                {
                   agent.disconnect();
                   MQListQueueAttributes01.logger("disconnected from agent");
                }
             }
             catch (MQDataException e)
             {
                MQListQueueAttributes01.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
             }
    
             try
             {
                if (qMgr != null)
                {
                   qMgr.disconnect();
                   MQListQueueAttributes01.logger("disconnected from "+ qMgrName);
                }
             }
             catch (MQException e)
             {
                MQListQueueAttributes01.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);
       }
    
       public static void main(String[] args)
       {
          MQListQueueAttributes01 mqlqs = new MQListQueueAttributes01();
          
          try
          {
             mqlqs.init(args);
             mqlqs.doPCF();
          }
          catch (IllegalArgumentException e)
          {
             MQListQueueAttributes01.logger("Usage: java MQListQueueAttributes01 -m QueueManagerName -h host -p port -c channel -u UserID -x Password");
             System.exit(1);
          }
    
          System.exit(0);
       }
    }

    Regards,
    Roger Lacroix
    Capitalware Inc.

    Capitalware, HPE NonStop, IBM i (OS/400), IBM MQ, Java, Linux, macOS (Mac OS X), Open Source, PCF, Programming, Unix, Windows Comments Off on Java MQ Code to List All Local Queues and their Attributes

    Its All Fun & Games Until Your Message Is Empty!

    I’ve collected a bunch of JSON sample files from the internet for testing with MQ Visual Edit. It is always good to have a variety of samples when testing features of a program rather than making up a couple of your own.

    I was doing some testing with MQ Visual Edit and the JSON samples when I happen to select a particular JSON sample, clicked the “Format” button (pretty-print format) then clicked “Save to Queue” button. The message on the queue was empty (data length of zero). At first, I thought I did some wrong. I did the test again a couple of times, sure enough, every time the message was empty.

    I looked at MQ Visual Edit’s logfile and it had an IOException. The IOException getMessage method error text was:

    Input length = 1

    And the IOException getClause method error text was null.

    I shock my head because the first character of the JSON sample was a bracket. i.e. {
    And the second character was a new-line. The error message made no sense. I ran the code in the Eclipse debugger and everything looked fine. The code extracts the data from the window panel and as it does the MQMessage writeString method, it throws the IOException.

    Again more head shaking and thinking WTF!! Why doesn’t MQ like the JSON data. I went through all of the other samples, and not a problem. How can MQ not like a particular JSON sample. More specifically, I can load the same unformatted JSON sample without issue, it was only when I performed the pretty-print formatting that there was an issue.

    The formatted JSON sample is 146 lines long, so I started to rip it apart. After several iteration, I found an interesting difference.

    Here is a line from the unformatted JSON sample:

    "album_information":"<p>Funk-punk party starters !!! performs live at KEXP\u2019s \u201cBean Room\u201d stage during our broadcast at the Capitol Hill Block Party 2010.\u00a0\u00a0\u00a0 <br \/><\/p>",

    And here is the same line from the formatted JSON sample:

    "album_information": "<p>Funk-punk party starters !!! performs live at KEXP’s “Bean Room” stage during our broadcast at the Capitol Hill Block Party 2010.    <br /></p>",

    MQ Visual Edit uses the GSON library to perform the pretty-print formatting. If you look near the end of the unformatted line you will see 3 \u00a0 characters. For some strange reason, the GSON library converts \u00a0 to the real character of 0xA0 and MQMessage writeString method throws an exception when it encounters those characters. Weird, very weird.

    So I put together a little hack that fixes the issue:

    boolean flag = false;
    for (int i=0; i < panelData.length(); i++)
    {
       if (Character.UnicodeBlock.of(panelData.charAt(i)) != Character.UnicodeBlock.BASIC_LATIN)
       {
          flag = true;
          break;
       }
    }
    
    if (flag)  //found weird character
       mqMsg.write(panelData.getBytes());
    else
       mqMsg.writeString(panelData);

    If anyone has a better way of doing it then I’m all ears. 🙂

    Now, I did do some searches on turning off Unicode conversion in the GSON library but all I found was for disabling HTML conversion. This is what my GSON code looks like for pretty-print formatting:

    Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
    JsonParser jp = new JsonParser();
    JsonElement je = jp.parse(origMsgData);  // original message data
    
    panel.setText(gson.toJson(je));

    Again, if anyone has a better way of doing it then I’m all ears. 🙂

    Regards,
    Roger Lacroix
    Capitalware Inc.

    IBM MQ, Java, Linux, macOS (Mac OS X), MQ Visual Edit, Programming, Windows 2 Comments

    IBM MQ Fix Pack 8.0.0.12 Released

    IBM has just released Fix Pack 8.0.0.12 for IBM MQ
    https://www.ibm.com/support/docview.wss?uid=ibm10884142

    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 8.0.0.12 Released

    Capitalware’s Help Desk is Disabled

    Well, I just discovered another casualty of upgrading to PHP 7.0, it broke the open source “PHP Support Tickets” (aka Help Desk) that I am using.

    Now when I try to use it, I get the error message:

    Fatal error: Uncaught Error: Call to undefined function mysql_connect() in /aaa/bbb/ccc/phpst/class/functions.php:56 Stack trace: #0 /aaa/bbb/ccc/phpst/index.php(35): include_once() #1 {main} thrown in /aaa/bbb/ccc/phpst/class/functions.php on line 56

    A quick internet search and I discovered that “mysql_connect” was depreciated in PHP 5.5.0 and removed in PHP 7.0. I don’t have time to attempt to fix/update all MySQL database calls in it. So, I have removed the link to the Help Desk from Capitalware’s web site.

    Regards,
    Roger Lacroix
    Capitalware Inc.

    Capitalware Comments Off on Capitalware’s Help Desk is Disabled

    Upgrading to WordPress 5.2 and my Issue

    For a few weeks, the WordPress Dashboard has been reminding me to upgrade to WordPress 5.2. So, I finally decided to upgrade but then I found out there was a new requirement: PHP 5.6.20. My web server was running PHP 5.4.45. So, I contacted HostGator (Capitalware’s hosting company) about upgrading PHP. They said they could upgrade it to PHP 7. I checked WordPress’s site and it said they support it. So, I gave the go ahead for the PHP upgrade then I upgrade WordPress to 5.2 Everything look good, as far as WordPress and plugins were concerned.

    Next, I check my online registration system. Of course, that is were things went wrong. I got the following warning:

    PHP Deprecated:  Methods with the same name as their class will not be constructors in a future version of PHP; XYZ has a deprecated constructor in /aaa/bbb/ccc/xyz.php on line 35

    After a lot of head scratching and internet searches I came across this post at StackOverflow. Basically, you cannot have the construct name be the same as the class name. I do a lot of Java and C# and having the constructor be the same name as the class is standard. Once I adjusted the code, the warning message went away.

    Normally, I wouldn’t care about a warning message written to the logfile but PHP also put the warning message in the output stream to the remote client application which broke MQ Visual Edit’s ability to communicate with the online registration system.

    Now that everything is back to normal, WordPress claims that PHP 7 is twice as fast as PHP 5 which is pretty cool.

    Regards,
    Roger Lacroix
    Capitalware Inc.

    Capitalware Comments Off on Upgrading to WordPress 5.2 and my Issue

    Red Hat Enterprise Linux 8.0 Released

    Red Hat has just released Red Hat Enterprise Linux 8.0.
    https://developers.redhat.com/blog/2019/05/07/red-hat-enterprise-linux-8-now-generally-available/

    Red Hat Enterprise Linux (RHEL) is a Linux distribution developed by Red Hat and targeted toward the commercial market. Red Hat Enterprise Linux is released in server versions for x86, x86-64, Itanium, PowerPC and IBM Z, and desktop versions for x86 and x86-64. All of the Red Hat’s official support and training, together with the Red Hat Certification Program, focuses on the Red Hat Enterprise Linux platform. Red Hat Enterprise Linux is often abbreviated to RHEL, although this is not an official designation.

    Regards,
    Roger Lacroix
    Capitalware Inc.

    Linux, Open Source, Operating Systems Comments Off on Red Hat Enterprise Linux 8.0 Released