Last active
October 6, 2022 06:17
-
-
Save ibmmqmet/a20a2eb13978448ae4d65f4865b444b3 to your computer and use it in GitHub Desktop.
Building an MQ RFH2 structure - see https://marketaylor.synology.me/?p=1335
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Enumeration; | |
import javax.jms.Connection; | |
import javax.jms.JMSException; | |
import javax.jms.Message; | |
import javax.jms.Queue; | |
import javax.jms.QueueBrowser; | |
import javax.jms.Session; | |
import javax.jms.TextMessage; | |
import com.ibm.msg.client.jms.JmsConnectionFactory; | |
import com.ibm.msg.client.jms.JmsFactoryFactory; | |
import com.ibm.msg.client.wmq.WMQConstants; | |
/** | |
* A JMS queue browser application that looks at all available messages on the named queue, without | |
* removing them, in the order they would be received by a consumer application. | |
* | |
* Tip: A browser is not applicable for topics. | |
* | |
* Notes: | |
* | |
* API type: IBM JMS API (v1.1, unified domain) | |
* | |
* Messaging domain: Point-to-point | |
* | |
* Provider type: IBM MQ | |
* | |
* Connection mode: Client connection | |
* | |
* JNDI in use: No | |
* | |
* Usage: | |
* | |
* JmsBrowser -m queueManagerName -d queueName [-h host -p port -l channel] | |
* | |
* for example: | |
* | |
* JmsBrowser -m QM1 -d Q1 | |
* | |
* JmsBrowser -m QM1 -d Q1 -h localhost -p 1414 | |
*/ | |
public class JmsBrowser { | |
private static String host = "localhost"; | |
private static int port = 1414; | |
private static String channel = "SYSTEM.DEF.SVRCONN"; | |
private static String queueManagerName = null; | |
private static String queueName = null; | |
private static boolean clientTransport = false; | |
// System exit status value (assume unset value to be 1) | |
private static int status = 1; | |
/** | |
* Main method | |
* | |
* @param args | |
*/ | |
public static void main(String[] args) { | |
String prop,val; | |
// Parse the arguments | |
parseArgs(args); | |
// Variables | |
Connection connection = null; | |
Session session = null; | |
Queue destination = null; | |
QueueBrowser browser = null; | |
System.out.println("JmsBrowser - starts here"); | |
System.out.println("************************"); | |
try { | |
// Create a connection factory | |
JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER); | |
JmsConnectionFactory cf = ff.createConnectionFactory(); | |
// Set the properties | |
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, host); | |
cf.setIntProperty(WMQConstants.WMQ_PORT, port); | |
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, channel); | |
if (clientTransport) { | |
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT); | |
} | |
else { | |
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_BINDINGS); | |
} | |
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, queueManagerName); | |
// Create JMS objects | |
connection = cf.createConnection(); | |
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); | |
destination = session.createQueue(queueName); | |
browser = session.createBrowser(destination); | |
// Start the connection | |
connection.start(); | |
// And, browse the message | |
Enumeration<?> messages = browser.getEnumeration(); | |
int count = 0; | |
TextMessage current; | |
while (messages.hasMoreElements()) { | |
Message m = (Message)messages.nextElement(); | |
if (m instanceof TextMessage) { | |
current = (TextMessage) m; | |
System.out.println("\nMessage " + ++count + ":\n"); | |
@SuppressWarnings("unchecked") | |
Enumeration<String> props = (Enumeration<String>)current.getPropertyNames(); | |
System.out.printf("Properties:\n"); | |
while (props.hasMoreElements()) { | |
prop = props.nextElement(); | |
val = current.getStringProperty(prop); | |
System.out.printf(" Prop: %-20.20s Val:%s\n",prop,val); | |
} | |
System.out.printf("Body: \n <%s>\n",current.getText()); | |
} else { | |
System.out.printf("Message is not a TextMessage\n"); | |
} | |
} | |
System.out.println("\nNo more messages\n"); | |
recordSuccess(); | |
} | |
catch (JMSException jmsex) { | |
recordFailure(jmsex); | |
} | |
finally { | |
if (browser != null) { | |
try { | |
browser.close(); | |
} | |
catch (JMSException jmsex) { | |
System.out.println("Browser could not be closed."); | |
recordFailure(jmsex); | |
} | |
} | |
if (session != null) { | |
try { | |
session.close(); | |
} | |
catch (JMSException jmsex) { | |
System.out.println("Session could not be closed."); | |
recordFailure(jmsex); | |
} | |
} | |
if (connection != null) { | |
try { | |
connection.close(); | |
} | |
catch (JMSException jmsex) { | |
System.out.println("Connection could not be closed."); | |
recordFailure(jmsex); | |
} | |
} | |
} | |
System.exit(status); | |
return; | |
} // end main() | |
/** | |
* Process a JMSException and any associated inner exceptions. | |
* | |
* @param jmsex | |
*/ | |
private static void processJMSException(JMSException jmsex) { | |
System.out.println(jmsex); | |
Throwable innerException = jmsex.getLinkedException(); | |
if (innerException != null) { | |
System.out.println("Inner exception(s):"); | |
} | |
while (innerException != null) { | |
System.out.println(innerException); | |
innerException = innerException.getCause(); | |
} | |
return; | |
} | |
/** | |
* Record this run as successful. | |
*/ | |
private static void recordSuccess() { | |
System.out.println("SUCCESS"); | |
status = 0; | |
return; | |
} | |
/** | |
* Record this run as failure. | |
* | |
* @param ex | |
*/ | |
private static void recordFailure(Exception ex) { | |
if (ex != null) { | |
if (ex instanceof JMSException) { | |
processJMSException((JMSException) ex); | |
} else { | |
System.out.println(ex); | |
} | |
} | |
System.out.println("FAILURE"); | |
status = -1; | |
return; | |
} | |
/** | |
* Parse user supplied arguments. | |
* | |
* @param args | |
*/ | |
private static void parseArgs(String[] args) { | |
try { | |
int length = args.length; | |
//for (int i=1;i<args.length;i++) | |
// System.out.printf("Arg:%d Val:%s\n",i,args[i]); | |
if (length == 0) { | |
throw new IllegalArgumentException("No arguments! Mandatory arguments must be specified."); | |
} | |
if ((length % 2) != 0) { | |
throw new IllegalArgumentException("Incorrect number of arguments!"); | |
} | |
int i = 0; | |
while (i < length) { | |
if ((args[i]).charAt(0) != '-') { | |
throw new IllegalArgumentException("Expected a '-' character next: " + args[i]); | |
} | |
char opt = (args[i]).toLowerCase().charAt(1); | |
switch (opt) { | |
case 'h' : | |
host = args[++i]; | |
clientTransport = true; | |
break; | |
case 'p' : | |
port = Integer.parseInt(args[++i]); | |
break; | |
case 'l' : | |
channel = args[++i]; | |
break; | |
case 'm' : | |
queueManagerName = args[++i]; | |
break; | |
case 'd' : | |
queueName = args[++i]; | |
break; | |
default : { | |
throw new IllegalArgumentException("Unknown argument: " + opt); | |
} | |
} | |
++i; | |
} | |
if (queueManagerName == null) { | |
throw new IllegalArgumentException("A queueManager name must be specified."); | |
} | |
if (queueName == null) { | |
throw new IllegalArgumentException("A queue name must be specified."); | |
} | |
} | |
catch (Exception e) { | |
System.out.println(e.getMessage()); | |
printUsage(); | |
System.exit(-1); | |
} | |
return; | |
} | |
/** | |
* Display usage help. | |
*/ | |
private static void printUsage() { | |
System.out.println("\nUsage:"); | |
System.out.println("JmsBrowser -m queueManagerName -d queueName [-h host -p port -l channel]"); | |
return; | |
} | |
} // end class |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: rfh2put JmsBrowser.class | |
rfh2put: rfh2put.c | |
cc -o $@ rfh2put.c -I/opt/mqm/inc -L/opt/mqm/lib64 -lmqm_r | |
JmsBrowser.class: JmsBrowser.java | |
javac -cp /opt/mqm/java/lib/com.ibm.mq.allclient.jar JmsBrowser.java |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <cmqc.h> | |
#include <cmqstrc.h> | |
#ifndef RoundTo4 | |
#define RoundTo4(u) (((u)+ (( 4-((u)%4))%4))) | |
#endif | |
int main(int argc, char **argv) | |
{ | |
MQOD od = {MQOD_DEFAULT}; | |
MQMD md = {MQMD_DEFAULT}; | |
MQPMO pmo = {MQPMO_DEFAULT}; | |
MQRFH2 rfh2Header = {MQRFH2_DEFAULT}; | |
MQHCONN hConn; | |
MQHOBJ hObj; | |
MQLONG openOptions; | |
MQLONG CC; | |
MQLONG RC; | |
MQLONG messageLen; | |
MQLONG folderLen; // this must be a 4-byte integer | |
char qMgrName[50]; | |
char buffer[65535] = {0}; | |
char inputLine[BUFSIZ] = {0}; | |
int offset; | |
char *body; | |
char *folder; | |
int s; | |
if (argc < 2) | |
{ | |
printf("Required parameter missing - queue name\n"); | |
exit(1); | |
} | |
qMgrName[0] = 0; | |
if (argc > 2) | |
{ | |
strncpy(qMgrName, argv[2], (size_t)MQ_Q_MGR_NAME_LENGTH); | |
} | |
MQCONN(qMgrName, &hConn, &CC, &RC); | |
if (CC == MQCC_FAILED) | |
{ | |
printf("MQCONNX ended with RC code %d\n", RC); | |
exit((int)RC ); | |
} | |
strncpy(od.ObjectName, argv[1], (size_t)MQ_Q_NAME_LENGTH); | |
printf("target queue is %s\n", od.ObjectName); | |
openOptions = MQOO_OUTPUT | MQOO_FAIL_IF_QUIESCING; | |
MQOPEN(hConn, &od, openOptions, &hObj, &CC, &RC); | |
if (RC != MQRC_NONE) | |
{ | |
printf("MQOPEN ended with RC code %d\n", RC); | |
exit(1); | |
} | |
printf("Enter folder strings (empty string ends):\n"); | |
offset = MQRFH_STRUC_LENGTH_FIXED_2; // 36 | |
do | |
{ | |
memset(inputLine,0,sizeof(inputLine)); | |
folder = fgets(inputLine,sizeof(inputLine)-1,stdin); | |
// Remove trailing LF | |
if (folder[strlen(folder)-1] == '\n') | |
{ | |
folder[strlen(folder) -1] = 0; | |
} | |
folderLen = RoundTo4(strlen(folder)); // Length must be multiple of 4. | |
if (folderLen) | |
{ | |
// NameValueLength - how long is the adjacent folder | |
memcpy(&buffer[offset],&folderLen,sizeof(folderLen)); | |
offset += sizeof(folderLen); | |
// NameValueData - copy in the actual length read from input, not the rounded value. | |
// But bump the offset by the rounded amount, ready for next element. Gaps caused by | |
// rounding up are ignored. | |
memcpy(&buffer[offset],folder,strlen(folder)); | |
offset += folderLen; | |
} | |
} while(folderLen); | |
// Fill out the RFH2 header block | |
memcpy(rfh2Header.Format, MQFMT_STRING,(size_t)MQ_FORMAT_LENGTH); // Message body will be a string | |
rfh2Header.CodedCharSetId = MQCCSI_INHERIT; | |
rfh2Header.StrucLength = offset; // We now know the complete length, including the fixed header | |
rfh2Header.NameValueCCSID = 1208L; | |
memcpy(buffer,&rfh2Header,sizeof(rfh2Header)); // Copy the header into the start of the buffer now we know lengths | |
// And tell the MQMD that there is an RFH2 | |
memcpy(md.Format, MQFMT_RF_HEADER_2, (size_t)MQ_FORMAT_LENGTH); | |
// Message body is a single input string | |
printf("Enter body string:\n"); | |
memset(inputLine,0,sizeof(inputLine)); | |
body = fgets(inputLine,sizeof(inputLine)-1,stdin); | |
s = strlen(body); | |
if (body[s-1] == '\n') | |
{ | |
body[s-1] = 0; | |
s--; | |
} | |
memcpy(&buffer[offset],body,s); | |
messageLen = offset + s; | |
pmo.Options = MQPMO_NO_SYNCPOINT | MQPMO_FAIL_IF_QUIESCING; | |
MQPUT(hConn, hObj, &md, &pmo, messageLen, buffer, &CC,&RC); | |
if (RC != MQRC_NONE) | |
{ | |
printf("MQPUT ended with RC code %s [%d]\n", MQRC_STR(RC),RC); | |
} | |
MQCLOSE(hConn, &hObj, 0, &CC, &RC); | |
MQDISC(&hConn, &CC, &RC); | |
return(0); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
make -f Makefile | |
if [ $? -ne 0 ] | |
then | |
exit 1 | |
fi | |
q="DEV.QUEUE.1" | |
qm="QM1" | |
. setmqenv -m $qm -k | |
export PATH=$PATH:/opt/mqm/samp/bin | |
echo "CLEAR QL($q)" | runmqsc $qm | |
# Message body | |
msg="Hello at `date`" | |
# These strings are complete folders | |
f1="<myfolder content='properties'><colour>red</colour></myfolder>" | |
f1a="<myfolder2'><colour>yellow</colour></myfolder2>" # Can use this to see behaviour when not marked as properties | |
f2="<usr><colour>green</colour><size>large</size></usr>" | |
cat << EOF | rfh2put $q $qm | |
$f1 | |
$f2 | |
$msg | |
EOF | |
# Get the message showing raw RFH2 | |
amqsbcg $q $qm 3 | |
# Get the message showing properties | |
amqsbcg $q $qm 1 | |
# Get the message removing RFH2 entirely | |
amqsbcg $q $qm 2 | |
echo | |
java -cp /opt/mqm/java/lib/com.ibm.mq.allclient.jar:. JmsBrowser -m $qm -d $q -h localhost -l SYSTEM.DEF.SVRCONN | grep -v "Prop: JMS" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment