MQ Exit Programming Tips

Here are some things that MQ Exit developers need to be aware of:

1. Most people have never developed and will never develop an MQ Exit. Developing a MQ Exit is an ‘advanced topic’ – hence, you SHOULD have experience developing Windows DLLs or Unix shared Libraries and understand the concept of parallel processing (i.e. threading). Test, search, test again, search again. Google is now man’s best friend. USE IT.

2. Windows XP, 7, 2003 and 2008 have restrictions on system accounts (MUSR_MQADMIN is a system account!!!) for what files or directories that account can access ( i.e. On WinXP, the Exit cannot write to C:\ ) So, if in your exit, the code is writing to C:\myexit.log, and you have a problem then TRY ANOTHER DIRECTORY (even try another file name).

3. MQ Exit Library names are CASE SENSITIVE.

    e.g.
    C:\Program Files\IBM\MQ\Exits64\testexit(SECEXIT)
    is NOT the same as
    C:\Program Files\IBM\MQ\Exits64\testexit(SecExit)

4. Do NOT write a large convoluted exit before testing it. Start with a VERY SIMPLE EXIT and then move to a more complex exit.

5. Before you post a question (on MQ ListServer or mqseries.net) about your MQ security exit, make sure you have tested the following VERY, VERY BASIC MQ security exit. Note: If you cannot get this to work, you should give your MQ exit development project to someone else (Do not post why or complain!!).

You can download the source code from here. Copy the following code to a file and call the file: testexit.c

/**
 *  TestExit for debugging MQ exit issue.
 *
 *  Location of:
 *  Unix/Linux:   /var/mqm/exits64/testexit(SecExit)
 *
 *  Windows DLL:  C:\Program Files\IBM\MQ\Exits64\testexit(SecExit)
 *
 *  MQSC command for Unix/Linux queue manager:
 *  DEFINE CHANNEL ('APP.CH01') CHLTYPE(SVRCONN) +
 *         TRPTYPE(TCP) +
 *         SENDEXIT('/var/mqm/exits64/testexit(SecExit)') +
 *         SENDDATA(' ') +
 *         REPLACE
 *
 *  MQSC command for Windows queue manager:
 *  DEFINE CHANNEL ('APP.CH01') CHLTYPE(SVRCONN) +
 *         TRPTYPE(TCP) +
 *         SENDEXIT('C:\Program Files\IBM\MQ\Exits64\testexit(SecExit)') +
 *         SENDDATA(' ') +
 *         REPLACE
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined (_WIN32)
#include <windows.h>
#include <lm.h>
#endif

#include <cmqc.h>
#include <cmqxc.h>

#if defined (_WIN32)
__declspec (dllexport) void MQENTRY SecExit(PMQCXP  pChannelExitParms,
                                   PMQCD   pChannelDefinition,
                                   PMQLONG pDataLength,
                                   PMQLONG pAgentBufferLength,
                                   PMQBYTE pAgentBuffer,
                                   PMQLONG pExitBufferLength,
                                   PMQPTR  pExitBufferAddr);
#else
extern void MQENTRY MQStart(void) {;}
#endif

void MQENTRY SecExit( PMQCXP  pChannelExitParms,
                  PMQCD   pChannelDefinition,
                  PMQLONG pDataLength,
                  PMQLONG pAgentBufferLength,
                  PMQVOID pAgentBuffer,
                  PMQLONG pExitBufferLength,
                  PMQPTR  pExitBufferAddr)
{
   char       outBuff[512];
   char       tempChl[ MQ_CHANNEL_NAME_LENGTH + 1];
   FILE*      fh;
   struct tm  *newtime;
   time_t     tclock;
   char       *timeBuff;
   PMQCXP     pParms = pChannelExitParms;
   PMQCD      pChDef = pChannelDefinition;

   // Attention newbie user: Make sure you select a valid directory and filename!!!

//   fh = fopen("C:\\Program Files\\IBM\\MQ\\Exits64\\testexit.log", "a+");
   fh = fopen("C:\\Temp\\testexit.log", "a+");

   time( &tclock );
   newtime = localtime( &tclock );
   timeBuff = asctime(newtime);
   timeBuff[strlen(timeBuff) - 1] = 0x00;

   fprintf(fh, "%s : Now entering the security exit.\n", timeBuff);

   memcpy(tempChl, pChannelDefinition->ChannelName, MQ_CHANNEL_NAME_LENGTH);
   tempChl[MQ_CHANNEL_NAME_LENGTH] = 0x00;
   fprintf(fh, "%s : Channel name is %s\n", timeBuff, tempChl);

   if (pParms->ExitId == MQXT_CHANNEL_SEC_EXIT)
   {
      switch (pParms->ExitReason)
      {
         case MQXR_INIT:
              pParms->ExitResponse = MQXCC_OK;
              fprintf(fh, "%s : MQXR_INIT - Channel Initialization\n", timeBuff);
              break;
         case MQXR_INIT_SEC:
              pParms->ExitResponse = MQXCC_OK;
              fprintf(fh, "%s : MQXR_INIT_SEC  - Initialize Security\n", timeBuff);
              break;
         case MQXR_SEC_MSG:
              pParms->ExitResponse = MQXCC_OK;
              fprintf(fh, "%s : MQXR_SEC_MSG - Security Message\n", timeBuff);
              break;
         case MQXR_SEC_PARMS:
              pParms->ExitResponse = MQXCC_OK;
              fprintf(fh, "%s : MQXR_SEC_PARMS - Security Parameters\n", timeBuff);
              break;
         case MQXR_TERM:
              pParms->ExitResponse = MQXCC_OK;
              fprintf(fh, "%s : MQXR_TERM - Channel Terminating\n", timeBuff);
              break;
         default:
              pParms->ExitResponse = MQXCC_SUPPRESS_FUNCTION;
              fprintf(fh, "%s : ERROR - Unknown Exit Reason\n", timeBuff);
              break;
      }
   }
   else
   {
      pParms->ExitResponse = MQXCC_SUPPRESS_FUNCTION;
      fprintf(fh, "%s : ERROR - Not invoked by a security exit.\n", timeBuff);
      return;
   }

   fprintf(fh, "%s : Now exiting the security exit.\n\n", timeBuff);
   fclose(fh);

   return;
}

6. Read the IBM MQ Intercommunication manual for how to compile the security exit (e.g. testexit.c) for your particular platform.

7. Here is the channel definition for this MQ security exit to run on Windows:

DEFINE CHANNEL ('TEST.EXIT') CHLTYPE(SVRCONN) +
      TRPTYPE(TCP) +
      SCYEXIT('C:\Program Files\IBM\MQ\Exits64\testexit(SecExit)') +
      SCYDATA(' ') +
      REPLACE

8. Consult the following web page that contains several security exits that may help you out:
https://www.capitalware.com/mq_code_c.html#exitcode

9. Buy vs Build: You and your management should seriously review the costs associated with building your own security exit / solution. A company can easily spend $50,000 to $100,000 or more building an MQ security solution but they could have spent a fraction of the money if they would have purchased Capitalware’s MQ Authenticate User Security Exit or MQ Standard Security Exit. Also, who will support the internally build custom solution in years to come? Food for thought.

10. Last but not least: Read The Manual (RTM). In particular read IBM MQ Programming Guide, IBM MQ Programming Reference, IBM MQ Intercommunication and IBM MQ Messages and Codes manuals

Regards,
Roger Lacroix
Capitalware Inc.

C, IBM MQ, Programming Comments Off on MQ Exit Programming Tips

Java Programming Tips

The following Java programming tips should help developers write Java programs that will have fewer bugs / problems and run faster:

1. Avoid “equals” conditional statements where the variable is checked against a constant. Always check the constant against the variable.

If myStr (String) is ever null then the following conditional statement will throw an exception

if (myStr.equals(""))
{
   //  blah, blah, blah
}

Whereas if myStr is null then doing the conditional statement as follows will not generate an exception

if ("".equals(myStr))
{
   //  blah, blah, blah
}

2. Avoid “==” (equal to operator) conditional statements where the variable is on the left of the “==” operator. It is best to have the variable on the right of the “==” operator.

Example: You meant to type “==” but you accidentally typed “=”.

if (myInt = 7)
{
   //  blah, blah, blah
}

“myInt” will be set to 7 and the conditional statement will return true but this is not what you wanted to happen.

The safest way to handle this potential problem from ever happening is to flip around the test:

If (7 == myInt)
{
   //  blah, blah, blah
}

The Java compiler will not allow you to have “7 = myInt”. So, these types of typos will be immediately caught by the developer.

3. Use the following simple method to safely test if a string is blank or null:

public static boolean isNullOrBlank(String myStr)
{
   if (null == myStr)
      return true;
   else
      return ("".equals(myStr));
}

4. Avoid using string concatenation operator (+) since it is extremely slow. Use StringBuffer instead.

Use StringBuffer rather than the string concatenation operator (+). String concatenation is extremely slow.

5. Use compound operators with integers as they are faster.

Compound operators such as n += 4; are faster than n = n + 4; because less bytecode is generated by the Java compiler.

6. Use shifting by powers instead of multiplying since shifting is faster.

Shifting by powers of two is faster than multiplying.

7. Limit the number of temporary objects especially in methods and loops. The creation and deletion of objects is time consuming.

8. Reuse objects where possible.

This is easy to implement.

9. Us Double.toString instead of java.text.DecimalFormat for converting Doubles to Strings.

Note: Double.toString is not very fast, so you may want to search the internet for a faster routine.

10. Follow the KISS principle (i.e. Keep It Short and Simple or Keep It Simple Stupid!)

A method should do one thing and do that one thing well.

11. Use static variables for fields that only need to be assigned once.

Static variables will help to speed up your code.

12. Use ArrayList instead of Vector when possible since ArrayList is faster.

13. Use char[] rather than StringBuffer to convert to Strings when possible, since converting from char[] to a String is faster than StringBuffer to String.

14. Use local variables rather than class variables since it is easier to understand the scope of the (local) variables. Also, the JVM can access local variables faster than class variables.

15. Use logical (meaningful) names for your variables and methods in your Java programs. It will be easier for other people to follow (read) your programs. Also, in 6 months, it will be easier for you to recall what you were doing in the code.

Summary:

If you follow the above 15 Java programming tips, you will have fewer ‘strange bugs’ in your code and your Java code will be faster.

Regards,
Roger Lacroix
Capitalware Inc.

Java, Programming Comments Off on Java Programming Tips

Lotus Symphony 3.0 FixPack 1 Now Available

IBM has just released the first FixPack for Lotus Symphony 3.0. It contains a number of small fixes. You can find more detail on what is included and how to install the Fixpack from the following link:
http://symphony.lotus.com/software/lotus/symphony/help.nsf/ReleaseNotes?OpenForm&version=3 fix pack 1

IBM® Lotus® Symphony™ is a richly-featured set of productivity tools that are intuitive and easy to use and provided at no charge. There are three applications that make up Lotus Symphony: Lotus Symphony Documents, Lotus Symphony Spreadsheets, Lotus Symphony Presentations.

In other words, Lotus Symphony is a free alternative to Microsoft Office. 🙂 Lotus Symphony runs on Linux, Mac OS X and Windows.

Regards,
Roger Lacroix
Capitalware Inc.

Linux, macOS (Mac OS X), Windows Comments Off on Lotus Symphony 3.0 FixPack 1 Now Available

Why a Default Transmit Queue is a Bad Idea

A default Transmit Queue (DEFXMITQ) is a bad idea since an endless loop can potentially be created between queue managers or a group of queue managers when a poor configuration is implemented.

Queue Manager Names:
• QMA is the name of a queue manager (shown above)
• QMB is the name of a queue manager (shown above)
• QMC is the name of a queue manager (not shown)

Queue Names:
• A1 is the name of queue in QMA (shown above)
• B1 is the name of queue in QMB (shown above)
• C1 is the name of queue in QMC (not shown)

The loop:
• The MQ application connects to QMA and opens queue C1 that resides on queue manager QMC
• The application puts a message to the opened queue
• Since queue manager MQA does not have a resolution entry for queue C1 or queue manager QMC, queue manager QMA puts the message on its default transmit queue (i.e. queue QMB)
• Queue manager QMB receives the message but since queue manager QMB does not have a resolution entry for queue C1 or queue manager QMC, it puts the message on its default transmit queue (i.e. queue QMA)
• Hence, the message arrives back at queue manager QMA and the loop begins again. The message(s) will loop forever. 🙁

I strongly suggest that companies not use a default transmit queue.

Regards,
Roger Lacroix
Capitalware Inc.

IBM MQ 4 Comments

Are you having MQ Cluster problems or issues?

The following are links to solutions in the IBM WebSphere MQ documentation for particular problems / issues.

Regards,
Roger Lacroix
Capitalware Inc.

IBM MQ Comments Off on Are you having MQ Cluster problems or issues?

IBM’s Watson computer to be on Jeopardy!

In February 2011, IBM’s Watson computer will be on the TV game show Jeopardy!. Watson will take on 2 of the greatest Jeopardy champions ever: Ken Jennings and Brad Rutter.

IBM press release:
http://www.ibm.com/press/us/en/pressrelease/33233.wss

From a nerd point of view, this is really interesting. I definitely will be watching those 3 Jeopardy! episodes (Feb. 14, 15 and 16). Boy, it would be really fascinating / stimulating / stressful to be part of the team that develops Watson. 🙂

Regards,
Roger Lacroix
Capitalware Inc.

General Comments Off on IBM’s Watson computer to be on Jeopardy!

Information on MQ Message Behavior

The following is general information on WebSphere MQ (aka MQSeries) message behavior during normal and abnormal message processing. The first thing to understand about MQ is that, it is not a database but a real-time messaging system. It was built on the following 2 principles:

  1. Once-only delivery of a message
  2. Assured delivery of a message (not guaranteed for legal reasons)

MQ supports 2 types of messaging models: point-to-point and Publish/Subscribe (Pub/Sub).

MQ messaging behavior when MQ is used as a point-to-point messaging system:

  1. Unconsumed non-persistent messages will remain on a queue regardless of what has happened to the application (i.e. crashes, normal disconnects, etc). If a queue manager is restarted then ALL non-persistent messages in a queue with attribute NPMCLASS equal to Normal are deleted. If the queue’s attribute NPMCLASS is equal to High then the messages are not deleted.
  2. Unconsumed persistent messages will remain on a queue regardless of what has happened to the application (i.e. crashes, normal disconnects, etc). If a queue manager is restarted then persistent messages survive a queue manager restart.

MQ messaging behavior when MQ is used as a Pub/Sub messaging system:

  1. For non-durable subscriptions, if a consumer disconnects or crashes or loses connectivity to the queue manager for any reason, then ALL published messages will NOT be saved / stored for that particular consumer (Other consumers are not affected). When the consumer reconnects, they will begin receiving messages ONLY from the point in time that they successfully reconnected. All previous pub/sub messages (during the disconnection period) will be discarded.
  2. For durable subscriptions, if a consumer disconnects or crashes or loses connectivity to the queue manager for any reason, then all published messages will be saved / stored for that particular consumer. When the consumer reconnects they will receive all outstanding messages for that particular topic. Of course, the biggest problem with durable subscriptions is ‘what if the consumer never reconnects?’ This means that messages would accumulate forever and fill-up the queue. MQ applications should only use durable subscriptions when the application will be reconnecting to the queue manager in a timely fashion.

Unit of Work (i.e. SYNCPOINT)

If any message is put on a queue under a Unit Of Work (UOW) then there are other MQ behaviors that must be considered.

  1. If an application issues an MQDISC or ends normally, with current uncommitted operations, an implied MQCMIT is executed by WebSphere MQ (i.e. all operations done under SYNCPOINT are committed).
  2. If an application crashes / abnormally ends then an implied MQBACK is executed by WebSphere MQ (i.e. all operations done under SYNCPOINT are backed-out).

Once the user understands how MQ behaves then they will understand what is happening to the application’s messages during normal and abnormal processing.

Regards,
Roger Lacroix
Capitalware Inc.

IBM MQ, Programming Comments Off on Information on MQ Message Behavior

JMSException and MQ Reason Codes

J2EE (JMS) programmers who are new to IBM MQ (formally WebSphere MQ, MQSeries) sometimes are confused as to why they are getting a particular JMS exception. The problem with the JMS / MQ layer is that the useful MQ information is hidden in the JMSException. By useful MQ information, I mean the MQ Completion Code (CC) and Reason Code (RC). In particular, it is the MQ Reason Code that provides the key to why the code is having the issue.

Generally, J2EE programmers will catch the JMS exception via the JMSException clause and dump out the exception message. A typical JMSException clause:

catch (JMSException e)
{
   System.err.println(e.getLocalizedMessage());
}

The J2EE programmer may see one of the following JMS exception messages in their program’s output / log file:

javax.jms.JMSException: MQJMS1000: Failed to create JMS message
javax.jms.JMSException: MQJMS1016: an internal error has occurred.
javax.jms.JMSException: MQJMS1017: non-local MQ queue not valid for receiving or browsing
javax.jms.JMSException: MQJMS1079: Unable to write message to dead letter queue
javax.jms.JMSException: MQJMS1107: connection problem
javax.jms.JMSException: MQJMS1068: failed to obtain XAResource
javax.jms.JMSException: MQJMS2002: failed to get message from MQ queue
javax.jms.JMSException: MQJMS2005: failed to create MQQueueManager
javax.jms.JMSException: MQJMS2007: failed to send message to MQ queue
javax.jms.JMSException: MQJMS2008: failed to open MQ queue
javax.jms.JMSException: MQJMS2009: MQQueueManager.commit() failed
javax.jms.JMSException: MQJMS2014: Queue manager rejected XA client connection
javax.jms.JMSException: MQJMS3011: Failed to publish message to MQ queue
javax.jms.JMSSecurityException: MQJMS2013: invalid security authentication supplied for MQQueueManager

The problem is that there is no MQ related information in those JMS exception messages. So, the $100,000 question is: ‘How can the J2EE programmer retrieve MQ related information’?

Simple: You need to dump out the LinkedException for the JMS exception:

catch (JMSException e)
{
   System.err.println(&quot;getLinkedException()=&quot; + e.getLinkedException());
   System.err.println(e.getLocalizedMessage());
}

The getLinkedException method will give you the MQ reason code which will help you determine what is the real issue. Using the above snippet of code, the output may look like:

getLinkedException()=com.ibm.mq.MQException: MQJE001: Completion Code 2, Reason 2035.
javax.jms.JMSException: MQJMS2007: failed to send message to MQ queue.

Now the user can look up what the reason code means. If you have WMQ Server or WMQ Client installed then you can execute the mqrc command and pass it the reason code. Open a Command prompt or Unix shell and type the following:

mqrc 2035

And the command will output:

      2035  0x000007f3  MQRC_NOT_AUTHORIZED

For more information, you can look up the MQ Reason Code in the IBM MQ Knowledge Center.

I strongly recommend that all JMSException clauses related to MQ use the getLinkedException method and dump out the MQ information (as noted in Amendent # 2 in my blog posting of Ten Commandments of IBM MQ)

Regards,
Roger Lacroix
Capitalware Inc.

IBM MQ, Java, JMS, Programming 2 Comments

Capitalware Products for WMQ v5.3 on 32-bit Unix

As of December 31st, 2010, Capitalware will no longer support its products on the 32-bit release of WebSphere MQ v5.3 (or earlier) on Unix (AIX, HP-UX and Solaris). Note: This does not affect the support of WebSphere MQ 32-bit for Linux.

IBM ended support for WebSphere MQ v5.3 for distributed platforms on September 22, 2006.
http://www.ibm.com/common/ssi/cgi-bin/ssialias?subtype=ca&infotype=an&appname=iSource&supplier=897&letternum=ENUS906-119

Since WebSphere MQ v6, MQ Server on Unix (AIX, HP-UX and Solaris) is only supported for 64-bit mode, Capitalware’s products will also only support 64-bit mode for WebSphere MQ on Unix.

Regards,
Roger Lacroix
Capitalware Inc.

Capitalware, IBM MQ, MQ Authenticate User Security Exit, MQ Standard Security Exit, Unix Comments Off on Capitalware Products for WMQ v5.3 on 32-bit Unix

WebSphere MQ v6 End of Service

Well, we are now down to 9 and 1/2 months before WebSphere MQ v6 goes out of service. The end of service date for WebSphere MQ v6 on distributed platforms (Linux, Unix, Windows, IBM i, etc…) is September 30th, 2011. The official official announcement can be found here:
http://www.ibm.com/support/docview.wss?uid=swg21418724

So MQAdmins, it is time to push your managers, directors, etc.. into scheduling some time for you to do the upgrade. 🙂

Now to through a twist into the picture, I am 99% sure that IBM will announce WebSphere MQ v8 in April 2011. If you are still running MQ v6, do you upgrade to v7 or wait for v8? Something to think about.

By the way, if you have been pining for a new feature in MQ then you should immediately fill out a WebSphere MQ Requirements request form and send it in ASAP. The web site is at:
http://www-01.ibm.com/support/docview.wss?&uid=swg21266802

    I have already sent in 2 requests to IBM:

  • Add support for API Exit on z/OS for Batch, CICS and IMS environments
  • Add support for CHAD exit support of SVRCONN channel on z/OS

I would like to kindly ask any and all people who use WMQ on z/OS to submit a feature request for the next release of WMQ to support API Exits on z/OS and CHAD exit support of SVRCONN channels on z/OS.

Regards,
Roger Lacroix
Capitalware Inc.

IBM i (OS/400), IBM MQ, Linux, Unix, Windows Comments Off on WebSphere MQ v6 End of Service