Question
· May 10, 2021

Ensemble Delete Individual Rules and Ensemble classes programmatically

Hi Team,

I have a requirement to delete the Ensemble interfaces , as per User request. I would like to write a routine for that and once I execute, it should remove the interface components through code.
Could you please provide code samples for the following actions ?

  • Deleting an individual rule from a rule class
  • Deleting a class from Ensemble
  • Deleting a Host (Service/Operation/Process) from the Production.

Appreciate the help.

Thanks,

Purushothaman.T

Product version: Ensemble 2017.1
$ZV: Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2017.1.3 (Build 317_0_18252U)
Discussion (6)1
Log in or sign up to continue

Delete class from Ensemble

set classToDelete = "mypackage.myclass"
if ($$$ISOK($system.OBJ.IsValidClassname(classToDelete)))
{
    do $system.OBJ.Delete(classToDelete,"e")
}

Remove a Host from production

set productionName = "mypackage.myproduction"
set itemName = "NameItemInProduction"

If ##class(Ens.Config.Item).NameExists(productionName,itemName,.idItem)
{
    Set production = ##class(Ens.Config.Production).%OpenId(productionName)
    Set objItem = production.FindItemByConfigName(itemName)
    Do production.RemoveItem(objItem)
    Set st = production.%Save()
    Do ##class(Ens.Director).RestartProduction(0,1)
}

I hope this code helps you.

Best regards,
Kurro Lopez

Hello T,

I see that Kurro has already provided some samples but you are still waiting on the first question.

I'm not sure if my understanding of your desire is correct, but individual rules in a routing rule are a part of the overarching rule class. While it is technically possible to programmatically edit a class, my personal feeling is that this approach feels more complicated than necessary. To make changes to individual rules it might make more sense to use a source control solution and deploy the version of the rule class that has the rules that you want.

Another benefit of the source control methodology is that to make changes in prod, rather than editing production code in a live system, you would be choosing between deployment of (hopefully) tested versions of the rule.

I agree with Vic that this is probably not worth the complexity. The rule definitions are stored as XML -- to change them you'll need to fetch the XML, modify it, then save the changed XML and re-compile the class. It would look something like this:

    set tMyRuleClassName="My.RoutingRuleClass"
    
    &SQL(select %id into :tXDataID from %Dictionary.XDataDefinition where parent = :tMyRuleClassName and Name='RuleDefinition')
    
    if (SQLCODE > 0) {
        // Query returned no results. Do some error handling
        quit
    }

    set tRuleDefinition=##class(%Dictionary.XDataDefinition).%OpenId(tXDataID)

    /* This stream contains the raw XML of the RuleDefinition. It looks like this:
    <ruleDefinition alias="" context="EnsLib.HL7.MsgRouter.RoutingEngine" production="TESTINGPKG.FoundationProduction">
        <ruleSet name="" effectiveBegin="" effectiveEnd="">
            <rule name="">
                <when condition="1">
                    <send transform="" target="HL7.File.Out"/>
                    <return/>
                </when>
            </rule>
        </ruleSet>
    </ruleDefinition>
    */
    set tRuleDefinitionXMLStream=##class(%Stream.GlobalCharacter).%New()
    do tRuleDefinitionXMLStream.CopyFrom(tRuleDefinition.Data)

    // Use XML classes to manipulate the stream
    // (docs about XML classes: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GXML_intro)
    // ...
    // ...
    // ...
    // Ok, done making changes to the stream

    // Copy the changed XML back into the RuleDefinition
    do tRuleDefinition.Data.CopyFrom(tRuleDefinitionXMLStream)

    // Save the changees to the rule definition XData
    set tSC=tRuleDefinition.%Save()
    // Check if tSC indicates an error and do something about it
    if $$$ISERR(tSC) {
        // Do some error handling
    }

    // Recompile the rule class
    set tSC=$System.OBJ.Compile(tMyRuleClassName,"cuk",.errorlog,1)

    // Check if tSC indicates an error and do something about it
    if $$$ISERR(tSC) {
        // Do some error handling
    }

Hi Marc,

Thanks for your suggestion. I have written the below piece, to remove the individual rule node, as per my requirement.
But , after removing,  to copy that back to rule class, it's not reflecting , if i save and compile the rule. 
What am i missing here ?

 

DelIndRule(RuleId) [tXDataID,tMyRuleClassName,SQLCODE] public 
{
     set tMyRuleClassName="SJHSOCAL.Rule.TestRule"
    
    &SQL(select %id into :tXDataID from %Dictionary.XDataDefinition where parent = :tMyRuleClassName and Name='RuleDefinition')
    
    if (SQLCODE > 0) {
        // Query returned no results. Do some error handling
        quit
    }
    
    Write "tXDataID : "_tXDataID,!

    set tRuleDefinition=##class(%Dictionary.XDataDefinition).%OpenId(tXDataID)
    
    Write "tRuleDefinition : "_tRuleDefinition,!

    /* This stream contains the raw XML of the RuleDefinition. It looks like this:
    <ruleDefinition alias="" context="EnsLib.HL7.MsgRouter.RoutingEngine" production="TESTINGPKG.FoundationProduction">
        <ruleSet name="" effectiveBegin="" effectiveEnd="">
            <rule name="" disabled ="true">
                <when condition="1">
                    <send transform="" target="HL7.File.Out"/>
                    <return/>
                </when>
            </rule>
        </ruleSet>
    </ruleDefinition>
    */
    set tRuleDefinitionXMLStream=##class(%Stream.GlobalCharacter).%New()
    do tRuleDefinitionXMLStream.CopyFrom(tRuleDefinition.Data)
    
    
    set reader=##class(%XML.Reader).%New()
    set status=reader.OpenStream(tRuleDefinitionXMLStream)
    if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status}
    #dim document as %XML.Document
    #dim node as %XML.Node
    set document=reader.Document
    
    Write document.CountNamespace()_"document : "_document,!
    
        Set node = document.GetDocumentElement()
        Write "NodeDocElement"_node,!
        
        Write document.GetDocumentNode(),!
        
        //Set node = document.GetNode(i)
        //Write "node : "_node,!
        
        Set nodeName = node.LocalName
        W "nodeName : "_nodeName,!
        
        Do node.MoveToFirstChild(1)
        Do node.MoveToFirstChild(1)
    
    For i=1:1
    { 

          Set nodeName = node.LocalName
        W "nodeName : "_nodeName,!
        
        If (nodeName = "rule")
        {    
            W i_"    :    inside rule tag    :    "_node.GetAttributeValue("name"),!
            //Get Node Attributes, check disable status            
            If (i=RuleId)
            {
                If (node.GetAttributeValue("disabled")="true")
                {
                    //Remove the node 
                    W "Inside Remove node",!
                    //If remove successfull , move to child node, since the control will go back to parent node.
                    // 1 childnode
                    Do node.Remove()
                    W "after Remove    :    "_node.LocalName,!
                    If 1 
                    {
                        Do node.MoveToFirstChild(1)
                        // move i number of sibiling
                        Set i=i-1
                        For j=1:1:i-1
                        {
                            Do node.MoveToNextSibling(1)
                        }
                        W "after moving to Rule    :    "_node.LocalName,!
                    }
                }

            
               }
               //Write node.MoveToNextSibling(1),!
            Quit:node.MoveToNextSibling(1)=0
        }
        Else 
        {
            Quit
        }
    }
    
    
    // Ok, done making changes to the stream

    //Write tRuleDefinitionXMLStream.%Save()
    // Copy the changed XML back into the RuleDefinition
    do tRuleDefinition.Data.CopyFrom(tRuleDefinitionXMLStream)

    // Save the changees to the rule definition XData
    set tSC=tRuleDefinition.%Save()
    // Check if tSC indicates an error and do something about it
    if $$$ISERR(tSC) {
        // Do some error handling
        W "Save status"_tSC,!
    }

    // Recompile the rule class
    set tSC=$System.OBJ.Compile(tMyRuleClassName,"cuk",.errorlog,1)

    // Check if tSC indicates an error and do something about it
    if $$$ISERR(tSC) {
        // Do some error handling
         W "Compile status"_tSC,!
    } 
    
}

%XML.Reader and %XML.Document won't automatically update the original stream. You need to use %XML.Writer to output the %XML.Document into a stream.

set writer=##class(%XML.Writer).%New()
set outStream=##class(%Stream.GlobalCharacter).%New()
set tSC=writer.OutputToStream(.outStream)
set tSC=writer.Document(document)
write "Stream:[",outStream.Read(3000000),"]",!