web stats
Mirth Tools: User defined functions - Page 6 - Mirth Community

Go Back   Mirth Community > Mirth Connect > Support

Reply
 
Thread Tools Display Modes
  #51  
Old 02-21-2018, 07:37 PM
agermano agermano is offline
Mirth Guru
 
Join Date: Apr 2017
Location: Indiana, USA
Posts: 902
agermano is on a distinguished road
Default Format offset of current local time as string

I made a library because I needed to get a formatted datetime string for x number of days prior to now to use in a File Reader.

I put the following line in my channel deploy script to place the object in my globalChannelMap, but I suppose that it could also go in the global deploy script and globalMap, since each channel really doesn't need its own instance of it.
Code:
// Get object from code template that can be used to generate filenames with dates in the past.
$gc('mdu', MyDateUtil.getJavaObject());
Then for my Filename Filter Pattern I would use the following to get four days ago:
Code:
prefix_${mdu.formatCurrentDateTimeByOffset('yyyyMMdd', 'days', -4)}
It uses java 8 time functions and can do offsets in units from nanos to years.
Attached Files
File Type: xml MyDateUtil.xml (6.8 KB, 26 views)
Reply With Quote
  #52  
Old 03-16-2018, 04:47 AM
aTom aTom is offline
OBX.3 Kenobi
 
Join Date: Feb 2016
Location: Lake Geneva Area
Posts: 113
aTom is on a distinguished road
Default Custom DB aggregator

Here's my small contribution. I had to work on this some time ago and I though it was worth to share.

Starting with Mirth 3.5 new DB Reader "Aggregate Results" option, this scripts allows you to debatch/aggregate records according to one column value.

To use it
- go to Source tab, enable Process Batch, enable "Aggregate Results" and set appropriate ORDER BY clause to your query
- go to Summary tab, open Set Data Types window, set Split Batch By to Javascript, paste script in corresponding field and set target column name (in lower case)

As DB Reader generates pretty printed XML, we are able to build results reading one line after the other. This might change in a future release.

EDIT : Actually, while reading it for the first time in weeks, I just figured out there is a much more efficient way to handle this (first version of script is left for info) :

Code:
var columnName = "column name in lower case" //<== SET TARGET COLUMN NAME HERE
var line = ''; // holds single lines read from buffered reader		
var result = ''; //string representation of one <result/> element
var results =  <results/> ; // will hold one batch message
var currentAggregation = ''; 
// anything remaining from last call?
var lastResult = $gc('lastReadResult'); // last record read (empty if we start reading) ; WARNING, it's actually a java String, not a js string
if(lastResult != null && (''+lastResult).length>0) {
    // a result was read previously ==> it's part of current "batch" 
    var xmlResult = new XML(lastResult) ;
    results.appendChild(xmlResult);
    currentAggregation = xmlResult[columnName].toString();
    globalChannelMap.remove('lastReadResult');	
} 
// start/continue reading lines
while ((line = reader.readLine()) != null) {
    // ignore first and last <results> elements
    if (line != "<results>" && line != "</results>") {
        line = line.trim();
        result += line;
        // end of a record?
        if (line == '</result>') {
            var xmlResult = new XML(result); // get result as XML
            // same or new batch
            if (currentAggregation != xmlResult[columnName].toString()) {
                if (results == '') {
                    // tricky here, an empty <results/> means that we're in the very 1st iteration : we just have to set currentAggregation for next iterations
                    currentAggregation = xmlResult[columnName].toString();
                } else {
                    // store new result for next batch	                  		
                    $gc('lastReadResult', result);
                    // return this batch
                    return results.toString();
                }
            }
            // same batch : add result
            results.appendChild(xmlResult);
            // reinit for next record
            result = '';	               
        }
    }
}
// one last batch to return?
return results.toString(); // will return "" if there's nothing remaining
Attached Files
File Type: txt original version.txt (1.8 KB, 3 views)
__________________
Tom

Last edited by aTom; 03-19-2018 at 12:39 AM.
Reply With Quote
  #53  
Old 03-19-2018, 05:50 AM
siddharth siddharth is offline
Mirth Guru
 
Join Date: Feb 2013
Posts: 832
siddharth is on a distinguished road
Default configMap Resolver

If not already known, then there is a Mirth feature called configuration Map available from Settings->ConfigurationMap, where you can store your sensitive Credentials information like DB Credentials, API Credentials and values that are stored can be pulled by just doing configurationMap.get('key'), just like with channel Map.

However, you cannot update details to the configMap from channels or code templates, in a way that configurationMap.put('key') is not possible. It is a read only static Map.

Configuration Map Resolver
This function returns a credentials object thereby fetching values from the configurationMap. All that is necessary is to settle for a "pattern" while storing information in configurationMap.

Let's say that you have stored DB credentials to an EMR database with customerID as ABCD, so I would name the keys as.

ABCD-DB_URL
ABCD-DB_UserName
ABCD-DB_Password

Now, I will call the resolver function like

configMapResolver('ABCD','DB');

and this will return a credentials object with the information.

Code:
function configMapResolver(customerID,type) {

sPattern=customerID+'-'+type+'_';

oCredentials=new Object();
oCredentials.Type=type;
oCredentials.URL=configurationMap.get(sPattern+'URL');
oCredentials.UserName=configurationMap.get(sPattern+'UserName');
oCredentials.Password=configurationMap.get(sPattern+'Password');

return oCredentials;
}

You can add more flags like version or environment to it.

We use this method for all purpose, DB as well as API credentials (differentiated by the type variable)
__________________
HL7v2.7 Certified Control Specialist!

Last edited by siddharth; 03-19-2018 at 05:52 AM. Reason: fix
Reply With Quote
  #54  
Old 04-20-2018, 10:11 AM
jridderhoff jridderhoff is offline
OBX.1 Kenobi
 
Join Date: Jan 2015
Posts: 37
jridderhoff is on a distinguished road
Default Get HL7v2 text-delimited representation of field from XML fragment

We had a specific use case where we needed to get the original HL7 "pipe-delimited" representation of selected fields from incoming HL7v2 text messages and use them elsewhere in the channel output. This function allowed us to transform the HL7 message to an E4X message object, pick the specific fields we needed, and convert the XML fragments back to how they appeared in the original HL7 pipe-delimited message.

Function will handle fields with repeating values as well as empty components/sub-components.

The function:
Code:
/**
 * Function to convert an E4X XML fragment representing an HL7 field into its original HL7 text representation
 * 
 * @param XMLList nodeList         XML representing the field to translate.
 * @param array   joinStrArray     Array containing your HL7 delimiters for repeating fields, components, and subcomponents
 * @param int     joinStrIdx       Index representing the current delimiter in joinStrArray to use (should be 0 on first call)
 * @param int     startComponentId Used for recursion; leave null for first call. (Represents the sub-field element the function is starting from.)
 *
 * @return string
 */
function xmlToPipes(nodeList, joinStrArray, joinStrIdx, startComponentId) {
	var elementList = [];
	var componentIndex = null;

	if (startComponentId !== undefined) {
		componentIndex = parseInt(startComponentId);
	}

	for each (node in nodeList) {
		var nodeChildren = node.elements();
		var nodeNameParts = node.name().toString().split('.');
		var nodeComponentIndex = parseInt(nodeNameParts.pop());
		
		if (componentIndex === null) {
			componentIndex = nodeComponentIndex;
		}
		
		var componentIndexDiff = nodeComponentIndex - componentIndex;
		
		if (componentIndexDiff > 0) {
			for (var i = 0; i < componentIndexDiff; i++) {
				elementList.push('');
				componentIndex++;
			}
		}

		if (nodeChildren.length() > 0) {
			elementList.push(xmlToPipes(nodeChildren, joinStrArray, joinStrIdx+1, 1));
		} else {
			elementList.push(node.toString());
		}

		componentIndex++;
	}

	return elementList.join(joinStrArray[joinStrIdx]);
}
Usage example:
Code:
// array should contain HL7 delimiters you use for (in order) repeating fields, components, and subcomponents
var joinStrStarterArray = ["~", "^", "&"];

var msh4 = xmlToPipes(msg['MSH']['MSH.4'], joinStrStarterArray, 0);
var pid3 = xmlToPipes(msg['ORU_R01.PATIENT_RESULT']['ORU_R01.PATIENT']['PID']['PID.3'], joinStrStarterArray, 0);
Reply With Quote
  #55  
Old 04-24-2018, 09:54 AM
agermano agermano is offline
Mirth Guru
 
Join Date: Apr 2017
Location: Indiana, USA
Posts: 902
agermano is on a distinguished road
Default Access globalChannelMap of any channel

Sometimes you need to alter the globalChannelMap of a running channel but do not want to stop it.

Code:
function $gcById(id, key, value) {
	var maps = com.mirth.connect.server.util.GlobalChannelVariableStoreFactory.getInstance();
	var map;
	if (maps.globalChannelVariableMap.containsKey(id)) {
		map = maps.get(id);
	}
	else {
		throw "globalChannelMap not found for channel: " + id;
	}

	if (arguments.length == 2) {
		return map.get(key);
	}
	else {
		return map.put(key, value);
	}
}
Usage is similar to $gc, except also pass the channelId of the channel for which you want to access or update the globalChannelMap.

Code:
$gcById('388f7dfc-4a1a-45a6-b89b-91faacd67044', 'test', 'added from another channel');
logger.info($gcById('febe3d1e-97d6-47eb-bfe0-ca6bf895c967', 'importantMap').toString());
Reply With Quote
  #56  
Old 05-21-2018, 07:32 AM
narupley's Avatar
narupley narupley is online now
Mirth Employee
 
Join Date: Oct 2010
Posts: 7,119
narupley is on a distinguished road
Default Extract Text From PDF

Quote:
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!
This comes up from time to time...

extractTextFromPDF: Extracts and returns all text from a PDF. Uses the built-in iText library, version 2.1.7.

Parameters:
  • pdfBytes: The raw byte array for the PDF.

Examples:
  • Extract text from a Base64-encoded PDF string:
    Code:
    var pdfBytes = FileUtil.decode(pdfBase64String);
    var pdfText = extractTextFromPDF(pdfBytes);
  • Extract text from a PDF message attachment (before 3.6):
    Code:
    // Is a byte array containing Base64 ASCII bytes
    var attachmentContent = getAttachments().get(0).getContent();
    // Convert to a Base64 string
    var attachmentBase64String = new java.lang.String(attachmentContent, 'US-ASCII');
    // Convert to raw PDF bytes
    var pdfBytes = FileUtil.decode(attachmentBase64String);
    // Extract the text
    var pdfText = extractTextFromPDF(pdfBytes);
  • Extract text from a PDF message attachment (3.6 and later):
    Code:
    // Pass in true for base64Decode, then content is already raw PDF bytes
    var pdfBytes = getAttachments(true).get(0).getContent();
    // Extract the text
    var pdfText = extractTextFromPDF(pdfBytes);

The code:
Code:
/**
	Extracts and returns all text from a PDF. Uses the built-in iText library, version 2.1.7.

	@param {byte[]} pdfBytes - The raw byte array for the PDF.
	@return {String} The extracted text.
*/
function extractTextFromPDF(pdfBytes) {
	var text = new java.lang.StringBuilder();
	var reader = new com.lowagie.text.pdf.PdfReader(pdfBytes);
	
	try {
		var extractor = new com.lowagie.text.pdf.parser.PdfTextExtractor(reader);
		var pages = reader.getNumberOfPages();
		
		for (var i = 1; i <= pages; i++) {
			text.append(extractor.getTextFromPage(i));
			if (i < pages) {
				text.append('\n\n');
			}
		}
	} finally {
		reader.close();
	}

	return text.toString();
}
Attached Files
File Type: xml Extract Text From PDF.xml (1.4 KB, 12 views)
__________________
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.

Last edited by narupley; 06-08-2018 at 10:37 AM.
Reply With Quote
  #57  
Old 06-08-2018, 10:32 AM
narupley's Avatar
narupley narupley is online now
Mirth Employee
 
Join Date: Oct 2010
Posts: 7,119
narupley is on a distinguished road
Default

FYI, 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!
__________________
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.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -8. The time now is 01:40 PM.


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