Here’s a little utility which allows you to match an integer against WMQ constants, or find WMQ bit flags it contains.
You might find it useful if you are looking at output from an application which prints WMQ fields as an integer, or in hex.
Don’t forget the ‘mqrc’ utility which comes with WMQ, as this is especially useful for AMQXXXX numbers.
Screenshots


Usage
- Save the source below as WmqBitFlags.java in a directory called hursleyonwmq.
For example:c:\utils\hursleyonwmq - Set your CLASSPATH environment variable to include the directory where you created hursleyonwmq and
com.ibm.mq.jarset CLASSPATH=c:\utils;c:\Program Files\IBM\WebSphere MQ\java\lib\com.ibm.mq.jar
- Compile
javac hursleyonwmq\WmqBitFlags.java - Run
java hursleyonwmq.WmqBitFlags
Source
package hursleyonwmq;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class WmqBitFlags extends JFrame implements ActionListener, ChangeListener {
static final long serialVersionUID = -3064567943053904981L;
private JTextField prefixField = new JTextField("MQOO_", 20);
private JTextField valueField = new JTextField(Integer.toHexString(Integer.MAX_VALUE), 15);
private JCheckBox hexCB = new JCheckBox("Hex?", true);
private JCheckBox endianCB = new JCheckBox("BE?", true);
private JButton goButton = new JButton("Find WMQ Flags");
private JTextArea outputArea = new JTextArea(10, 60);
/** Disable endian checkbox with hex checkbox */
public void stateChanged(ChangeEvent ce) {
if (ce.getSource() == hexCB) endianCB.setEnabled(hexCB.isSelected());
}
/** When the user clicks the button, find all matching flags */
public void actionPerformed(ActionEvent ae) {
String prefix = prefixField.getText().toUpperCase();
String valueStr = valueField.getText().replaceAll("\\s", "");
outputArea.setText("");
// Parse the integer
int val = -1;
try {
if (valueStr.length() == 0) valueStr = "0";
if (hexCB.isSelected()) {
// Do we need to byte-swap?
if (!endianCB.isSelected()) {
// Ensure we have an even number of characters
if (valueStr.length() % 2 == 1) valueStr = "0" + valueStr;
String swappedValStr = "";
// Do the swap
for (int i = 0; i < valueStr.length(); i += 2) {
swappedValStr = valueStr.substring(i,i+2) + swappedValStr;
}
valueStr = swappedValStr;
}
val = Integer.parseInt(valueStr, 16);
}
else {
val = Integer.parseInt(valueStr, 10);
}
}
catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this, "Bad integer: \"" + valueStr + "\"",
"Error", JOptionPane.ERROR_MESSAGE);
return;
}
// Print the hex value of the string we're using
String outString = "Prefix: \"" + prefix +
"\" Value: " + val +
" (0x" + Integer.toHexString(val) + ")\n";
// Check we've got the MQC/MQException classes
Class constants = null;
Class reasons = null;
try {
constants = ClassLoader.getSystemClassLoader().loadClass("com.ibm.mq.MQC");
reasons = ClassLoader.getSystemClassLoader().loadClass("com.ibm.mq.MQException");
}
catch (ClassNotFoundException e) {
JOptionPane.showMessageDialog(this, e.toString() +
"\nEnsure your CLASSPATH contains com.ibm.mq.jar", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
// Get a list of all integer public fields with the specified prefix
ArrayList matchingFields = new ArrayList();
Field[] fields = constants.getFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (field.getType() == int.class &&
((field.getModifiers() & Modifier.FINAL) != 0) &&
field.getName().toUpperCase().startsWith(prefix)) {
matchingFields.add(field);
}
}
fields = reasons.getFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (field.getType() == int.class &&
((field.getModifiers() & Modifier.FINAL) != 0) &&
field.getName().toUpperCase().startsWith(prefix)) {
matchingFields.add(field);
}
}
// Check for exact matches with constants
outString += "\nExact matches:\n";
outString += "--------------\n";
Iterator iterator = matchingFields.iterator();
while (iterator.hasNext()) {
Field field = (Field)iterator.next();
Integer fieldVal = null;
try {
fieldVal = (Integer)field.get(null);
}
catch (Exception e) {
JOptionPane.showMessageDialog(this, "Unable to query MQC." + field.getName(),
"Error", JOptionPane.ERROR_MESSAGE);
return;
}
// Is this a match?
if (fieldVal.intValue() == val) {
outString += field.getName() + "\n";
}
}
// Check each bit in the source integer against the list
outString += "\nMatches as bit flags:\n";
outString += "---------------------\n";
for (int bit = 0; bit < 32; bit++) {
int matchInt = 1 << bit;
// Is this bit specified?
if ((val & matchInt) == matchInt) {
iterator = matchingFields.iterator();
while (iterator.hasNext()) {
Field field = (Field)iterator.next();
Integer fieldVal = null;
try {
fieldVal = (Integer)field.get(null);
}
catch (IllegalAccessException e) {
JOptionPane.showMessageDialog(this, "Unable to query MQC." + field.getName(),
"Error", JOptionPane.ERROR_MESSAGE);
return;
}
// Is this a match?
if (fieldVal.intValue() == matchInt) {
outString += field.getName() + " (0x" + Integer.toHexString(fieldVal.intValue()) + ")\n";
}
}
}
}
// Display the change
outputArea.setText(outString);
}
/** Constructor lays out and displays the dialog */
private WmqBitFlags() {
super("WMQ bit flags");
Font fixedWidthFont = new Font("Monospaced", Font.PLAIN, 12);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container mainContent = getContentPane();
mainContent.setLayout(new BorderLayout());
Container inputContainer = new Container();
inputContainer.setLayout(new FlowLayout());
inputContainer.add(new JLabel("Flag Prefix: "));
prefixField.setFont(fixedWidthFont);
prefixField.setToolTipText("Only search for flags with the specified prefix");
inputContainer.add(prefixField);
inputContainer.add(new JLabel("Value: "));
valueField.setFont(fixedWidthFont);
valueField.setToolTipText("The integer to search for enabled WMQ bit flags");
inputContainer.add(valueField);
hexCB.addChangeListener(this);
hexCB.setToolTipText("Has the integer been specified in hex?");
inputContainer.add(hexCB);
endianCB.setToolTipText("Is the hex big-endian? Un-tick for binary hex output on Windows or Linux x86/x86-64/IA64");
inputContainer.add(endianCB);
goButton.setToolTipText("Search for WMQ bit flags with the specified prefix in the value");
goButton.addActionListener(this);
inputContainer.add(goButton);
mainContent.add(inputContainer, BorderLayout.NORTH);
outputArea.setEditable(false);
outputArea.setFont(fixedWidthFont);
JScrollPane scrollPane = new JScrollPane(outputArea);
scrollPane.setPreferredSize(new Dimension(400, 600));
mainContent.add(scrollPane, BorderLayout.CENTER);
pack();
setVisible(true);
}
/** main method */
public static void main(String[] args) throws Exception {
new WmqBitFlags();
}
}

1 comment
Comments feed for this article
December 11, 2007 at 7:28 pm
Tim Halbur
This is a good little tool, something to put into my “toolbelt” to help debug issues. Wonder if you’ve considered extending it further. Frequently I have an mqmd or mqgmo in a trace written out in hex. I then have to get out my trusty Application Programming Reference and figure out the MQMD structure, then count up my number of bytes, and do reverse mapping (02 00 00 00 actually = 00000002) in my head for each field, and figure out that B8 04 00 00 = 1208 which is in the encoding field and so it means Decimal normal. This tool helps, but, I need to know that the constant starts mqenc to figure out what 1208 means. If I just put in the B8 04 00 00 with no constants there are just too many options.
So the extension would be, if I passed in a hex MQMD, could you translate the whole thing?
4D 44 20 20 02 00 00 00 00 00 00 00 08 00 00 00
FF FF FF FF 00 00 00 00 22 02 00 00 B8 04 00 00
4D 51 48 52 46 32 20 20 04 00 00 00 01 00 00 00
41 4D 51 20 44 49 47 50 41 51 4D 31 20 20 20 20
46 F1 82 CD 20 03 35 02 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 44 49 47 50 41 51 4D 31 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 6D 71 6D 20 20 20 20 20 20 20 20 20
03 31 30 36 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
1C 00 00 00 57 65 62 73 70 68 65 72 65 20 4D 51
20 43 6C 69 65 6E 74 20 66 6F 72 20 4A 61 76 61
32 30 30 37 31 30 30 38 31 36 35 39 31 39 37 32
20 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00
00 00 00 00 00 00 00 00 FF FF FF FF
If I use M071 to browse a queue with a message on it, it basically gives me this:
StrucId :’MD ‘
Version :2
Report :0
Message Type :8
Expiry :-1
Feedback :0
MQEncoding :0x’222′
CCSID :437
Format :’MQHRF2 ‘
Priority :4
Persistence :1 (Persistent)
Message Id :414D51204449494E464F425131202020AA03E84646713E21
Correl. Id :414D51580000000000000000000000000000000000000000
Backout Cnt. :0
ReplyToQ :’ ‘
ReplyToQMgr :’DIINFOBQ1 ‘
UserId :’mqm ‘
AccountingTkn:0000000000000000000000000000000000000000000000000000000000000000
ApplIndentity:’ ‘
PutApplType :26
PutApplName :’DIINFOBR1 ‘
Put Date :’20071128′
Put Time :’21251484′
ApplOriginDat:’ ‘
Group Id :414D51204449494E464F425131202020AA03E84606873E21
Msg Seq No. :1
Offset :0
MsgFlags :24
Original Len.:-1
but if I only have the message in a trace, could I get this basic information from feeding in the hex and have it spit the formated MQMD out?
No matter what, again, this is a good thing to work with. Just looking to see if it goes to the next step.