Iterate over Business process activities
Recently I needed a classmethod that returns annotation value based on a name of a activity.
As doing it at runtime seemed inefficient, I wrote compile-time utility that iterates over all business process activities and generates relevant code.
This code could be used in a variety of situations when you need to iterate over business process activities, just add it as a secondary superclass to your BPL processes.
Class isc.ens.ProcessUtils
{
/// List of nodes that may contain ActivityList.
/// Retrieved with:
/// SELECT parent, ID, Name, Type
/// FROM %Dictionary.CompiledProperty
/// WHERE Parent %STARTSWITH 'Ens.BPL' AND Name='Activities'
Parameter ActivityNodes = {$lb("Ens.BPL.Case", "Ens.BPL.CaseNode", "Ens.BPL.Catch", "Ens.BPL.CatchAll", "Ens.BPL.CompensationHandler", "Ens.BPL.Default", "Ens.BPL.Flow", "Ens.BPL.ForEach", "Ens.BPL.Message", "Ens.BPL.Request", "Ens.BPL.Response", "Ens.BPL.Scope", "Ens.BPL.Sequence", "Ens.BPL.Until", "Ens.BPL.While")};
/// Get value of activity annatation by name
ClassMethod GetAnnotation(name) As %String [ CodeMode = objectgenerator ]
{
set sc = $$$OK
try {
#; Don't run this method on the base class
quit:%compiledclass.Name="isc.py.ens.AbstractBPLProcess"
quit:##class(%Dictionary.CompiledXData).%ExistsId(%class.Name_"||BPLERROR")
#; find XDATA block named BPL
if ##class(%Dictionary.CompiledXData).%ExistsId(%class.Name_"||BPL") {
set index = %compiledclass.XDatas.FindObjectId(%class.Name_"||BPL")
#; get XDATA as stream
set stream = %compiledclass.XDatas.GetAt(index).Data
do stream.Rewind()
set parser=##class(Ens.BPL.Parser).%New()
#; Parse the specified stream and obtain the root of the parse tree,
#; Ens.BPL.Process
#dim process As Ens.BPL.Process
set sc = parser.ParseStream(stream,.process)
quit:$$$ISERR(sc)
#dim activities As Ens.BPL.ActivityList
set activities = process.Sequence.Activities
// place all code you want executed before node iteration here
do ..ParseActivities(activities)
// place all code you want executed after node iteration here
do %code.WriteLine(" quit """"")
}
} catch ex {
set sc = ex.AsStatus()
}
quit sc
}
// Iterate over all activities
ClassMethod ParseActivities(activities As Ens.BPL.ActivityList)
{
for i=1:1:activities.Count() {
#dim activity As Ens.BPL.Activity
set activity = activities.GetAt(i)
set class = activity.%ClassName(1)
if $lf(..#ActivityNodes, class) {
do ..ParseActivities(activity.Activities)
} elseif (class="Ens.BPL.If") {
do ..ParseActivities(activity.True)
do ..ParseActivities(activity.False)
} elseif (class ="Ens.BPL.Switch"){
do ..ParseActivities(activity.Cases)
} else {
set annotationText = $$$quote(activity.Annotation)
// code that would be executed for each activity
do:activity.Annotation'="" %code.WriteLine(" quit:name=""" _ activity.Name _ """ " _ annotationText)
}
}
}
}
Discussion (2)0
Comments
Thanks Ed! Will it work in IRIS too?
Yes, tested it in Ensemble 2017.2 and InterSystems IRIS 2018.1.