Author |
Message
|
speediii |
Posted: Mon Mar 05, 2007 12:23 am Post subject: MQRFH2 and Java base classes |
|
|
Novice
Joined: 11 Apr 2006 Posts: 19
|
Hi
I need some advice please! We have a new system sending MQ messages in a RFH2 format. The MQ messages contain a file, and properties in the RFH2 header contain fields such as the desired filename etc.
I've read through this forum and it seems to me that the Java base api classes do not have any helper classes for reading and writing MQRFH2, is this correct? I understand that JMS messages sent to MQ are by default written in RFH2 format - in my case, my application is Java but the sending/receiving application might not be JMS, but C/C++, using the RFH2 format. Strange that the Java base classes don't have any get/set RFHProperty() type methods?
The answer seems to be "switch to JMS". If no one has any helper functions for RFH2 then I need to write a new JMS Reader & JMS Writer and use that instead of my native MQ adapters. Question: Could someone post some example code; I am confused about how to write these as some examples use pure javax.jms.* but wonder what the com.ibm.mqjms.jar is for?
A bit of decent example code would help me immensely! Or if anyone has some useful links as I've tried google and haven't had much luck, hence this post.
Thanks in advance! |
|
Back to top |
|
 |
EddieA |
Posted: Mon Mar 05, 2007 10:19 am Post subject: |
|
|
 Jedi
Joined: 28 Jun 2001 Posts: 2453 Location: Los Angeles
|
No, there aren't any helper classes. If you search the site, you can find some Java "snippets" for reading/writing RFH2 headers.
You can also "tell" the JMS application to PUT messages without the RFH2 header, if the messages are destined for a non-JMS application.
Cheers, _________________ Eddie Atherton
IBM Certified Solution Developer - WebSphere Message Broker V6.1
IBM Certified Solution Developer - WebSphere Message Broker V7.0 |
|
Back to top |
|
 |
fjb_saper |
Posted: Mon Mar 05, 2007 1:12 pm Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
And if working in C/C# you can use the XMS package (JMS for non java languages)...
Enjoy  _________________ MQ & Broker admin |
|
Back to top |
|
 |
speediii |
Posted: Tue Mar 06, 2007 12:26 am Post subject: |
|
|
Novice
Joined: 11 Apr 2006 Posts: 19
|
But the sending application isn't JMS. It's a C/C++ but it's using MQRFH2 in the message structure for sending files over MQ.
It seems strange that I have to write a JMS adaptor just because of RFH2? RFH2 isn't just for JMS. Or?
Thanks |
|
Back to top |
|
 |
Vitor |
Posted: Tue Mar 06, 2007 12:52 am Post subject: |
|
|
 Grand High Poobah
Joined: 11 Nov 2005 Posts: 26093 Location: Texas, USA
|
RFH2 is used for any message created from any language which needs to hold additional information, typically within a MQSI/WMB environment where you want to clue the broker in on message type for example, not just JMS. It's used in JMS apps because there's not enough space in the MQMD to hold all the fields of a JMS header. _________________ Honesty is the best policy.
Insanity is the best defence. |
|
Back to top |
|
 |
fjb_saper |
Posted: Tue Mar 06, 2007 1:05 pm Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
JMS and XMS are not a must but a very convenient way not to reinvent the wheel and ideal for RFH header manipulation...
Enjoy  _________________ MQ & Broker admin |
|
Back to top |
|
 |
speediii |
Posted: Fri Mar 23, 2007 4:40 am Post subject: |
|
|
Novice
Joined: 11 Apr 2006 Posts: 19
|
For anyone who's interested I got the reading & writing of RFH2 to work using Java base classes. I think the below code is more complete than any other code examples on this forum:
For reading MQRFH2:
Code: |
public void parseMQRFH2(com.ibm.mq.MQMessage mqMessage) throws Exception {
mqMessage.seek(0); //Set read position back to the beginning of Message Data part
rfhStrucID = mqMessage.readString(4); //MQC.MQRFH_STRUC_ID
rfhVersion = mqMessage.readInt(); //MQRFH_VERSION_1 or MQRFH_VERSION_2
rfhStrucLength = mqMessage.readInt(); //MQRFH_STRUC_LENGTH_FIXED or MQRFH_STRUC_LENGTH_FIXED_2
rfhEncoding = mqMessage.readInt(); //MQC.MQENC_NATIVE
rfhCodedCharSetId = mqMessage.readInt(); //MQC.MQCCSI_DEFAULT
rfhFormat = mqMessage.readString(8); //MQFMT_RF_HEADER_2
rfhFlags = mqMessage.readInt(); //MQC.MQRFH_NO_FLAGS
rfhNameValueCCSID = mqMessage.readInt(); //1208 - UTF-8
//
// Validate Header
if (!mqMessage.format.equals(MQC.MQFMT_RF_HEADER_2)) {
throw new Exception("Invalid MQRFH2 format. MQFormat["+mqMessage.format+"] should be["+MQC.MQFMT_RF_HEADER_2+"]");
}
//The coded character set identifier of character data in the application
//message data. The behavior of the readString, readLine, and writeString
//methods is altered accordingly.
mqMessage.characterSet = rfhNameValueCCSID;
int hdrOffset = mqMessage.getDataOffset();
//
// Now parse through all the pairs of data (length, xml data)
// Part 1: <mcd></mcd>
// Part 2: <jms></jms>
// Part 3: <usr></usr> - Contains USER Set properties
// ...etc ...
// Last Part: Trailing Message Data
//
int dataLen;
String xml;
while (hdrOffset < rfhStrucLength) {
dataLen = mqMessage.readInt(); //Get the length of the XML Data part
xml = mqMessage.readString(dataLen); //Get the XML data
hdrOffset += dataLen + 4;
//
//Try to parse XML element, and place the element in the HashMap store
try {
Document doc = XMLUtils.getXmlFromString(xml);
Element e = doc.getRootElement();
String xmlName = e.getName();
rfhXmlSection.put(xmlName, e);
} catch (Exception ex) {
log.error("Failed to parse XML into JDOM Element. XML String["+xml+"]", ex);
throw ex;
}
}
mqMessage.encoding = rfhEncoding;
mqMessage.characterSet = rfhCodedCharSetId;
//
// Read Trailing Message Data
int pos = mqMessage.getDataOffset(); //Current Position
dataLen = mqMessage.getDataLength(); //Number of bytes remaining
rfhDataBytes = new byte[dataLen];
rfhDataString = mqMessage.readString(dataLen);
mqMessage.seek(pos); //Set read position back to the beginning of Data part
mqMessage.readFully(rfhDataBytes);
} |
And writing an MQRFH2 structure:
Code: |
public com.ibm.mq.MQMessage createMQRFH2(Message message) throws Exception {
com.ibm.mq.MQMessage mqMessage = new com.ibm.mq.MQMessage();
//
// Extract the mcd, jms, usr sections from the Message Properties
constructXmlSectionFromProperties(message);
if (message.isByteModified()) {
rfhDataBytes = message.getMsgByte();
m_writeMode = "BYTE ARRAY";
} else if (message.isStrModified()) {
rfhDataBytes = message.getMsgString().getBytes();
m_writeMode = "STRING";
} else if (message.getMsgByte() != null) {
rfhDataBytes = message.getMsgByte();
m_writeMode = "BYTE ARRAY";
} else {
rfhDataBytes = message.getMsgString().getBytes();
m_writeMode = "STRING";
}
//The StrucLength value must be a multiple of 4 (the data in the NameValueData/XML Section
//fields can be padded with space characters to achieve this).
rfhStrucLength = MQC.MQRFH_STRUC_LENGTH_FIXED_2;
while(m_mcd_data.getBytes().length % 4 != 0) {
m_mcd_data += " ";
}
rfhStrucLength += m_mcd_data.getBytes().length;
while(m_jms_data.getBytes().length % 4 != 0) {
m_jms_data += " ";
}
rfhStrucLength += m_jms_data.getBytes().length;
while(m_usr_data.getBytes().length % 4 != 0) {
m_usr_data += " ";
}
rfhStrucLength += m_usr_data.getBytes().length;
rfhStrucLength += 12; //Add 4 bytes x 3 for each XML NameValueData section
rfhStrucLength += rfhDataBytes.length;
mqMessage.format = MQC.MQFMT_RF_HEADER_2;
//RFH2 Part 1: Header Part
mqMessage.writeString(rfhStrucID); //StrucID
mqMessage.writeInt4(rfhVersion); //Version
mqMessage.writeInt4(rfhStrucLength ); //StrucLength
mqMessage.writeInt4(rfhEncoding); //Encoding
mqMessage.writeInt4(rfhCodedCharSetId); //CodedCharSetID
mqMessage.writeString(rfhFormat); //Format
mqMessage.writeInt4(rfhFlags); //Flags
mqMessage.writeInt4(rfhNameValueCCSID); //NameValueCCSID
mqMessage.writeInt4(m_mcd_data.getBytes().length);//NameValueLength <mcd>
mqMessage.writeString(m_mcd_data); //NameValueData <mcd>
mqMessage.writeInt4(m_jms_data.getBytes().length);//NameValueLength <mcd>
mqMessage.writeString(m_jms_data); //NameValueData <mcd>
mqMessage.writeInt4(m_usr_data.getBytes().length);//NameValueLength <jms>
mqMessage.writeString(m_usr_data); //NameValueData <usr>
mqMessage.write(rfhDataBytes); //Actual MESSAGE data
return mqMessage;
} |
|
|
Back to top |
|
 |
fjb_saper |
Posted: Fri Mar 23, 2007 1:29 pm Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
Great, now where do I have my getter setter methods for the usr folder (property / value pairs) and where does it enforce the CCSID for those? (see the limited list available...)
Thanks I'd rather stick with JMS that handles all this behind the scenes for me.
By the way you can in your classes stick with
javax.jms.* and javax.naming.*
but remember that those are just interfaces. You still need the implementation on the classpath and that's where the com.ibm.mqjms.jar packages comes in...
In fact for a successful JMS connection you will need on your classpath at a minimum:
- com.ibm.mq.jar
- com.ibm.mqjms.jar
- connector.jar
- fscontext.jar (if you use a file context)
- jms.jar
- jta.jar
- jndi.jar
- providerutil.jar
- rmm.jar
Note that some are provided by your Web Applications Server provider (jms, jta, jndi)
Best practice is to use all those in <MQ_INSTALL>/java/lib and subtract the ones already provided by your WAS provider....
Enjoy  _________________ MQ & Broker admin |
|
Back to top |
|
 |
Mohd-Imran |
Posted: Sun Apr 01, 2007 7:35 pm Post subject: WebSphere MQ JAVA/JMS -- Visual basic |
|
|
Novice
Joined: 01 Apr 2007 Posts: 12
|
Hi,
First time i am using MQ , I build application in Visual Basic 6.0 to connect mq and put message and get message. Issue is that I need to put message with MQRFH2 (message header) but i am unable to do this , Acutally i don't know how to do this , if anybody help me in this regard and if possible send me code so i add this code in my application.
Need this very very urgent.[quote] |
|
Back to top |
|
 |
Vitor |
Posted: Mon Apr 02, 2007 12:18 am Post subject: Re: WebSphere MQ JAVA/JMS -- Visual basic |
|
|
 Grand High Poobah
Joined: 11 Nov 2005 Posts: 26093 Location: Texas, USA
|
Mohd-Imran wrote: |
Issue is that I need to put message with MQRFH2 (message header) but i am unable to do this , Acutally i don't know how to do this , if anybody help me in this regard and if possible send me code so i add this code in my application. |
MQRFH2 is one of the headers supplied in the .bas file you've already got included with your VB app if it's successfully connecting and putting messages. So all you need to do is add the header to the payload buffer, change whatever parts of the RFH2 you need to set (type and so forth), and change the MQMD.Format to the RFH2 constant. IIRC one of the samples deals with this, but it's been a while & I don't have VB6 installed atm to look.
Also, and a little pedantically, you should really have started a new thread in the Application Programming section rather than added to the bottom of an old one in the Java one. It'd get you a faster response to a non-Java issue. But that's a very esoteric point and I wouldn't loose sleep over it!
Welcome to MQ.  _________________ Honesty is the best policy.
Insanity is the best defence. |
|
Back to top |
|
 |
chrisgclark |
Posted: Fri May 22, 2009 4:29 am Post subject: |
|
|
Apprentice
Joined: 26 Mar 2009 Posts: 35
|
Hi,
Sorry for replying on such an old post, but was using the sample code and found a problem. Thought i'd post my amended version in case anyone hits the same problem I did...
When using the 'For reading MQRFH2' code above I found an extra hex value was present after the rfhNameValueCCSID field and before the RFH2 folders beginning. This caused my message positions to be incorrect, therefore not extracting the RFH2 folders and message data.
I therefore added another field read before the while loop that gets the folders. This addition field read get the message position to the correct place going into the while loop.
i.e.
Code: |
public void parseMQRFH2(com.ibm.mq.MQMessage mqMessage) throws Exception {
mqMessage.seek(0); //Set read position back to the beginning of Message Data part
rfhStrucID = mqMessage.readString(4); //MQC.MQRFH_STRUC_ID
rfhVersion = mqMessage.readInt(); //MQRFH_VERSION_1 or MQRFH_VERSION_2
rfhStrucLength = mqMessage.readInt(); //MQRFH_STRUC_LENGTH_FIXED or MQRFH_STRUC_LENGTH_FIXED_2
rfhEncoding = mqMessage.readInt(); //MQC.MQENC_NATIVE
rfhCodedCharSetId = mqMessage.readInt(); //MQC.MQCCSI_DEFAULT
rfhFormat = mqMessage.readString(8); //MQFMT_RF_HEADER_2
rfhFlags = mqMessage.readInt(); //MQC.MQRFH_NO_FLAGS
rfhNameValueCCSID = mqMessage.readInt(); //1208 - UTF-8
unknownRFHFieldContainingNoValue = mqMessage.readInt(); //unknown field containing hex value 00000000
.
.
.
.
|
My ammended is the last line of code. This moves to the correct message position to begin looping through the RFH2 folders.
Anyone know why I found an additional hex value after rfhNameValueCCSID ?
If not, don't worry, but hopefully this code will avoid someone the same problem. |
|
Back to top |
|
 |
|