Wednesday, December 31, 2014

Transforming and Routing HL7 Messages with Camel

Introduction

I am highlighting the HL7 Camel component in one of this weeks Fuse Component Blogs.  We will give a brief introduction, a brief HL7 Component overview and then the HL7 Component Demo so you can easily run an example.
Health Level 7 (HL7) is a not-for-profit, ANSI-accredited standards developing organization dedicated to providing a comprehensive framework and related standards for the exchange, integration, sharing, and retrieval of electronic health information that supports clinical practice and the management, delivery and evaluation of health services.
An HL7 Interface Engine (a.k.a. Message Broker) is used to refer to a kind of middleware application which is used to transform, route, clone and translate HL7 messages.  The HL7 Component with Camel is perfect for using Fuse as a HL7 Interface Engine.  We give you an example of using the component in a Camel Route in our example.  The component works with v2 messages using the HAPI library which we will describe further below.  People who have worked with HL7 are normally familiar with the two versions so I wanted to give the main differences between the two.
HL7 V2 
  • Not “Plug and Play” – it provides 80 percent of the interface and a framework to negotiate the remaining 20 percent on an interface-by-interface basis
  • Historically built in an ad hoc way because no other standard existed at the time
  • Generally provides compatibility between 2.X versions
  • Messaging-based standard built upon pipe and hat encoding
  • In the U.S., V2 is what most people think of when people say “HL7″ 
HL7 V3 
  • Approaching “Plug and Play” – less of a “framework for negotiation”
  • Many decades of effort over ten year period reflecting “best and brightest” thinking
  • NOT backward compatible with V2
  • Model-based standard built upon Reference Information Model (RIM) provides consistency across entire standard
  • In the U.S., when Clinical Document Architecture (CDA) is what most people in the U.S. think of when people say “HL7 V3″
http://www.hl7standards.com/blog/2007/12/12/key-differences-between-hl7-v2-and-v3/  

 HL7 Camel Component Overview

The HL7 component is used for working with the HL7 MLLP protocol and HL7 v2 messages using the HAPI library.

This component supports the following:

  • HL7 MLLP codec for Mina
  • Type Converter from/to HAPI and String
  • HL7 DataFormat using the HAPI library
  • Even more ease-of-use as it's integrated well with the camel-mina2 component.
Maven users will need to add the following dependency to their pom.xml for this component:


<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-hl7</artifactId>
    <version>x.x.x</version>
</dependency>

HL7 is often used with the HL7 MLLP protocol, which is a text based TCP socket based protocol. This component ships with a Mina Codec that conforms to the MLLP protocol so you can easily expose an HL7 listener accepting HL7 requests over the TCP transport layer.


The HL7 component ships with a HL7 data format that can be used to marshal or unmarshal HL7 model objects.
  • marshal = from Message to byte stream (can be used when responding using the HL7 MLLP codec)
  • unmarshal = from byte stream to Message (can be used when receiving streamed data from the HL7 MLLP
You can find more information on the Camel component at http://camel.apache.org/hl7.html  Also on the HAPI site a HAPI Test Panel is available which is a full featured HL7 message editor, transmitter and receiver. 

Running the Demonstration

This example will run a HL7 message through a Camel Route to show how to easily use the HL7 component.  When the message is a ADT (Admission/Discharge/Transfer) Message as in the MSH segment and the MSH segment has the FUSEDEMO namespace then the PID (Patient Identifier) segment has the Patient Name removed.  In the demo we are starting the route with the message in a file.  The route can also be started with Mina2 through the HAPI test panel.  You can see the outline of the routes below which can also be seen in the camel-context.xml file:


NOTE: init-fabric.sh will be future for a fabric example. menu.sh will be future for building a local install or docker install.

The message used in the unit tests and our example is a ADT Message:
MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4PID|||20301||Durden^Tyler^^^Mr.||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA|||||||PV1||O|OP^^||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718
Steps for the Demo:
Step 2: Download the JBoss Fuse product from jboss.org at http://www.jboss.org/products/fuse/overview/
Step 3: Place the downloaded zip file under installs folder.
Step 4: Run init.sh to setup the environment which will also start Fuse.
 
Step 5: 
Enter the following in the console: features:addurl mvn:org.fusebyexample.examples/hl7-example-features/1.0.0-SNAPSHOT/xml/features
Step 6: Enter the following in the console: features:install hl7-example-all
Step 7: Move the camel-test.hl7 file to /tmp/ then watch the log, located at target/jboss-fuse-6.1.0.redhat-379/data/log/fuse.log, for the following trace output to show the Patient Name is removed from the message:

21:47:28,228 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7FileRoute) from(file:///tmp/?delete=true&filter=%23hl7FileFilter&moveFailed=.error) --> convertBodyTo[java.lang.String] <<< Pattern:InOnly, Headers:{CamelFileNameOnly=camel-test.hl7, CamelFileAbsolute=true, CamelFileName=camel-test.hl7, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelFileLastModified=1420054586000, CamelFileNameConsumed=camel-test.hl7, CamelFilePath=/tmp/camel-test.hl7, CamelFileParent=/tmp, CamelFileRelativePath=camel-test.hl7, CamelFileLength=285}, BodyType:org.apache.camel.component.file.GenericFile, Body:[Body is file based: GenericFile[/tmp/camel-test.hl7]]

21:47:28,234 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7FileRoute) convertBodyTo[java.lang.String] --> direct://hl7Direct <<< Pattern:InOnly, Headers:{CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelFileAbsolute=true, CamelFileNameOnly=camel-test.hl7, CamelFileName=camel-test.hl7, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelFileRelativePath=camel-test.hl7, CamelFileParent=/tmp, CamelFileLength=285, CamelFilePath=/tmp/camel-test.hl7, CamelFileLastModified=1420054586000, CamelFileNameConsumed=camel-test.hl7}, BodyType:String, Body:MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||Durden^Tyler^^^Mr.||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA|||||||
PV1||O|OP^^||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,236 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectRoute) direct://hl7Direct --> log[HL7 Request: ${body}] <<< Pattern:InOnly, Headers:{CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelFileAbsolute=true, CamelFileNameOnly=camel-test.hl7, CamelFileName=camel-test.hl7, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelFileRelativePath=camel-test.hl7, CamelFileParent=/tmp, CamelFileLength=285, CamelFilePath=/tmp/camel-test.hl7, CamelFileLastModified=1420054586000, CamelFileNameConsumed=camel-test.hl7}, BodyType:String, Body:MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||Durden^Tyler^^^Mr.||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA|||||||
PV1||O|OP^^||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,237 | INFO | 0 - file:///tmp/ | hl7DirectRoute | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | HL7 Request: MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||Durden^Tyler^^^Mr.||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA|||||||
PV1||O|OP^^||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,238 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectRoute) log[HL7 Request: ${body}] --> unmarshal[org.apache.camel.component.hl7.HL7DataFormat@5ecb0fc4] <<< Pattern:InOnly, Headers:{CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelFileAbsolute=true, CamelFileNameOnly=camel-test.hl7, CamelFileName=camel-test.hl7, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelFileRelativePath=camel-test.hl7, CamelFileParent=/tmp, CamelFileLength=285, CamelFilePath=/tmp/camel-test.hl7, CamelFileLastModified=1420054586000, CamelFileNameConsumed=camel-test.hl7}, BodyType:String, Body:MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||Durden^Tyler^^^Mr.||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA|||||||
PV1||O|OP^^||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,313 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectRoute) unmarshal[org.apache.camel.component.hl7.HL7DataFormat@5ecb0fc4] --> direct://hl7DirectCBR <<< Pattern:InOnly, Headers:{CamelFileParent=/tmp, CamelHL7Security=null, CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelFileAbsolute=true, CamelHL7MessageType=ADT, CamelFilePath=/tmp/camel-test.hl7, CamelHL7TriggerEvent=A01, CamelHL7ReceivingApplication=TEST, CamelFileNameConsumed=camel-test.hl7, CamelHL7VersionId=2.4, CamelFileRelativePath=camel-test.hl7, CamelHL7ReceivingFacility=JBOSS, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelFileLastModified=1420054586000, CamelHL7SendingApplication=FUSEDEMO, CamelHL7ProcessingId=P, CamelHL7MessageControl=MSGID12349876, CamelFileNameOnly=camel-test.hl7, CamelFileLength=285, CamelFileName=camel-test.hl7, CamelHL7SendingFacility=ORG, CamelHL7Timestamp=20061019172719}, BodyType:ca.uhn.hl7v2.model.v24.message.ADT_A01, Body:MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||Durden^Tyler^^^Mr.||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA
PV1||O|OP||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,317 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectCBRRoute) direct://hl7DirectCBR --> choice <<< Pattern:InOnly, Headers:{CamelFileParent=/tmp, CamelHL7Security=null, CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelFileAbsolute=true, CamelHL7MessageType=ADT, CamelFilePath=/tmp/camel-test.hl7, CamelHL7TriggerEvent=A01, CamelHL7ReceivingApplication=TEST, CamelFileNameConsumed=camel-test.hl7, CamelHL7VersionId=2.4, CamelFileRelativePath=camel-test.hl7, CamelHL7ReceivingFacility=JBOSS, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelFileLastModified=1420054586000, CamelHL7SendingApplication=FUSEDEMO, CamelHL7ProcessingId=P, CamelHL7MessageControl=MSGID12349876, CamelFileNameOnly=camel-test.hl7, CamelFileLength=285, CamelFileName=camel-test.hl7, CamelHL7SendingFacility=ORG, CamelHL7Timestamp=20061019172719}, BodyType:ca.uhn.hl7v2.model.v24.message.ADT_A01, Body:MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||Durden^Tyler^^^Mr.||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA
PV1||O|OP||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,836 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectCBRRoute) choice --> log[Transforming message.] <<< Pattern:InOnly, Headers:{CamelFileParent=/tmp, CamelHL7Security=null, CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelFileAbsolute=true, CamelHL7MessageType=ADT, CamelFilePath=/tmp/camel-test.hl7, CamelHL7TriggerEvent=A01, CamelHL7ReceivingApplication=TEST, CamelFileNameConsumed=camel-test.hl7, CamelHL7VersionId=2.4, CamelFileRelativePath=camel-test.hl7, CamelHL7ReceivingFacility=JBOSS, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelFileLastModified=1420054586000, CamelHL7SendingApplication=FUSEDEMO, CamelHL7ProcessingId=P, CamelHL7MessageControl=MSGID12349876, CamelFileNameOnly=camel-test.hl7, CamelFileLength=285, CamelFileName=camel-test.hl7, CamelHL7SendingFacility=ORG, CamelHL7Timestamp=20061019172719}, BodyType:ca.uhn.hl7v2.model.v24.message.ADT_A01, Body:MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||Durden^Tyler^^^Mr.||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA
PV1||O|OP||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,836 | INFO | 0 - file:///tmp/ | hl7DirectCBRRoute | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | Transforming message.

21:47:28,839 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectCBRRoute) log[Transforming message.] --> transform[groovy: adt = request?.body; adt?.PID?.removePatientName(0); request.body = adt;] <<< Pattern:InOnly, Headers:{CamelFileParent=/tmp, CamelHL7Security=null, CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelFileAbsolute=true, CamelHL7MessageType=ADT, CamelFilePath=/tmp/camel-test.hl7, CamelHL7TriggerEvent=A01, CamelHL7ReceivingApplication=TEST, CamelFileNameConsumed=camel-test.hl7, CamelHL7VersionId=2.4, CamelFileRelativePath=camel-test.hl7, CamelHL7ReceivingFacility=JBOSS, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelFileLastModified=1420054586000, CamelHL7SendingApplication=FUSEDEMO, CamelHL7ProcessingId=P, CamelHL7MessageControl=MSGID12349876, CamelFileNameOnly=camel-test.hl7, CamelFileLength=285, CamelFileName=camel-test.hl7, CamelHL7SendingFacility=ORG, CamelHL7Timestamp=20061019172719}, BodyType:ca.uhn.hl7v2.model.v24.message.ADT_A01, Body:MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||Durden^Tyler^^^Mr.||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA
PV1||O|OP||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,922 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectCBRRoute) transform[groovy: adt = request?.body; adt?.PID?.removePatientName(0); request.body = adt;] --> log[HL7 Transformed Request: ${body}] <<< Pattern:InOnly, Headers:{CamelFileLength=285, CamelFilePath=/tmp/camel-test.hl7, CamelFileName=camel-test.hl7, CamelHL7MessageControl=MSGID12349876, CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelHL7SendingApplication=FUSEDEMO, CamelHL7VersionId=2.4, CamelHL7TriggerEvent=A01, CamelHL7ReceivingFacility=JBOSS, CamelHL7Security=null, CamelHL7SendingFacility=ORG, CamelFileNameConsumed=camel-test.hl7, CamelHL7ProcessingId=P, CamelFileRelativePath=camel-test.hl7, CamelFileLastModified=1420054586000, CamelFileNameOnly=camel-test.hl7, CamelHL7MessageType=ADT, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelHL7ReceivingApplication=TEST, CamelFileParent=/tmp, CamelFileAbsolute=true, CamelHL7Timestamp=20061019172719}, BodyType:ca.uhn.hl7v2.model.v24.message.ADT_A01, Body:MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA
PV1||O|OP||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,925 | INFO | 0 - file:///tmp/ | hl7DirectCBRRoute | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | HL7 Transformed Request: MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA
PV1||O|OP||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,928 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectRoute) log[HL7 Transformed Request: ${body}] --> bean[ref:hl7AckGenerator] <<< Pattern:InOnly, Headers:{CamelFileLength=285, CamelFilePath=/tmp/camel-test.hl7, CamelFileName=camel-test.hl7, CamelHL7MessageControl=MSGID12349876, CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelHL7SendingApplication=FUSEDEMO, CamelHL7VersionId=2.4, CamelHL7TriggerEvent=A01, CamelHL7ReceivingFacility=JBOSS, CamelHL7Security=null, CamelHL7SendingFacility=ORG, CamelFileNameConsumed=camel-test.hl7, CamelHL7ProcessingId=P, CamelFileRelativePath=camel-test.hl7, CamelFileLastModified=1420054586000, CamelFileNameOnly=camel-test.hl7, CamelHL7MessageType=ADT, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelHL7ReceivingApplication=TEST, CamelFileParent=/tmp, CamelFileAbsolute=true, CamelHL7Timestamp=20061019172719}, BodyType:ca.uhn.hl7v2.model.v24.message.ADT_A01, Body:MSH|^~\&|FUSEDEMO|ORG|TEST|JBOSS|20061019172719||ADT^A01^ADT_A01|MSGID12349876|P|2.4
PID|||20301||||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA
PV1||O|OP||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718

21:47:28,950 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectRoute) bean[ref:hl7AckGenerator] --> marshal[org.apache.camel.component.hl7.HL7DataFormat@65783d7a] <<< Pattern:InOnly, Headers:{CamelHL7Security=null, CamelFilePath=/tmp/camel-test.hl7, CamelFileNameConsumed=camel-test.hl7, CamelFileRelativePath=camel-test.hl7, CamelHL7ProcessingId=P, CamelFileLastModified=1420054586000, CamelHL7ReceivingApplication=TEST, CamelHL7TriggerEvent=A01, CamelFileNameOnly=camel-test.hl7, CamelHL7SendingFacility=ORG, CamelFileAbsolute=true, CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelHL7VersionId=2.4, CamelHL7SendingApplication=FUSEDEMO, CamelFileParent=/tmp, CamelFileLength=285, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelFileName=camel-test.hl7, CamelHL7MessageType=ADT, CamelHL7MessageControl=MSGID12349876, CamelHL7Timestamp=20061019172719, CamelHL7ReceivingFacility=JBOSS}, BodyType:ca.uhn.hl7v2.model.v24.message.ACK, Body:MSH|^~\&|TEST|JBOSS|FUSEDEMO|ORG|20141231214728.945-0500||ACK^A01|1|P|2.4
MSA|AA|MSGID12349876

21:47:28,953 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectRoute) marshal[org.apache.camel.component.hl7.HL7DataFormat@65783d7a] --> log[HL7 Response: ${body}] <<< Pattern:InOnly, Headers:{CamelHL7TriggerEvent=A01, CamelHL7VersionId=2.4, CamelHL7MessageControl=MSGID12349876, CamelFileNameOnly=camel-test.hl7, CamelFileNameConsumed=camel-test.hl7, CamelHL7Timestamp=20061019172719, CamelHL7MessageType=ADT, CamelHL7Security=null, CamelHL7SendingApplication=FUSEDEMO, CamelFileRelativePath=camel-test.hl7, CamelFileLastModified=1420054586000, CamelHL7ReceivingApplication=TEST, CamelHL7SendingFacility=ORG, CamelFileAbsolute=true, CamelHL7ProcessingId=P, CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelFileParent=/tmp, CamelFilePath=/tmp/camel-test.hl7, CamelFileLength=285, CamelFileName=camel-test.hl7, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelHL7ReceivingFacility=JBOSS}, BodyType:byte[], Body:MSH|^~\&|TEST|JBOSS|FUSEDEMO|ORG|20141231214728.945-0500||ACK^A01|1|P|2.4
MSA|AA|MSGID12349876

21:47:28,954 | INFO | 0 - file:///tmp/ | hl7DirectRoute | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | HL7 Response: MSH|^~\&|TEST|JBOSS|FUSEDEMO|ORG|20141231214728.945-0500||ACK^A01|1|P|2.4
MSA|AA|MSGID12349876

21:47:28,954 | INFO | 0 - file:///tmp/ | Tracer | 142 - org.apache.camel.camel-core - 2.12.0.redhat-610379 | ID-localhost-50691-1420080376277-0-2 >>> (hl7DirectRoute) log[HL7 Response: ${body}] --> mock://hl7DirectResponse <<< Pattern:InOnly, Headers:{CamelHL7TriggerEvent=A01, CamelHL7VersionId=2.4, CamelHL7MessageControl=MSGID12349876, CamelFileNameOnly=camel-test.hl7, CamelFileNameConsumed=camel-test.hl7, CamelHL7Timestamp=20061019172719, CamelHL7MessageType=ADT, CamelHL7Security=null, CamelHL7SendingApplication=FUSEDEMO, CamelFileRelativePath=camel-test.hl7, CamelFileLastModified=1420054586000, CamelHL7ReceivingApplication=TEST, CamelHL7SendingFacility=ORG, CamelFileAbsolute=true, CamelHL7ProcessingId=P, CamelFileAbsolutePath=/tmp/camel-test.hl7, CamelFileParent=/tmp, CamelFilePath=/tmp/camel-test.hl7, CamelFileLength=285, CamelFileName=camel-test.hl7, breadcrumbId=ID-localhost-50691-1420080376277-0-1, CamelHL7ReceivingFacility=JBOSS}, BodyType:byte[], Body:MSH|^~\&|TEST|JBOSS|FUSEDEMO|ORG|20141231214728.945-0500||ACK^A01|1|P|2.4
MSA|AA|MSGID12349876

Monday, December 29, 2014

Using HermesJMS with JBoss A-MQ

Today I welcome a guest blogger, Bryan Saunders who is a Red Hat Senior Consultant in North America and a Certified Scrum Professional.  In October I posted a blog to show how to use JMeter with JBoss A-MQ.  Bryan was doing message testing with HermesJMS, SOAPUI and JBoss A-MQ so we wanted to share another method for testing messages with JBoss A-MQ.  We used the steps in my environment that Bryan used in order to make HermesJMS work with JBoss A-MQ.

HermesJMS can be started from within SOAPUI.  HermesJMS is an extensible console that helps you interact with JMS providers making it simple to publish and edit messages, browse or seach queues and topics, copy messages around and delete them.  SoapUI is the world leading Open Source Functional Testing Tool, mainly it is used for API Testing.

Bryan discovered a bug with the HermesJMS distribution included with SOAPUI that affects using it with ActiveMQ 5.8 and above.  The HermesJMS standalone version does produce the error.  So we use the standalone HermesJMS version and point to the distribution from the preferences/tools from within SOAPUI.  The error that is produced with the SOAPUI included version is below and Bryan found a related bug HJMS-223.


Environment

I used the following environment in a VirtualBox Virtual Machine:

JBoss A-MQ Setup

Step 1:  Download JBoss A-MQ 6.1 from JBoss A-MQ 6.1 product page.  
Step 2:  Extract the files to a AMQInstallDir
Step 3:  Uncomment the admin credentials in AMQInstallDir/etc/users.properties.  You should modify the username and password in your environment to unique credentials.


Step 4: Start JBoss A-MQ by running the ./bin/start from the AMQInstallDir.
Step 5: Verify the installation by running Producer and Consumer clients.
  • Run the Producer from the AMQInstallDir with the command below.  The producer will connect to the broker and produce 100 messages.
java -jar extras/mq-client.jar producer --user admin --password admin

  • Run the Consumer from the AMQInstallDir with the command below.  The consumer will connect to the broker and consume 100 messages.
java -jar extras/mq-client.jar consumer --user admin --password admin

Step 6: Open the apache-activemq-5.9.0.redhat-610379-bin.zip file that is in extras as we need two jar files.  Extract activemq-all-5.9.0.redhat-610379.jar and lib/geronimo-j2ee-management_1.1_spec-1.0.1.jar to the extras directory.

SOAPUI and HermesJMS Setup

Step 1:  Download the SOAPUI distribution which will be a shell script
Step 2:  Change the permissions to make the install script, SoapUI-x64-5.0.0.0.sh, executeable, ie chmod 755 SoapUI-x64-5.0.0.sh
Step 3:  Run the setup script ./SoapUI-x64-5.0.0.sh and run SOAPUI at the end of the installation
Step 4:  Download and then install HermesJMS standalone, ie java -jar hermes-installer-1.14.jar
Step 5:  Point SOAPUI tools to the HermesJMS Standalone instead of the included HermesJMS distribution.


Step 6:  Start HermesJMS from the SOAPUI menu


Step 7:  Create a new session by going to Actions, New, New Session


Step 8:  Setup the Provider so it is the same as the below.
  • Click on the Providers tab at the bottom of the screen.  
  • Right click in the Classpath Groups panel and click add group.  
  • Right click on the Library panel and click add jars.  
  • Click on the Scan button when prompted.  Make sure to add both jars.
  • Click Apply and then the Sessions tab.



Step 9:  Setup the session so it is the same as the below.
  • Change the session name, ie JBossAMQSession
  • Update the loader and class in the Connection Factory to the JBossAMQGroup Loader and the org.apache.activemq.ActiveMQConnectionFactory Class
  • Right click in the Connection Factory Panel and add the brokerURL property with the value tcp://localhost:61616.
  • Change the plugin to ActiveMQ and add the properties
    • serviceURL with property service:jmx:rmi://jndi/rmi://localhost:1099/jmxrmi
    • brokerName with property localhost
  • Add the TEST queue name in destinations with a domain of QUEUE
  • Click on the user credentials and add user admin and password admin
  • Click Apply and Ok


Send a test message

Step 1:  Click on the Session, JBossAMQSession, and destination, TEST that were created.


Step 2:  Click on Messages and then Send TestMessage from the menu.  Select a text file that you want to send as a message and click Send file to TEST.
Step 3:  Click the Refresh icon in the toolbar.  You will see the message you sent.




Wednesday, December 17, 2014

Connecting to SAP from Fuse 6.1 Part 1 - Netweaver Gateway Component

Overview

We won't go into great detail on describing Camel other than it is the open source integration framework based on Enterprise Integration Patterns.  Apache Camel uses URIs to work directly with any kind of Transport or messaging model such as HTTP, ActiveMQ, JMS, JBI, SCA, MINA or CXF, as well as pluggable Components and Data Format options.  One of these components is the sap-netweaver component which is available in Fuse 6.1.  Part 1 focuses on this component while Part 2 focuses on the JCo component which is available in Fuse 6.1 but not in Camel.  For more detailed information on Camel and Enterprise Integration Patterns you can read the Primer at http://jbossevangelist.slides.com/kpeeples-jte/enterprise-integration-patterns-primer#/.


The sap-netweaver component, available in Camel 2.12, integrates with the SAP NetWeaver Gateway using HTTP transports.  This camel component supports only producer endpoints.  Maven users will need to add the following dependency to their pom.xml for this component:

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-sap-netweaver</artifactId>
    <version>x.x.x</version>
    <!-- use the same version as your Camel core version -->
</dependency>
You would need to have an account to the SAP NetWeaver system to be able to leverage this component. Also, this component uses the basic authentication scheme for logging into SAP NetWeaver.

Component and endpoint options
Name
Default Value
Description
username

Username for account. This is mandatory.
password

Password for account. This is mandatory.
json
true
Whether to return data in JSON format. If this option is false, then XML is returned in Atom format.
jsonAsMap
true
To transform the JSON from a String to a Map in the message body.
flatternMap
true
If the JSON Map contains only a single entry, then flattern by storing that single entry value as the message body.

Message Headers

The following headers can be used by the producer.
Name
Type
Description
CamelNetWeaverCommand
String
Mandatory: The command to execute in MS ADO.Net Data Service format.

Setup a SAP Developer Account

In order to run the project a SAP Developer account should be setup. Visit the SAP Netweaver Gateway Developer Page at http://scn.sap.com/docs/DOC-31221  Also visit the Red Hat JBoss Enterprise Middleware for SAP page on SCN at http://scn.sap.com/docs/DOC-39134

Running a test of the component

Step 1 - Download the Project from JBoss Demo Central - https://github.com/jbossdemocentral/fuse-components-sap-netweaver

Step 2 - Import the Project into JBDS and take a look at the camel-context.xml which is the Spring DSL that contains the Camel Route for the project.  We used this command to get specific flight information which is put into the CamelNetWeaverCommand:  FlightCollection(carrid='AZ',connid='0555',fldate=datetime'2014-07-09T00%3A00%3A00')


<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
        <description>here is a sample which processes the input files then performs content based routing on the message using XPath</description>
        <from uri="file:src/sap-netweaver?fileName=command.txt&amp;noop=true"/>
        <setHeader headerName="CamelNetWeaverCommand">
            <simple>in.body</simple>
        </setHeader>
        <to uri="sap-netweaver:https://sapes1.sapdevcenter.com/sap/opu/odata/IWFND/RMTSAMPLEFLIGHT/?username=USERNAME&amp;password=PASSWORD&amp;json=false"/>
        <to uri="log:response"/>
    </route>
</camelContext>


I used the following software to view and run the Camel Context:
-JBDS 7.1.1 - https://www.jboss.org/products/jbds.html
-Integration Stack 4.1.6.Final - http://download.jboss.org/jbosstools/updates/stable/kepler/integration-stack

Step 3 - Update the Username and Password in the camel-context.xml

Step 4 - Right click on camel-context.xml and run as 'Local Camel Context'






















Step 5 - The output will look like the below in the console.  Notice the Response Flight Information from SAP.