Integrating with Outbound Broker web services for Initiate Patient V9.2

Connecting patient information

IBM Initiate® Patient is an industry-leading Enterprise Master Patient Indexing (EMPI) product. This article explores Outbound Broker, an integration feature of Initiate Patient that allows it to send notifications about events within the hub to external systems. It demonstrates how Outbound Broker can be implemented in a web services framework.

Jeremy Kohansimeh (jkohans@us.ibm.com), Senior Consultant, IBM Software Services for WebSphere, Healthcare and Life Sciences Practice, IBM

Jeremy KohansimehJeremy Kohansimeh has experience leading small teams to deliver solutions around patent analytics for drug discovery, clinical information systems to manage quality of care, and health information exchanges.



04 August 2011

Also available in Chinese

Overview

IBM recently acquired Initiate, a company that specializes in master data management (MDM) for the healthcare industry. Its flagship product, Initiate Patient, provides many advanced and industry-leading capabilities around Enterprise Master Patient Indexing (EMPI). EMPI is used in healthcare settings to identify when different patient records refer to the same person. This functionality is critical in establishing a comprehensive view of a patient — to create a longitudinal health record compiled from their treatments at different facilities, for example. It forms the basis for most Health Information Exchange (HIE) implementations.

There are several approaches to integrating Initiate Patient with the systems of a healthcare enterprise. A feature often needed when doing so is to be able to asynchronously notify external systems of events that happen within Initiate, so they are able to perform appropriate reconciliation actions. Initiate's Message Broker Suite comes with an Outbound Broker component, which can be configured to hook into specific events within the Initiate hub and send messages notifying external systems when they happen.

This article covers a new feature of Outbound Broker that allows notifications to external systems to be sent as web services, using SOAP messages over HTTP. Previous to the availability of this enhancement, notifications could only be sent over TCP sockets, making integration with web-based systems more complex. This form of socket communication worked well for earlier healthcare systems that operate on HL7 V2 messaging, which is implemented as LLP over TCP/IP. However, with the introduction of HL7 V3 messaging standards, commonly implemented as web services with SOAP over HTTP, more modern healthcare systems will have the need to be integrated using web-based technologies.

The article assumes you have a basic understanding of Initiate Patient and its data constructs.


System prerequisites

To carry out the instructions and examples in this article, you should have the following installed:

  • Initiate Patient V9.2.x
  • Initiate Message Broker Suite V9.2.0.178 or later
  • WebSphere® Application Server V6.1 or equivalent servlet container

Outbound Broker overview

A general overview of Outbound Broker is outlined in this section. More specific implementation details are well covered in the Message Broker documentation.

After installing the Message Broker Suite, the hub is ready to participate in broadcasting events to external systems. When an Outbound Broker instance is being set up, there are four specific events it can be configured to hook into. As selected events happen within the hub, a series of steps will be triggered, culminating in a message about the event being sent to an external system. The format of a message, as well as its contents, is able to be configured based on the needs of each Outbound Broker instance. There also are several options for the message transport, which include TCP, SSL, and SOAP, over HTTP.

The four events for which an Outbound Broker instance can be configured to listen are:

  • Add Member — Triggers when a new member is added to Initiate
  • EID Updates — Triggers when the entity to which a member belongs is changed
  • Has Shadow — Triggers when a member attribute has been changed through Initiate Inspector and requires a confirmation from the source system in order to be moved to active
  • PreMerge — Triggers when a potential duplicate task in Inspector has been resolved by merging two member records and requires a confirmation from the source system so one of the members can be made obsolete

There are two services installed for each Outbound Broker instance created. The Outbound Broker service puts the message onto the outbound queues when triggering events happen within the hub. The Message Sender service is responsible for picking up messages from the outbound queues and delivering them to the appropriate external system. The Message Sender will then await acknowledgement — a confirmation or rejection from the external system — to decide if it will move the message onto the success or reject queue.


Real-world example

The steps involved in setting up and integrating an Outbound Broker instance with a web-based system will be illustrated through a common scenario. A healthcare enterprise has built a Java™ EE-based application that needs to be notified when a patient record has been added into the Initiate hub so its internal representation of the patient record can be populated with a link to the hub's record. Please note that this illustrates just one approach in integrating Initiate with an external system. Alternative architectures exist and should be evaluated with an expert based on all available information.

For this example, there are a couple of things that will need to be put together. The first is an Outbound Broker instance which will send web services messages using SOAP over HTTP when new members are added to the hub. The second is an endpoint for the Java-EE based application that will be able to receive and process the messages being sent by the instance's Message Sender. If a TCP socket-based approach is chosen as the messaging transport for the instance, a separate adapter component would need to be built to transform the raw socket messages into HTTP transport ones that can be consumed by the web-based application.

Below is an outline of the key steps to integrate the two systems:

  1. Install the Message Broker Suite (if not already installed). Please refer to the Message Broker documentation for detailed instructions.
  2. Create a data source. Please refer to the Message Broker documentation for detailed instructions.
  3. Create an outbound instance that will notify an external system when a member is added to the hub. Please refer to the Message Broker documentation for detailed instructions. Pay close attention to the following options referred to in the documentation:
    • Sending host name — The hostname of the external system
    • Sending port number — The port over which HTTP communication will happen with the external system
    • Enter y when asked if the Message Sender will be calling a web service
      • For the To URL option, type the complete URL endpoint to the servlet that will receive messages from the Message Sender
    • For the message type option, type xml
    • Enter y when asked to create a message when a member is added to the hub
  4. After creating an outbound instance, it will need to be configured so the right data is included in messages that are sent. This is done by editing the OutboundEIDAddXML.ini configuration file in the config_<instance name> directory of the outbound instance home. Among other things, this file specifies the data that will be included in messages to external systems from the Message Sender. An excerpt from a simple example, which includes basic demographic information, is provided in Listing 1. A corresponding example message to illustrate how the configuration directs message creation is shown in Listing 2. Please note that the example configuration may need to be edited to match the data names in your hub.
    Listing 1. Excerpt from configuration file
    [Global-Data]
    
    0||MSGHEADER||||||
    	evtType||ADD|/EmpiMsg/MsgHeader/evtType
    	evtId|||/EmpiMsg/MsgHeader/evtId
    	evtInitiator|||/EmpiMsg/MsgHeader/evtInitiator
    	evtCtime|||/EmpiMsg/MsgHeader/evtCtime
    
    1||MEMHEAD||||||
    	srcCode|||/EmpiMsg/Member/MemHead/srcCode
    	memIdnum|||/EmpiMsg/Member/MemHead/memIdnum
    	entRecno|||/EmpiMsg/Member/MemHead/entRecno
    
    2||MEMNAME|PATNAME|||||
    	recStat|||/EmpiMsg/Member/MemName[attrCode="PATNAME"][@deleteInd]
    	onmFirst|||/EmpiMsg/Member/MemName[attrCode="PATNAME"]/onmFirst
    	onmMiddle|||/EmpiMsg/Member/MemName[attrCode="PATNAME"]/onmMiddle
    	onmLast|||/EmpiMsg/Member/MemName[attrCode="PATNAME"]/onmLast
    	onmPrefix|||/EmpiMsg/Member/MemName[attrCode="PATNAME"]/onmPrefix
    	onmSuffix|||/EmpiMsg/Member/MemName[attrCode="PATNAME"]/onmSuffix
    	onmDegree|||/EmpiMsg/Member/MemName[attrCode="PATNAME"]/onmDegree
    	onmTitle|||/EmpiMsg/Member/MemName[attrCode="PATNAME"]/onmTitle
    Listing 2. Sample outbound broker message
    <?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
    <!DOCTYPE EmpiMsg SYSTEM "initiate.dtd">
    <EmpiMsg>
    	<MsgHeader>
    		<evtType>ADD</evtType>
    		<evtId>103-466</evtId>
    		<evtInitiator></evtInitiator>
    		<evtCtime>20110222133649</evtCtime>
    	</MsgHeader>
    	<Member>
    		<MemHead>
    			<srcCode>OUTP</srcCode>
    			<memIdnum>1782^^^&2.16.840.1.113883.3.18.104&ISO</memIdnum>
    			<entRecno>205</entRecno>
    		</MemHead>
    		<MemName>
    			<attrCode deleteInd="A">PATNAME</attrCode>
    			<onmFirst>Blake</onmFirst>
    			<onmMiddle></onmMiddle>
    			<onmLast>Griffin</onmLast>
    			<onmPrefix></onmPrefix>
    			<onmSuffix></onmSuffix>
    			<onmDegree></onmDegree>
    			<onmTitle></onmTitle>
    		</MemName>
    	</Member>
    </EmpiMsg>
  5. The simplest way to set up a web services endpoint for SOAP over HTTP in Java EE is to hand-code a servlet that parses the SOAP payload and accordingly processes it. A more sophisticated approach would be to use the web services tooling available in your favorite Java EE IDE to auto-generate code that will perform the message unmarshalling into Java objects.
  6. A sample SOAP message is needed to fully implement the servlet endpoint. One way to obtain this is to start out your servlet implementation by coding just an endpoint that echoes whatever SOAP messages it is sent. From there, you can build up your code to parse and further process the message.
  7. In order for messages to be sent to the endpoint, the Outbound Broker service and the Message Sender service corresponding to the instance will need to be started. Note that the first time these are started, a message will be sent for each member that exists in the hub. After that, messages will only be sent when a new member is added.
  8. A sample servlet implementation that uses XPath to parse the data out of the incoming message is shown in Listing 3. It includes an example of the XML response that notifies the Message Sender that a message was successfully processed and causes the Message Sender to move the message onto the success queue.
    Listing 3. Servlet implementation
    package com.ibm.initiate.broker.sample;
    
    import java.io.IOException;
    import java.util.Enumeration;
    import java.util.logging.Logger;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.xml.soap.MessageFactory;
    import javax.xml.soap.MimeHeaders;
    import javax.xml.soap.SOAPBody;
    import javax.xml.soap.SOAPConstants;
    import javax.xml.soap.SOAPEnvelope;
    import javax.xml.soap.SOAPException;
    import javax.xml.soap.SOAPFault;
    import javax.xml.soap.SOAPHeader;
    import javax.xml.soap.SOAPMessage;
    import javax.xml.soap.SOAPPart;
    import javax.xml.xpath.XPath;
    import javax.xml.xpath.XPathConstants;
    import javax.xml.xpath.XPathExpressionException;
    import javax.xml.xpath.XPathFactory;
    
    public class MemberAddedEndpoint extends HttpServlet 
    {
      private static final long serialVersionUID = 1L;
      
      private static final String CLASS_NAME = MemberAddedEndpoint.class.getName();
      private static Logger logger = Logger.getLogger(CLASS_NAME);
      
      private static final String CONTENT_TYPE_XML = "text/xml";
      private static final String CHAR_ENCODING_UTF_8 = "utf-8";
      
      // success Ack message for Outbound Broker Sender
      private static final String OUTBOUND_ACK_MSG =
    "<EmpiResp><MsgHeader><code>ok</code></MsgHeader></EmpiResp>";
      
      private static final String XPATH_PREFIX_MEMBER = "//EmpiMsg/Member";
      
      private static final String XPATH_PREFIX_MEMHEAD = 
        XPATH_PREFIX_MEMBER + "/MemHead";
      private static final String XPATH_SRCCODE = XPATH_PREFIX_MEMHEAD + "/srcCode";
      private static final String XPATH_MEMIDNUM = XPATH_PREFIX_MEMHEAD + "/memIdnum";
      private static final String XPATH_ENTRECNO = XPATH_PREFIX_MEMHEAD + "/entRecno";
      
      private static final String XPATH_PREFIX_MEMNAME = 
        XPATH_PREFIX_MEMBER + "/MemName";
      private static final String XPATH_FIRSTNAME = XPATH_PREFIX_MEMNAME + "/onmFirst";
      private static final String XPATH_MIDDLENAME = XPATH_PREFIX_MEMNAME + "/onmMiddle";
      private static final String XPATH_LASTNAME = XPATH_PREFIX_MEMNAME + "/onmLast";
      private static final String XPATH_NAMESUFFIX = XPATH_PREFIX_MEMNAME + "/onmSuffix";
      
      public MemberAddedEndpoint() {
        super();
      }
        
      protected void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException 
      {
        // TODO Auto-generated method stub
      }
      
      protected void doPost(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException 
      { 
        MessageFactory messageFactory = null;
        SOAPMessage responseMsg = null;
        
        try {
          messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
          SOAPMessage soapMsg = 
            messageFactory.createMessage( getMimeHeaders( request), 
                                          request.getInputStream());
          
          SOAPBody body = soapMsg.getSOAPBody();
          logger.fine(
            "Received SOAP Message from Initiate Outbound Broker for Member Add: " 
            + body);
          
          // just parses message data and emits to log file
          // this is where business logic for the endpoint could be implemented
          displayParsedMessageData( body);
          responseMsg = messageFactory.createMessage();
            
          response.setContentType(CONTENT_TYPE_XML);
          response.setCharacterEncoding(CHAR_ENCODING_UTF_8);
    
          // send HTTP OK & custom XML message Ack back to Outbound Broker sender
          response.setStatus( HttpServletResponse.SC_OK);
          response.getWriter().write( OUTBOUND_ACK_MSG);
        } catch ( Exception e) {
          try {
            // send HTTP error and SOAPFault back to Outbound Broker sender
            addSOAPFault(responseMsg);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 
                               responseMsg.toString());
          } catch (SOAPException soape) {
            // couldn't generate SOAPFault, so just send HTTP error back to sender
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
          }
          
          logger.severe( "An unexpected error occurred: " +  e.getLocalizedMessage());
          e.printStackTrace();
        } 
      }
      
      private void displayParsedMessageData( SOAPBody body)
      throws XPathExpressionException
      {
        StringBuffer buff = new StringBuffer();
        
        buff.append( "Message received with contents: [");
        buff.append( "Member ID Number=").append( getDataValue(body,XPATH_MEMIDNUM));
        buff.append( ", Entity Record Number=").append( 
                                                  getDataValue(body,XPATH_ENTRECNO));
        buff.append( ", Source Code=").append( getDataValue(body,XPATH_SRCCODE));
        buff.append( ", First Name=").append( getDataValue(body,XPATH_FIRSTNAME));
        buff.append( ", Last Name=").append( getDataValue(body,XPATH_LASTNAME));
        buff.append( "]");
        
        logger.info(buff.toString());
      }
      
      private String getDataValue( SOAPBody body, String xpathExpr) 
      throws XPathExpressionException
      {
          XPathFactory factory = XPathFactory.newInstance();
          XPath xpath = factory.newXPath();
          
          String value = null;
          
          Object result = xpath.evaluate( xpathExpr, body, XPathConstants.STRING);
          if ( result != null) {
            value = result.toString();
          }
          
          return value;
      }
      
      private MimeHeaders getMimeHeaders( HttpServletRequest request)
      {
        MimeHeaders mimeHeaders = new MimeHeaders();
        Enumeration mimeHeaderNames = request.getHeaderNames();
        
        String headerName = "";
        String headerVal = "";
        
        while (mimeHeaderNames.hasMoreElements()) {
          headerName = (String)mimeHeaderNames.nextElement();
          headerVal = request.getHeader(headerName);
          mimeHeaders.addHeader(headerName, headerVal);
        }
        
        return mimeHeaders;
      }
      
      private void addSOAPFault( SOAPMessage msg)
      throws SOAPException
      {
          SOAPPart part = msg.getSOAPPart();
          SOAPEnvelope env = part.getEnvelope();
          SOAPHeader head = msg.getSOAPHeader();
          SOAPBody body = msg.getSOAPBody();
          
          head.detachNode();
          SOAPFault soapFault = body.addFault();
          soapFault.addNamespaceDeclaration(env.getPrefix(), env.getNamespaceURI());
          soapFault.setFaultCode(env.createName("Receiver", 
                                                env.getPrefix(),env.getNamespaceURI()));
          
          String faultMsg = 
               "System is unable to process the Initiate Outbound Broker Message";
          soapFault.setFaultString(faultMsg);
          soapFault.setFaultActor("Add Member Outbound Broker Endpoint");
      }
    }

Tips and tricks

It's often useful to be able to send messages from the hub without actually adding a new member into it, which can sometimes be a time-consuming activity. There's a simple way to do this. Run the following SQL statement from inside your hub database:

update mpi_eidtrigger_<entity name> 
	set complete = 0 
	where memrecno = <existing member’s MemRecNo>

To better debug issues within the outbound instance, the level of logging can be independently turned up for both the Outbound Broker and Message Sender. This is done by editing the section of the services.ini file corresponding to the service whose level of logging you want to increase. Setting MAD_TRACE=1 will cause the most verbose level of logging to be enabled, and MAD_DEBUG is the next highest. Increasing the level of logging will cause performance to degrade because of the additional I/O operations that need to be coordinated to write to the log files. For this reason, trace and debug logging levels should be cautiously used in a production environment. The location of the services.ini file is configured by the MAD_CONFNAME environment variable. The log files for each of the services are themselves located in the log directory of the outbound instance home.

There are three queues used to process messages that are sent to external systems. The input, success, and failure queues are all maintained on the file system through a series of interrelated files. They are located in the data/interface/outbound_<instance name> directory of the instance home. In order to flush the queues, the Outbound Broker and Message Sender services should be stopped, then all the files in the directory can be safely deleted. Further details on how the queues work are very well covered in the Message Broker documentation.

There was a bug that has been fixed in V9.2.0.178 of the Message Broker Suite, which caused problems with the length of time a Message Sender would wait to receive acknowledgment from external systems. All Message Senders performing web services messaging would only wait one second, and if they did not receive a success acknowledgement within that time, messages would be retried and eventually moved onto the failure queue. This has been fixed, and the length of time a Message Sender will wait for acknowledgement from an external system can now be configured by adjusting the MAD_SOTIMEOUT setting in its corresponding section of the services.ini file.


Summary

Included with later version of Initiate Outbound Broker is the capability to send web services messages using SOAP over HTTP. This new functionality enables a more seamless integration with web-based systems than was previously supported through TCP socket communication:

  • See Listing 1 for Excerpt from sample Outbound Broker configuration file.
  • See Listing 2 for Sample XML message sent from Outbound Broker.
  • See Listing 3 for Example Java Servlet endpoint to receive Outbound Broker messages.

Resources

Learn

Get products and technologies

  • Build your next development project with IBM trial software, available for download directly from developerWorks.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Information management on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Information Management, SOA and web services
ArticleID=749952
ArticleTitle=Integrating with Outbound Broker web services for Initiate Patient V9.2
publish-date=08042011