|
RSS Feed - WebSphere MQ Support
|
RSS Feed - Message Broker Support
|
Coding LLZZ IMS header in C++ |
« View previous topic :: View next topic » |
Author |
Message
|
gpklos |
Posted: Thu Mar 05, 2020 11:17 am Post subject: Coding LLZZ IMS header in C++ |
|
|
Centurion
Joined: 24 May 2002 Posts: 108
|
I have been tasked to code a sample program that writes a message to the IMS Bridge using C++. I have done this same sample using vb.net and Java. However I am struggling to find how to write out the LLZZ header. I've looked at the IBM IMS Bridge C++ example, but that only gives pseudo code
"msg.write( 2, /* ? */ ); // Total message length.
msg.write( 2, /* ? */ ); // IMS flags.
msg.write( 7, /* ? */ ); // Transaction code.
msg.write( /* ? */, /* ? */ ); // String data."
The LL portion is the length of the message (plus transaction name) to send to the imsbridge plus 4, which is the length of the LLZZ header itself. Normally this is written out in binary I believe. NOTE: I've done this in vb.net using mqMsg.WriteShort(message.Length +4).
I have looked on Google for hours for examples in C++, but none exist for the IMSBridge. There was one listed on Capitalware's page, but when you click on it, it actually points to another program corrid.cpp.
I am not worried about including the MQIIH header for my example. We haven't used that for our other applications that use the IMSBridge. I just want to send a basic message that has the IMS transaction plus data. I need to prepend the LLZZ header.
Does anyone have a working example of how the write out the LLZZ header, or at least a little more detail.
Also please keep in mind, I'm not a C++ coder, so maybe it is simple, but I just don't know enough.
Thanks,
Gary |
|
Back to top |
|
 |
tczielke |
Posted: Thu Mar 05, 2020 12:12 pm Post subject: |
|
|
Guardian
Joined: 08 Jul 2010 Posts: 941 Location: Illinois, USA
|
amqsclma.c comes with distributed MQ in the /opt/mqm/samp directory, and it gives examples of how to build a PCF message in C (which would contain binary data in the message).
When working with multi-byte binary data in a message (e.g. signed 4-byte binary integer) you do have to take into account the endianness of your platform. For example, a signed 4-byte binary integer on the x86 processor (little endian, or lowest order byte in lowest memory location) is byte ordered differently than a 4-byte binary integer on a z/OS processor (big endian, or highest order byte in lowest memory location). Not sure if this bridge handles this for you. _________________ Working with MQ since 2010. |
|
Back to top |
|
 |
hughson |
Posted: Fri Mar 06, 2020 1:24 am Post subject: Re: Coding LLZZ IMS header in C++ |
|
|
 Padawan
Joined: 09 May 2013 Posts: 1959 Location: Bay of Plenty, New Zealand
|
gpklos wrote: |
I've looked at the IBM IMS Bridge C++ example, but that only gives pseudo code |
There's an IMS Bridge C++ example? Where? _________________ Morag Hughson @MoragHughson
IBM MQ Technical Education Specialist
Get your IBM MQ training here!
MQGem Software |
|
Back to top |
|
 |
gpklos |
Posted: Fri Mar 06, 2020 3:58 am Post subject: |
|
|
Centurion
Joined: 24 May 2002 Posts: 108
|
It is from IBM's documentation. Like I said it is only pseudo code and isn't complete. It can be found at this link.
https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.1.0/com.ibm.mq.dev.doc/q030390_.htm
The fact that you asked where it is at makes me think very few people have written c++ code to access the IMS Bridge.
In case the link doesn't work here is the pseudo code. It is the msg.write statement that has me confused on how to write out the LLZZ header. The documentation says ImqBoolean write ( const size_t length, const char * external-buffer ); So I'm not sure how to get it to write out a byte of data. Again let me reiterate, I'm not a C++ programmer at all so this is a bit over my head, but I'm trying.
Example program code for writing a message to the IMS bridge.
Messages sent to the IBM® MQ - IMS bridge might use a special header. The IMS bridge header is prefixed to regular message data.
ImqQueueManager mgr; // The queue manager.
ImqQueue queueBridge; // IMS bridge message queue.
ImqMessage msg; // Outgoing message.
ImqIMSBridgeHeader header; // IMS bridge header.
// Set up the message.
//
// Here we are constructing a message with format
// MQFMT_IMS_VAR_STRING, and appropriate data.
//
msg.write( 2, /* ? */ ); // Total message length.
msg.write( 2, /* ? */ ); // IMS flags.
msg.write( 7, /* ? */ ); // Transaction code.
msg.write( /* ? */, /* ? */ ); // String data.
msg.setFormat( MQFMT_IMS_VAR_STRING ); // The format attribute.
// Set up the IMS bridge header information.
//
// The reply-to-format is often specified.
// Other attributes can be specified, but all have default values.
//
header.setReplyToFormat( /* ? */ );
// Insert the IMS bridge header into the message.
//
// This will:
// 1) Insert the header into the message buffer, before the existing
// data.
// 2) Copy attributes out of the message descriptor into the header,
// for example the IMS bridge header format attribute will now
// be set to MQFMT_IMS_VAR_STRING.
// 3) Set up the message attributes to describe the header, in
// particular setting the message format to MQFMT_IMS.
//
msg.writeItem( header );
// Send the message to the IMS bridge queue.
//
queueBridge.setConnectionReference( mgr );
queueBridge.setName( /* ? */ );
queueBridge.put( msg ); |
|
Back to top |
|
 |
gpklos |
Posted: Fri Mar 06, 2020 4:05 am Post subject: |
|
|
Centurion
Joined: 24 May 2002 Posts: 108
|
tczielke wrote: |
amqsclma.c comes with distributed MQ in the /opt/mqm/samp directory, and it gives examples of how to build a PCF message in C (which would contain binary data in the message).
Thank you. I will take a look at it. I'm still very confused on how to use the specific msg.write to write out binary data, when the command specifies it is writing out Character data. I would have thought there would have been some type of overload on the function to allow something other than characters to be written. Again I'm probably missing some other detail
When working with multi-byte binary data in a message (e.g. signed 4-byte binary integer) you do have to take into account the endianness of your platform. For example, a signed 4-byte binary integer on the x86 processor (little endian, or lowest order byte in lowest memory location) is byte ordered differently than a 4-byte binary integer on a z/OS processor (big endian, or highest order byte in lowest memory location). Not sure if this bridge handles this for you. |
|
|
Back to top |
|
 |
hughson |
Posted: Sat Mar 07, 2020 1:37 am Post subject: |
|
|
 Padawan
Joined: 09 May 2013 Posts: 1959 Location: Bay of Plenty, New Zealand
|
gpklos wrote: |
... makes me think very few people have written c++ code ... |
The C++ interface to MQ was stabilised a long time ago. Even before then many people used the C API from within C++ applications.
Cheers,
Morag _________________ Morag Hughson @MoragHughson
IBM MQ Technical Education Specialist
Get your IBM MQ training here!
MQGem Software |
|
Back to top |
|
 |
gpklos |
Posted: Sat Mar 07, 2020 3:32 pm Post subject: |
|
|
Centurion
Joined: 24 May 2002 Posts: 108
|
I'm not doubting whether it was stabilised. I'm sure it was, I just can't find any example for C++ coding to write to the IMS Bridge. Again I'm feeling really stupid. Do you know of any samples anywhere for writing to the IMS Bridge in C++?
Thanks
Gary |
|
Back to top |
|
 |
gpklos |
Posted: Sat Mar 07, 2020 3:34 pm Post subject: |
|
|
Centurion
Joined: 24 May 2002 Posts: 108
|
hughson wrote: |
Even before then many people used the C API from within C++ applications.
Cheers,
Morag |
Are you suggesting to somehow use the Regular C routines to do the writing of the IMS Bridge message within a C++ program?
Thanks,
Gary |
|
Back to top |
|
 |
hughson |
Posted: Sat Mar 07, 2020 3:58 pm Post subject: |
|
|
 Padawan
Joined: 09 May 2013 Posts: 1959 Location: Bay of Plenty, New Zealand
|
gpklos wrote: |
hughson wrote: |
Even before then many people used the C API from within C++ applications.
Cheers,
Morag |
Are you suggesting to somehow use the Regular C routines to do the writing of the IMS Bridge message within a C++ program?
Thanks,
Gary |
Just giving reasons why I suspect it unlikely that you will see (m)any samples.
Looking at the documentation for the MQFMT_IMS_VAR_STRING (not familiar with it myself) it says:-
IBM Knowledge Center wrote: |
MQFMT_IMS_VAR_STRING
The message is an IMS variable string, which is a string of the form llzzccc, where:
ll
is a 2-byte length field specifying the total length of the IMS variable string item. This length is equal to the length of ll (2 bytes), plus the length of zz (2 bytes), plus the length of the character string itself. ll is a 2-byte binary integer in the encoding specified by the Encoding field.
zz
is a 2-byte field containing flags that are significant to IMS. zz is a byte string consisting of two MQBYTE fields, and is transmitted without change from sender to receiver (that is, zz is not subject to any conversion).
ccc
is a variable-length character string containing ll-4 characters. ccc is in the character set specified by the CodedCharSetId field. |
This seems to align with the psuedo code you provide. The text showing /* ? */ is telling you that you need to put the appropriate value in there.
Code: |
// Here we are constructing a message with format
// MQFMT_IMS_VAR_STRING, and appropriate data.
//
msg.write( 2, /* ? */ ); // Total message length.
msg.write( 2, /* ? */ ); // IMS flags.
msg.write( 7, /* ? */ ); // Transaction code.
msg.write( /* ? */, /* ? */ ); // String data. |
Do you know what the values are in your case for each of these pieces of the variable string? Then we can at least work with some real data (since I don't know what a real-life example would look like to make one up!).
Cheers,
Morag _________________ Morag Hughson @MoragHughson
IBM MQ Technical Education Specialist
Get your IBM MQ training here!
MQGem Software |
|
Back to top |
|
 |
gpklos |
Posted: Mon Mar 09, 2020 11:37 am Post subject: |
|
|
Centurion
Joined: 24 May 2002 Posts: 108
|
hughson wrote: |
Do you know what the values are in your case for each of these pieces of the variable string? Then we can at least work with some real data (since I don't know what a real-life example would look like to make one up!).
Cheers,
Morag |
Hi Morag,
So a real life example of the data we send to IMS is the following.
1CHMU76 00INQ99CJW001
1CHMU76 is the IMS transaction (up to 8 bytes - we use 7). 00INQ99CJW001 is the dataset to that IMS transaction. Now the "data" section is in the form of LLZZ header + transaction + data. The LL portion is the length of the transaction ( + the length of the data (13) + the length of the LLZZ portion itself (4). So 25 in this case. It is written as binary. Now when we say LLZZ header, it is really just part of the message data. It isn't a real HEADER, like the MQMD. So once it is written to the queue it looks like this in message data bytes in MQ Explorer.
19 00 00 00 31 43 48 4D--55 37 36 20 30 30 49 4E |....1CHMU76 00IN|
51 39 39 43 4A 57 30 30--31 |Q99CJW001 |
Notice the 19, which is hex for the data length (25 decimal). The ZZ is just the 3rd and 4th set of 00. ZZ are always 0.
So in vb.net that would be coded like this.
'LL comment
mqMsg.WriteShort(message.Length + 4)
' ZZ comment
mqMsg.WriteByte(0)
mqMsg.WriteByte(0)
In C++ I only seem to find one method to write to the message. I'm sure I'm missing something, but I just don't know what that is.
Thanks!!
|
|
Back to top |
|
 |
hughson |
Posted: Mon Mar 09, 2020 1:21 pm Post subject: |
|
|
 Padawan
Joined: 09 May 2013 Posts: 1959 Location: Bay of Plenty, New Zealand
|
gpklos wrote: |
So a real life example of the data we send to IMS is the following.
1CHMU76 00INQ99CJW001
1CHMU76 is the IMS transaction (up to 8 bytes - we use 7). 00INQ99CJW001 is the dataset to that IMS transaction. Now the "data" section is in the form of LLZZ header + transaction + data. The LL portion is the length of the transaction ( + the length of the data (13) + the length of the LLZZ portion itself (4). So 25 in this case. It is written as binary. Now when we say LLZZ header, it is really just part of the message data. It isn't a real HEADER, like the MQMD. So once it is written to the queue it looks like this in message data bytes in MQ Explorer.
19 00 00 00 31 43 48 4D--55 37 36 20 30 30 49 4E |....1CHMU76 00IN|
51 39 39 43 4A 57 30 30--31 |Q99CJW001 |
Notice the 19, which is hex for the data length (25 decimal). The ZZ is just the 3rd and 4th set of 00. ZZ are always 0.
So in vb.net that would be coded like this.
'LL comment
mqMsg.WriteShort(message.Length + 4)
' ZZ comment
mqMsg.WriteByte(0)
mqMsg.WriteByte(0) |
So, if in your C++ application you do the following:-
Code: |
msg.write( 2, 25 ); // Total message length.
msg.write( 2, 0 ); // IMS flags.
msg.write( 8, "1CHMU76 " ); // Transaction code.
msg.write( 13, "00INQ99CJW001" ); // String data. |
Does it produce the same message data bytes when you view it on the queue as you did with your other application?
Alternatively, you could follow, the rather more C language like example, in https://www.capitalware.com/dl/code/cplusplus/imsbridge.zip (I guessed at the name and was rewarded with a helpful download).
Cheers,
Morag _________________ Morag Hughson @MoragHughson
IBM MQ Technical Education Specialist
Get your IBM MQ training here!
MQGem Software |
|
Back to top |
|
 |
gpklos |
Posted: Tue Mar 10, 2020 4:59 am Post subject: |
|
|
Centurion
Joined: 24 May 2002 Posts: 108
|
hughson wrote: |
So, if in your C++ application you do the following:-
Code: |
msg.write( 2, 25 ); // Total message length.
msg.write( 2, 0 ); // IMS flags.
msg.write( 8, "1CHMU76 " ); // Transaction code.
msg.write( 13, "00INQ99CJW001" ); // String data. |
Does it produce the same message data bytes when you view it on the queue as you did with your other application?
Alternatively, you could follow, the rather more C language like example, in https://www.capitalware.com/dl/code/cplusplus/imsbridge.zip (I guessed at the name and was rewarded with a helpful download).
Cheers,
Morag |
Unfortunately that won't even compile. The msg.write (2,25) is flagged because it says the 'argument of type INT is incompatible with parameter of type const CHAR *'. Which is one of the reasons I didn't know how to send in a binary number, etc. Funny though the msg.write (2, 0) doesn't get flagged, even though the 0 (zero) is an INT. I even reversed the lines of the so that 2,0 was first, but no difference.
Let me look at the sample from Capitalware and see if I can make sense of it. That was a really good guess to get the IMSbridge example. I guess the link on the page needs updated.
Thank you so much for your help so far!
Gary |
|
Back to top |
|
 |
rekarm01 |
Posted: Tue Mar 10, 2020 6:57 pm Post subject: Re: Coding LLZZ IMS header in C++ |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 1415
|
gpklos wrote: |
Does anyone have a working example of how the write out the LLZZ header, or at least a little more detail? |
MQ defines portable datatypes for 16-bit integers, either signed (MQINT16), or unsigned (MQUINT16). The write() method expects a pointer to data, so values have to be passed by address; scalar variables need an '&' operator, (but string literals do not):
Code: |
MQUINT16 imslen=25, imsflags=0;
msg.write( 2, &imslen); // Total message length.
msg.write( 2, &imsflags); // IMS flags.
msg.write( 8, "1CHMU76 "); // Transaction code.
msg.write(13, "00INQ99CJW001"); // String data. |
Or, to avoid (future) issues with 'imsflags' endian-ness, declare it as an array of MQBYTEs instead; (arrays don't need an '&' operator either):
Code: |
MQBYTE imsflags[2] = {0x00, 0x00}; // byte values, in hex
// ...
msg.write( 2, imsflags); // IMS flags. |
The compiler may generate warnings about "incompatible pointer types", but a 'reinterpret_cast' operator should suppress those warnings:
Code: |
msg.write( 2, reinterpret_cast<char *>(&imslen)); // Total message length.
msg.write( 2, reinterpret_cast<char *>(imsflags)); // IMS flags. |
Use explicit casts with caution, though; suppressing compiler warnings is not always the best practice.
gpklos wrote: |
In C++ I only seem to find one method to write to the message. |
The ImqMessage class also has a writeItem() method, but write() is much easier to use here.
gpklos wrote: |
Unfortunately that won't even compile. The msg.write (2,25) is flagged because it says the 'argument of type INT is incompatible with parameter of type const CHAR *'. |
C++ is a case-sensitive language. When quoting a compiler-generated error message, changing 'INT' and 'CHAR' to upper-case (for emphasis?) can be misleading. (Besides, the incompatibility has more to do with the '*', (scalar vs. pointer), and less to do with 'int' vs. 'char'.)
gpklos wrote: |
Funny though the msg.write (2, 0) doesn't get flagged, even though the 0 (zero) is an INT. |
0 (zero) is a special case for C++; it can also represent a null pointer.
[Edit: changed 'static_cast' to 'reinterpret_cast' in sample code.]
Last edited by rekarm01 on Wed Mar 18, 2020 3:55 am; edited 1 time in total |
|
Back to top |
|
 |
gpklos |
Posted: Wed Mar 11, 2020 3:34 am Post subject: Re: Coding LLZZ IMS header in C++ |
|
|
Centurion
Joined: 24 May 2002 Posts: 108
|
rekarm01 wrote: |
gpklos wrote: |
Does anyone have a working example of how the write out the LLZZ header, or at least a little more detail? |
MQ defines portable datatypes for 16-bit integers, either signed (MQINT16), or unsigned (MQUINT16). The write() method expects a pointer to data, so values have to be passed by address; scalar variables need an '&' operator, (but string literals do not):
Code: |
MQUINT16 imslen=25, imsflags=0;
msg.write( 2, &imslen); // Total message length.
msg.write( 2, &imsflags); // IMS flags.
msg.write( 8, "1CHMU76 "); // Transaction code.
msg.write(13, "00INQ99CJW001"); // String data. |
Or, to avoid (future) issues with 'imsflags' endian-ness, declare it as an array of MQBYTEs instead; (arrays don't need an '&' operator either):
Code: |
MQBYTE imsflags[2] = {0x00, 0x00}; // byte values, in hex
// ...
msg.write( 2, imsflags); // IMS flags. |
The compiler may generate warnings about "incompatible pointer types", but a 'static_cast' operator should suppress those warnings:
Code: |
msg.write( 2, static_cast<char *>(&imslen)); // Total message length.
msg.write( 2, static_cast<char *>(imsflags)); // IMS flags. |
Use explicit casts with caution, though; suppressing compiler warnings is not always the best practice.
gpklos wrote: |
In C++ I only seem to find one method to write to the message. |
The ImqMessage class also has a writeItem() method, but write() is much easier to use here.
gpklos wrote: |
Unfortunately that won't even compile. The msg.write (2,25) is flagged because it says the 'argument of type INT is incompatible with parameter of type const CHAR *'. |
C++ is a case-sensitive language. When quoting a compiler-generated error message, changing 'INT' and 'CHAR' to upper-case (for emphasis?) can be misleading. (Besides, the incompatibility has more to do with the '*', (scalar vs. pointer), and less to do with 'int' vs. 'char'.)
gpklos wrote: |
Funny though the msg.write (2, 0) doesn't get flagged, even though the 0 (zero) is an INT. |
0 (zero) is a special case for C++; it can also represent a null pointer. |
Thank you very much, I'm going to look at this and the sample program and give a few different things a try. As I said my lack of c++ experience is showing, but this makes some sense to me. I didn't realize you could pass by reference and fill that field with something other than characters.
ie.
Code: |
MQBYTE imsflags[2] = {0x00, 0x00}; // byte values, in hex
// ...
msg.write( 2, imsflags); // IMS flags. |
All the responses to date and the time spent responding are very appreciated!!
Gary |
|
Back to top |
|
 |
gpklos |
Posted: Wed Mar 11, 2020 11:57 am Post subject: Re: Coding LLZZ IMS header in C++ |
|
|
Centurion
Joined: 24 May 2002 Posts: 108
|
[quote]
Code: |
MQUINT16 imslen=25, imsflags=0;
msg.write( 2, &imslen); // Total message length.
msg.write( 2, &imsflags); // IMS flags.
msg.write( 8, "1CHMU76 "); // Transaction code.
msg.write(13, "00INQ99CJW001"); // String data. |
Or, to avoid (future) issues with 'imsflags' endian-ness, declare it as an array of MQBYTEs instead; (arrays don't need an '&' operator either):
Code: |
MQBYTE imsflags[2] = {0x00, 0x00}; // byte values, in hex
// ...
msg.write( 2, imsflags); // IMS flags. |
The compiler may generate warnings about "incompatible pointer types", but a 'static_cast' operator should suppress those warnings:
Code: |
msg.write( 2, static_cast<char *>(&imslen)); // Total message length.
msg.write( 2, static_cast<char *>(imsflags)); // IMS flags. |
Use explicit casts with caution, though; suppressing compiler warnings is not always the best practice.
[\quote]
So I couldn't get any of these options to compile, they all complained that I was trying assign something to *char that wasn't the same type. I tried the static_cast and that also complained. The msg.write is very picky I guess. I will keep trying different options.
Gary |
|
Back to top |
|
 |
|
|
 |
Goto page 1, 2 Next |
Page 1 of 2 |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|
|
|