Announcement

Collapse
No announcement yet.

Mirth Tools: User defined functions

Collapse
This is a sticky topic.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Mirth Tools: User defined functions

    Hi,

    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 :
    -STARTED
    -STOPPED
    -PAUSED
    -NA (Non-available)

    Code:
    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.

  • #2
    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:

    Code:
    function CDRSelect(sql) {
    
        var dbConn = DatabaseConnectionFactory.createDatabaseConnection("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/cdrexample","USER","PASSWORD");
        
        var results = dbConn.executeCachedQuery(sql);
    
        dbConn.close();
    
        return results;
    }
    Now, in your Source or in a javascript transformer, you can execute a SELECT query by calling the following:

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

    Code:
    function CDRUpdate(sql) {
    
        var dbConn = DatabaseConnectionFactory.createDatabaseConnection("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/cdrexample","USER","PASSWORD");
        var results = dbConn.executeUpdate(sql);
        dbConn.close();
    
        return results;
    }
    ...which can be referenced by :

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

    Comment


    • #3
      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.

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

      Now, the function can be called within a transformer or mapper step:
      Code:
      var fname= trim(msg['patient_first'].toString());

      Comment


      • #4
        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).

        Code:
        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:
        Code:
        wordwrap('The quick brown fox jumped over the lazy dog.', 20, '<br/>\n');
        ---------
        The quick brown fox <br/>
        jumped over the lazy <br/>
        dog.

        Comment


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

          Code:
          function getCurrentLocalTimestamp() {
             var formatter = new Packages.java.text.SimpleDateFormat("yyyyMMddhhmmss"); 
             // your local TZ
             formatter.setTimeZone(Packages.java.util.TimeZone.getTimeZone("EST")); 
             return formatter.format(new Packages.java.util.Date()); 
          }
          The function can be used to get the local server date/time by the following:
          Code:
          tmp['MSH']['MSH.7']['MSH.7.1'] = getCurrentLocalTimestamp();

          Comment


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

            https://github.com/nextgenhealthcare/connect-examples

            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:

            xmlToHL7

            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):

            Code:
            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
            	importPackage(org.apache.commons.lang);
            	
            	// 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
            				else
            					// 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
            	else
            		// Just add the contents of the node
            		output = node.toString().replaceAmp();
            
            	// Return the final output
            	return output;
            }
            Examples

            Deserialize the entire message:
            Code:
            logger.info(xmlToHL7(msg));
            Deserialize just the PID segment:
            Code:
            logger.info(xmlToHL7(msg.PID));
            Deserialize just the PID.3 segment (even if there are repetitions):
            Code:
            logger.info(xmlToHL7(msg.PID['PID.3']));
            Attached Files
            Last edited by narupley; 06-08-2018, 10:34 AM.
            Step 1: JAVA CACHE...DID YOU CLEAR ...wait, ding dong the witch is dead?

            Nicholas Rupley
            Work: 949-237-6069
            Always include what Mirth Connect version you're working with. Also include (if applicable) the code you're using and full stacktraces for errors (use CODE tags). Posting your entire channel is helpful as well; make sure to scrub any PHI/passwords first.


            - How do I foo?
            - You just bar.

            Comment


            • #7
              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).

              Code:
              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
              		channelStatusController.stopChannel(cid);
              		//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:
              Code:
              // will stop the current channel when errorcount greater than 10.
              stopOnErrorCount(channelId, 10);
              return;

              Comment


              • #8
                Converting HL7 DTG to English Date

                I'm swamped so can't add much but here's something:

                Code:
                //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

                Code:
                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;
                
                
                }
                I can be reached through gmail and Google Talk using davidrothbauer at gmail dot com
                http://www.linkedin.com/pub/david-rothbauer/5/923/518
                codeismydrug.wordpress.com
                hl7coders.wordpress.com

                Test all my code suggestions prior to implementation

                Comment


                • #9
                  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.
                  Jacob Brauer
                  Director, Software Development
                  NextGen Healthcare

                  sigpic

                  Comment


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

                    https://github.com/nextgenhealthcare/connect-examples

                    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:

                    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';
                    
                    msg.appendChild(nte);
                    then your NTE segment will come out looking like:

                    Code:
                    NTE|1||comment|TX
                    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:

                    Code:
                    <NTE>
                    	<NTE.1>
                    		<NTE.1.1>1</NTE.1.1>
                    	</NTE.1>
                    	<NTE.3>
                    		<NTE.3.1>comment</NTE.3.1>
                    	</NTE.3>
                    	<NTE.2>
                    		<NTE.2.1>TX</NTE.2.1>
                    	</NTE.2>
                    </NTE>
                    would be changed to:

                    Code:
                    <NTE>
                    	<NTE.1>
                    		<NTE.1.1>1</NTE.1.1>
                    	</NTE.1>
                    	<NTE.2>
                    		<NTE.2.1>TX</NTE.2.1>
                    	</NTE.2>
                    	<NTE.3>
                    		<NTE.3.1>comment</NTE.3.1>
                    	</NTE.3>
                    </NTE>
                    Here's the code, or you can just import the attached code template. Cheers!

                    Code:
                    /*
                    	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.
                    
                    	Arguments
                    	---------
                    		Required
                    		--------
                    		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())
                    				newSibling.appendChild(fixHL7NodeOrder(child));
                    			// If the child doesn't have its own children, then just add the child to the new sibling node
                    			else
                    				newSibling.appendChild(child);
                    		// 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
                    					newNode.insertChildBefore(newNode.children()[i],child);
                    					// Set our flag, indicating that an insertion was made
                    					inserted = true;
                    					// No need to continue iteration
                    					break;
                    				}
                    			}
                    			// 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)
                    				newNode.appendChild(child);
                    		}
                    	}
                    	// Return the sorted HL7 node
                    	return newNode;
                    }
                    Attached Files
                    Last edited by narupley; 06-08-2018, 10:34 AM.
                    Step 1: JAVA CACHE...DID YOU CLEAR ...wait, ding dong the witch is dead?

                    Nicholas Rupley
                    Work: 949-237-6069
                    Always include what Mirth Connect version you're working with. Also include (if applicable) the code you're using and full stacktraces for errors (use CODE tags). Posting your entire channel is helpful as well; make sure to scrub any PHI/passwords first.


                    - How do I foo?
                    - You just bar.

                    Comment


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

                      https://github.com/nextgenhealthcare/connect-examples

                      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!
                      UPDATE 2-13-13: Made a change so that segName can be a regular expression

                      Okay, this one might be helpful to some people....

                      getSegmentsAfter: Returns an array of segments with the specified name that come after a given segment in the message.

                      Say you have multiple OBR groups in your message. Sometimes you want to do something with only the OBXs that come after that particular OBR, and not necessarily all of the OBXs in the entire message. The same goes for NTEs after an OBX, etc. Assuming that you're not using the strict HAPI parser (most of us don't), this might be fairly tricky to do.

                      The getSegmentsAfter function does it for you. Given the root node (root), the segment you want to start at (startSeg), and the name of the segments you want to get (segName), this function will return an array of those segments.

                      There are two other optional parameters:
                      • consecutiveInd: If this is true, then the segments to be collected are expected to come directly after the starting segment. If any segment is encountered that doesn't have a name of segName, collection is immediately stopped. If this is false, then collection is stopped when another segment of the same name as startSeg is encountered. For example, say you have the following message:
                        Code:
                        MSH...
                        PID...
                        OBR...
                        OBX...
                        OBX...
                        NTE...
                        OBX...
                        OBR...
                        OBX...
                        If startSeg is the first OBR, segName is "OBX", and consecutiveInd is true, then getSegmentsAfter will return the first two OBXs in the message, but not the third one. If consecutiveInd is false, then it will return the first three OBXs, but not the fourth one.

                      • stopSegNames: This is an array of segment names that you want to act as an "emergency brake" to stop collection. If one of these segments is encountered, then iteration is stopped. This is useful when, for example, you have a message like this:
                        Code:
                        MSH...
                        PID...
                        OBR...
                        OBX...
                        NTE...
                        OBX...
                        SPM...
                        OBX...
                        In HL7Land, the OBR segment contains two groups, the observation group (consisting of the first two OBXs) and the specimen group (consisting of the SPM and the third OBX). In this case you don't want to get consecutive OBXs because there may be NTEs/ZDSs in between, but on the other hand you don't want to include the OBX that is part of the specimen group. So if "SPM" is included in stopSegNames, then all will be good.


                      Examples
                      • Get all OBXs after the first OBR segment:
                        Code:
                        getSegmentsAfter(msg,msg.OBR[0],'OBX')
                      • Get all consecutive NTEs after the first OBX segment:
                        Code:
                        getSegmentsAfter(msg,msg.OBX[0],'NTE',true)
                      • Get all OBXs after the first OBR segment, but don't include any OBXs in the SPM or ZBP groups:
                        Code:
                        getSegmentsAfter(msg,msg.OBR[0],'OBX',false,['SPM','ZBP'])
                      • Add a new NTE segment to the first OBR group (at the order level rather than the observation level):
                        Code:
                        var newNTE = <NTE/>;
                        newNTE['NTE.3']['NTE.3.1'] = 'whatever';
                        var nteGroup = getSegmentsAfter(msg,msg.OBR[0],'NTE',true);
                        if (nteGroup.length > 0)
                             msg.children()[nteGroup[nteGroup.length-1].childIndex()] += newNTE;
                        else
                             msg.OBR[0] += newNTE;
                      • Reset all of the set IDs of the OBXs after every OBR in the message:
                        Code:
                        for each (obr in msg.OBR) {
                             var obxGroup = getSegmentsAfter(msg,obr,'OBX',false,['SPM','ZBP']);
                             for (var i = 0; i <= obxGroup.length-1; i++)
                                  msg.children()[obxGroup[i].childIndex()]['OBX.1']['OBX.1.1'] = (i+1);
                        }
                      • Get all Z-segments after each OBR segment:
                        Code:
                        for each (obr in msg.OBR) {
                        	for each (zseg in getSegmentsAfter(msg,obr,/Z[A-Z\d]{2}/)) {
                        		// Do something
                        	}
                        }


                      The code:

                      Code:
                      /*
                      	Author: Nick Rupley
                      	Date Modified: 2/13/2013
                      	getSegmentsAfter: Returns an array of segments with the specified name that come after a given segment in the message.
                      
                      	Arguments
                      	---------
                      		Required
                      		--------
                      			root:			The root HL7Message node of the message, or the parent of the segment node.
                      			startSeg:		The segment AFTER which to start collecting segments.
                      			segName:		The name (String or RegExp) of the segments you want to collect.
                      
                      		Optional
                      		--------
                      			consecutiveInd:	If true, indicates that the segments are expected to come directly after startSeg. 
                      					If false, segments are collected until another segment with the same name as startSeg is encountered.
                      					Defaults to false.
                      			stopSegNames:	An array of segment names that, when encountered, stop the collection of segments.
                      */
                      
                      function getSegmentsAfter(root, startSeg, segName, consecutiveInd, stopSegNames) {
                      	function test(str) {
                      		return segName instanceof RegExp ? segName.test(str) : segName === str;
                      	}
                      
                      	// The index to start collection is the next one up from the starting segment
                      	var index = startSeg.childIndex()+1;
                      	// The return array
                      	var out = [];
                      	// Boolean placeholder to stop iteration
                      	var done = false;
                      	// Object that will contain all of the stopSegNames strings, bound to a truthy value (1)
                      	var stopNames = {};
                      	// Indicates whether we have any stop segments
                      	var stopNamesInd = false;
                      	// If stopSegNames is defined
                      	if (stopSegNames !== undefined && stopSegNames !== null) {
                      		// Set our indicator to true
                      		stopNamesInd = true;
                      		// Add each string in the array to our object
                      		for each (name in stopSegNames)
                      			stopNames[name] = 1;
                      	}
                      
                      	// Iterate through each child in the root, starting at the segment after startSeg, and
                      	// ending at the final segment, or when the done flag is set to true.
                      	while (index < root.children().length() && !done) {
                      		// If a stop segment is encountered, stop iteration
                      		if (stopNamesInd && root.children()[index].name().toString() in stopNames)
                      			done = true;
                      		// If a segment with the same name as startSeg is encountered, stop iteration
                      		else if (root.children()[index].name().toString() == startSeg.name().toString() && !consecutiveInd)
                      			done = true;
                      		// If we're only collecting consecutive segments and we encounter a segment with a name other than segName, stop iteration
                      		else if (!test(root.children()[index].name().toString()) && consecutiveInd)
                      			done = true;
                      		// If all previous tests passed, and the current segment has a name of segName, then add it to our array
                      		else if (test(root.children()[index].name().toString()))
                      			out.push(root.children()[index]);
                      		// Increment our index counter
                      		index++;
                      	}
                      
                      	// Return the output array
                      	return out;
                      }
                      Attached Files
                      Last edited by narupley; 06-08-2018, 10:35 AM.
                      Step 1: JAVA CACHE...DID YOU CLEAR ...wait, ding dong the witch is dead?

                      Nicholas Rupley
                      Work: 949-237-6069
                      Always include what Mirth Connect version you're working with. Also include (if applicable) the code you're using and full stacktraces for errors (use CODE tags). Posting your entire channel is helpful as well; make sure to scrub any PHI/passwords first.


                      - How do I foo?
                      - You just bar.

                      Comment


                      • #12
                        NOTE: This code template is probably not necessary for 3.0 because we now have the ChannelUtil utility class, which has methods to deploy/undeploy/start/stop/etc. channels and connectors. However you can still use this to deploy channels on a different instance of Mirth Connect.

                        deployChannels: Deploys channels using an array of channel IDs and an optional client info object.

                        Rather self-explanatory; you just pass it an array or comma-separated string of channel IDs, and it will initiate a Client and deploy the specified channels. Client connection settings are hard-coded as defaults, but they can be overridden via the optional clientInfo argument.

                        The function returns an object containing a status String element, a message String element, and an overloaded toString method. The status will be "SUCCESS" if the client was able to successfully login, and at least one of the channel IDs refers to an enabled channel. Otherwise, the status is "FAILURE".

                        Here's the code (also attached as a code template):

                        Code:
                        /*
                        	Author: Nick Rupley
                        	Date Modified: 5/9/2012
                        
                        	deployChannels
                        	--------------
                        		Deploys channels using an array of channel IDs and an optional client info object.
                        
                        	Arguments
                        	---------
                        		Required
                        		--------
                        		channelIds: An array of channel IDs, or a string containing a comma-separated list of channel IDs.
                        		
                        		Optional
                        		--------
                        		clientInfo: An object containing zero or more of the following elements:
                        			URL: The Mirth Connect Administrator URL to connect to.
                        			user: Username to connect with.
                        			pass: Password to connect with.
                        			version: Version of Mirth Connect to bind to.
                        			timeout: HTTPS Connection timeout in milliseconds.
                        
                        	Return Value
                        	------------
                        		Returns an object containing a status String element, a message String element, 
                        		and an overloaded toString method. The status will be "SUCCESS" if the client
                        		was able to successfully login, and at least one of the channel IDs refers to
                        		an enabled channel. Otherwise, the status is "FAILURE".
                        */
                        
                        function deployChannels(channelIds,clientInfo) {
                        	var crlf = '\x0D\x0A', tab = '     ';
                        	var status = {status:'FAILURE', message:''};
                        	status.toString = function() {return this.status + ':' + crlf + this.message;};
                        
                        	try {
                        		if (!(channelIds instanceof Array)) {
                        			channelIds = channelIds.replace(/\s/g,'');
                        			if (channelIds.length > 0)
                        				channelIds = channelIds.split(',');
                        			else
                        				channelIds = [];
                        		}
                        		if (channelIds.length <= 0)
                        			throw('');
                        	}
                        	catch(e) {
                        		status.message = 'Invalid Channel ID List.';
                        		return status;
                        	}
                        
                        	var info = {
                        		URL: 'https://localhost:8443',
                        		user: 'admin',
                        		pass: 'admin',
                        		version: '2.2.1.5861',
                        		timeout: 10000
                        	};
                        	if (clientInfo) {
                        		info.URL = clientInfo.URL || info.URL;
                        		info.user = clientInfo.user || info.user;
                        		info.pass = clientInfo.pass || info.pass;
                        		info.version = clientInfo.version || info.version;
                        		if ((clientInfo.timeout || clientInfo.timeout === 0) && clientInfo.timeout >= 0)	
                        			info.timeout = clientInfo.timeout;
                        	}
                        
                        	try {
                        		var client = new com.mirth.connect.client.core.Client(info.URL,info.timeout);
                        		var loginStatus = client.login(info.user,info.pass,info.version);
                        		status.message += 'Login status: ' + loginStatus.getStatus() + crlf;
                        
                        		if (!loginStatus.getStatus().toString().startsWith('FAIL')) {
                        			var list = new java.util.ArrayList();
                        			var channels = {}, failures = [];
                        			var successMessage = 'Channels successfully deployed:' + crlf;
                        			var failureMessage = 'Disabled channels not deployed:' + crlf;
                        
                        			for each (channel in client.getChannel(null).toArray())
                        				channels[channel.getId()] = channel.isEnabled();
                        			for each (channelId in channelIds)
                        				if (channels[channelId]) {
                        					list.add(channelId);
                        					successMessage += tab + channelId + crlf;
                        				}
                        				else {
                        					failures.push(channelId);
                        					failureMessage += tab + channelId + crlf;
                        				}
                        
                        			client.deployChannels(list);
                        			status.status = list.size() > 0 ? 'SUCCESS' : 'FAILURE';
                        			status.message += (list.size() > 0 ? successMessage : '') + (failures.length > 0 ? failureMessage : '');
                        		}
                        		else
                        			status.message += loginStatus.getMessage() + crlf;
                        
                        		try {client.logout();} catch (e) {}
                        	}
                        	catch(e) {
                        		status.status = 'FAILURE';
                        		status.message += e.toString() + crlf;
                        	}
                        
                        	return status;
                        }
                        And an example of its use (a channel that accepts a CSV string of channelIds as Delimited Text and outputs the result of deployChannels to the server log):

                        Code:
                        logger.info(deployChannels(messageObject.getRawData().split(',')).toString());
                        Attached Files
                        Last edited by narupley; 10-17-2013, 07:54 AM.
                        Step 1: JAVA CACHE...DID YOU CLEAR ...wait, ding dong the witch is dead?

                        Nicholas Rupley
                        Work: 949-237-6069
                        Always include what Mirth Connect version you're working with. Also include (if applicable) the code you're using and full stacktraces for errors (use CODE tags). Posting your entire channel is helpful as well; make sure to scrub any PHI/passwords first.


                        - How do I foo?
                        - You just bar.

                        Comment


                        • #13
                          I believe this will also be useful to others.

                          Date(Time) is always a pain in the **** especially with javascript.
                          So we ended up developing a javascript object that does the translation.
                          note the date is still string based note a javascript Date object.

                          You can set any date(time) you want and get any other format back.

                          Code:
                          /*
                          	Author(s): Stefan Scholte /Barry van der Veen
                          	Isala Klinieken Zwolle The Netherlands
                          
                          	InternalDateTimeObject
                          	--------------
                          		Sets or gets Date(time) in numerous formats.
                          
                          */
                          
                          function InternalDateTimeObject()
                          {
                          	this.innerDate = '';
                          
                          	this.GetHL7UniversalDateTimeWithMilliseconds = function() 
                          	{
                          		return this.innerDate;
                          	}
                          
                          	this.GetHL7UniversalDateTime = function() 
                          	{
                          		return this.GetDateFromCustomTemplate("yyyyMMddHHmmss");
                          	}
                          
                          	this.GetHL7UniversalDate = function() 
                          	{
                          		return this.GetDateFromCustomTemplate("yyyyMMdd");
                          	}
                          
                          	this.GetDBDateTimeEN = function() 
                          	{
                          		return this.GetDateFromCustomTemplate("yyyy-MM-dd HH:mm:ss");
                          	}
                          
                          	this.GetDBDateEN = function() 
                          	{
                          		return this.GetDateFromCustomTemplate("yyyy-MM-dd");
                          	}
                          
                          	this.GetDBDateTimeNL = function() 
                          	{
                          		return this.GetDateFromCustomTemplate("dd-MM-yyyy HH:mm:ss");
                          	}
                          	this.GetDBDateNL = function() 
                          	{
                          		return this.GetDateFromCustomTemplate("dd-MM-yyyy");
                          	}
                          
                          	this.GetTime = function()
                          	{
                          		return this.GetDateFromCustomTemplate("HH:mm:ss");
                          	}
                          
                          	this.GetTimeWithMilliseconds = function()
                          	{
                          		return this.GetDateFromCustomTemplate("HH:mm:ss.SSS");
                          	}
                          	this.GetWeek = function()
                          	{
                          		return this.GetDateFromCustomTemplate("ww");
                          	}
                          
                          	this.SetCurrentDate = function()
                          	{
                          		this.innerDate = DateUtil.getCurrentDate('yyyyMMddHHmmssSSS');
                          	}
                          
                          	this.SetFromDBDateNL = function(strDate)
                          	{
                          		this.innerDate = this.SetDateFromCustomTemplate("dd-MM-yyyy",strDate);
                          	}
                          
                          	this.SetFromDBDateEN = function(strDate)
                          	{
                          		this.innerDate = this.SetDateFromCustomTemplate("yyyy-MM-dd",strDate);
                          	}
                          
                          	this.SetFromDBDateTimeNL = function(strDate)
                          	{
                          		this.innerDate = this.SetDateFromCustomTemplate("dd-MM-yyyy HH:mm:ss",strDate);
                          	}
                          
                          	this.SetFromDBDateTimeEN = function(strDate)
                          	{
                          		this.innerDate = this.SetDateFromCustomTemplate("yyyy-MM-dd HH:mm:ss",strDate);
                          	}
                          
                          
                          	this.SetFromHL7UniversalDate = function(strDate)
                          	{
                          		this.innerDate = this.SetDateFromCustomTemplate("yyyyMMdd",strDate);
                          	}
                          
                          	this.SetFromHL7UniversalDateTime = function(strDate)
                          	{
                          		this.innerDate = this.SetDateFromCustomTemplate("yyyyMMddHHmmss",strDate);
                          	}
                          
                          
                          	this.GetDateFromCustomTemplate = function (pattern) 
                          	{
                          		if (this.innerDate == '')
                          			return this.innerDate;
                          		else
                          			return DateUtil.convertDate ("yyyyMMddHHmmssSSS", pattern, this.innerDate);
                          	}
                          
                          	this.SetDateFromCustomTemplate = function (pattern, strDate) 
                          	{
                          		if(!strDate || strDate == '')
                          			return '';
                          		else
                          			return DateUtil.convertDate (pattern,"yyyyMMddHHmmssSSS", strDate);
                          	}
                          }
                          
                          //Formatting options
                          // yyyy year (four-digit)
                          // M, MM month, month with leading 0
                          // d, dd day, day with leading 0
                          // HH hour, 24-hour-format
                          // hh hour, 12-hour-format
                          // mm minutes
                          // ss seconds
                          // SSS milliseconds
                          // ww week in year
                          usage:

                          Code:
                          //Make a new InternalDateTimeObject instance.
                          var date = new InternalDateTimeObject();
                          
                          //You can set the currentdate in the object
                          date.SetCurrentDate();
                          //or set a specific date(time)
                          date.SetFromDBDateTimeEN("2012-04-30 12:58:57");
                          
                          //And if you have special formatting you can use this option
                          
                          date.SetDateFromCustomTemplate ("yyyy/dd/MM/", "2012/03/04") ;
                          
                          //And this is how you can get the date(times) back.
                          
                          var englishDateTime = date.GetDBDateTimeEN(); 
                          var HL7DateTime = date.GetHL7UniversalDateTimeWithMilliseconds();; 
                          
                          
                          //Here are all the getters
                          date.GetHL7UniversalDateTimeWithMilliseconds();; 
                          date.GetHL7UniversalDateTime(); 
                          date.GetHL7UniversalDate(); 
                          date.GetDBDateTimeEN(); 
                          date.GetDBDateEN(); 
                          date.GetDBDateTimeNL(); 
                          date.GetDBDateNL(); 
                          date.GetTime();
                          date.GetTimeWithMilliseconds();
                          date.GetWeek();
                          
                          
                          
                          
                          //And here are all the setters
                          date.SetCurrentDate();
                          date.SetFromDBDateNL("30-04-2012");
                          date.SetFromDBDateEN("2012-04-30");
                          date.SetFromDBDateTimeNL("30-04-2012 12:58:57");
                          date.SetFromDBDateTimeEN("2012-04-30 12:58:57");
                          date.SetFromHL7UniversalDate("20120430");
                          date.SetFromHL7UniversalDateTime(20120430125857)
                          date.GetDateFromCustomTemplate ("yyyy/dd/MM/"); 
                          date.SetDateFromCustomTemplate ("yyyy/dd/MM/", "2012/03/04") ;
                          Last edited by StefanScholte; 05-16-2012, 03:34 AM.
                          Stefan

                          Mirth Certified|Epic Bridges Certified|Cloverleaf Level 2 Certified

                          Comment


                          • #14
                            String Functions

                            Here's some string functions I use all the time, simple but effective. -cp

                            function startsWith(str, prefix) {
                            return str.indexOf(prefix) === 0;
                            }

                            function endsWith(str, suffix) {
                            return str.match(suffix+"$")==suffix;
                            }

                            function Left(str, n){
                            if (n <= 0)
                            return "";
                            else if (n > String(str).length)
                            return str;
                            else
                            return String(str).substring(0,n);
                            }
                            function Right(str, n){
                            if (n <= 0)
                            return "";
                            else if (n > String(str).length)
                            return str;
                            else {
                            var iLen = String(str).length;
                            return String(str).substring(iLen, iLen - n);
                            }
                            }

                            Comment


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

                              https://github.com/nextgenhealthcare/connect-examples

                              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!
                              renameField: Returns a copy of the given HL7 field, changing all segment names to the given name.

                              It has two parameters, the field node you want to change, and the new segment name to give the node (and all of it's descendants).

                              Examples:

                              Copy PID.2 over to PID.3 without having to map over each individual component/subcomponent:

                              Code:
                              msg.PID['PID.3'] = renameField(msg.PID['PID.2'],'PID.3');
                              The code:

                              Code:
                              /*
                              	Author: Nick Rupley
                              	Date Modified: 1/6/2012
                              */
                              
                              function renameField(oldField,name) {
                              	String.prototype.entityReplace = function() {return this.replace(/&/g,'&amp;').replace(/"/g,'&quot;').replace(/'/g,'&apos;').replace(/</g,'&lt;').replace(/>/g,'&gt;');};
                              	var out = new XML();
                              	for each (field in oldField) {
                              		var outField = new XML('<'+name+'/>');
                              		for each (component in field.children()) {
                              			var cname = name + component.name().toString().substring(component.name().toString().indexOf('.',component.name().toString().indexOf('.')+1));
                              			if (component.children().length() > 1) {
                              				// Has subcomponents
                              				var outComponent = new XML('<'+cname+'/>');
                              				for each (subcomponent in component.children()) {
                              					var scname = name + subcomponent.name().toString().substring(subcomponent.name().toString().indexOf('.',subcomponent.name().toString().indexOf('.')+1));
                              					var outSubcomponent = new XML('<'+scname+'>'+subcomponent.toString().entityReplace()+'</'+scname+'>');
                              					outComponent.scname = outSubcomponent;
                              				}
                              				outField.cname = outComponent;
                              			}
                              			else
                              				outField.cname = new XML('<'+cname+'>'+component.toString().entityReplace()+'</'+cname+'>');
                              		}
                              		out += outField;
                              	}
                              	return out;
                              }
                              Attached Files
                              Last edited by narupley; 06-08-2018, 10:35 AM.
                              Step 1: JAVA CACHE...DID YOU CLEAR ...wait, ding dong the witch is dead?

                              Nicholas Rupley
                              Work: 949-237-6069
                              Always include what Mirth Connect version you're working with. Also include (if applicable) the code you're using and full stacktraces for errors (use CODE tags). Posting your entire channel is helpful as well; make sure to scrub any PHI/passwords first.


                              - How do I foo?
                              - You just bar.

                              Comment

                              Working...
                              X