Mirth Community

Mirth Community (http://www.mirthcorp.com/community/forums/index.php)
-   Support (http://www.mirthcorp.com/community/forums/forumdisplay.php?f=6)
-   -   Mirth Tools: User defined functions (http://www.mirthcorp.com/community/forums/showthread.php?t=6902)

upstart33 04-17-2012 10:32 AM

Mirth Tools: User defined functions

Out of a desire to learn, partial boredom, and a double-dog dare, I decided to create a thread topic to list some things that I find useful when dealing with Mirth, creating Channels, or fine-tuning the database.

First, I'd figure I would start out with some functions that some may find useful when developing channels.

Feel free to use them, tweak them, or add more to this thread of others to gaze upon. I hope to start other threads with other tools/scripts/code examples to assist in making our daily Mirth Connect experience that more enjoyable and less migraine inducing.

These functions can be defined and called from within a single Channel itself, or placed into the Code Template section for use throughout all of your Channels.

1. Determine a Channel's status
Purpose: To determine the current state of a channel.

Sometimes, you need to know the status of a certain channel, from within another channel. To accomplish this, you can use the following to see if the channel is :
-NA (Non-available)


function GetChannelState(channel_id) {

    var channel_status = "NA";

    var channel_count = parseInt(Packages.com.webreach.mirth.server.controllers.ChannelStatusController.getInstance().getChannelStatusList().size());

    for(var i=0;i<channel_count;i++) {
        if (channel_id == Packages.com.webreach.mirth.server.controllers.ChannelStatusController.getInstance().getChannelStatusList().get(i).getChannelId()) {
            channel_status = Packages.com.webreach.mirth.server.controllers.ChannelStatusController.getInstance().getChannelStatusList().get(i).getState();

    return channel_status;


If you do not know your channel_id, you can view it next to the channel_name on the 'Channels' section of your Mirth Connect Administrator.

upstart33 04-17-2012 10:39 AM

2. Quick SELECT/UPDATE/INSERT functions
Purpose: If most of your channels are connecting to the same database, you can use these functions to cut down some lines of code and for re-usability

Let's say that all of your channels are connecting to the same MySQL database. You could create a SELECT function as such:


function CDRSelect(sql) {

    var dbConn = DatabaseConnectionFactory.createDatabaseConnection("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/cdrexample","USER","PASSWORD");
    var results = dbConn.executeCachedQuery(sql);


    return results;

Now, in your Source or in a javascript transformer, you can execute a SELECT query by calling the following:


var results= CDRSelect("SELECT * FROM results");
....and for an UPDATE query, it would look like the following:


function CDRUpdate(sql) {

    var dbConn = DatabaseConnectionFactory.createDatabaseConnection("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/cdrexample","USER","PASSWORD");
    var results = dbConn.executeUpdate(sql);

    return results;

...which can be referenced by :


var results= CDRUpdate("UPDATE results set name = 'test'");

upstart33 04-17-2012 10:43 AM

3. Misc. Trim functions
Purpose: Sometimes, you need to do some trimming of strings. If you do not feeling like memorizing Regex, you can use something along the lines of the following.


function trim(in_str) {
    return new String(in_str).replace(/^\s+|\s+$/g,"");


function ltrim(in_str) {
    return new String(in_str).replace(/^\s+/,"");


function rtrim(in_str) {
    return new String(in_str).replace(/\s+$/,"");

Now, the function can be called within a transformer or mapper step:

var fname= trim(msg['patient_first'].toString());

upstart33 04-17-2012 11:07 AM

4. Word-Wrap
Purpose: If for some reason, you need to perform some Work Wrapping, then this function emulates PHP's 'wordwrap'.

-The string to be wrapped.
-The column width (a number, default: 75)
-The character(s) to be inserted at every break. (default: \n)
-The cut: a Boolean value (false by default).


function wordwrap( str, width, brk, cut ) {
  brk = (brk ? brk :\n);
  width = (width ? width : 75);
  cut = (cut ? cut : false);
    if (!str) { return str; }
    var regex = '.{1,' +width+ '}(\\s|$)' + (cut ? '|.{' +width+ '}|.+$' : '|\\S+?(\\s|$)');
    return str.match( RegExp(regex, 'g') ).join( brk );

The function can be called by:

wordwrap('The quick brown fox jumped over the lazy dog.', 20, '<br/>\n');
The quick brown fox <br/>
jumped over the lazy <br/>

upstart33 04-17-2012 11:20 AM

5: Local Timzones
Purpose: Sometimes, your not running Mirth locally and you need the correct timezone.


function getCurrentLocalTimestamp() {
  var formatter = new Packages.java.text.SimpleDateFormat("yyyyMMddhhmmss");
  // your local TZ
  return formatter.format(new Packages.java.util.Date());

The function can be used to get the local server date/time by the following:

tmp['MSH']['MSH.7']['MSH.7.1'] = getCurrentLocalTimestamp();

narupley 04-17-2012 12:02 PM

1 Attachment(s)

UPDATE: I've created a public GitHub repository to track these example channels, code templates, scripts, or whatever else!


To start with I only added the ones I wrote, because I didn't want to presume and add code from others without their explicit permission. Pull requests welcome!
Haha, I'll play along:


Deserializes an E4X XML node into HL7 v2.x. This allows you to pass any E4X node of a message and convert it into HL7 v2.x correctly. Here's the code (I've also attached it as a code template):


function xmlToHL7(node,fieldSeparator,componentSeparator,repetitionMarker,subcomponentSeparator) {
        // Data validation
        if (!node) return '';
        // This shouldn't really ever happen with E4X anyway, but just in case.
        String.prototype.replaceAmp = function() {return this.replace(/&amp;/g,'&');};
        // If we're just dealing with a simple node, then just return its contents.
        if (node.hasSimpleContent()) return node.toString().replaceAmp();
        // Used for StringUtils
        // Defaults to standard HL7 encoding characters
        var fs = fieldSeparator || '|';
        var cs = componentSeparator || '^';
        var rm = repetitionMarker || '~';
        var ss = subcomponentSeparator || '&';
        var cr = '\x0D';

        // What will actually be returned
        var output = '';
        // Get the XML name of the node (in the case of an XMLList of repeating fields, the first one will be returned, since they all have the same name anyway)
        var qname = node[0].name().toString();
        // Use the HL7 dot notation to find what level we're at
        var level = StringUtils.countMatches(qname,'.');

        // If the name is HL7Message, we're at the root node
        if (qname == 'HL7Message')
                // Recursively append serialization for each segment
                for each (segment in node.children())
                        output += xmlToHL7(segment,fs,cs,rm,ss);

        // If we're at the segment level
        else if (level == 0) {
                // If the node is an XMLList of multiple segments
                if (node.length() > 1) {
                        // Recursively append serialization for each segment
                        for each (segment in node)
                                output += xmlToHL7(segment,fs,cs,rm,ss);
                else {
                        // Add the segment name to the output
                        output += qname;
                        // Initialize name placeholder
                        var prevName = '';
                        // Iterate through each field in the segment
                        for each (field in node.children()) {
                                // Get the QName of the field
                                var fieldName = field.name().toString();
                                // If we're dealing with the special cases of MSH.1/2, then just add the field contents
                                if (fieldName in {'MSH.1':1,'MSH.2':1})
                                        output += field.toString().replaceAmp();
                                // Otherwise add the recursive serialization of the field
                                        // If we're on a field repetition, then prepend a repetition marker, otherwise prepend a field separator
                                        output += (prevName==fieldName?rm:fs) + xmlToHL7(field,fs,cs,rm,ss);
                                // Update the field name placeholder
                                prevName = fieldName;
                        // Add a carriage return to the end of the segment
                        output += cr;

        // If we're at the field level
        else if (level == 1) {
                // If the node is an XMLList of multiple fields
                if (node.length() > 1) {
                        // Recursively append serialization for each field
                        for each (field in node)
                                output += xmlToHL7(field,fs,cs,rm,ss) + rm;
                        // Remove the final repetition marker
                        output = StringUtils.chomp(output,rm);
                else {
                        // Recursively append serialization for each component
                        for each (component in node.children())
                                // Append a component separator to the end
                                output += xmlToHL7(component,fs,cs,rm,ss) + cs;
                        // Remove the last component separator
                        output = StringUtils.chomp(output,cs);

        // If we're at the component level
        else if (level == 2) {
                // Recursively append serialization for each subcomponent
                for each (subcomponent in node.children())
                        // Append a subcomponent separator to the end
                        output += xmlToHL7(subcomponent,fs,cs,rm,ss) + ss;
                // Remove the last subcomponent separator
                output = StringUtils.chomp(output,ss);

        // If we're at the subcomponent level
                // Just add the contents of the node
                output = node.toString().replaceAmp();

        // Return the final output
        return output;


Deserialize the entire message:

Deserialize just the PID segment:

Deserialize just the PID.3 segment (even if there are repetitions):


glenn71 04-17-2012 02:26 PM

Function to Stop a channel if it reaches a particular error count. Also sends an alert message via another channel (this sends a sms via our monitoring system).


function stopOnErrorCount(cid, errorCount) {
        var channelStatisticsController = Packages.com.mirth.connect.server.controllers.ChannelStatisticsController.getInstance();
        var channelStatusController = Packages.com.mirth.connect.server.controllers.ChannelStatusController.getInstance();
        var stats = channelStatisticsController.getStatistics(cid);
        // var numOfQueued = stats.queued;
        var numOfErrors = stats.error;

        if(numOfErrors > errorCount )
                //Stop Me
                //Alert msg sent to _SVHALERT channel
                var channelController = Packages.com.mirth.connect.server.controllers.ChannelController.getInstance();
                var channelName = channelController.getDeployedChannelById(cid).getName();
                var alertmsg = 'mirth01 mirth_channel_status codeTemplate_stopOnErrorCount 0 ' +
                                          'channel ' + channelName + ' stopped';
                router.routeMessage('_SVHALERT', alertmsg);

To use this in the Postprocessor:

// will stop the current channel when errorcount greater than 10.
stopOnErrorCount(channelId, 10);

Bostad 04-18-2012 06:35 AM

Converting HL7 DTG to English Date
I'm swamped so can't add much but here's something:


//presumes YYYYYMMDDHHSS  -although I don't get the time with this one

function DateConvert(strString) {

var months = new Array ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');

var year = strString.substring(0,4);
var mm = strString.substring(5,6);
var day = strString.substring(7,8);

return day + ', ' + months[mm] + ', ' + year;


This one does the time as well


function DTGConvert(strString) {

if (strString.length < 9) {    //user requirement

strString = strString + '0000'


var months = new Array ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');

var year = strString.substring(0,4);
var mm = parseInt(strString.substring(4,6),10);
var day = strString.substring(6,8);
var hh = strString.substring(8,10);
var min = strString.substring(10,12);

return day + ', ' + months[(mm-1)] + ', ' + year + ' ' + hh + ':' + min;


jacobb 04-18-2012 10:36 AM

Thanks for all of the contributions! These seem really useful and they should probably be posted to the wiki so they don't get lost in the forums.

narupley 04-19-2012 04:47 AM

1 Attachment(s)

UPDATE: I've created a public GitHub repository to track these example channels, code templates, scripts, or whatever else!


To start with I only added the ones I wrote, because I didn't want to presume and add code from others without their explicit permission. Pull requests welcome!
Fix the node order of an HL7 v2.x E4X XML object

When you add fields/components/subcomponents out of order in a message, it isn't serialized correctly by Mirth. For example, if you have the following code:


var nte = <NTE/>;

nte['NTE.1']['NTE.1.1'] = '1';
nte['NTE.3']['NTE.3.1'] = 'comment';
nte['NTE.2']['NTE.2.1'] = 'TX';


then your NTE segment will come out looking like:


Issue 625 is scheduled to be fixed in 3.0, but in the meantime, here's another way to fix it:

fixHL7NodeOrder takes in a single HL7 v2.x node (it can be the root HL7Message, or a single segment/field/component/etc.), and returns the same node, with all children sorted in ascending order as per the HL7 dot notation. So the following node:



would be changed to:



Here's the code, or you can just import the attached code template. Cheers!


        Author: Nick Rupley
        Date Modified: 4/18/2012

        fixHL7NodeOrder: Returns a new E4X node where the order of all siblings and descendants have been fixed as per the Mirth HL7 dot notation convention.

                node: The node to be fixed.

function fixHL7NodeOrder(node) {
        // Create output node
        var newNode = new XML();
        // In case the node is an XMLList of multiple siblings, loop through each sibling
        for each (sibling in node) {
                // Create new sibling node
                var newSibling = new XML('<'+sibling.name().toString()+'/>');
                // Iterate through each child node
                for each (child in sibling.children())
                        // If the child has its own children, then recursively fix the node order of the child
                        if (child.hasComplexContent())
                        // If the child doesn't have its own children, then just add the child to the new sibling node
                // After recursively fixing all of the child nodes, now we'll fix the current node
                newNode += sortHL7Node(newSibling);
        // Return the fixed node
        return newNode;

// Helper function for fixHL7NodeOrder
function sortHL7Node(node) {
        // If the node has no children, then there's nothing to sort
        if (node.hasSimpleContent())
                return node;
        // Create new output node
        var newNode = new XML('<'+node.name().toString()+'/>');
        // Iterate through each child in the node
        for each (child in node.children()) {
                // If the child has a QName, then we can sort on it
                if (child.name()) {
                        // Get the current "index" of the child. Id est, if the QName is PID.3.1, then the index is 1
                        curChildIndex = parseInt(child.name().toString().substring(child.name().toString().lastIndexOf('.')+1),10);
                        // Boolean placeholder
                        var inserted = false;
                        // Iterate through each child currently in the NEW node
                        for (var i = 0; i <= newNode.children().length()-1; i++) {
                                // Get the index of the child of the new node
                                loopChildIndex = parseInt(newNode.child(i).name().toString().substring(newNode.child(i).name().toString().lastIndexOf('.')+1),10);
                                // If the child we want to insert has a lower index then the current child of the new node, then we're going to insert the child
                                // right before the current newNode child
                                if (curChildIndex < loopChildIndex) {
                                        // Insert the child
                                        // Set our flag, indicating that an insertion was made
                                        inserted = true;
                                        // No need to continue iteration
                        // If no insertion was made, then the index of the child we want to insert is greater than or equal to all of the
                        // indices of the children that have already been inserted in newNode. So, we'll just append the child to the end.
                        if (!inserted)
        // Return the sorted HL7 node
        return newNode;

All times are GMT -8. The time now is 03:30 PM.

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