Mirth (NextGen) Connect Bits #8: Using Attachment Handler

Mirth (NextGen) Connect allows you to handle attachments from an HL7 message or by reading a file. Attachments can be viewed in the Dashboard in the “Attachments Tab”. The viewer supports four types: Text, Image, DICOM, and PDF.

Using the Attachment handler allows you to reduce the memory footprint in the channel. For example, a base64 string in the HL7 message is quite heavy when viewing in the dashboard, the Attachment handlers reduces this workload. Here’s a direct explanation from the NextGen Connect User Guide.

An Attachment Handler allows you to extract pieces of any incoming message and store them separately. As a message processes through a channel, multiple copies of it will be held in memory at once (for the raw / transformed/encoded versions of a message, etc.). Attachments are stored only once, so by using them you can greatly reduce your channels’ memory footprint. These are configured in the Channel Properties section of the Summary Tab within the Edit Channel View.

You can check the User Guide for the built-in functions, AttachmentUtil class, and the Attachment Object. In this blog, we’ll handle PDF files attached as a base64 encoded string on an HL7 message and by reading the file itself.

Case #1: Reading a PDF file and attaching it on an HL7 message as a Base64 encoded string.

Here we’ll use the connector type “File Reader” on our source and will process PDF files. The PDF is stored as an attachment and we’ll get the base64 encoded string that will be added in the HL7 V2 output message.

Step 1: Set data type

Attachment handler case 1 data type

Step 2: Enable “Store Attachments” option and configure other settings. Here we’ll set the MIME type to “application/pdf” since we’re expecting PDF files to be read in the file reader.

attachment handler case 1 settings

The attachment handler option here will store the content somewhere and will replace the data with a token or an attachment id.

Step 3: The file reader is set to read the content as binary.

Scroll down to see the option “File Type” and change it to Binary.

file reader file type option

Step 4: On my destination’s transformer, I set up an outbound template with some predefined values on my HL7 message. Here the JavaScript code will:

  • Get all attachment ids on the message
  • We’ll loop to the array list
  • Create a new OBX object for each instance of an attachment ID
  • Assign values on the OBX field
  • For OBX.5.1, we’ll add the base64 encoded string using the methods of the AttachmentUtil class.
attachment handler case 1 transformer

Here’s the code I use.

var attachmentIds = getAttachmentIds(); 

for(var i = 0; i < attachmentIds.size(); i++) {
	var newObx = <OBX/>;
		newObx['OBX.1']['OBX.1.1'] = i + 1;
		newObx['OBX.2']['OBX.2.1'] = 'ED';
		newObx['OBX.3']['OBX.3.1'] = 'PDF';
		
		var str = String(AttachmentUtil.getMessageAttachment(channelId, connectorMessage.getMessageId(), attachmentIds.get(i)).getContentString());
		newObx['OBX.5']['OBX.5.1'] = str.toString().replace(/\r\n|\r|\n/gm, '');

		tmp.appendChild(newObx);
}

return tmp;

In your destination you can then use ${message.encodedData} which would return the tmp updated in our transformer.

Here’s an example where you can see that the raw message from the source has been changed into an attachment token or id.

mirth connect attachment handler sample token

In our destination, you can see that the base64 encoded string is now on our OBX.5.1 field.

Case 2: Get the PDF base64 encoded string from an HL7 message and write into a folder

Here we’re expecting an HL7 message that has a base64 encoded string in one of the OBX.5.1. We will then write the file in our local folder, instead of using a File Writer protocol in our Destination, we’ll use JavaScript in the transformer to write the file using the FileUtil class.

Step 1: Set data type.

attachment handler case 2 data type

Step 2: Enable the “Store Attachments” option, then use the option “JavaScript”. The code below would basically replace the base64 encoded string into an attachment id.

attachment handler case 2 js code

Here’s the code I used:

// Modify the message variable below to create attachments

var hl7 = new XML(SerializerFactory.getSerializer('HL7V2').toXML(message));

for each(seg in hl7.OBX) {
	if(seg.name() == 'OBX') {
		if(seg['OBX.2']['OBX.2.1'].toString() == 'ED' && seg['OBX.3']['OBX.3.1'].toString() == 'PDF') {
			var attachmentObj = addAttachment(seg['OBX.5']['OBX.5.1'].toString(), 'application/pdf');
			seg['OBX.5']['OBX.5.1'] = attachmentObj.id;
		}
	}
}

return SerializerFactory.getSerializer('HL7V2').fromXML(hl7);

What the code does:

  1. Convert the HL7 pipe delimited message into an XML object.
  2. Loop through the OBXs and find the fields which have a base64 encoded string.
  3. Using the function addAttachment, this will store the base64 string as an attachment and replace the value in the field with a token or an attachment id.
  4. Convert the XML object back to an HL7 v2 format and return it.

Step 3: In my destination’s transformer, I’ll loop into the OBXs, find the field with the attachment id, using then the methods of AttachmentUtil class to get the content of the attachment. FileUtil.write will then write the file into a folder.

mirth connect attachment handler javascript to write file

Here’s the code used:

for each(obx in msg.OBX) {		
	var filepath = 'D:/Attachments/output/' + obx['OBX.5']['OBX.5.1'].toString() + '.pdf';
	if(obx['OBX.2']['OBX.2.1'].toString() == 'ED' && obx['OBX.3']['OBX.3.1'].toString() == 'PDF') {
		var res = FileUtil.write(filepath, true, AttachmentUtil.getMessageAttachment(channelId, connectorMessage.getMessageId(), obx['OBX.5']['OBX.5.1'].toString()).getContent());
	
	}
}

In my case, this code would cover instances where the HL7 message has multiple base64 encoded string. You could, of course, pass the attachment content into your destination’s template if you’re only expecting one base64 string in your HL7 message.

Here’s a sample HL7 message with the base64 encoded string, which is the output from case #1.

MSH|^~\&|MIRTH|MIRTH|LAB|LAB|20201031000217||ORU^R01|8b5c4a3f-830e-4942-8c18-5375708b566d|T|2.3|||AL|AL|
PID|1||||XXXX^XXXXX||19900101|F||||||||||||||||||||||
ORC|1|ID1234|ID1234
OBR|1|ID1234|ID1234|COVID19^COVID-19|||20201021123200|||||||||||||||20201031000217|||F
OBX|1|ST|COVID19^COVID-19||||||||F|||20201021123200|
OBX|1|ED|PDF||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L1BhZ2VzIDQgMCBSPj4KZW5kb2JqCjggMCBvYmoKPDwvTW9kRGF0ZShEOjIwMjAxMTE3MDQ1MDM0KzA4JzAwJykvQ3JlYXRpb25EYXRlKEQ6MjAyMDExMTcwNDUwMzQrMDgnMDAnKS9Qcm9kdWNlcihpVGV4dCAyLjEuNyBieSAxVDNYVCk+PgplbmRvYmoKeHJlZgowIDkKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMjMxIDAwMDAwIG4gCjAwMDAwMDQwNzAgMDAwMDAgbiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDA0NDE0IDAwMDAwIG4gCjAwMDAwMDAzODggMDAwMDAgbiAKMDAwMDAwMzg3OSAwMDAwMCBuIAowMDAwMDA0NDc3IDAwMDAwIG4gCjAwMDAwMDQ1MjIgMDAwMDAgbiAKdHJhaWxlcgo8PC9JbmZvIDggMCBSL0lEIFs8ZTdjYjk0YjI2YWI4YzkxYjRkODRmYTE0M2FjYjQ2Nzc+PDFkY2RhODljOGU1OTk1MmM2ODE2NjJiZTYxYWVkNjUxPl0vUm9vdCA3IDAgUi9TaXplIDk+PgpzdGFydHhyZWYKNDY0NAolJUVPRgo=

I guess that’s it, Mirth allows you to handle files quite extensively. Using JavaScript functions, classes and methods, there’s lots of way to solve file based problems. Heck, you can even use the engine to run a NoSQL or non-relational database like JSON file types.

For more Mirth Connect related blog posts, check out the Mirth (NextGen) Bits tag or Health IT page.

Add a Comment

Your email address will not be published. Required fields are marked *