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

Leave a Comment