Advanced java code dealing with real world problems.

Thursday, September 2, 2010

Simple IBM MQ Message Age Monitor

For those that are still running IBM MQ (or Websphere MQ) on mainframes, presented here is a simple java message age monitor program that polls a queue periodically for how long the oldest message has been living in the queue. This sample code will output a message to the console when the oldest message in the queue has been living in there for more that 60 seconds at the moment of polling. You can change it to send out an email or snmp alert instead.
In order to compile and run this program, PCF package (MS0B) is needed and can be downloaded from IBM. You will also need "com.ibm.mq.jar" and IBM's "j2ee.jar". They can be found from IBM's WSAD or RAD IDE development tools.
/*
 * blog/javaclue/ibmmq/MessageAgeMonitor.java
 * 
 * Copyright (C) 2009 JackW
 * 
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with this library.
 * If not, see <http://www.gnu.org/licenses/>.
 */
package blog.javaclue.ibmmq;

import java.util.GregorianCalendar;

import org.apache.log4j.Logger;

import com.ibm.mq.MQC;
import com.ibm.mq.MQEnvironment;
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;

/**
 * Simple message age monitor program that uses IBM MQ Java to read PCF-format
 * messages from a queue.
 */
public class MessageAgeMonitor implements Runnable {
 protected static Logger logger = Logger.getLogger(MessageAgeMonitor.class);
 protected static boolean isDebugEnabled = logger.isDebugEnabled();
 
 final private String qmgrName;
 final private String host;
 final private int port;
 final private String queueName;
 final private int alertAge; // in seconds
 final private String channel;
 
 final static int Polling_Freq = 30 * 1000; // 30 seconds

 MessageAgeMonitor(String qmgrName, String host, int port, String queueName, String channel,
   int alertAge) {
  this.qmgrName = qmgrName;
  this.host = host;
  this.port = port;
  this.channel = channel;
  this.queueName = queueName;
  this.alertAge = alertAge;
 }
 
 public void run() {
  if (isDebugEnabled)
   logger.debug("Starting Message Age monitor for " + queueName + "...");
  while (true) {
   checkAge();
   try {
    Thread.sleep(Polling_Freq); // sleep for 30 seconds
   }
   catch (InterruptedException e) {
    logger.info("The monitor has been interrupted, exit...");
    break;
   }
  }
 }

 private void checkAge() {
  MQQueueManager qm = null;
  MQQueue queue = null;
  if (isDebugEnabled) {
   logger.debug("Connecting to " + qmgrName + " at " + host + ":" + port + " over " + channel);
  }
        try {
   // Turn off unnecessary output before we start
   MQEnvironment.disableTracing ();
         MQException.log = null;
   MQEnvironment.hostname = host;
   MQEnvironment.port = port;
   MQEnvironment.channel = channel;
   qm = new MQQueueManager ("");
        queue = qm.accessQueue (queueName, MQC.MQOO_BROWSE | MQC.MQOO_FAIL_IF_QUIESCING);
            MQMessage message = new MQMessage ();
            MQGetMessageOptions gmo = new MQGetMessageOptions ();
            
            gmo.options = MQC.MQGMO_BROWSE_FIRST | MQC.MQGMO_NO_WAIT | MQC.MQGMO_CONVERT;
         
         message.messageId = null;
         message.correlationId = null;
         queue.get (message, gmo);
         // get message put date time
         GregorianCalendar cal = message.putDateTime;
         long ageInMillis = new java.util.Date().getTime() - cal.getTime().getTime();
         int ageInSeconds = (int) ageInMillis/1000;
         if (isDebugEnabled)
    logger.debug("Put Date: " + cal.getTime() + " age in seconds: " + ageInSeconds);
   if (ageInSeconds > alertAge) {
    logger.info(qmgrName + "/" + queueName + " age = " + ageInSeconds
      + ", exceeded alert threshold: " + alertAge);
    // XXX: add your code here to send out alert
   }
        }
        catch (MQException mqe) {
         if (mqe.reasonCode == MQException.MQRC_NO_MSG_AVAILABLE) {
          if (isDebugEnabled) {
           logger.debug("Queue " + qmgrName + "/" + queueName + " is empty.");
          }
         }
         else {
          logger.error("MQException caught", mqe);
         }
        }
        finally {
         if (queue != null && queue.isOpen()) {
          try {
           queue.close();
          }
          catch (Exception e) {
     logger.error("Exception caught during queue.close()", e);
          }
         }
   if (qm != null) {
    if (qm.isOpen()) {
     try {
      qm.close();
     }
     catch (Exception e) {
      logger.error("Exception caught during qm.close()", e);
     }
    }
    if (qm.isConnected()) {
     try {
      qm.disconnect();
     }
     catch (Exception e) {
      logger.error("Exception caught during qm.disconnect()", e);
     }
    }
   }
        }
    }

 public static void main (String [] args) {
  String qmgrName = "QMGR";
  String host = "localhost";
  int port = 1450;
  String channel = "SYSTEM.DEF.SVRCONN";
  String queueName = "TEST_QUEUE";
  
  MessageAgeMonitor monitor = new MessageAgeMonitor(qmgrName, host, port, queueName, channel, 60);
  new Thread(monitor).start();
 }
}

2 comments:

  1. This post is probably where I got the most useful information for my research. Thanks for posting, maybe we can see more on this.
    Are you aware of any other websites on this

    IBM-MQ WEBSPHERE Online training


    ReplyDelete
  2. Two improvements suggested:
    1. Do a zero-length get to fetch only the MQMD
    gmo.options |= MQConstants.MQGMO_ACCEPT_TRUNCATED_MSG;
    get (message, gmo , 0 ); // zero length message
    catch-and-ignore
    MQConstants.MQRC_TRUNCATED_MSG_ACCEPTED
    the .get() still worked even if it throws an exception.
    2. check cal for nullness. I've run into a case where someone PUT a no-Context message and the MQMD PUTDATE and PUTTIME being blank result in a null GregorianCalendar

    ReplyDelete

Followers

About Me

An IT professional with more than 20 years of experience in enterprise computing. An Audio enthusiast designed and built DIY audio gears and speakers.