Mirth Community

Mirth Community (http://www.mirthcorp.com/community/forums/index.php)
-   Support (http://www.mirthcorp.com/community/forums/forumdisplay.php?f=6)
-   -   Message validation (http://www.mirthcorp.com/community/forums/showthread.php?t=6626)

Linh 02-20-2012 09:02 PM

Message validation
Hi All,

I am a bit stuck on how the message validation and filtering work. Reading previous posts did not solve my problem. Your help would be greatly appreciated.

My requirements and set up are like this:
- I have an LLP Listener accepting incoming HL7 messages. When messages are not valid, I will need to send a Error ACK back to the sender. In addition, I will need to write the error messages to a directory. With the LLP Listener, I cannot configure it to write error messages to a directory.
- I can write some Filtering rule in the Destination Filter, however this only marked the messages as Filtered; the sender does not get any Error ACK, and the sender sees a normal ACK as if the message was sent successfully.

Is there any way that I can fulfill the requirements: "on invalid messages, send Error ACK and write the invalid messages to a directory"?

Thank you very much for your help and guidance.


narupley 02-20-2012 09:07 PM

In your Source filter, put whatever qualifications you want in one JavaScript step. That way you can call whatever custom code you want for writing the file to an error directory, in the case that the message should be filtered. Then on your LLP Listener settings, set the "rejected" code and message as appropriate.

Linh 02-20-2012 10:22 PM

Thanks narupley.

I now see the difference between Source Filter (will send message rejected back to sender on filtered messages) and Destination Filter (silent on filtered messages).

I modified my LLP Listener as follow:
Send ACK: Yes
Rejected ACK Code: AR

In my Source filter, I have a JavaScript with "return false;" for testing purposes. Upon receiving a message, the message is filtered and I got a correct ACK:

<0x0b>MSH|^~\&|Hospital|8003621231167888|Medical|8 003614166667350|20120221165514||ACK|20120221165514 |P|2.3.1<0x0d> MSA|AR|499e58ee-2934-4d0a-8b37-8b94a0a0bb6e|Message Rejected.<0x0d> <0x1c><0x0d>

However, my LLP Listener is just a gate keeper receiving messages and forward to the next channel to do further processing. I have tried to set up a response variable with this method: ResponseFactory.getFilteredResponse('AR') and assign it to a response map variable 'ResponseMsg'. I then changed my LLP Listener to Send ACK: Respond from "ResponseMsg".

When I send a message, I got the ACK as follow:


And upon receiving that ACK, my sender complains: "Warning: Last segment have no segment termination char 0x0d ! Acknowledge message received. Invalid acknowledge message structure. Segment MSA is missing."

Is there a way to fully generate the ACK message with MSA segment? Or I have to build the response message manually?

Thanks for your help.


narupley 02-21-2012 04:07 AM

Unfortunately, in that case you'll have to build the ACK yourself. Fortunately, it's a relatively easy thing to do:


function setACK(sourceMsg,responseCode,responseMsg,responseStatus) {
        // responseStatus is an optional parameter
        if (!responseStatus)
                responseStatus = {'AA':Response.Status.SUCCESS,'AR':Response.Status.FILTERED,'AE':Response.Status.FAILURE}[responseCode] || Response.Status.UNKNOWN;
        var ack = <HL7Message/>;
        ack.MSH['MSH.1'] = sourceMsg.MSH['MSH.1'].toString();
        ack.MSH['MSH.2'] = sourceMsg.MSH['MSH.2'].toString();
        ack.MSH['MSH.3'] = sourceMsg.MSH['MSH.5'].copy();
        ack.MSH['MSH.4'] = sourceMsg.MSH['MSH.6'].copy();
        ack.MSH['MSH.5'] = sourceMsg.MSH['MSH.3'].copy();
        ack.MSH['MSH.6'] = sourceMsg.MSH['MSH.4'].copy();
        ack.MSH['MSH.7']['MSH.7.1'] = DateUtil.getCurrentDate('yyyyMMddHHmmss');
        ack.MSH['MSH.9']['MSH.9.1'] = sourceMsg.MSH['MSH.9']['MSH.9.1'].toString();
        ack.MSH['MSH.9']['MSH.9.2'] = sourceMsg.MSH['MSH.9']['MSH.9.2'].toString();
        ack.MSH['MSH.9']['MSH.9.3'] = 'ACK';
        ack.MSH['MSH.10'] = sourceMsg.MSH['MSH.10'].copy();
        ack.MSH['MSH.11'] = sourceMsg.MSH['MSH.11'].copy();
        ack.MSH['MSH.12'] = sourceMsg.MSH['MSH.12'].copy();
        ack.MSA['MSA.1']['MSA.1.1'] = responseCode;
        ack.MSA['MSA.2']['MSA.2.1'] = sourceMsg.MSH['MSH.10']['MSH.10.1'].toString();
        ack.MSA['MSA.3']['MSA.3.1'] = responseMsg;
        responseMap.put('ACK',new Response(responseStatus,SerializerFactory.getHL7Serializer().fromXML(ack)));

For example, if you want to send an AR NACK back for ADTs, you could do this:


if (msg['MSH']['MSH.9']['MSH.9.1'].toString() == 'ADT')
        setACK(msg,'AR',"We don't take kindly to the likes of you.");
        setACK(msg,'AA','Pull up a chair.');

Linh 02-21-2012 04:06 PM

Hi narupley,

That is an excellent answer. Thank you very much for showing me how to build up the ACK msg.
I got the pathway of what needs to be done now. Thanks again.


Linh 02-21-2012 05:34 PM

Hi narupley,

This is my setup. Hope it will helps other people and if you see any problem, please let me know. I really appreciate your and other people's feedback.

I put your ACK setAck() function in the Channels' Code Template to be able to reuse it. The function buildAckMsg will have this statement "return new Response(responseStatus,SerializerFactory.getHL7Se rializer().fromXML(ack));" at the end.

My set up has 1) HL7 Receiver Channel, which will forward to the next Channel for further processing.

1) HL7 Receiver Channel:
LLP Listener
Send ACK: Respond from "ResponseMsg" (this is a variable which will be set in Channel's postprocessor)

Connector type: Channel Writer, write to Channel "My Next Channel")
Wait for Channel Response: Yes

Transformer: javascript: (to save a reference to the message in postprocessor)
channelMap.put('rawMsg', messageObject.getRawData());
channelMap.put('xmlMsg', msg);

Postprocessor script:
// This script executes once after a message has been processed

var responseFromChannel = responseMap.get('My Next Channel').toString();

var xmlMsg = channelMap.get('xmlMsg');

if(responseFromChannel.indexOf('Message has been filtered') >= 0)
var ackMsg = buildAckMsg(xmlMsg, 'AR', "Message Rejected");
responseMap.put('ResponseMsg', ackMsg);
else if (responseFromChannel.indexOf('ERROR') >= 0 || responseFromChannel.indexOf('FAILURE') >= 0)
var ackMsg = buildAckMsg(xmlMsg, 'AE', "An Error Occurred Processing Message");
responseMap.put('ResponseMsg', ackMsg);
var ackMsg = buildAckMsg(xmlMsg, 'AA', "Message received and processed successfully");
responseMap.put('ResponseMsg', ackMsg);


2) My Next Channel:
Channel Reader

Has a Filter that has my filtering logic.

Thanks narupley, you have saved my day.


Linh 02-21-2012 07:08 PM

Now in my Dashboard, for the filtered messages, the "My Next Channel" show they are filtered, however the "HL7 Receiver Channel" showed them as "Sent". Is there a way in Postprocessor script to update the message status so that they are shown on the Dashboard as "Filtered"?

I have tried: messageObject.setStatus(Status.FILTERED) but was not successful.



narupley 02-21-2012 07:27 PM

This should work:


com.mirth.connect.server.controllers.DefaultMessageObjectController.create().updateMessageStatus(new java.lang.String(channelId),new java.lang.String($('messageId')),com.mirth.connect.model.MessageObject.Status.FILTERED);
com.mirth.connect.server.controllers.DefaultChannelStatisticsController.create().decrementSentCount(new java.lang.String(channelId));

You'll also have to set the messageId variable (at least at the channel map level) somewhere in your destination connector, otherwise it'll try to update your Source connector entry.

Linh 02-21-2012 07:49 PM

That works perfectly. Thanks narupley.

All times are GMT -8. The time now is 07:14 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Mirth Corporation