Custom Message Handlers

Previous  Top  Next

ADVANCED FEATURE:

 

First implemented in Version 3.0 of the HL7 Multi-Destination Router is the ability to define a custom message handler ActiveX/Com object.  To configure the HL7 Multi-Router to use a custom message handler check the box marked 'Implement a custom message handler' in the 'Global Settings' panel and then enter the ActiveX/Com objects [ObjectName.ClassName] in the text box provided.  Clicking the 'Test' button will inform you whether the message handler is a valid multi-router plugin.

 

configuration window

 

What is a custom message handler?

 

A custom message handler allows you to create (or have created for you) a custom ActiveX/COM process that will be called from the EasyHL7 Multi-Router.  With your custom message handler you can override the default behavior of the Router service.  This can be useful if you need to:

 

1. Integrate your own message handling directly into the EasyHL7 Multi-Router. I.E. you want to manage individual message transmission without using a Listener.
2. Manipulate the contents of a message before transmission to the Listener.
3. Dynamically route messages to their destination based upon your own criteria (such as the 'Receiving Facility' MSH segment field).

 

To understand how to implement custom message handlers it is necessary to recap how the HL7 Multi-Router works without a custom message handler in place.  When operating without a custom message handler HL7 data flows like so:

 

example 1

example 1

 

 

When operating with a custom message handler the HL7 message data flows like so:

 

 

example 2

example 2

 

The COM Interface

 

It's not within the scope of this document to discuss "HOW TO" write and design ActiveX/COM objects.  That's why this feature is an 'advanced' feature.  If you are not a programmer, this section will probably not make sense to you.

 

When designing your custom message handler it MUST have the following interface:

 

It must be an ActiveX/COM object.  This means that the object must able to be created using the CreateObject() method implemented in MS VB and MS VB.Net.

 

It must contain the following Public Read/Write Properties:

 

IsError - Boolean  (0 = false, -1 = True)
LastError - VB String (BSTR for C#,C++ Programmers)

 

It must contain the following Public Methods:

 

ClearErrors() - No Parameters, no return value.  When called, it should set the IsError property to 0 and the LastError Property to ""
ProfileListInit(pv_sProfileNameList As String, ByVal pv_sProfileXML As String) - This method will be called by the Multi-Router each time the plug-in class is instantiated. The first parameter (pv_sProfileNameList) will contain a pipe-delimited (|) string of active profile names, the second parameter will contain the full configuration XML (see below). the employmen of this information is entirely at the disposal of the user. There is no return value.
ProcessMessage(ByRef pv_sMessage As String, ByVal pv_sOriginProfile As String) - This is the main processing method and the heart of the custom message handler.  It must return a VB String (BSTR for C#,C++ Programmers).  The parameters are:

 

1. pv_sMessage - VB String (BSTR for C#,C++ Programmers).  Will contain the entire HL7 message being pocessed by the Multi-Router service.
2. pv_sOriginProfile - VB String (BSTR for C#,C++ Programmers).  Will contain the default router profile name being used for this message.

 

The return value may contain either a valid profile name which, if different from the original profile, will cause the message to be re-routed using the returned profile settings. Alternatively, return the literal "ERROR" to indicate that further processing of the message is to be abandoned - the message will be sent to he error folder, or leave blank (ie., an empty string ("") to skip this message wih no further processing at all.

 

Design/Programming Notes:

 

The Multi-Router service will instantiate (create) the custom message handler when the service starts.  If an error occurs (i.e. the object cannot be created because it's not registered properly OR the object is created but the IsError property returns True (-1) immediately after creation) the service will immediately shut down.

 

Whenever the service receives an HL7 message it will do the following:

1. Call the ClearErrors() method of the object
2. Call the ProfileListInit() method of the object with the appropriate values.
3. Call the ProcessMessage() method, passing it the 2 parameters described above and saving the return value.
4. Check the IsError property of the object.  If it is True (-1), the Router will abandon further processing of he message.  Also the value of the LastError property will be written to the Multi-Router service log file.  If the IsError property is False (0) it will continue with step 5.
5. If the return value is a recognised profile name then the returned message will be sent to the listener using the returned profile settings. See the return value notes above for alternative processing.

 

A simple scenario:

 

In this example you want to re-route messages dynamically based upon the 'Receiving Facility' field of the MSH segment.

 

Your code could look like this (VB6 Notation). Note that we are using the EasyHL7 components to interrogate the message:

 

Public Function ProcessMessage(ByRef pv_sMessage As String, ByVal pv_sOriginProfile As String) As String

    

    Dim sReceivingFacility As String

    Dim oMSH As Object

    

    ' Note lack of error handling for clarity

    

    With MyMessageObj

        ' Bind the Vendor object to the message object

        .SetVendorObject MyVendorObj

        ' Load message object with the HL7 Message string

        .CreateFromHL7 pv_sMessage

        ' Get the MSH Segment

        Set oMSH = .GetSegment("MSH")

        ' Get the Receiving Facility

        sReceivingFacility = .GetFieldValue(oMSH, 4)

    End With

    

    ' In this example we will select the message destination based

    ' upon the Receiving Facility: all facilities except MEDICAN and HOSDEF will

    ' be re-routed to the XL5 Listener

    Select Case UCase(sReceivingFacility)

        Case "MEDICAN"

            ProcessMessage = pv_sOriginProfile

        Case "HOSDEF"

            ProcessMessage = pv_sOriginProfile

        Case Else

            ProcessMessage = "XL5 Listener"

    End Select

        

    Set oMSH = Nothing

    

End Function

 

 

Configuration XML Sample (See ProfileListInit)

 

<PROFILES ITEMCOUNT="2" MONITOR_PORT="6772" HAVE_ACTIVE_EXT_MSG_HANDLER="0" EXT_MSG_HANDLER_NAME="RouterMsgHandler.MsgHandler">

       <PROFILE PROFILE_NAME="Local Listener" IS_ACTIVE="True" 

               USE_REMOTE_ACK_PORT="False" ACK_PORT="0" ACK_PORT_STAYALIVE="True" 

               ACK_ADDRESS_TYPE="LOCAL" ACK_IP_ADDRESS="" ACK_COMPUTER_NAME="LOCAL" 

               STORE_ACK_METHOD="2" STORE_ARCHIVE_METHOD="2" STORE_ERROR_METHOD="2" 

               STORE_CONTROL_METHOD="0" MAX_LOG_SIZE="10" CONNECTIONTYPE="LOCAL" 

               COMPUTERNAME="HERETIC" IPADDRESS="" EOB="0x1C,0x0D" SOB="0x0B" 

               FOB="0x7C" ROB="0x0D" LISTEN_PORT="6660" ACK_TIMEOUT="300" TIMEOUT="300" 

               WAITFOR_ACK="NEVER" INBOX_EXTENSION="hl7" INBOX_FOLDER="D:\HL7_IN\Local\" 

               ARCHIVE_FOLDER="D:\HL7_IN\Local\Archive\" ERROR_FOLDER="D:\HL7_IN\Local\Errors\" 

               LOG_FOLDER="D:\HL7_IN\Local\ControlLogs\" 

               ACK_FOLDER="D:\HL7_IN\Local\Acknowledgements\" 

               POLLING_INTERVAL="10" POLLING_INCREMENT="SECONDS" 

               SLEEP_ENABLED="False" SLEEP_DURATION="1" SLEEP_BEGIN="12:00 AM" 

               STORE_ACK_MESSAGES="True" STORE_ARCHIVE_MESSAGES="True" 

               STORE_ERROR_MESSAGES="True" STORE_CONTROL_LOG="True" 

               ACK_ANYRESPONSEOK="False" ACK_PESSIMISTICNOACK="False" 

               KEEP_SOCKET_ALIVE="True" INTER_MESSAGE_DELAY="0" 

               EXT_MSG_HANDLER_IS_ACTIVE="True">

       </PROFILE>

       <PROFILE PROFILE_NAME="XL5 Listener" IS_ACTIVE="True" 

               USE_REMOTE_ACK_PORT="False" ACK_PORT="0" ACK_PORT_STAYALIVE="True" 

               ACK_ADDRESS_TYPE="COMPUTER" ACK_IP_ADDRESS="" ACK_COMPUTER_NAME="COMPUTER" 

               STORE_ACK_METHOD="2" STORE_ARCHIVE_METHOD="2" STORE_ERROR_METHOD="2" 

               STORE_CONTROL_METHOD="0" MAX_LOG_SIZE="10" CONNECTIONTYPE="COMPUTER" 

               COMPUTERNAME="Xl5" IPADDRESS="" EOB="0x1C,0x0D" SOB="0x0B" 

               FOB="0x7C" ROB="0x0D" LISTEN_PORT="6660" ACK_TIMEOUT="300" TIMEOUT="300" 

               WAITFOR_ACK="NEVER" INBOX_EXTENSION="hl7" INBOX_FOLDER="D:\HL7_IN\XL5\" 

               ARCHIVE_FOLDER="D:\HL7_IN\XL5\Archive\" ERROR_FOLDER="D:\HL7_IN\XL5\Errors\" 

               LOG_FOLDER="D:\HL7_IN\XL5\ControlLogs\" 

               ACK_FOLDER="D:\HL7_IN\XL5\Acknowledgements\" 

               POLLING_INTERVAL="10" POLLING_INCREMENT="SECONDS" 

               SLEEP_ENABLED="False" SLEEP_DURATION="1" SLEEP_BEGIN="12:00 AM" 

               STORE_ACK_MESSAGES="True" STORE_ARCHIVE_MESSAGES="True" 

               STORE_ERROR_MESSAGES="True" STORE_CONTROL_LOG="True" 

               ACK_ANYRESPONSEOK="False" ACK_PESSIMISTICNOACK="False" 

               KEEP_SOCKET_ALIVE="True" INTER_MESSAGE_DELAY="0" 

               EXT_MSG_HANDLER_IS_ACTIVE="False">

       </PROFILE>

</PROFILES>

 

 

 

EXAMPLE CODE TEMPLATES:

 

HermeTech provides some example templates for writing custom message handler DLLs.  They can be downloaded at the following URL:

 

     For MS Visual Basic 6 and VB.Net:

http://www.hermetechnz.com/EasyHL7/Examples

 

 

All of the examples use the HermeTech EasyHL7 ActiveX toolbox (it is not required that you do this) which you can download at www.hermetechnz.com

 

 

 


EasyHL7 Home Page