Hi, Community!
Business Rules in IRIS Interoperability are one of those features that work smoothly until they suddenly do not anymore. You build a rule, the condition looks correct, the routing target is right, but the message keeps falling through to the default action. There is no error in the Event Log and no obvious clue in the Visual Trace.
One of the most common causes is a dynamic object whose properties are not accessible the way you expect. This two-part series covers the full picture. Part 1 walks us through setting up a production using the HL7 Messaging type and building a BPL Business Process that enriches an incoming HL7 message with a dynamic object. Part 2 uses the same production and demonstrates seven real-world property-access pitfalls that cause silent failures in production integrations.
TL;DR
- A
%DynamicObjectin IRIS is a schema-free object you create on the fly without defining a class. - Use it inside a BPL Business Process to carry enrichment data alongside an HL7 message before the routing rule evaluates it.
- Exploit
%Set()to set properties with special characters like underscores and%Get()to read them back. - Part 2 of this series covers seven property-access pitfalls that all silently return empty with no error.
Who This Article Is For
This guide is for IRIS Interoperability developers working with BPL Business Processes and HL7 routing who want to understand how to enrich messages with dynamic objects before routing decisions are made.
What Is a Business Rule?
A Business Rule in IRIS Interoperability is a routing engine that evaluates conditions against an incoming message and decides where to send it. Business Rules do not run on their own; they run inside a Business Process.
In this article, all the data preparation work happens in a BPL Business Process before the routing rule fires. The routing rule then evaluates clean, simple values and makes the decision.
What Is a Dynamic Object?
A %DynamicObject in IRIS is a schema-free object. Unlike a regular ObjectScript class where you define properties upfront, a %DynamicObject lets you create any property on the fly at runtime without a class definition. This makes it extremely useful in integration scenarios where you need to carry extra data alongside a message as it moves through production.
A common real-world pattern is enriching an incoming HL7 message with additional metadata before the routing rule evaluates it. Instead of modifying the original HL7 message class, you create a %DynamicObject, set whatever properties you need, store it in the BPL context, and read from it downstream.
In our example, we read the message type, patient name, and sending application from the incoming HL7 message and store them in a dynamic object. That object then travels with the message through production, and anything downstream can read from it without touching the original HL7 structure.
The Production We Will Build
The production uses standard auto-created components plus one new BPL Business Process:
- HL7FileService: Scans a folder for incoming HL7 files.
- HL7Router: Our new BPL Business Process that builds the dynamic object.
- MsgRouter: Evaluates the routing rule.
- HL7FileOperation: Writes the routed message to an output folder.
Step 1: Create the Production
Go to Management Portal > Interoperability > List > Production and click New.
Fill in the form with the following data:
-
Package:
Demo -
Name:
HL7RulesDemo -
Description:
Demonstrates dynamic objects and property access pitfalls using a BPL process alongside the HL7 routing engine. -
Production Type:
HL7 Messaging
Click OK.
When you select HL7 Messaging, IRIS automatically creates a set of standard components:
- HL7FileService: A Business Service that monitors a folder for incoming HL7 files.
-
MsgRouter: An
EnsLib.HL7.MsgRouter.RoutingEnginethat evaluates routing rules. - HL7FileOperation: A Business Operation that writes routed messages to an output folder.
- BadMessageHandler, EMailAlert, PagerAlert: Alert components you can configure later.
It saves significant setup time, so we will simply reuse these components and add only one new BPL Business Process.
Step 2: Configure the Auto-Created Components
Configure HL7FileService
Click on HL7FileService in the canvas to open its settings panel. Set up the following information:
- File Path: Your incoming folder (e.g., C:\hl7\in)
-
File Spec:
*.hl7 -
Message Schema Category:
2.5
Click Apply.
Configure HL7FileOperation
Click on HL7FileOperation in the canvas and set the following:
- File Path: Your outgoing folder (e.g., C:\hl7\out)
Click Apply.
Step 3: Build the BPL Business Process
The MsgRouter routing engine evaluates simple conditions but does not support Code activities for building dynamic objects. We add a BPL Business Process between HL7FileService and MsgRouter to handle all data preparation.
3A. Create the Process
Go to Management Portal > Interoperability > List > Business Processes and click New. In the General tab, set Language to ObjectScript. Then save it as Demo.HL7Router.
3B. Define Context Properties
In BPL, context is a typed class, and every property you want to use must be declared upfront in the Context tab before you write any code. If you skip this and try to set a property inside a Code activity, IRIS will throw a PROPERTY DOES NOT EXIST error at runtime. So, before touching the canvas, let us define all the properties this process will need.
In the right-side panel, click the Context tab, then click + to add each property:
| Property Name | Property Type |
|---|---|
| MetaData | %DynamicObject |
| PatientId | %String(MAXLEN=50) |
| PatientSex | %String(MAXLEN=50) |
3C. Add the Code Activity
Click Add Activity and select Code. Drag it between <start> and <end>. Label it Build Dynamic Object.
Connect the arrows:
-
<start>toBuild Dynamic Object -
Build Dynamic Objectto<end>
Click on the Code activity to select it. In the right-side panel, find the Code field and click the magnifier icon next to it. It will open a larger editor where you can enter the code below:
$$$LOGINFO("Request class: " _ $classname(request))
Set dynObj = ##class(%DynamicObject).%New()
// Read values from the actual HL7 message
Set dynObj.MsgType = request.GetValueAt("MSH:MessageType.MessageCode")
Set dynObj.PatientName = request.GetValueAt("PID:PatientName(1).FamilyName")
Set dynObj.SendingApp = request.GetValueAt("MSH:SendingApplication")
// Use %Set() for underscore-named properties
Do dynObj.%Set("patient_id", request.GetValueAt("PID:PatientIDList(1).IDNumber"))
Do dynObj.%Set("patient_sex", request.GetValueAt("PID:AdministrativeSex"))
Do dynObj.%Set("date_of_birth", request.GetValueAt("PID:DateTimeofBirth"))
// Log each value for testing purposes
$$$LOGINFO("Dynamic Object built:")
$$$LOGINFO(" MsgType : " _ dynObj.MsgType)
$$$LOGINFO(" PatientName: " _ dynObj.PatientName)
$$$LOGINFO(" SendingApp : " _ dynObj.SendingApp)
$$$LOGINFO(" patient_id : " _ dynObj.%Get("patient_id"))
// Store in context
Set context.MetaData = dynObj
Click OK to close the editor, then click Save and Compile. Ensure that no errors appear before moving forward.
3D. Add the Process to Production
Go back to the production canvas. Click Add in the Processes section:
-
Process Class:
Demo.HL7Router -
Process Name:
HL7Router -
Description:
BPL process that builds dynamic objects before routing - Enable Now: Checked
Click OK.
Before starting the production, make sure that the following steps are complete:
1. Set Business Service Target
Click on HL7FileService in the production canvas. Confirm Target Config Names is set to HL7Router. If not, type HL7Router and click Apply.
2. Enable All Components
Confirm the Enabled checkbox is marked off for the following:
HL7FileServiceHL7RouterMsgRouterHL7FileOperation
How It All Fits Together
It is worth pausing here to understand the full flow before we start testing:
-
HL7FileServicepicks up the.hl7file from the incoming folder and parses it into anEnsLib.HL7.Message. It forwards the message toHL7Routerbased on the Target Config Names setting. -
HL7Routerruns theBuild Dynamic ObjectCode activity, stores the enriched object incontext.MetaData, and then callsMsgRouterusingSendRequestAsync.MsgRouterevaluates the routing rule and sends the message toHL7FileOperation. -
HL7FileOperationwrites the routed message to the outgoing folder.
Step 4: Start the Production and Test
Start the production. All components should show green status indicators.
The Sample HL7 Message
Create the test file using the IRIS terminal to ensure correct segment separators:
Set file = ##class(%File).%New("C:\hl7\in\test1.hl7")
Do file.Open("NWS")
Set content = "MSH|^~\&|SENDING_APP|SENDING_FAC|RECEIVING_APP|RECEIVING_FAC|20250315143022||ADT^A01|MSG00001|P|2.5" _ $Char(13)
Set content = content _ "EVN|A01|20250315143022" _ $Char(13)
Set content = content _ "PID|1||MRN001^^^HOSP||Smith^John^M||19850101|M|||123 Main Street^^Lahore^Punjab^54000^PK||03001234567" _ $Char(13)
Set content = content _ "PV1|1|I|WARD-A^Room101^Bed1|E|||DOC001^Smith^James|||SUR|||||||V01|ACC001" _ $Char(13)
Do file.Write(content)
Do file.Close()
Write "File created", !
(Remember to replace C:\hl7\in\ with your actual incoming folder path.)
Verify in Message Viewer and Visual Trace
Within 5 seconds, the adapter picks up the file. Go to Management Portal > Interoperability > View > Messages.
Click the message to open the Visual Trace. You will see the complete flow:
-
HL7FileServicereads the file. -
HL7Routerprocesses it and builds the dynamic object. -
MsgRouterevaluates the routing rule. -
HL7FileOperationwrites the output file.
Common Mistakes
Not defining context properties upfront: If you try to set context.MetaData without first declaring it in the Context tab, IRIS will throw PROPERTY DOES NOT EXIST at runtime. Always define all context properties before writing any code.
Setting the Target Config Names after adding the process: If you add HL7Router to production but forget to update HL7FileService Target Config Names to point to it, messages will bypass HL7Router entirely and go directly to MsgRouter. Always confirm the target after adding a new component.
Practical Recommendations
- Always define all context properties in the Context tab before writing any Code activity logic.
- Log every dynamic object property immediately after setting it during development; this is the fastest way to confirm values are correct before testing the routing rule.
- Keep the dynamic object lean by only storing values you actually need downstream.
FAQ
Q: Do I need a dynamic object if I can pass the HL7 message directly to the routing rule?
A: Simple property names (e.g., context.MetaData.MsgType = "ADT") work well and get evaluated correctly. However, properties with underscores in their names do not work reliably in the rule expression editor. Extract those values into typed context variables in the Code activity and evaluate them in the rule instead.
Q: Why does my Code activity compile but fail at runtime with PROPERTY DOES NOT EXIST?
A: This happens when you reference a context property that was not declared in the Context tab. Go to the Context tab, add the missing property, and recompile.
Q: Can I use %DynamicObject properties directly in a routing rule condition?
A: Simple property names work context.MetaData.MsgType = "ADT" evaluates correctly. Properties with underscores in their names do not work reliably in the rule expression editor. Extract those values into typed context variables in the Code activity and evaluate those in the rule instead.
Q: What happens if I forget to call Compile after editing the BPL?
A: The production will run the previous compiled version of the class. Your changes will not take effect until you compile. Always compile after every code change and confirm there are no errors before testing.
Q: Can I store a nested object inside a %DynamicObject?
A: Yes. You can set a nested %DynamicObject as a property value using %Set(). However, to access nested properties, you should get the nested object first. (It will be covered in detail in Part 2.)
What Is Coming in Part 2
Part 1 covered building and using a %DynamicObject inside a BPL Business Process. Part 2 will use the same production but add a second Code activity that will demonstrate seven real-world property-access pitfalls.
Conclusion
Dynamic objects are a practical tool that enriches HL7 messages with metadata before routing decisions are made. The key is to build them in a BPL Code activity, logging every property during development, and storing them in context variables that downstream components can evaluate cleanly.
The production we built in this article gives you a working foundation to experiment with. Try adding more properties to the dynamic object, or update the routing rule condition to evaluate context.MetaData.MsgType directly and see how it behaves. In the next article in this series, we will take this exact production and break down seven real-world property-access pitfalls every developer encounters when working with %DynamicObject in production integrations.
Thanks for reading!












Top comments (0)