Written by

Software Developer at J2 Interactive
Article Rizmaan Marikar · Aug 30, 2023 5m read

Add/Edit Business Hosts to Interoperability production - A different approach

Wanted to share something I learned recently while working on a problem. We needed to add and change some Business Hosts in one of our edge productions.

In the past, we simply added the production class to CCR and then spreading it around. But there was a problem because different developers were working on different things, and we only wanted to include only the relevent production changes onto the CCR. 

Here's a little piece of code that can help add new things to an existing production:

class HSEDGE1PKG.ProductionDefinition
{

/// define the Productions Definitions which are listed below/// should be a comma seperated stringParameter ProdDefinitions = "EdgeGatewayProduction";
XData EdgeGatewayProduction
{
<Item Name="EnsLib.HL7.Service.FileService" Category="" ClassName="EnsLib.HL7.Service.FileService" PoolSize="1" Enabled="true" Foreground="false" DisableErrorTraps="false" Comment="" LogTraceEvents="false" Schedule="">
    <Setting Target="Host" Name="InactivityTimeout">0</Setting>
    <Setting Target="Host" Name="TargetConfigNames">HS.Gateway.HL7.InboundProcess</Setting>
    <Setting Target="Host" Name="AckMode">Never</Setting>
    <Setting Target="Host" Name="MessageSchemaCategory">2.5</Setting>
    <Setting Target="Adapter" Name="FilePath">..\..\Data\HSEDGE1\HL7In</Setting>
  </Item>
  <Item Name="HUB" Category="" ClassName="HS.Hub.HSWS.RemoteOperations" PoolSize="1" Enabled="true" Foreground="false" DisableErrorTraps="false" Comment="" LogTraceEvents="false" Schedule="">
    <Setting Target="Host" Name="InactivityTimeout">0</Setting>
    <Setting Target="Host" Name="ServiceName">HSREGISTRY</Setting>
    <Setting Target="Adapter" Name="ResponseTimeout">2592000</Setting>
    <Setting Target="Host" Name="FailureTimeout">-1</Setting>
    <Setting Target="Host" Name="Retry">1</Setting>
    <Setting Target="Host" Name="RetryInterval">120</Setting>
  </Item>
  <Item Name="HS.Gateway.HSWS.WebServices" Category="" ClassName="HS.Gateway.HSWS.WebServices" PoolSize="0" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
    <Setting Target="Host" Name="InactivityTimeout">0</Setting>
    <Setting Target="Host" Name="ECRTarget">HS.Gateway.ECR.Manager</Setting>
    <Setting Target="Host" Name="PushRepMgr">HS.Gateway.ECR.Push.RepositoryManager</Setting>
    <Setting Target="Host" Name="ECRProcess">HS.Gateway.ECR.Process</Setting>
    <Setting Target="Host" Name="ResourceRequired">%HS_WebServices</Setting>
    <Setting Target="Host" Name="GatewayName">j2windowsvm:HSEDGE1</Setting>
    <Setting Target="Host" Name="AnalyticsNotificationTargets">AnalyticsSubscriptionHandler</Setting>
  </Item>
}



ClassMethod AddUpdateProductions() As%Status
{
    #dim status as%Status = $$$OK// set the XDATA IDSSet xdataID =""Set tInitNamespace = $namespace//loop through the defined production definitions //if multiple productions needs to be updated simply add new xdata blocksSet tProdDefinitionsList = $ListFromString(..#ProdDefinitions,",")
    Set n = $ListLength(tProdDefinitionsList)
    
    // loop through the defined production definitionsFor xdataID=1:1:n {

        #dim tFromProd As Ens.Config.Production
        #dim tItem As Ens.Config.Item
        
        Set status = ..OpenProduction($classname(),$list(tProdDefinitionsList,xdataID),.tFromProd)
        
        //switch to the corret namespaceset tNamespace = "HSEDGE01"set$namespace = tNamespace
        
        // Open the original production, and add itemsSet tToProduction=##class(Ens.Config.Production).%OpenId(tFromProd.Name,,.tSC) Throw:$$$ISERR(tSC)
        For tI=1:1:tFromProd.Items.Count() {
            Set tItem=tFromProd.Items.GetAt(tI)
            Set tSC=..AddConfigItem(tItem,tToProduction) 
            Quit:$$$ISERR(tSC)
        }
        
        Set:$$$ISOK(tSC) tSC=..SaveProduction(tToProduction)
        Kill tFromProd,tToProduction,tItem
        
    }
    
    set$namespace = tInitNamespace
    Quit status
}

/// This will look for the production Item in pToProd/// if pItem.Name exists in pToProd delete it and /// add pItem with the above defined setting in the XData blockClassMethod AddConfigItem(pItem As Ens.Config.Item, pToProd As Ens.Config.Production) As%Status
{
    #dim tItem As Ens.Config.Item
    #dim tFromItem As Ens.Config.Item
    set tFoundItem=""// check if production item exists and remove itSet tI=""For tI=1:1:pToProd.Items.Count() {
        set tItem = pToProd.Items.GetAt(tI)
        If tItem.Name=pItem.Name{
            Set tFoundItem=1do pToProd.Items.RemoveAt(tI)
            Quit
        }
    }
    
    //add the production itemset tSC = pToProd.Items.Insert(pItem)

    Quit tSC
}

/// method to open a productionClassMethod OpenProduction(pProdClass As%String, pProductionDef As%String, Output pProdRef As Ens.Config.Production) As%Status
{
    Quit##Class(Ens.Util.XML.Reader).ObjectFromXData(.pProdRef,pProdClass,pProductionDef,"Ens.Config.Production")
}

// Save pProd (oRef)ClassMethod SaveProduction(pProd As Ens.Config.Production) As%Status
{
    Do {
        Set tSC=pProd.%Save() Quit:$$$ISERR(tSC)
        Set tSC=pProd.SaveToClass() Quit:$$$ISERR(tSC)
        Set tProdClass=pProd.Name
        Set tSC = $System.OBJ.Compile(tProdClass,"-d") Quit:$$$ISERR(tSC)
        // Only reload on IRIS versions starting with 2020.1// Needed to reswizzleIf ($System.Version.GetMajor() >= 2020) {
            Set tSC = pProd.%Reload() Quit:$$$ISERR(tSC)
        }
    } While0Quit tSC
}

}

The good thing about this way is that we can just copy a part of the code from the production class to make our changes.

I hope you find this helpful. I am sure we can make this code even better, but it's working well for me right now.