Automate Import/Export channels functionality – Part2

This code will consist of the data needed for Mirth channel (B) in the server 2.

Basically, this channel will be reading the JSON message, decode the incoming encoded message, then automatically import those channel and then deploy it. This channel will be responsible to do all the importing operations and this will happen without any manual intervention.

Please use the below code in the source transformer of the channel and proceed connecting the mirth server 1 and mirth server 2

importPackage(Packages.com.mirth.connect.server.controllers);
importPackage(Packages.com.mirth.connect.model);
importPackage(Packages.com.mirth.connect.model.codetemplates);
importPackage(Packages.com.mirth.connect.model.converters);
importPackage(Packages.com.mirth.connect.server.controllers);
importPackage(Packages.com.mirth.connect.server.util);

//Define and Initilize Mirth controller instances
var channelController = ChannelController.getInstance();
var codeTemplateController = CodeTemplateController.getInstance();
var configurationController = ConfigurationController.getInstance();

//Get list of existing libraries & channel dependencies here
var existingLibraries = codeTemplateController.getLibraries(null, true);
var channelDependencies = configurationController.getChannelDependencies();
var restoreChannelGroups = channelController.getChannelGroups(null);
var restoreLibraries = codeTemplateController.getLibraries(null, true);
var restoreChannelTagSet = configurationController.getChannelTags();
var restoreChannelDependencies = configurationController.getChannelDependencies();
var restoreDeployedChannels = channelController.getDeployedChannels(null);

//Get channel metadata
var channelMetaDataMap = configurationController.getChannelMetadata();

var abortDeploymentAndRestoreBackup = false;
var fileSuffix = DateUtil.getCurrentDate(“MMddyyyyHHmmss”);
var backupFileName = “channel backups/backup-” + fileSuffix + “.json”;
channelMap.put(“backupFileName”, backupFileName);

backup(restoreChannelGroups, restoreLibraries, restoreChannelTagSet, restoreChannelDependencies, restoreDeployedChannels);

//Variables
var serializer = ObjectXMLSerializer.getInstance();
var jsonMessage = msg;
var toBeDeployedList = new Packages.java.util.ArrayList();
var groups = new Packages.java.util.HashSet();

//Populate existing channel groups on the mirth instance
var existingGroups = channelController.getChannelGroups(null);
if (existingGroups === null || existingGroups === undefined) {
existingGroups = new Packages.java.util.ArrayList();
}

//Iterae through the groups (from json message received)
for (var groupCounter = 0; groupCounter < jsonMessage.length && !abortDeploymentAndRestoreBackup; groupCounter++) {
var currentChannelGroup = jsonMessage[groupCounter];

var groupAlreadyPresent = false;
var indexFound = -1;
//Check to see if group alredy exists on mirth by iterating through the existing groups
for (existingCounter = 0; existingCounter < existingGroups.size(); existingCounter++) {
if (existingGroups.get(existingCounter).getId().equals(currentChannelGroup.groupId)) {
groupAlreadyPresent = true;
indexFound = existingCounter;
break;
}
}
//If group is already present, then get copy of that in a variable. If not, then add it to existing groups list.
var chGroup = null;
if (!groupAlreadyPresent) {
logger.info(“Group NOT present. Creating a new one”);
var chGroup = new Packages.com.mirth.connect.model.ChannelGroup(currentChannelGroup.groupName, “”);
chGroup.setId(currentChannelGroup.groupId);
existingGroups.add(chGroup);
} else {
logger.info(“Group Already present”);
chGroup = existingGroups.get(indexFound);
}

//Parse channels element from json message and iterate through the channels
var channels = currentChannelGroup.channels;
for (channelCounter = 0; channelCounter < channels.length && !abortDeploymentAndRestoreBackup; channelCounter++) {
var decodedChannel = new Packages.java.lang.String(FileUtil.decode(channels[channelCounter]));
logger.debug(“Decoded Channel for import:” + decodedChannel);
var channelObject = serializer.deserialize(decodedChannel, Channel);
//Get channel dependency list from decoded channel being imported
var dependentIDS = channelObject.getExportData().getDependentIds().iterator();
var dependencyIDS = channelObject.getExportData().getDependencyIds().iterator();
//Before importing a new channel, try to stop and undeploy existing channel (max 5 times) after waiting for a second each time.
//If deploy fails, abort import with message and move over to next channel
for (retryCount = 0; retryCount < 5; retryCount++) {
if (retryCount >= 1) {
Packages.java.lang.Thread.sleep(1000);
}
if (ChannelUtil.isChannelDeployed(channelObject.getId())) {
ChannelUtil.stopChannel(channelObject.getId());
logger.info(“Request raised for stopping channel: ” + channelObject.getName());
ChannelUtil.undeployChannel(channelObject.getId());
logger.info(“Request raised for undeploying channel: ” + channelObject.getName());
} else {
logger.info(“Channel is undeployed:” + channelObject.getName());
break;
}
}

if (ChannelUtil.isChannelDeployed(channelObject.getId())) {
logger.error(“Aborting import of channel as it is still deployed:” + channelObject.getName());
abortDeploymentAndRestoreBackup = true;
break;
}

//Get code template libraries details linked with a channel, iterate through it and import those first before channel.
var chLibraries = channelObject.getExportData().getCodeTemplateLibraries();
for (ch1 = 0; ch1 < chLibraries.size(); ch1++) {
var currentLibrary = chLibraries.get(ch1);
var isLibraryAlreadyPresent = false;
//Find if the code template library is already present in mirth, then overwrite and update that library. Else import a new one.
for (exLibraryCounter = 0; exLibraryCounter < existingLibraries.size(); exLibraryCounter++) {
if (existingLibraries.get(exLibraryCounter).getId().equals(currentLibrary.getId())) {
isLibraryAlreadyPresent = true;
existingLibraries.set(exLibraryCounter, currentLibrary);
break;
}
}
//Add new library, if not already present
if (!isLibraryAlreadyPresent) {
existingLibraries.add(currentLibrary);
}
//Find list of code templates from the library and update & import them in mirth
var chTemplates = chLibraries.get(ch1).getCodeTemplates();
for (ch2 = 0; ch2 < chTemplates.size(); ch2++) {
var codeT = chTemplates.get(ch2); //serializer.deserialize(chTemplates.get(ch2), Packages.com.mirth.connect.model.codetemplates.CodeTemplate);
codeTemplateController.updateCodeTemplate(codeT, null, true);
}
codeTemplateController.updateLibraries(existingLibraries, null, true);
}
//Import the new channel in mirth and add it deployment list
channelController.updateChannel(channelObject, null, true);
toBeDeployedList.add(channelObject.getId());
var channelAlreadyFound = false;
//Check to see, if channel is already linked to channel group. If so, no need to link it again. If not, then add to channel group.
for (existingChannelCounter = 0; existingChannelCounter < chGroup.getChannels().size(); existingChannelCounter++) {
if (chGroup.getChannels().get(existingChannelCounter).getId().equals(channelObject.getId())) {
logger.debug(channelObject.getId() + ” channel id already found. No need to add again to the group. – ” + channelObject.getName());
channelAlreadyFound = true;
break;
}
}
if (!channelAlreadyFound) {
chGroup.getChannels().add(channelObject);
}
//Update dependency and dependent Id list (in mirth memory for now)
while (dependentIDS.hasNext()) {
var dependentId = dependentIDS.next();
if (dependentId != null && dependentId !== undefined && !dependentId.equals(channelObject.getId())) {
channelDependencies.add(new Packages.com.mirth.connect.model.ChannelDependency(dependentId, channelObject.getId()));
}
}
while (dependencyIDS.hasNext()) {
var dependencyId = dependencyIDS.next();
if (dependencyId != null && dependencyId !== undefined && !dependencyId.equals(channelObject.getId())) {
channelDependencies.add(new Packages.com.mirth.connect.model.ChannelDependency(channelObject.getId(), dependencyId));
}
}
//Clear channel’s export data’s code template libraries and dependcies from memory before moving to next channel in channel group.
channelObject.getExportData().clearCodeTemplateLibraries();
channelObject.getExportData().clearDependencies();
}
}
//If import of channels is done successfully, then set channel dependencies and update channel groups and deploy channels
if (!abortDeploymentAndRestoreBackup) {
//Update dependency and dependent Id list (in mirth persistence)
configurationController.setChannelDependencies(channelDependencies);

//Convert list of channel groups to be updated to a set and update channel groups
var newGroups = new Packages.java.util.HashSet();
for (i = 0; i < existingGroups.size(); i++) {
newGroups.add(existingGroups.get(i));
}
channelController.updateChannelGroups(newGroups, null, true);

//Deploy all the channels that were earlier added to deployment list.
for (k = 0; k < toBeDeployedList.size(); k++) {
ChannelUtil.deployChannel(toBeDeployedList.get(k));
}

//Wait for 5 seconds before deployment is verified.
Packages.java.lang.Thread.sleep(5000); // Not mandatory

//Identify if channel is not deployed even after 5 seconds.
for (k = 0; k < toBeDeployedList.size(); k++) {
if (!ChannelUtil.isChannelDeployed(toBeDeployedList.get(k))) {
logger.info(toBeDeployedList.get(k) + ” channel is not deployed yet after the import, so recovery process would start now.”);
abortDeploymentAndRestoreBackup = true;
}
}
}

if (abortDeploymentAndRestoreBackup) {
//Read json back up file for restoring previous version
var jsonBackupObject = JSON.parse(FileUtil.read(backupFileName));

//Get list of deployed channels from backup file
var deployedChannelIds = jsonBackupObject.deployedChannelIds;
var deserializerRestore = ObjectXMLSerializer.getInstance();

//Get list of channel groups from backup file
var channelGroupSetForRestore = new Packages.java.util.HashSet();
for (i = 0; i < jsonBackupObject.encodedChannelGroups.length; i++) {
channelGroupSetForRestore.add(deserializerRestore.deserialize(decode(jsonBackupObject.encodedChannelGroups[i]), ChannelGroup));
}

//Get list of code template libraries from backup file
var codeTemplateLibrariesForRestore = new Packages.java.util.ArrayList();
for (i = 0; i < jsonBackupObject.encodedCodeTemplateLibraries.length; i++) {
codeTemplateLibrariesForRestore.add(deserializerRestore.deserialize(decode(jsonBackupObject.encodedCodeTemplateLibraries[i]), CodeTemplateLibrary));
}

//Get channel tags from backup file
var channelTagSetForRestore = new Packages.java.util.HashSet();
for (i = 0; i < jsonBackupObject.encodedChannelTags.length; i++) {
channelTagSetForRestore.add(deserializerRestore.deserialize(decode(jsonBackupObject.encodedChannelTags[i]), ChannelTag));
}

//Get channel dependencies from backup file
var channelDependenciesSetForRestore = new Packages.java.util.HashSet();
for (i = 0; i < jsonBackupObject.encodedChannelDependencies.length; i++) {
channelDependenciesSetForRestore.add(deserializerRestore.deserialize(decode(jsonBackupObject.encodedChannelDependencies[i]), ChannelTag));
}

//Revert code templates and libraries
for (lb = 0; lb < codeTemplateLibrariesForRestore.size(); lb++) {
var currLibrary = codeTemplateLibrariesForRestore.get(lb);
for (ct = 0; ct < currLibrary.getCodeTemplates().size(); ct++) {
codeTemplateController.updateCodeTemplate(currLibrary.getCodeTemplates().get(ct), null, true);
}
}

//Revert channel code
var channelGrpIterator = channelGroupSetForRestore.iterator();
while (channelGrpIterator.hasNext()) {
var channelGroupToBeRestored = channelGrpIterator.next();
for (k = 0; k < channelGroupToBeRestored.getChannels().size(); k++) {
var channelToBeRestored = channelGroupToBeRestored.getChannels().get(k);
channelController.updateChannel(channelToBeRestored, null, true);
}
}

//Revert libraries, channel groups, channel tags and channel dependencies by calling mirth classes with values parsed from backup file.
codeTemplateController.updateLibraries(codeTemplateLibrariesForRestore, null, true);
channelController.updateChannelGroups(channelGroupSetForRestore, null, true);
configurationController.setChannelTags(channelTagSetForRestore);
configurationController.setChannelDependencies(channelDependenciesSetForRestore);

//Deploy old version channels
for (i = 0; i < deployedChannelIds.length; i++) {
ChannelUtil.deployChannel(deployedChannelIds[i]);
}
}

If you guys have a look at the code deeply, you can find that it uses three functions to achieve the above code. You can either place the below functions in the code template area or in the transformer as well.

//Function to decode the value and return string
function decode(value) {
return new Packages.java.lang.String(FileUtil.decode(value));
}

//Function to get an array of objects with xml representation of collection of objects
function getXml(collection) {
var returnList = [];
var counter = 0;
var backupSerializer = ObjectXMLSerializer.getInstance();
var iterator = collection.iterator();
while (iterator.hasNext()) {
var object = iterator.next();
var writerObject = new Packages.java.io.StringWriter();
backupSerializer.serialize(object, writerObject);
returnList[counter++] = FileUtil.encode(writerObject.toString().getBytes());
}
return returnList;
}

//This function takes backup of entire set of channel groups, code templates/libraries, channel tags, dependencies and list of deployed channels in time.
//backup is kept in json file with content as base64 encoded.
function backup(channelGroups, codeTemplateLibraries, channelTags, restoreChannelDependencies, restoreDeployedChannels) {
if (channelMetaDataMap != null) {
for (i = 0; i < channelGroups.size(); i++) {
var currentChannelGroup = channelGroups.get(i);
for (j = 0; j < currentChannelGroup.getChannels().size(); j++) {
var channelSetId = new Packages.java.util.HashSet();
channelSetId.add(currentChannelGroup.getChannels().get(j).getId());

var currentChannels = channelController.getChannels(channelSetId);
if (currentChannels != null) {
var currentChannel = currentChannels.get(0);
currentChannelGroup.getChannels().set(j, currentChannel);
currentChannel.getExportData().setMetadata(channelMetaDataMap.get(currentChannel.getId()))
}
}
}
}
var restoreDeployedChannelIds = new Packages.java.util.ArrayList();
if (restoreDeployedChannels != null) {
for (i = 0; i < restoreDeployedChannels.size(); i++) {
restoreDeployedChannelIds.add(restoreDeployedChannels.get(i).getId());
}
}
var encodedChannelGroups = getXml(channelGroups);
var encodedCodeTemplateLibraries = getXml(codeTemplateLibraries);
var encodedChannelTags = getXml(channelTags);
var encodedChannelDependencies = getXml(restoreChannelDependencies);
var backup = {};
backup.encodedChannelGroups = encodedChannelGroups;
backup.encodedChannelTags = encodedChannelTags;
backup.encodedCodeTemplateLibraries = encodedCodeTemplateLibraries;
backup.encodedChannelDependencies = encodedChannelDependencies;
backup.deployedChannelIds = restoreDeployedChannelIds;

var outputBackup = JSON.stringify(backup);
FileUtil.write(backupFileName, false, JsonUtil.prettyPrint(outputBackup));
}

Yup. That’s how you can automate the tool which turns up to save much of your valuable time. Happy Automation

Advertisements

Automate Import/Export channels functionality – Part1

This is a weird experiment.

Just in-case we want to automate the exporting/importing of channels in mirth, then this feature will be very helpful. The user will be giving the ID’s of the channel group which needs to be exported to one mirth server to be imported into another mirth server, and this operation will be performed without any manual intervention.

The Mirth channel (A) from SERVER1 will accept all the channel group ID’s in a comma separated value, and then export the entire channel group along with the code template and dependencies attached with that channels of the group and generate a Json containing all the exported value in a base 64 encoded format.

The Mirth channel (B) from SERVER2 will consume this Json data decode the encoded string and automatically import those channels along with the group and their code templates and deploy them.

Server 1 – Mirth Channel (A):

This channel will consume the group ID’s in a comma separated value and then generate and JSON string out of it. Please copy the below code to the source/destination transformer.

importPackage(Packages.com.mirth.connect.server.controllers);
importPackage(Packages.com.mirth.connect.model);
importPackage(Packages.com.mirth.connect.model.converters);
importPackage(Packages.com.mirth.connect.server.controllers);
importPackage(Packages.com.mirth.connect.server.util);

//Defined and Initalized all controller instances
var configurationController = ConfigurationController.getInstance();
var channelController = ChannelController.getInstance();
var codeTemplateController = CodeTemplateController.getInstance();
var serializer = ObjectXMLSerializer.getInstance();

//Define required variables.
var groupIds = new Packages.java.util.HashSet();

//Parse the group ids passed into an array using comma as a separator
var commaSeparatedGroupIds = connectorMessage.getRaw().getContent();
var arrayGroupIds = commaSeparatedGroupIds.split(“,”);
for (i = 0; i < arrayGroupIds.length; i++) {
groupIds.add(arrayGroupIds[i].trim());
}

//Get channel groups and channel metadata and existing libraries.
var channelGroups = channelController.getChannelGroups(groupIds);
var channelMetaDataMap = configurationController.getChannelMetadata();
var libraries = codeTemplateController.getLibraries(null, true);

var output = [];

var newJsonObj = {};
newJsonObj.Manifest = [];
newJsonObj.ChannelExportData = [];

//Iterae through the channel groups (passed as input)
for (i = 0; i < channelGroups.size(); i++) {
var channelGroup = channelGroups.get(i);
var channelIds = new Packages.java.util.HashSet();
var groupNameValue = channelGroup.getName();

var groupNames = {};
groupNames.groupInfo = channelGroup.getName();
groupNames.channelNames = [];

var channelGroupJson = {};
channelGroupJson.groupId = channelGroup.getId();
channelGroupJson.groupName = channelGroup.getName();
channelGroupJson.channels = [];
output[i] = channelGroupJson;

// logger.info(“CHANNEL GROUP EXPORTED WITH NUMBER OF CHANNELS: ” + channelGroup.getChannels().size());
//Iterate through all the channels in the group and add channel ids of those to a list.
for (channelCounter = 0; channelCounter < channelGroup.getChannels().size(); channelCounter++) {
var currentChannelId = channelGroup.getChannels().get(channelCounter).getId();
channelIds.add(currentChannelId);
}

//Load the channel objects based on channel ids collected previously.
var channels = channelController.getChannels(channelIds);

//Iterate through the channels loaded previously and update following for each channel
//1. Export Data -> Metadata
//2. Export Data -> Code template libraries
//3. Export Data -> Channel Tags
//4. Export Data -> Dependent Ids
//5. Export Data -> Dependency Ids
//Then convert that channel object into xml with base 64 encoding
for (channelCounter = 0; channelCounter < channels.size(); channelCounter++) {
var currentChannelId = channels.get(channelCounter).getId();
var channelDetails = {};
channelDetails.channelName = channels.get(channelCounter).getName();
channelDetails.Library = [];

if (channelMetaDataMap != null) {
channels.get(channelCounter).getExportData().setMetadata(channelMetaDataMap.get(currentChannelId));
}

for (ctCounter = 0; libraries != null && ctCounter < libraries.size(); ctCounter++) {
var library = libraries.get(ctCounter);
//logger.info(“library : “+library.getName())

if (library.getEnabledChannelIds().contains(currentChannelId) ||
(library.isIncludeNewChannels() && !library.getDisabledChannelIds().contains(currentChannelId))) {
channels.get(channelCounter).getExportData().getCodeTemplateLibraries().add(library);
channelDetails.Library.push(library.getName());
}
}

groupNames.channelNames.push(channelDetails);

var channelTagSet = configurationController.getChannelTags();
var channelTags = null;
if (channelTagSet != null) {
channelTags = channelTagSet.iterator();

while (channelTags.hasNext()) {
var channelTag = channelTags.next();
if (channelTag.getChannelIds().contains(currentChannelId)) {
channels.get(channelCounter).getExportData().getChannelTags().add(channelTag);
}
}
}

var channelDependenciesSet = configurationController.getChannelDependencies();
var channelDependencies = null;
if (channelDependenciesSet != null) {
channelDependencies = channelDependenciesSet.iterator();
while (channelDependencies.hasNext()) {
var channelDependency = channelDependencies.next();
if (channelDependency.getDependencyId().equals(currentChannelId)) {
channels.get(channelCounter).getExportData().getDependentIds().add(channelDependency.getDependentId());
} else if (channelDependency.getDependentId().equals(currentChannelId)) {
channels.get(channelCounter).getExportData().getDependencyIds().add(channelDependency.getDependencyId());
}
}
}

var writer = new Packages.java.io.StringWriter();
serializer.serialize(channels.get(channelCounter), writer);

channels.get(channelCounter).getExportData().clearAllExceptMetadata();
channels.get(channelCounter).getExportData().clearMetadata();
channelGroupJson.channels[channelCounter] = FileUtil.encode(writer.toString().getBytes());
}
newJsonObj.ChannelExportData.push(channelGroupJson);
newJsonObj.Manifest.push(groupNames);
}

var newJson = JSON.stringify(newJsonObj);
logger.debug(newJson);

//Write entire channel group and base64 list of its channel xmls into a file at defined location
FileUtil.write(“C:/Labs/POC/Import_Export/output.json”, false, JsonUtil.prettyPrint(newJson));
channelMap.put(“output”, JsonUtil.prettyPrint(newJson));

 

 

 

Bi-directional Channel (JSON-HL7V2):

Let’s create a channel in Mirth that will consume the incoming JSON message and convert that into an equivalent HL7v2 message in Mirth (i.e) we are converting JSON format of message to the pipe-delimiter format message with Mirth interoperability.

Pre-requisite:

  • MirthConnect : 3.4.1.8057 (latest version)

Channel setup :

  1. Create a New channel name it as your wish Here I have named JSON to HL7V2
  2. Click on Set Data Types button set the source connector inbound to JSON
  3. Outbound and Destination 1 to HL7V2.x
     – that’s it the channel setup is done for it.

Source Transformer :

  • Go to the source transformer and right click to create a new step
  • Name the step as JSONto HL7V2 
  • Select the drop-down of  the step that you have created and select Javascript

Code : 

//Get the incoming JSON Data

var input = JSON.parse(connectorMessage.getRawData());

// parse MSH content
var patienId = input.header.patient_id;
var patientName = input.header.patient_name;
var idCard = input.header.id;
var messagetType = input.header.type;
var subType = input.header.subType;
var ctrlNum = input.header.controlNumber;
var pId = input.header.processingId;
var version = input.header.version;

//parse patientInfo
var internalId = input.patientInfo.internalId;
var firstName = input.patientInfo.nameDetails.firstName;
var lastName = input.patientInfo.nameDetails.lastName;
var initial = input.patientInfo.nameDetails.initial;
var suffix = input.patientInfo.nameDetails.suffix;
var motherName = input.patientInfo.motherName;
var DateOfBirth = input.patientInfo.DOB;
var gender = input.patientInfo.sex;
var race = input.patientInfo.race;
var status = input.patientInfo.maritalStatus;
var religion = input.patientInfo.Religion;
var ssn = input.patientInfo.SSN;
var birthPlace = input.patientInfo.birthPlace;
var orderOfBirth = input.patientInfo.birthOrder;
var citizenship =input.patientInfo.citizenship;

//NextOfKin Details
var nk1Len=msg[‘kinDetails’].length;
for(var nk1Counter=0;nk1Counter<nk1Len;nk1Counter++)
{
var kinFirstName=input.kinDetails[nk1Counter].firstName;
var kinLastName=input.kinDetails[nk1Counter].lastName;
var relationShip=input.kinDetails[nk1Counter].relationship;
var phNumber=input.kinDetails[nk1Counter].phoneNumber;
var contactRole=input.kinDetails[nk1Counter].contactRole;
}

//Equal msg=tmp
msg=tmp;

//Generate HL7v2 Message
//MSH
createSegment(‘MSH’, msg);
msg[‘MSH’][‘MSH.1’]= “|”;
msg[‘MSH’][‘MSH.2’]= “^~\\&”;
msg[‘MSH’][‘MSH.3’]= patienId;
msg[‘MSH’][‘MSH.4’]= patientName;
msg[‘MSH’][‘MSH.5’]= idCard;
msg[‘MSH’][‘MSH.9’][‘MSH.9.1’]=messagetType;
msg[‘MSH’][‘MSH.10’][‘MSH.10.1’]=ctrlNum;
msg[‘MSH’][‘MSH.11’][‘MSH.11.1’]=pId;
msg[‘MSH’][‘MSH.12’][‘MSH.12.1’]=version;

//PID
createSegment(‘PID’, msg);
msg[‘PID’][‘PID.3’][‘PID.3.1’]=internalId;
msg[‘PID’][‘PID.5’][‘PID.5.1’]=firstName;
msg[‘PID’][‘PID.5’][‘PID.5.2’]=lastName;
msg[‘PID’][‘PID.5’][‘PID.5.3’]=initial;
msg[‘PID’][‘PID.5’][‘PID.5.4’]=suffix;
msg[‘PID’][‘PID.6’][‘PID.6.1’]=motherName;
msg[‘PID’][‘PID.7’][‘PID.7.1’]=DateOfBirth;
msg[‘PID’][‘PID.8’][‘PID.8.1’]=gender;
msg[‘PID’][‘PID.10’][‘PID.10.1’]=race;
msg[‘PID’][‘PID.16’][‘PID.16.1’]=status;
msg[‘PID’][‘PID.17’][‘PID.17.1’]=religion;
msg[‘PID’][‘PID.19’][‘PID.19.1’]=ssn;
msg[‘PID’][‘PID.23’][‘PID.23.1’]=birthPlace;
msg[‘PID’][‘PID.25’][‘PID.25.1’]=orderOfBirth;
msg[‘PID’][‘PID.26’][‘PID.26.1’]=citizenship;

//NK1
var nk1Counter=0;
var NK1Segment = createSegment(‘NK1’, msg);
msg[‘NK1’][nk1Counter][‘NK1.2’][‘NK1.2.1’]=kinFirstName
msg[‘NK1’][nk1Counter][‘NK1.2’][‘NK1.2.2’]=kinLastName;
msg[‘NK1’][nk1Counter][‘NK1.3’][‘NK1.3.1’]=relationShip;
msg[‘NK1’][nk1Counter][‘NK1.5’][‘NK1.5.1’]=phNumber;
msg[‘NK1’][nk1Counter][‘NK1.7’][‘NK1.7.1’]=contactRole;
nk1Counter++;

//Convert Mirth based XMl to HL7v2
var output = SerializerFactory.getSerializer(‘HL7V2’).fromXML(msg);
logger.info(“output : “+output);

Consider you are sending an JSON message like this provided below:

{
“header”: {
“patient_id”: “XXXX”,
“patient_name”: “John”,
“id”: “454141541”,
“type”: “ADT”,
“subType”: “A04”,
“controlNumber”: “12345678”,
“processingId”: “T”,
“version”: “2.8”
},
“patientInfo”: {
“internalId”: “12345684”,
“nameDetails”: {
“firstName”: “XXXXX”,
“lastName”: “YYYY”,
“initial”: “Z”,
“suffix”: “III”
},
“motherName”: “YYYYYYYY”,
“DOB”: “19940401”,
“sex”: “M”,
“race”: “white”,
“maritalStatus”: “Single”,
“Religion”: “Jew”,
“SSN”: “112-546-878”,
“birthPlace”: “Minnesota”,
“birthOrder”: “test”,
“citizenship”: “US”
},
“kinDetails”: [{
“firstName”: “WWWWWW”,
“lastName”: “ZZZZZ”,
“relationship”: “XXXXX”,
“phoneNumber”: “(216)123-4567”,
“contactRole”: “EC”
}]
}

Note : In the above JSON message you can see that the data being transmitted is primarily a ADT message. specifically an A04 message which is basically a Patient Registration message format.

Here MSH and PID segments are mandatory. That’s why you can see that In the JSON structure I have not used array (‘[]’) for the key values ‘header‘ and ‘patientInfo‘. If there is a possibility that multiple values may occur in future then we will be having a array structure specified there as in kinDetails. That’s why I have looped the kin details in the transformer code.

If everything goes well upon deploying the channel you will get an output message like this show below.

MSH|^~\&|XXXX|John|454141541||||ADT|12345678|T|2.8
PID|||12345684||XXXXX^YYYY^Z^III|YYYYYYYY|19940401|M||white||||||Single|Jew||112-546-878||||Minnesota||test|US
NK1||WWWWWW^ZZZZZ|XXXXX||(216)123-4567||EC

In case of NK1 segment there can be multiple next of kin available then in that case you will have a JSON like this:

“kinDetails”: [{
“firstName”: “WWWWWW”,
“lastName”: “ZZZZZ”,
“relationship”: “XXXXX”,
“phoneNumber”: “(216)123-4567”,
“contactRole”: “EC”
},{
“firstName”: “WWWWWW”,
“lastName”: “ZZZZZ”,
“relationship”: “XXXXX”,
“phoneNumber”: “(216)123-4567”,
“contactRole”: “EC”
}]

If you print the data inside the loop of the transformer code then you can see both the data are logged. Hence the output should also have multiple NK1 segment available in it.

NOTE :  HIPPA policies are strictly followed in this BLOG so I will never reveal any patient name, other relation name etc here. I will only build a dummy data set, don’t look in specific to message logic.

 

HL7V2 to JSON in Mirth

Bi-directional Channel (HL7v2-JSON) : 

Let’s learn to make the conversion from HL7V2 to JSON in Mith tool. Need for this conversion is high in demand, the end-users may be in need to consume the JSON data for their business use, from the HL7V2 which is basically  a pipe-delimiter message.

Pre-requisites :

  • MirthConnect : 3.4.1.8057 (latest version)

Channel setup :

  1. Create a New channel name it as your wish Here I have named HL7V2 to JSON
  2. Click on Set Data Types button set the source connector inbound to HL7V2.x
  3. Outbound and Destination 1 to JSON
     – that’s it the channel setup is done for it

Source Transformer :

  • Go to the source transformer and right click to create a new step
  • Name the step as HL7V2 to JSON
  • Select the drop-down of  the step that you have created and select Javascript

Code :

var hl7V2Array = [];
var hl7V2Obj = {};
hl7V2Obj.messageHeader ={};

hl7V2Obj.messageHeader.fieldSeparator = msg[‘MSH’][‘MSH.1’]
hl7V2Obj.messageHeader.encodingCharacter=msg[‘MSH’][‘MSH.2’]
hl7V2Obj.messageHeader.sendingApplication=msg[‘MSH’][‘MSH.3’][‘MSH.3.1’]
hl7V2Obj.messageHeader.sendingFacility=msg[‘MSH’][‘MSH.4’][‘MSH.4.1’]
hl7V2Obj.messageHeader.receivingApplication=msg[‘MSH’][‘MSH.5’][‘MSH.5.1’]
hl7V2Obj.messageHeader.receivingFacility=msg[‘MSH’][‘MSH.6’][‘MSH.6.1’]
hl7V2Obj.messageHeader.dateTimeMessage=msg[‘MSH’][‘MSH.7’][‘MSH.7.1’]
hl7V2Obj.messageHeader.security=msg[‘MSH’][‘MSH.8’][‘MSH.8.1’]
hl7V2Obj.messageHeader.messageType=msg[‘MSH’][‘MSH.9’][‘MSH.9.1’]
hl7V2Obj.messageHeader.eventType=msg[‘MSH’][‘MSH.9’][‘MSH.9.2’]
hl7V2Obj.messageHeader.controlID=msg[‘MSH’][‘MSH.10’][‘MSH.10.1’]
hl7V2Obj.messageHeader.processingID=msg[‘MSH’][‘MSH.11’][‘MSH.11.1’]
hl7V2Obj.messageHeader.versionID=msg[‘MSH’][‘MSH.12’][‘MSH.12.1’]
hl7V2Obj.messageHeader.sequenceNumber=msg[‘MSH’][‘MSH.13’][‘MSH.13.1’]

hl7V2Obj.patientIdentification ={};
hl7V2Obj.patientIdentification.setId=msg[‘PID’][‘PID.1’][‘PID.1.1’]
hl7V2Obj.patientIdentification.patientIdExternal=msg[‘PID’][‘PID.2’][‘PID.2.1’]
hl7V2Obj.patientIdentification.patientIdInternal=msg[‘PID’][‘PID.3’][‘PID.3.1’]
hl7V2Obj.patientIdentification.alternateId=msg[‘PID’][‘PID.4’][‘PID.4.1’]
hl7V2Obj.patientIdentification.patientName={};
hl7V2Obj.patientIdentification.patientName.familyName=msg[‘PID’][‘PID.5’][‘PID.5.1’]
hl7V2Obj.patientIdentification.patientName.givenName=msg[‘PID’][‘PID.5’][‘PID.5.2’]
hl7V2Obj.patientIdentification.motherName=msg[‘PID’][‘PID.6’][‘PID.6.1’]
hl7V2Obj.patientIdentification.dateTimeBirth=msg[‘PID’][‘PID.7’][‘PID.7.1’]
hl7V2Obj.patientIdentification.sex=msg[‘PID’][‘PID.8’][‘PID.8.1’]
hl7V2Obj.patientIdentification.patientAlias=msg[‘PID’][‘PID.9’][‘PID.9.1’]
hl7V2Obj.patientIdentification.race=msg[‘PID’][‘PID.10’][‘PID.10.1’]
hl7V2Obj.patientIdentification.patientAddress=msg[‘PID’][‘PID.11’][‘PID.11.1’]
hl7V2Obj.patientIdentification.countryCode=msg[‘PID’][‘PID.12’][‘PID.12.1’]
hl7V2Obj.patientIdentification.phoneHome=msg[‘PID’][‘PID.13’][‘PID.13.1’]
hl7V2Obj.patientIdentification.phoneBusiness=msg[‘PID’][‘PID.14’][‘PID.14.1’]
hl7V2Obj.patientIdentification.primaryLanguage=msg[‘PID’][‘PID.15’][‘PID.15.1’]
hl7V2Obj.patientIdentification.maritalStatus=msg[‘PID’][‘PID.16’][‘PID.16.1’]
hl7V2Obj.patientIdentification.religion=msg[‘PID’][‘PID.17’][‘PID.17.1’]
hl7V2Obj.patientIdentification.accountNumber=msg[‘PID’][‘PID.18’][‘PID.18.1’]
hl7V2Obj.patientIdentification.ssnNumber=msg[‘PID’][‘PID.19’][‘PID.19.1’]
hl7V2Obj.patientIdentification.driverLicense=msg[‘PID’][‘PID.20’][‘PID.20.1’]

hl7V2Array.push(hl7V2Obj);

var output = JSON.stringify(hl7V2Array);
logger.info(output);
channelMap.put(‘JSON’,output);

Consider you send a HL7V2 message like this:

MSH|^~\&|CERNER||PriorityHealth||||ORU^R01|Q479004375T431430612|P|2.3|
PID|||001677980||SMITH^CURTIS||19680219|M||||||||||929645156318|123456789|
PD1||||1234567890^LAST^FIRST^M^^^^^NPI|
OBR|1|341856649^HNAM_ORDERID|000002006326002362|648088^Basic Metabolic Panel|||20061122151600|||||||||1620^Hooker^Robert^L||||||20061122154733|||F|||||||||||20061122140000|
OBX|1|NM|GLU^Glucose Lvl|59|mg/dL|65-99^65^99|L|||F|||20061122154733|

You will get a JSON like this as output:

[{
“messageHeader”: {
“fieldSeparator”: “|”,
“encodingCharacter”: “^~\\&”,
“sendingApplication”: “CERNER”,
“sendingFacility”: “”,
“receivingApplication”: “PriorityHealth”,
“receivingFacility”: “”,
“dateTimeMessage”: “”,
“security”: “”,
“messageType”: “ORU”,
“eventType”: “R01”,
“controlID”: “Q479004375T431430612”,
“processingID”: “P”,
“versionID”: “2.3”,
“sequenceNumber”: “”
},
“patientIdentification”: {
“setId”: “”,
“patientIdExternal”: “”,
“patientIdInternal”: “001677980”,
“alternateId”: “”,
“patientName”: {
“familyName”: “SMITH”,
“givenName”: “CURTIS”
},
“motherName”: “”,
“dateTimeBirth”: “19680219”,
“sex”: “M”,
“patientAlias”: “”,
“race”: “”,
“patientAddress”: “”,
“countryCode”: “”,
“phoneHome”: “”,
“phoneBusiness”: “”,
“primaryLanguage”: “”,
“maritalStatus”: “”,
“religion”: “”,
“accountNumber”: “929645156318”,
“ssnNumber”: “123456789”,
“driverLicense”: “”
}
}]

Blog at WordPress.com.

Up ↑