routing rule compiles to refer to old package

Hi,

I have a routing rule that calls some utility classmethods, but for some reason the compiled version insists on linking to a utility function in a different package.

The call to 'SendToEaling(HL7)' in  isn't compiling to a call to the LNWTIEPackage as expected:

##class(LNWTIEPackage.RoutingRules.Utility).SendToEaling((pContext.HL7))

but is instead becoming a call to the LNWDeploy package

##class(LNWDeploy.RoutingRules.Utility).SendToEaling((pContext.HL7))

Specifically 

<assign property="@SendToEaling" value="SendToEaling(HL7)"></assign>

 gets compiled to

set tTempVars("SendToEaling")=##class(LNWDeploy.RoutingRules.Utility).SendToEaling((pContext.HL7))

Any ideas what could be causing this?

Kind regards,

Stephen

RoutingRule:

Class LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP Extends Ens.Rule.Definition
{

Parameter RuleAssistClass = "EnsLib.HL7.MsgRouter.RuleAssist";

XData RuleDefinition [ XMLNamespace = "http://www.intersystems.com/rule" ]
{
<ruleDefinition alias="" context="EnsLib.HL7.MsgRouter.RoutingEngine" production="LNWTIEPackage.LNWTIEProduction">
<variable name="SendToEaling"></variable>
<variable name="SendToNWL"></variable>
<variable name="NumberSearch"></variable>
<variable name="PracticeDetailSearch"></variable>
<variable name="GPDetailsUpdate"></variable>
<ruleSet name="iCS Main Router Ruleset" effectiveBegin="" effectiveEnd="">
<rule name="" disabled="true">
<constraint name="docCategory" value="iCS.Outbound"></constraint>
<when condition="1=1">
<send transform="" target="iCS Soak Test TCPIP Sender"></send>
</when>
</rule>
<assign property="@SendToEaling" value="SendToEaling(HL7)"></assign>
<assign property="@SendToNWL" value="SendToNWL(HL7)"></assign>
<trace value="&quot;SendToEaling = &quot;_@SendToEaling"></trace>
<trace value="&quot;SendToNWL = &quot;_@SendToNWL"></trace>
<assign property="@NumberSearch" value="PASNumbersCheck(HL7.{PID:3})"></assign>
<trace value="&quot;NumberSearch = &quot;_@NumberSearch"></trace>

Compiles to

 ;LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP.1
 ;(C)InterSystems, generated for class LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP.  Do NOT edit. 09/06/2018 11:50:46AM
 ;;702B766D;LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP
 ;
zevaluateRuleDefinition(pContext,pRuleSet,pEffectiveBegin,pEffectiveEnd,pReturnValue,pReason,pLogLevel,pDebugId="") public { Set:'($data(pLogLevel)#2) pLogLevel="r"
    set tSC=1,$ZE=""
    try {
        set pReturnValue="",pReason=""
        ; Initialize temporary variables
        set tTempVars("SendToEaling")=""
        set tTempVars("SendToNWL")=""
        set tTempVars("NumberSearch")=""
        set tTempVars("PracticeDetailSearch")=""
        set tTempVars("GPDetailsUpdate")=""
        ; No ruleSet dispatching code generated.
        set pEffectiveBegin=""
        set pEffectiveEnd=""
        set pRuleSet=""
        ;
ruleSet1 ; effectiveBegin = (not-specified); effectiveEnd = (not-specified)
        if (pLogLevel [ "c") set tSC = ##class(Ens.Rule.DebugLog).Log(pDebugId,"c","","Executing ruleSet1: effectiveBegin = (not-specified); effectiveEnd = (not-specified)",0) quit:('tSC)
        ;
        set tTempVars("SendToEaling")=##class(LNWDeploy.RoutingRules.Utility).SendToEaling((pContext.HL7))
        set tTempVars("SendToNWL")=##class(LNWDeploy.RoutingRules.Utility).SendToNWL((pContext.HL7))
        do ##class(Ens.Util.Trace).WriteTrace("user",$classname(),"evaluateRuleDefinition",(("SendToEaling = ")_(tTempVars("SendToEaling"))))
        do ##class(Ens.Util.Trace).WriteTrace("user",$classname(),"evaluateRuleDefinition",(("SendToNWL = ")_(tTempVars("SendToNWL"))))
        set tTempVars("NumberSearch")=##class(LNWDeploy.RoutingRules.Utility).PASNumbersCheck((pContext.HL7.GetValueAt("PID:3")))
        do ##class(Ens.Util.Trace).WriteTrace("user",$classname(),"evaluateRuleDefinition",(("NumberSearch = ")_(tTempVars("NumberSearch"))))
        ; Evaluating rule: rule#2(Teleologic ADT REF MFN)

Answers

As it stands there is no known way to specify the full class path to a utility function.

Alternatives are discussed in the other comments below.

When the rule gets compiled, the GetFunctionSet classmethod of Ens.Rule.Utils enumerates all classmethods of Ens.Rule.FunctionSet and of all its subclasses in the namespace. The first occurrence of a classmethod name is recorded, and the class in which it's found is going to be the one that the compiler uses when it generates the rule's class code.

In your case SendToEaling is first found in LNWDeploy.RoutingRules.Utility rather than in LNWTIEPackage.RoutingRules.Utility (which collates later).

Per your comment, I think you'll need to specify the full reference to your function, i.e.

##class(LNWTIEPackage.RoutingRules.Utility).SendToEaling(HL7)

Update: so far I haven't found a way of explicitly indicating which class you want your custom utility function to be called in.

Thanks John,

I thought about that but it fails- even if I copy/paste the class path reference '##class(LNWDeploy.RoutingRules.Utility).' from the successful compile:

set tTempVars("SendToEaling")=##class(LNWDeploy.RoutingRules.Utility).SendToEaling((pContext.HL7))

error text

Compilation started on 09/06/2018 14:43:45 with qualifiers 'cuk /checkuptodate=expandedonly'
Compiling class LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP
ERROR <Ens>ErrParsingExpression: Error parsing expression '##class(LNWDeploy.RoutingRules.Utility).SendToEaling(HL7)': ERROR <Ens>ErrInvalidName: Invalid name at offset 1
  > ERROR #5490: Error running generator for method 'evaluateRuleDefinition:LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP'
ERROR: Ens.Rule.Definition.cls(evaluateRuleDefinition) of generated code compiling subclass 'LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP'
    > ERROR #5030: An error occurred while compiling class 'LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP'
Detected 1 errors during compilation in 0.086s.)

Is my only option is to delete LNWDeploy.RoutingRules.Utility and recompile?  

(it would be nice to be able to specifiy the full class path - but if routing rules don't support it I don't want to keep 'banging my head against a brick wall')

Thanks again

Stephen

An alternative to deleting LNWDeploy.RoutingRules.Utility would be to amend it so it no longer extends Ens.Rule.FunctionSet. Doing this should make it invisible to the rule compiler, allowing your other class's methods to be detected.

Maybe also open a WRC ticket about your issue.

Comments

The documentation provides a method to specify the full class path for DTL's,

https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=EGDV_adv_custom_utilfunctions

e.g.

##class(HP.Util.funciones).normalizaSexo(source.{Sex})

While it does note the syntax for calling utility functions is different for routing rules (the '..' prefix is not required), I can't see the correct full class path syntax in the documentation.

Any help appreciated.

Stephen