I’m a Bad Programmer! ;)

If I was in a code walk-through of someone else’s code and found the bug that I just found in my code, I would say “that is some bad programming”. So, I’ll admit it – I’m a bad programmer! 😉

A long time ago, I created a nice logging framework (C code) for Capitalware’s products. I build it so that it would work on ALL platforms. i.e. AIX, HP-UX, IBM i (OS/400), Linux, Solaris, Windows and z/OS. I created it with various log modes: Quiet, Normal, Verbose and Debug.

For the log mode of verbose or debug, the output includes both the source filename (i.e. __FILE__) and source line number (i.e. __LINE__). If you’ve developed C code for awhile, you are probably aware of these C preprocessors.

My logging framework is made up of layers. The “application code” is 2 layers removed from the real logging code (just setting the mood).

For Linux, Unix and Windows, the __FILE__ preprocessor is just the path and file name. For IBM i and z/OS, it is the same concept except the source does not have a file extension and the member is surrounded by bracket. i.e. For z/OS, __FILE__ would be ‘ABC.TEST.C(XYZ)’ where “XYZ” is the source member.

For Linux, Unix and Windows, everything is fine. The code simply finds the last path delimiter (i.e. ‘\’ or ‘/’) and then sets the pointer to be +1 of the address (it points at the first of byte of the filename).

For IBM i and z/OS, the code finds the first bracket and sets the pointer to be +1 of the address. Next, it then finds the last bracket and as a quick and dirty thing that C programmers do, I just changed the right bracket “)” to a NULL. i.e. *p = ‘\0’;

Everything has worked fine for years (many, many years). Someone just deployed a beta of MQCCI for z/OS to their z/OS 2.2.0 LPAR and whenever they turned on debugging, the code would crash with:

+CSQX111E +MQQM CSQXDISP User channel exit error, TCB=007B1318  227 reason=0C4000-00000004
+CSQX599E +MQQM CSQXRESP Channel ORT.TO.HOST.MQCCI ended abnormally
CSQY291E CSQXDMPS SDUMPX FAILED, RC=00000B08,MQQM,ABN= 0C4-00000004,LOC=MQCCI   .????????+00852
+CSQX111E +MQQM CSQXDISP User channel exit error, TCB=007B1088  304 reason=0C4000-00000004
+CSQX599E +MQQM CSQXRESP Channel ORT.TO.HOST.MQCCI ended abnormally

When I ran MQCCI for z/OS on my LPAR and turned on debugging, everything worked as expected. 🙁

The “????????+00852” gave me a clue. I reviewed the compile map and that hex address (852) was located somewhere in my logging framework. I spent hours and hours trying to find something, anything that would explain the 0C4 (accessing wrong/invalid storage). Then it occurred to me, the pointer that was passed into the logging framework did not point to a copy of the value of “__FILE__” but the actual value of “__FILE__”. Hence, I was modifying a constant which clearly now on the newer z/OS LPAR is read-only storage. That is why my program crashed with an 0C4. 🙁

Hence, I’m a bad programmer!!! You got to call it like it is. 😉

Sooooooooooooooooooo. I need to do builds of all Capitalware products (commercial and ‘Licensed as Free’) for IBM i and z/OS platforms ASAP.

Regards,
Roger Lacroix
Capitalware Inc.

C, Capitalware, IBM i (OS/400), IBM MQ, Programming, z/OS Comments Off on I’m a Bad Programmer! ;)

ISF002I MASTER SDSF SYSLOG INDEX FULL

I have a z/OS LPAR via IBM’s RDP (Remote Development Program). Yesterday, I started receiving the following error message every time I went to SDSF’s log panel:

ISF002I MASTER SDSF SYSLOG INDEX FULL

I’m a developer and not a SysAdmin. At first I ignored it then got annoyed and did some internet searches. I found some commands but nothing worked for me. I found this command that the person said would delete all entries older than 90 days but it did not work for me.
I.e.

$P O JOBQ,READY,Q=x,A>90

I opened a ticket with IBM’s RDP support and here was there response:

Go to the SDSF O panel and delete all SYSLOGs entries that you no longer want by placing a P to the left of the output.

After some help from a fellow MQ ListServer person, I now understand why the above “P” command did not work for me. You need to know the class for the Q (Queue) parameter.

First go to SDSF O panel and set your prefix to “*”. i.e. PRE *

Next look at the “C” (class) column, (see highlight in picture):

My SYSLOG entries are class ‘C’. Therefore, the correct command (for me) is:

$P O JOBQ,READY,Q=C,A>90

This command will delete all SYSLOG entries older than 90 days.

Hope this helps other developers who are not SysAdmins with their z/OS LPAR SYSLOG issues. 🙂

Regards,
Roger Lacroix
Capitalware Inc.

Operating Systems, z/OS Comments Off on ISF002I MASTER SDSF SYSLOG INDEX FULL

IBM Champion Again.

Proud to be named as an IBM Champion for my contributions to IBM MQ community for the 2nd year in a row!
https://www.ibm.com/developerworks/champion/

Regards,
Roger Lacroix
Capitalware Inc.

IBM MQ Comments Off on IBM Champion Again.

Beta testers needed for MQ Channel Connection Inspector

All,

Capitalware is ready for beta testers for a new solution called: MQ Channel Connection Inspector.

Have you ever had client applications or remote queue managers attempt to connect to your queue manager but failed and the user claimed they used the “correct values”.

I’ve created a new solution to quickly diagnose this problem and need some beta testers to give me some feedback. MQ Channel Connection Inspector (MQCCI) is an MQ Channel Security Exit. For those who don’t know, a channel security exit is ONLY invoked/called by the MCA for MQCONN/X and MQDISC API calls (so it is very light-weight). The MCA passes the MQCD and MQCXP structures to the channel security exit. Those structures contain SSL/TLS fields, MCAUserId, batch size, retry information, etc. The MQCD structure has 82 fields and the MQCXP structure 26 fields (see MQ’s cmqxc.h file for more details).

I have designed MQCCI to output any or all of the fields from the MQCD and MQCXP structures (user selectable). The information is written to a CSV (Comma-Separated-Values) file. Right now, the output is in the format of “field=value,field=value,field=value,etc.”. The “value” data has been converted to human-readable format. The first question for beta testers is this an acceptable format or would you prefer a true CSV/spreadsheet format. i.e. where the field/column names are in row 1 and only the values are in rows 2 through to the last row.

Current format:

2018/01/10 17:25:07.712373, CONN, QMgrName=MQWT1, ChlName=TEST.EXIT, CD_MaxMsgLength=4194304, CD_PutAuthority=MQPA_DEFAULT, CD_MCAUserIdentifier=barney, CD_ConnectionName=10.10.10.10, CD_RemoteUserIdentifier=barney, CXP_RemoteProduct=MQCC, CXP_RemoteVersion=0800,

Or a true CSV/spreadsheet format would be (row # 1 would only be in the CSV file once):

"Date/Time", "API Call", Queue Manager Name", "Channel Name", "CD_MaxMsgLength", "CD_PutAuthority", "CD_MCAUserIdentifier", "CD_ConnectionName", "CD_RemoteUserIdentifier", "CXP_RemoteProduct", "CXP_RemoteVersion",
"2018/01/10 17:25:07.712373", "CONN", "MQWT1", "TEST.EXIT", 4194304, "MQPA_DEFAULT", "barney", "10.10.10.10", "barney", "MQCC", "0800",
"2018/01/10 17:25:09.446511", "CONN", "MQWT1", "TEST.EXIT", 4194304, "MQPA_DEFAULT", "wilma", "10.10.10.20", "wilma", "MQCC", "0800",

I plan on building MQ Channel Connection Inspector for AIX, HP-UX (RISC & IA64), Solaris (SPARC & x86_64), Linux (x86, x86_64, POWER & zSeries), Windows and IBM i (OS/400) and z/OS. MQ Channel Connection Inspector will support WMQ v6.0, v7.0, v7.1, v7.5, v8.0 & v9.0.

Beta testing MQ Channel Connection Inspector is absolutely free including support (no strings attached).

If you interesting in trying it out, please send an email to support@capitalware.com to request a trial of MQ Channel Connection Inspector,

Regards,
Roger Lacroix
Capitalware Inc.

Capitalware, IBM i (OS/400), IBM MQ, Linux, MQ Channel Connection Inspector, Security, Unix, Windows, z/OS Comments Off on Beta testers needed for MQ Channel Connection Inspector

Java/JMS MQ Applications and Maven

IBM has made available the MQ Redistributable Client (Java/JMS portion) on Maven. Mark Taylor of IBM has a blog posting on it and how to configure your files to use it:
https://developer.ibm.com/messaging/2018/01/09/developing-mq-java-applications-maven/

Regards,
Roger Lacroix
Capitalware Inc.

IBM MQ, Java, JMS, Linux, macOS (Mac OS X), Programming, Unix, Windows Comments Off on Java/JMS MQ Applications and Maven

I’m Already Sick of Winter!

Its January 9th, 2018 and I’m already sick of winter. Polar vortex, snow and more snow. I know it is early January and I’m Canadian but I’m sick of it. Snow banks are over 6 feet (2 meters) tall. I want Spring and not in 2 and half months but now. 🙁

Here’s a picture looking up my street (click to see a larger image):

Here’s another picture looking down my street (click to see a larger image):

Snow and cold is great for Christmas holidays but when the holidays are over, the snow needs to go too (just like the Christmas tree). I really need to move somewhere where it is warm this time of year. 🙂

Regards,
Roger Lacroix
Capitalware Inc.

General 1 Comment

New: MQ Batch Toolkit v3.0.0

Capitalware Inc. would like to announce the official release of MQ Batch Toolkit v3.0.0. MQ Batch Toolkit allows users to manipulate, monitor and manage messages in a queue of an IBM MQ (formally WebSphere MQ & MQSeries) queue manager from a command-line or shell scripting environment.

Starting with MQ Batch Toolkit v3.0.0, the licensing model has changed to be subscription based model meaning there will be no upfront software cost, only a yearly subscription fee.

New lower price: The cost for MQ Batch Toolkit is now $49.00 USD per user for a 1-year subscription.

For more information about MQ Batch Toolkit go to:
https://www.capitalware.com/mqbt_overview.html

    Changes for MQ Batch Toolkit v3.0.0:

  • Added BackupTopic function to subscribe to a topic and write the messages to a VEQ file.
  • Added RestoreTopic function to read a VEQ file and publish the messagse to a topic.
  • Added ReportTopic function to generate a report (PDF, RTF or HTML) from topic messages.
  • Added Subscribe function to subscribe to a topic and output the message data to the screen (console).
  • Added Publish function to publish a message to a topic.
  • Added TopicList function that will retrieve a list of topics from a local or remote queue manager.
  • Added SubscribeServer (SS) function that will continuously consume messages of a topic.
  • Added PublishServer (PBS) function that will publish (put) messages to a topic.
  • Added TopicMonitor (TM) function that will continuously monitor the topics of a queue manager writing the information to a CSV (Comma Separated Value) file.
  • Added SubscriptionMonitor (SUBM) function that continuously monitor the subscriptions of a queue manager writing the information to a CSV (Comma Separated Value) file.
  • Added QueueStatusMonitor (QSTM) function that will continuously monitor the queues of a queue manager writing the information to a CSV (Comma Separated Value) file.
  • Added Register function to allow an end-user to register the license key and retrieve an Access Code.
  • Added ‘-C’ parameter (Convert on Get) for ClearQByString function.
  • Added ‘-N’ parameter (Named Properties) for Report function.
  • Added JVM environment variables: com.ibm.mq.cfg.useIBMCipherMappings=false & com.ibm.jsse2.disableSSLv3=false
  • Added more SSL/TLS CipherSpecs
  • Added Send and receive exits for queue manager access profile (AddProfile & AlterProfile).
  • Updated GetServer to output the message payload to the console of the message received.
  • Fixed the error message for path to security exit JAR file for AddProfile and AlterProfile
  • MQ Batch Toolkit is now built as a 64-bit executable for Linux, macOS and Windows.
  • Updated docs (English only)

Regards,
Roger Lacroix
Capitalware Inc.

Capitalware, IBM MQ, IBM MQ Appliance, Linux, macOS (Mac OS X), MQ Batch Toolkit, Windows Comments Off on New: MQ Batch Toolkit v3.0.0

Merry Christmas and Happy New Year

I would like to wish everyone a Merry Christmas, Happy Hanukkah, Happy Kwanzaa, etc… and a Happy New Year. 🙂

Regards,
Roger Lacroix
Capitalware Inc.

General 1 Comment

Debian 9.3 Released

Debian Project has just released Debian 9.3.
https://www.debian.org/News/2017/2017120902

Debian is a free operating system (OS) for your computer. An operating system is the set of basic programs and utilities that make your computer run. Debian uses the Linux kernel (the core of an operating system), but most of the basic OS tools come from the GNU project; hence the name GNU/Linux.

Regards,
Roger Lacroix
Capitalware Inc.

Linux, Open Source, Operating Systems Comments Off on Debian 9.3 Released

Sample Java Code to Subscribe to an IBM MQ Topic

Here is blog posting # 2 on subscribing to a topic in IBM MQ. More code examples – here is a Java IBM MQ (non-JMS) sample program to subscribe to a topic within a queue manager of IBM MQ. It will receives messages until ‘no messages available’ exception which is set for 30 seconds.

You can download the source code from 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.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.MQTopic;
import com.ibm.mq.constants.CMQC;

/**
 * Program Name
 *  MQSub01
 *
 * Description
 *  This java class will connect to a queue manager, subscribe to a topic and receive messages.
 *
 * Sample Command Line Parameters
 *  -h 127.0.0.1 -p 1414 -c TEST.CHL -m MQA1 -t topicString -o topicObject -u userId -x password
 *
 * @author Roger Lacroix, Capitalware Inc.
 */
public class MQSub01
{
   private static final SimpleDateFormat  lOGGER_TIMESTAMP = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
   
   private Hashtable<String, String> params = null;
   private Hashtable<String, Object> mqht = null;
   private String qMgrName;
   private String topicString = null;
   private String topicObject = null;

   /**
    * The constructor
    */
   public MQSub01()
   {
      super();
      MQSub01.logger("Is now starting.");
   }

   /**
    * 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");
      
      // Need at least one
      if ( (!params.containsKey("-t")) && (!params.containsKey("-o")) )
         b = false;
      
      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 variables.
    * @param args
    * @throws IllegalArgumentException
    */
   private void init(String[] args) throws IllegalArgumentException
   {
      params = new Hashtable<String, String>();
      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");
         topicString = (String) params.get("-t");
         topicObject = (String) params.get("-o");
         
         mqht = new Hashtable<String, Object>();

         mqht.put(CMQC.CHANNEL_PROPERTY, params.get("-c"));
         mqht.put(CMQC.HOST_NAME_PROPERTY, params.get("-h"));

         try
         {
            mqht.put(CMQC.PORT_PROPERTY, new Integer(params.get("-p")));
         }
         catch (NumberFormatException e)
         {
            mqht.put(CMQC.PORT_PROPERTY, new Integer(1414));
         }
         
         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 topic, receive messages, close topic and disconnect.
    *
    */
   private void testSub()
   {
      int openOptionsForGet = CMQC.MQSO_CREATE | CMQC.MQSO_FAIL_IF_QUIESCING | CMQC.MQSO_MANAGED | CMQC.MQSO_NON_DURABLE;
      MQQueueManager _qMgr = null;
      MQTopic subscriber = null;
      MQGetMessageOptions gmo = new MQGetMessageOptions();
      gmo.options = CMQC.MQGMO_WAIT + CMQC.MQGMO_FAIL_IF_QUIESCING;
      gmo.waitInterval = 30000;  // wait up to 30 seconds
      MQMessage mqMsg = null;
      String msgText = null;
      boolean more = true;

      try
      {
         _qMgr = new MQQueueManager(qMgrName, mqht);
         MQSub01.logger("connected to queue manager: " + qMgrName);
         
         subscriber = _qMgr.accessTopic( topicString,
                                         topicObject,
                                         CMQC.MQTOPIC_OPEN_AS_SUBSCRIPTION,
                                         openOptionsForGet);
         logger("subscribed to topic: " + subscriber.getName());

         while (more)
         {
            try
            {
               mqMsg = new MQMessage();
               mqMsg.messageId = CMQC.MQMI_NONE;
               mqMsg.correlationId = CMQC.MQCI_NONE;
               subscriber.get(mqMsg, gmo);
               msgText = mqMsg.readStringOfByteLength(mqMsg.getMessageLength());
               MQSub01.logger("received message: " + msgText);
            }
            catch (MQException e)
            {
               more = false;
               MQSub01.logger("MQException CC=" +e.completionCode + " : RC=" + e.reasonCode);
            }
            catch (IOException e)
            {
               more = false;
               MQSub01.logger("IOException " + e.getLocalizedMessage());
            }
         }
      }
      catch (MQException e)
      {
         MQSub01.logger("MQException CC=" +e.completionCode + " : RC=" + e.reasonCode);
      }
      finally
      {
         try
         {
            if (subscriber != null)
               subscriber.close();
         }
         catch (MQException e)
         {
            MQSub01.logger("MQException CC=" +e.completionCode + " : RC=" + e.reasonCode);
         }

         try
         {
            if (_qMgr != null)
               _qMgr.disconnect();
         }
         catch (MQException e)
         {
            MQSub01.logger("MQException CC=" +e.completionCode + " : RC=" + e.reasonCode);
         }
      }
      
      MQSub01.logger("Is now ending.");
   }

   /**
    * 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)
   {
      MQSub01 mqs = new MQSub01();

      try
      {
         mqs.init(args);
         mqs.testSub();
      }
      catch (IllegalArgumentException e)
      {
         System.out.println("Usage: java MQSub01 -h host -p port -c channel -m QueueManagerName -t topicString -o topicObject -u userId -x password");
         System.exit(1);
      }

      System.exit(0);
   }
}

Things to note:

  • The allParamsPresent and init methods makes sure all of the required parameters are present at program startup.
  • The testSub method does the following:
    • Connects to the queue manager
    • Opens the specified topic as a subscription by either Topic String or Topic Object or both
    • Loop while there are more messages – the wait interval is set to 30 seconds
    • When Reason Code of 2033 (MQRC_NO_MSG_AVAILABLE) exception is thrown then exit the loop
    • Closes the topic
    • Disconnects from the queue manager

Regards,
Roger Lacroix
Capitalware Inc.

IBM i (OS/400), IBM MQ, IBM MQ Appliance, Java, Linux, macOS (Mac OS X), Programming, Unix, Windows, z/OS Comments Off on Sample Java Code to Subscribe to an IBM MQ Topic