Sunday, 12 October 2014

Oracle Healthcare Transport Callout

 

Recently I’m involved in a Healthcare project where Oracle SOA Suite for Healthcare is being used , its cool one and easy to configure though have some limitation like explained below,

Say you are passing input message like below to an inbound SSHI endpoint where message type support has ADT 2.3.1.   For simplicity I’m using Oracle provided SSHI sample available at https://java.net/projects/oraclesoasuite11g/pages/HealthCare.

MSH|^~\&|Admission APP|Admission FAC|MyCompany APP|MyCompany FAC|20050804162010||ADT^A04|001|P|2.3.1|||AL|ER|US|ASCII|ENG
PID|||387044045||Griffin^Leo^A||20140425103329|F||||||||||309563956
OBR|1|6654831.001SAH|6654831.001SAH|POR.ABD1^PORTABLE ABDOMEN SINGLE VIEW|||201404220104|||||||||||CR^R20140422-0008|SAH^CR||||||2|1|1
OBX|1|RP|||
http://10.90.0.2/EMR/Event.asp?xyz=Study&forLoginName=test&forAccession=6654831.001SAH&forPatientPublicID=952523||||||F
OBX|2|TX|EventType

If you carefully notice MSH segment it has & as subcomponent separator. So the web URL at OBX|1| will be treated as sub –component by SSHI as it has & within URL http://10.90.0.2/EMR/Event.asp?xyz=Study&forLoginName=test&forAccession=6654831.001SAH&forPatientPublicID=952523.

So this URL is becoming http://10.90.0.2/EMR/EventInterface.asp?fun=ShowStudy^forLoginName=migdemo^forAccession=6654831.001SAH^forPatientPublicID=927952523 at output wire message of SSHI which is NOT desirable. Here transport callout come as handy and it will play a role before the translation of the message for inbound scenario and after the translation of message for outbound scenario. For more details on how transport callout works in Oracle Healthcare you care refer to Oracle doc at http://docs.oracle.com/cd/E23943_01/user.1111/e23486/hcfp_callouts.htm.

Note this transport callout works only in Linux box and does NOT work in windows system.

Here is one of the high level solution for this problem,

  1. Need java API to parse the HL7 message , in our case I’ve used HAPI API available at http://hl7api.sourceforge.net/.
  2. Replace the special char like & [which essentially one of the delimiter in MSH segment] with some predefined char , in our case I’ll replace & with +.
  3. Process the inbound message and do the transformation , if needed, at SOA layer and hit the outbound SSHI endpoint.
  4. Add a transport callout in outbound SSHI which will replace back + with & , just exactly reverse of step 1.

Lets go through in more details.

Fist pick up any sample healthcare code from Oracle site , I took 2nd one as seen below,

image

Now verify the output message of Out_Patient_Laboratory with the input message I pasted above.

Now write a java code for transport callout like below,for inbound class name is EscapeSpecialCharacters and code like below,

import ca.uhn.hl7v2.DefaultHapiContext;
import ca.uhn.hl7v2.HapiContext;

import java.io.FileWriter;

import java.util.*;

import oracle.tip.b2b.callout.*;
import oracle.tip.b2b.callout.exception.*;

import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.parser.Parser;
import ca.uhn.hl7v2.util.Terser;

public class EscapeSpecialCharacters implements Callout {
    public void execute(CalloutContext context, List input,
                        List output) throws CalloutDomainException,
                                            CalloutSystemException {
        try {
            CalloutMessage cmIn = (CalloutMessage)input.get(0);
            String inHL7Msg = cmIn.getBodyAsString();

            String v23message =
                inHL7Msg.replaceAll("\n", "\r").replaceFirst("&", "#");

            HapiContext hapiContext = new DefaultHapiContext();
            Parser parser = hapiContext.getGenericParser();
            Message msg = parser.parse(v23message);

            Terser t23 = new Terser(msg);
            //System.out.println(t23.get("/MSH-10"));
            //System.out.println(t23.get("/PID-8"));
            //System.out.println(t23.get("/OBX-5").replaceAll("&", "+"));
            t23.set("/OBX-5", t23.get("/OBX-5").replaceAll("&", "+"));

            FileWriter fw =
                new FileWriter("/oracle/fmwhome/user_projects/domains/dev_soasuite/servers/AdminServer/logs/callout_in.txt");
            fw.write(msg.encode().replaceFirst("#", "&"));
            fw.close();

            CalloutMessage cmOut =
                new CalloutMessage(msg.encode().replaceFirst("#", "&"));

            output.add(cmOut);

        } catch (Exception e) {
            throw new CalloutDomainException(e);
        }
    }
}

You need to have b2b.jar and HAPI library in class-path for successful compilation. You can see here I’m parsing through HL7 message and using Tarser I’m retrieving the value of first OBX-5 and replacing all & of web url with +. All the segment list where special chars are appearing you can pass on as a parameter of callout and can make the program more generic.

For outbound AHOutboundCallout class just does the opposite thing,

import java.io.FileWriter;

import java.util.*;

import oracle.tip.b2b.callout.*;
import oracle.tip.b2b.callout.exception.*;

public class AHOutboundCallout implements Callout {
    public void execute(CalloutContext context, List input, List output) throws CalloutDomainException, CalloutSystemException {
        try {
            CalloutMessage cmIn = (CalloutMessage)input.get(0);
            String inHL7Msg = cmIn.getBodyAsString();
            StringBuffer outputMessage =
                new StringBuffer(inHL7Msg.length());
            outputMessage.append(inHL7Msg);
            String v23message=outputMessage.toString().contains("+")? outputMessage.toString().replace("+", "&"):outputMessage.toString();
            FileWriter fw = new FileWriter("/oracle/fmwhome/user_projects/domains/dev_soasuite/servers/AdminServer/logs/callout_out.txt");
            fw.write(v23message);
            fw.close();

            CalloutMessage cmOut =
                new CalloutMessage(v23message);
            output.add(cmOut);

        } catch (Exception e) {
            throw new CalloutDomainException(e);
        }
    }
}

You might have noticed in both the cases I’m writing input and output message at callout_in.txt and callout_out.txt for verification.

Now create a callout in Healthcare after deploying the above class in jar profile . Keep all the HAPI API related jar in domain home/lib directory.

Now for inbound SSHI endpoint , Out_Patient_Admission, associate the class like below,

image

For outbound SSHI endpoint Out_Patient_Laboratory , associate the class like below,

image 

Now its time to test the solution, I’m using HAPI HL7 tester to push the message ,

image

Now verify the callout_in.txt and callout_out.txt and transport callout parameters.

callout_in.txt

MSH|^~\&|Admission APP|Admission FAC|MyCompany APP|MyCompany FAC|20050804162010||ADT^A04|001|P|2.3.1|||AL|ER|US|ASCII|ENG
PID|||387044045||Griffin^Leo^A||20140425103329|F||||||||||309563956
OBR|1|6654831.001SAH|6654831.001SAH|POR.ABD1^PORTABLE ABDOMEN SINGLE VIEW|||201404220104|||||||||||CR^R20140422-0008|SAH^CR||||||2|1|1
OBX|1|RP|||
http://10.90.0.2/EMR/EventInterface.asp?fun=ShowStudy+forLoginName=migdemo+forAccession=6654831.001SAH+forPatientPublicID=927952523||||||F
OBX|2|TX|EventType^EventType|1|StudyCompleted
OBX|3|CN|Technologist^Technologist|1

callout_out.txt

MSH|^~\&|Admission APP|Admission FAC|MyCompany APP|MyCompany FAC|20050804162010||ADT^A04|001|P|2.3.1|||AL|ER|US|ASCII|ENG
PID|||387044045||Griffin^Leo^A||20140425103329|F||||||||||309563956
OBR|1|6654831.001SAH|6654831.001SAH|POR.ABD1^PORTABLE ABDOMEN SINGLE VIEW|||201404220104|||||||||||CR^R20140422-0008|SAH^CR||||||2|1|1
OBX|1|RP|||
http://10.90.0.2/EMR/EventInterface.asp?fun=ShowStudy&forLoginName=migdemo&forAccession=6654831.001SAH&forPatientPublicID=927952523||||||F
OBX|2|TX|EventType^EventType|1|StudyCompleted
OBX|3|CN|Technologist^Technologist|1

So it’s working as expected. Note, in wire message you might see still + for web URL , this is because transport callout happen just before delivering the message to the endpoint.

You can make the program more generic by adding parameters to the transport callout.