|
RSS Feed - WebSphere MQ Support
|
RSS Feed - Message Broker Support
|
 |
|
Strange problem - CorrelId as CHARACTER |
« View previous topic :: View next topic » |
Author |
Message
|
chrisc |
Posted: Sun Sep 30, 2007 7:32 pm Post subject: Strange problem - CorrelId as CHARACTER |
|
|
Voyager
Joined: 19 Mar 2006 Posts: 77
|
Hi everyone,
I've been beating my head against a brick wall for a couple of days now with this one...
At the moment I'm storing a copy of the message, including MQMD, MQRFH2 and payload, in a database, before going off to another service queue. (I won't go into the hoops I jumped through to do this reliably!) When I get the response from the other message flow, I want to reconstruct the message and pass the original on.
I've got all the ASBITSTREAM and CREATE...PARSE clauses happening OK so it's recreating them with the appropriate parsers, but I'm getting a weird problem with the MQMD.CorrelId.
The input message has no CorrelId (or at least it's set to zero). When I debug my flow at the ESQL, I look in the MQMD part of the tree and it says:
BLOB CorrelId 000000000000000000000000000000000000000000000000
...which is what I expected. It says this at the last line of the ESQL in the compute node.
But then when I step out to the message flow level and look in the MQMD, it now says:
CHARACTER CorrelId 000000000000000000000000000000000000000000000000
...and I now get an "Exception whilst writing field named MQMD.CorrelId"..."wrong type exception", because the field has turned itself into CHARACTER instead of BLOB.
This is the only field that is causing this problem - the MQMD parser seems to be correctly assigned, because all the other fields are picking up their expected types, and GroupId for example is also a blob with a zero value, but doesn't have this issue.
Any ideas what is going on here? I'm currently using WBI MB v5 CSD 8 and a bucket full of prozac.
Many thanks,
Chris |
|
Back to top |
|
 |
fjb_saper |
Posted: Mon Oct 01, 2007 2:54 am Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
When you manually define an MQMD don't forget the domain clause:
Code: |
create lastchild of OutputRoot domain 'MQMD' name 'MQMD'; |
This will probably fix your problem. As well if you saved is as char in the DB you probably will never get the right value back even casting it to a BLOB...
Search the forum to know why it is a VERY BAD idea to tread messageId or correlationId as a CHARACTER field.  _________________ MQ & Broker admin |
|
Back to top |
|
 |
chrisc |
Posted: Tue Oct 02, 2007 5:54 pm Post subject: |
|
|
Voyager
Joined: 19 Mar 2006 Posts: 77
|
I have been creating the MQMD using the MQMD domain. Also, I have never been setting the CorrelId to a CHAR value - as I said, the value is a BLOB when I debug in the compute node, but when I step out into the message flow it magically converts it into a CHAR value .
I actually discovered the problem, and it wasn't where I expected it to be! And I'm pretty sure it's a broker bug...
When I was restoring the message, I was also restoring the message properties using:
Code: |
-- Retrieved message is stored in Environment.RetrievedMessage
SET OutputRoot.Properties.*[] = Environment.RetrievedMessage.Properties.*[];
|
What I have discovered is that if I do this, the MQMD correlation ID gets changed to CHAR.
I am guessing it must be related to the fact that Properties has no parser, and so setting them in this way confuses certain values... Anyway, you live and learn.
Cheers,
Chris |
|
Back to top |
|
 |
dbjohnsson |
Posted: Wed Oct 29, 2008 10:22 pm Post subject: Any solution to this proble |
|
|
Newbie
Joined: 19 Apr 2007 Posts: 8
|
Hi chrisc,
What was your solution to this problem. You seem to say that you fixed it but
I'm getting a similar problem now. When the message comes out of the compute node it transforms the CorrelId into a Char???
Cheers |
|
Back to top |
|
 |
mgk |
Posted: Thu Oct 30, 2008 1:13 am Post subject: |
|
|
 Padawan
Joined: 31 Jul 2003 Posts: 1642
|
Hi Chris. I can guess why you had the problem. This code:
Code: |
SET OutputRoot.Properties.*[] = Environment.RetrievedMessage.Properties.*[]; |
will do a list assignment, which means that all children of the target will be deleted before the children of the source are assigned. Therefore, I would guess that Environment.RetrievedMessage.Properties is NOT owned by a Properties PARSER so that all its children are CHARacters. The way to get around this would be to CREATE Environment.RetrievedMessage.Properties with a DOMAIN 'PROPERTIES' clause.
The reason it changes from BLOB to CHAR as you leave the compute node is that when the message is propagated from the Compute node the MQMD is "fixed up" with headers from the Properties folder.
Regards, _________________ MGK
The postings I make on this site are my own and don't necessarily represent IBM's positions, strategies or opinions. |
|
Back to top |
|
 |
chrisc |
Posted: Thu Oct 30, 2008 2:38 pm Post subject: |
|
|
Voyager
Joined: 19 Mar 2006 Posts: 77
|
Actually the problem is that as far as I can tell there is no Properties parser at all.
The IBM documentation says that it supports these header parsers: MQMD, MQMDE, MQCFH, MQCIH, MQDLH, MQIIH, MQRFH, MQRFH2, MQRMH, MQSAPH, MQWIH, SMQ_BMH, JMS and HTTP. There is no mention of Properties listed. At the time the code was for Broker 5 as well, which means that this list was even smaller then.
From memory (and this was quite a long time ago now), it didn't work even with copying the Properties in their entirety, rather than using the list-style copy (Properties.*[]). I can't remember if the result was the same in both cases, though, or if it was a different error.
I ended up getting around this by actually disregarding the saved Properties entirely and picking the values up from the input message. It worked in my particular situation because the MsgId and CorrelId were not being changed between saving and restoring the message.
If you need a more general case than this then you might need to do some more substantial work to store both type and value, and then have logic to cast each value to its correct type when it assigns it across. It's a bit of a painful way to go, though...
For reference, the full save/restore code I used is below. I take no responsibility though if it has bugs in it or doesn't work for you! (I changed a few bits to hide any client-specific details.)
Save code:
Code: |
SET OutputRoot = InputRoot;
DECLARE msgid CHAR SUBSTRING(CAST(InputRoot.MQMD.MsgId AS CHAR) FROM 3 FOR 48);
DECLARE msg BLOB;
DECLARE msgDomain CHAR FIELDNAME(OutputRoot.*[<]);
-- Create an MQRFH2 after the MQMD if it doesn't already exist
IF FIELDNAME(OutputRoot.MQRFH2) is null THEN
IF msgDomain in ('MRM', 'XML', 'BLOB', 'XMLNS', 'XMLNSC') THEN
-- Message body is present
CREATE PREVIOUSSIBLING OF OutputRoot.*[<] DOMAIN 'MQRFH2' NAME 'MQRFH2';
ELSE
-- No supported message body
CREATE LASTCHILD OF OutputRoot DOMAIN 'MQRFH2' NAME 'MQRFH2';
END IF;
SET OutputRoot.MQMD.Format = 'MQHRF2';
SET OutputRoot.MQRFH2.(MQRFH2.Field)Format = 'MQSTR';
END IF;
-- Store the message domain for future use (parsing the blob)
IF msgDomain in ('MRM', 'XML', 'BLOB', 'XMLNS', 'XMLNSC') THEN
SET OutputRoot.MQRFH2.MessageDomain = msgDomain;
END IF;
-- Copy the Properties folder to the RFH2
SET OutputRoot.MQRFH2.Properties.*[] = InputRoot.Properties.*[];
-- Copy the Environment tree to the RFH2 as well
SET OutputRoot.MQRFH2.Environment.*[] = Environment.*[];
-- Bitstream the entire message, including headers
DECLARE enc INTEGER InputRoot.MQMD.Encoding;
DECLARE ccsid INTEGER InputRoot.MQMD.CodedCharSetId;
DECLARE msgSet CHAR InputRoot.Properties.MessageSet;
DECLARE msgType CHAR InputRoot.Properties.MessageType;
DECLARE msgFmt CHAR InputRoot.Properties.MessageFormat;
IF msgDomain = 'MRM' THEN
-- Use message set etc
SET msg = ASBITSTREAM(OutputRoot ENCODING enc CCSID ccsid SET msgSet TYPE msgType FORMAT msgFmt);
ELSE
-- Don't use message set etc
SET msg = ASBITSTREAM(OutputRoot ENCODING enc CCSID ccsid);
END IF;
-- Store the message (including all headers) in the database
CALL storeOFACMessage(Environment, msgid, msg, InputRoot.MQMD.ReplyToQueue);
...
CREATE PROCEDURE storeMessage
(
IN Environment REFERENCE,
IN tid CHAR,
IN payload BLOB,
IN replyToQ CHAR
)
BEGIN
DECLARE databaseCommand CHAR
'
INSERT INTO MYSCHEMA.MSG_STORE (TXN_ID, CREATED_TS, PAYLOAD, REPLYTO_Q)
VALUES (?, ?, ?, ?)
';
-- Execute the command to store the message RFH2
CALL PASSTHRU (databaseCommand, tid, CURRENT_TIMESTAMP, payload, replyToQ);
END; |
The restore code:
Code: |
...
DECLARE msgid CHAR SUBSTRING(CAST(InputRoot.MQMD.MsgId AS CHAR) FROM 3 FOR 48);
-- Retrieve the original message from the database
CALL retrieveMessage(Environment, msgid);
IF FIELDNAME(Environment.temp.retrieveMessage.results) is null THEN
// throw exception
);
END IF;
-- parse into the Environment tree. This results in a complete tree.
CREATE LASTCHILD of Environment.MSG_STORE
PARSE (Environment.temp.retrieveMessage.results[1].PAYLOAD,
InputRoot.MQMD.Encoding,
InputRoot.MQMD.CodedCharSetId);
-- Rebuild the message
SET OutputRoot.Properties = InputRoot.Properties;
CREATE LASTCHILD OF OutputRoot DOMAIN 'MQMD' NAME 'MQMD';
SET OutputRoot.MQMD.*[] = Environment.MSG_STORE.Root.MQMD.*[];
CREATE LASTCHILD OF OutputRoot DOMAIN 'MQRFH2' NAME 'MQRFH2';
SET OutputRoot.MQRFH2.*[] = Environment.MSG_STORE.Root.MQRFH2.*[];
-- Copy out the environment variables
SET Environment.MyContext.*[] = OutputRoot.MQRFH2.Environment.MyContext.*[];
IF FIELDNAME(InputBody) in ('MRM', 'XML', 'BLOB', 'XMLNS', 'XMLNSC') THEN
SET OutputRoot.BLOB = Environment.MSG_STORE.Root.BLOB;
END IF;
-- Clean up the RFH2
DELETE FIELD OutputRoot.MQRFH2.Environment;
DELETE FIELD OutputRoot.MQRFH2.Properties;
... |
Cheers,
Chris |
|
Back to top |
|
 |
dbjohnsson |
Posted: Thu Oct 30, 2008 3:36 pm Post subject: |
|
|
Newbie
Joined: 19 Apr 2007 Posts: 8
|
Thanks for your response chrisc.
I am still getting the exception so I thought I'll expand on what is happening.
I have a catch path message flow which takes in a JMS message with an ExceptionList with the thrown error and has a JMSMQTransform Node > Compute Node > MQOutput Node.
When the message enters the Compute Node there is no MQMD.CorrelId assigned but when the message returns from the Compute Node module WMB automatically creates a MQMD.CorrelId element with an empty string assigned. When the returned message then enters the MQOutput Node I get a MQMD parser exception.
Message Variables output before JMSMQTransform Node
Message
Properties
MessageSet = N8D3OC4002001
MessageType = PolicyRetrievalRequest
MessageFormat = XML1
Encoding = 0
CodedCharSetId = 1208
Transactional = false
Persistence = false
CreationTime =
ExpirationTime =
Priority =
ReplyIdentifier =
ReplyProtocol = JMS
Topic =
ContentType =
JMSTransport
Transport_Folders
Message_MetaData
PayloadType
Text
MessagePersistence
Non_Persistent
Header_Values
JMSDestination
queue:///ESBPXY.ESBSRV.POLICYRETRIEVAL.RQ
JMSDeliveryMode
dt = i4
1
JMSExpiration
dt = r8
0.0
JMSPriority
dt = i4
4
JMSTimestamp
dt = r8
1.225409085797E12
JMSMessageID
ID:414d5120514d44445644584a2020202022320a492000bb02
JMSCorrelationID
JMSReplyTo
JMSType
JMSRedelivered
dt = boolean
0
Application_Properties
JMS_Provider_Properties
JMS_IBM_PutDate
20081030
JMS_IBM_Format
MQSTR
JMS_IBM_PutApplType
dt = i4
28
JMS_IBM_MsgType
dt = i4
8
JMS_IBM_PutTime
23244579
Standard_Properties
JMSXAppID
WebSphere MQ Client for Java
JMSXUserID
ddvdxj
JMSXDeliveryCount
dt = i4
1
MRM
PolicyKey
Company = 1
Branch = 12
Number = 1234567
Product = 123
EffectiveDate = 1967-08-13
RequiredSegmentFlags
PolicyHeader = true
Account = true
Client = true
TaxDetails = true
RenewalDetails = true
LocalEnvironment
Environment
ExceptionList
RecoverableException
Message after the JMSMQTransform Node
Message
Properties
MessageSet = N8D3OC4002001
MessageType = PolicyRetrievalRequest
MessageFormat = XML1
Encoding = 0
CodedCharSetId = 1208
Transactional = false
Persistence = false
CreationTime =
ExpirationTime =
Priority =
ReplyIdentifier =
ReplyProtocol = JMS
Topic =
ContentType =
MQMD
Transactional = true
Format = MQHRF2
Version = 2
Priority = 4
Persistence = 0
PutApplName = ComIbmJMSMQTransformNode
PutApplType = 28
MsgType = 8
Report = 0
UserIdentifier =
Encoding = 546
CodedCharSetId = 1208
MQRFH2
MRM
LocalEnvironment
Environment
ExceptionList
The Compute Module Code
-- Populate Error Headers
CREATE COMPUTE MODULE PopulateErrorHeaders
CREATE FUNCTION Main() RETURNS BOOLEAN
BEGIN
-- CALL CopyMessageHeaders();
-- CALL CopyEntireMessage();
SET OutputRoot.Properties = InputRoot.Properties;
CREATE LASTCHILD OF OutputRoot DOMAIN 'MQMD' NAME 'MQMD';
SET OutputRoot.MQMD = InputRoot.MQMD;
DECLARE envRef REFERENCE TO Environment;
/********************************************************
Set MQDLH header information
*********************************************************/
SET OutputRoot.MQMD.Format = MQFMT_DEAD_LETTER_HEADER;
SET OutputRoot.MQDLH.StrucId = MQDLH_STRUC_ID;
SET OutputRoot.MQDLH.Version = MQDLH_VERSION_1;
SET OutputRoot.MQDLH.Reason = 0;
SET OutputRoot.MQDLH.DestQName = InputRoot.MQMD.SourceQueue;
SET OutputRoot.MQDLH.DestQMgrName = InputRoot.MQMD.ReplyToQMgr;
SET OutputRoot.MQDLH.Encoding = InputRoot.MQMD.Encoding;
SET OutputRoot.MQDLH.CodedCharSetId = InputRoot.MQMD.CodedCharSetId;
SET OutputRoot.MQDLH.Format = 'MQRFH2 ';
SET OutputRoot.MQDLH.PutApplType = InputRoot.MQMD.PutApplType;
SET OutputRoot.MQDLH.PutApplName = InputRoot.MQMD.PutApplName;
SET OutputRoot.MQDLH.PutDate = InputRoot.MQMD.PutDate;
SET OutputRoot.MQDLH.PutTime = InputRoot.MQMD.PutTime;
SET OutputRoot.MQMD.ApplIdentityData = 'SET APPLIDENTITYDATA';
/*************************************************************************************
Preserve the content of RFH2 header if exists in the incoming message
otherwise, we bring across the MQMD.format to newly created MQRFH2.format
***************************************************************************************/
IF InputRoot.MQRFH2 IS NOT NULL THEN
SET OutputRoot.MQRFH2 = InputRoot.MQRFH2;
ELSE
SET OutputRoot.MQRFH2.(MQRFH2.Field)Format = InputRoot.MQMD.Format;
END IF;
/* Populate MQRFH2 for additional information */
SET OutputRoot.MQRFH2.ESBEvent = envRef.ESBEvent;
DECLARE cursor REFERENCE TO InputBody;
IF LASTMOVE(cursor) = TRUE THEN
EVAL('SET ' || 'OutputRoot.' || FIELDNAME(InputBody) || ' = InputBody;');
END IF;
RETURN TRUE;
END;
CREATE PROCEDURE CopyMessageHeaders() BEGIN
DECLARE I INTEGER 1;
DECLARE J INTEGER;
SET J = CARDINALITY(InputRoot.*[]);
WHILE I < J DO
SET OutputRoot.*[I] = InputRoot.*[I];
SET I = I + 1;
END WHILE;
END;
CREATE PROCEDURE CopyEntireMessage() BEGIN
SET OutputRoot = InputRoot;
END;
END MODULE;
Output Root at the end of the Compute Node Code.
OutputRoot
Properties
MessageSet = N8D3OC4002001
MessageType = PolicyRetrievalRequest
MessageFormat = XML1
Encoding = 0
CodedCharSetId = 1208
Transactional = false
Persistence = false
CreationTime
ExpirationTime
Priority
ReplyIdentifier
ReplyProtocol = JMS
Topic
ContentType
MQMD
Transactional = true
Format = MQHRF2
Version = 2
Priority = 4
Persistence = 0
PutApplName = ComIbmJMSMQTransformNode
PutApplType = 28
MsgType = 8
Report = 0
UserIdentifier
Encoding = 546
CodedCharSetId = 1208
MQRFH2
CodedCharSetId = 1208
Version = 2
Encoding = 546
jms
Dst
queue:///ESBPXY.ESBSRV.POLICYRETRIEVAL.RQ
Dlv
1
Exp
0E+0
Pri
4
Tms
1.225409085797E+12
Cid
Rto
usr
mcd
Msd
mrm
Set
N8D3OC4002001
Type
PolicyRetrievalRequest
Fmt
XML1
Format
ESBEvent
MRM
OutputRoot after returning from the compute node (Notice the MQMD.correlId field has been created automatically by WMB)
MQMD
Transactional = false
Format = MQHRF2
Version = 2
Priority = 4
Persistence = 0
PutApplName = ComIbmJMSMQTransformNode
PutApplType = 28
MsgType = 8
Report = 0
UserIdentifier =
Encoding = 546
CodedCharSetId = 1208
CorrelId =
This is the exception I get when trying to output to MQOutput
ParserException
File = F:\\build\\S600_P\\src\\DataFlowEngine\\ImbMqmdParser.cpp
Line = 1073
Function = ImbMqmdParser::writeMqmd
Type = ComIbmComputeNode
Name = TestESBJMSInput#FCMComposite_1_1.ESBJMSInput#FCMComposite_1_4.ESBJMSCatch#FCMComposite_1_1
Label = TestESBJMSInput.ESBJMSInput.Call ESBJMSCatch.Populate Headers
Catalog = BIPv600
Severity = 2
Number = 5912
Text = Exception whilst writing field named
Insert
Type = 5
Text = MQMD
Insert
Type = 5
Text = CorrelId
Insert
Type = 5
Text =
RecoverableException
File = F:\\build\\S600_P\\src\\CommonServices\\ImbValue.cpp
Line = 936
Function = ImbValue::typeError
Type =
Name =
Label =
Catalog = BIPv600
Severity = 3
Number = 2328
Text = Wrong type exception
Insert
Type = 5
Text = CHARACTER
Insert
Type = 5
Text = BLOB
I'm hoping someone knows how to fix this.
Thanks |
|
Back to top |
|
 |
dbjohnsson |
Posted: Thu Oct 30, 2008 4:57 pm Post subject: |
|
|
Newbie
Joined: 19 Apr 2007 Posts: 8
|
I've just replaced the compute module with the following code for testing purposes and I am not getting the issue....
CREATE COMPUTE MODULE ESBLogFeeder_Compute
CREATE FUNCTION Main() RETURNS BOOLEAN
BEGIN
-- CALL CopyMessageHeaders();
CALL CopyEntireMessage();
RETURN TRUE;
END;
CREATE PROCEDURE CopyMessageHeaders() BEGIN
DECLARE I INTEGER 1;
DECLARE J INTEGER;
SET J = CARDINALITY(InputRoot.*[]);
WHILE I < J DO
SET OutputRoot.*[I] = InputRoot.*[I];
SET I = I + 1;
END WHILE;
END;
CREATE PROCEDURE CopyEntireMessage() BEGIN
SET OutputRoot = InputRoot;
END;
END MODULE;
That means that the problem has to be in my compute module code somewhere. |
|
Back to top |
|
 |
chrisc |
Posted: Thu Oct 30, 2008 5:27 pm Post subject: |
|
|
Voyager
Joined: 19 Mar 2006 Posts: 77
|
Sorry, I haven't used Broker for handling JMS messages before, so I'm not sure whether I can help much or not.
Also, the dump of your OutputRoot is quite difficult to read, given there is no indentation or anything. Where you have listed things like MQRFH2, Environment, MRM etc, with no values under them, does this mean they are present but empty, or does it mean they are not defined at all?
Are you sure your message payload is carrying over after your JMSMQTransform node? It looks like the entries listed under MRM are not there on output.
Your code is also testing for InputBody, but you need to remember that InputBody is just a reference to InputRoot.*[<], so you will ALWAYS have a successful LASTMOVE() check. It just may not be pointing to an actual payload! If you have no MRM then it may be pointing to the RFH2 or MQMD or whatever the last header in the message was. If this was the case, then what your evaluate statements are doing is re-copying all the fields from the last header over the top of the values already there.
Anyone else have any ideas? |
|
Back to top |
|
 |
|
|
 |
|
Page 1 of 1 |
|
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
|
|
|
|