Search code examples
apache-camelnettyhl7

How to generate a custom ack with apache camel hl7


I am trying to set up an mllp listener for hl7v2.x messages using camel.

My environment

  • apache camel and components version 2.18.3

Also I would like to avoid the use of the HAPI library, as I prefer a custom parser for the received and generated messages. As my clients are each one using different versions of the standard and really different fields usage.That's why there is no unmarshalling to the hl7 datatype in the following route, just to string. I'll do the parser myself.

And my route (all the beans and variables are defined elsewhere in the code, I think they are not relevant)

from("netty4:tcp://0.0.0.0:3333?
encoder=#encoderHl7&decoder=#decoderHl7&sync=true")
.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") 
.unmarshal().string()
.to("file://" + rutaSalidaFichero)
;

First, as a prove of concept, I am just trying to copy all the messages received into a file system directory. The messages are correctly received and wrote to the directory. But I do not know how to generate and send the ACK, an incorrect one is being automatically generated and sended.

If I send a hl7 message from an outer/sending system, the camel component send the same message as the ack, so the sending system sends an error in return as it is not the ack expected. I am sending the hl7 message using mirth, dcm4chee, hapi ... all of then with the same result.

For instance, if I send the following message from an outer/sender system MSH|^~\&|LIS|LIS|HIS|HIS|20170412131105||OML^O21|0000000001|P|2.5|||AL|||8859/1|||1.0 PID|1||123456||APELLIDO1&APELLIDO2^NOMBRE|19200101 ORC|RP|009509452919|317018426||||||20170412000000 OBR|1|317018426|317018426|CULT^CULTIVO

I received the same as the ack in the sending system. This is the camel generating the ack as the receiving message MSH|^~\&|LIS|LIS|HIS|HIS|20170412131105||OML^O21|0000000001|P|2.5|||AL|||8859/1|||1.0 PID|1||123456||APELLIDO1&APELLIDO2^NOMBRE|19200101 ORC|RP|009509452919|317018426||||||20170412000000 OBR|1|317018426|317018426|CULT^CULTIVO

I have not found in the camel docs references to the generation of the ack, or if I can use a custom "something" to generate it. I would like to change this default behaviour.


Solution

  • As camel hl7 component docs says (http://camel.apache.org/hl7.html, "HL7 Acknowledgement expression") you can generate default ack just by using

    import static org.apache.camel.component.hl7.HL7.ack;
    ...
    
       from("direct:test1")
          // acknowledgement
          .transform(ack())
    

    Here "ack()" is a call for "org.apache.camel.component.hl7.HL7#ack()". But you can check that "org.apache.camel.component.hl7.HL7" contains some other helpful methods like

    org.apache.camel.component.hl7.HL7#ack(ca.uhn.hl7v2.AcknowledgmentCode code)
    

    or

    org.apache.camel.component.hl7.HL7#ack(ca.uhn.hl7v2.AcknowledgmentCode code, java.lang.String errorMessage, ca.uhn.hl7v2.ErrorCode )
    

    You can use them to customise the actual ACK response. If we will go deeper then you can see that "org.apache.camel.component.hl7.HL7#ack" are just wrappers for

    new ValueBuilder(new AckExpression(...))
    

    and most params from "ack" methods are going directly to the org.apache.camel.component.hl7.AckExpression. Actual ACK generation is done in "org.apache.camel.component.hl7.AckExpression#evaluate" and looks like

    public Object evaluate(Exchange exchange) {
            Throwable t = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class);
            Message msg = exchange.getIn().getBody(Message.class);
            try {
                HL7Exception hl7e = generateHL7Exception(t);
                AcknowledgmentCode code = acknowledgementCode;
                if (t != null && code == null) {
                    code = AcknowledgmentCode.AE;
                }
                return msg.generateACK(code == null ? AcknowledgmentCode.AA : code, hl7e);
            } catch (Exception e) {
                throw ObjectHelper.wrapRuntimeCamelException(e);
            }
        }
    

    If you want deeper customization you can just write your own MyCustomAckExpression which will extend org.apache.camel.component.hl7.AckExpression and implement required logic instead of

    return msg.generateACK(code == null ? AcknowledgmentCode.AA : code, hl7e);
    

    and use it like

    ...
    
       from("direct:test1")
          // acknowledgement
          .transform(new ValueBuilder(new MyCustomAckExpression()))