ASG
IBM
Zystems
Cressida
Icon
Netflexity
 
  MQSeries.net
Search  Search       Tech Exchange      Education      Certifications      Library      Info Center      SupportPacs      LinkedIn  Search  Search                                                                   FAQ  FAQ   Usergroups  Usergroups
 
Register  ::  Log in Log in to check your private messages
 
RSS Feed - WebSphere MQ Support RSS Feed - Message Broker Support

MQSeries.net Forum Index » General IBM MQ Support » Coding LLZZ IMS header in C++

Post new topic  Reply to topic Goto page 1, 2  Next
 Coding LLZZ IMS header in C++ « View previous topic :: View next topic » 
Author Message
gpklos
PostPosted: Thu Mar 05, 2020 11:17 am    Post subject: Coding LLZZ IMS header in C++ Reply with quote

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
View user's profile Send private message
tczielke
PostPosted: Thu Mar 05, 2020 12:12 pm    Post subject: Reply with quote

Guardian

Joined: 08 Jul 2010
Posts: 939
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
View user's profile Send private message
hughson
PostPosted: Fri Mar 06, 2020 1:24 am    Post subject: Re: Coding LLZZ IMS header in C++ Reply with quote

Padawan

Joined: 09 May 2013
Posts: 1914
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
View user's profile Send private message Visit poster's website
gpklos
PostPosted: Fri Mar 06, 2020 3:58 am    Post subject: Reply with quote

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
View user's profile Send private message
gpklos
PostPosted: Fri Mar 06, 2020 4:05 am    Post subject: Reply with quote

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
View user's profile Send private message
hughson
PostPosted: Sat Mar 07, 2020 1:37 am    Post subject: Reply with quote

Padawan

Joined: 09 May 2013
Posts: 1914
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
View user's profile Send private message Visit poster's website
gpklos
PostPosted: Sat Mar 07, 2020 3:32 pm    Post subject: Reply with quote

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
View user's profile Send private message
gpklos
PostPosted: Sat Mar 07, 2020 3:34 pm    Post subject: Reply with quote

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
View user's profile Send private message
hughson
PostPosted: Sat Mar 07, 2020 3:58 pm    Post subject: Reply with quote

Padawan

Joined: 09 May 2013
Posts: 1914
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
View user's profile Send private message Visit poster's website
gpklos
PostPosted: Mon Mar 09, 2020 11:37 am    Post subject: Reply with quote

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
View user's profile Send private message
hughson
PostPosted: Mon Mar 09, 2020 1:21 pm    Post subject: Reply with quote

Padawan

Joined: 09 May 2013
Posts: 1914
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
View user's profile Send private message Visit poster's website
gpklos
PostPosted: Tue Mar 10, 2020 4:59 am    Post subject: Reply with quote

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
View user's profile Send private message
rekarm01
PostPosted: Tue Mar 10, 2020 6:57 pm    Post subject: Re: Coding LLZZ IMS header in C++ Reply with quote

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
View user's profile Send private message
gpklos
PostPosted: Wed Mar 11, 2020 3:34 am    Post subject: Re: Coding LLZZ IMS header in C++ Reply with quote

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
View user's profile Send private message
gpklos
PostPosted: Wed Mar 11, 2020 11:57 am    Post subject: Re: Coding LLZZ IMS header in C++ Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Post new topic  Reply to topic Goto page 1, 2  Next Page 1 of 2

MQSeries.net Forum Index » General IBM MQ Support » Coding LLZZ IMS header in C++
Jump to:  



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
Protected by Anti-Spam ACP
 
 


Theme by Dustin Baccetti
Powered by phpBB © 2001, 2002 phpBB Group

Copyright © MQSeries.net. All rights reserved.