Open eHealth IPF – Getting the HL7 Tutorial Running (in version 1.7 of the IPF)

The Open eHealth Integration Platform is pretty darn cool. In addition to enhancements that serve the healthcare domain, it also extends Camel with a great number of features that are of general value, including a Groovy based DSL that supports the likes of closures (!!) and more. I’m liking it.I’ve been looking at the available tutorials and didn’t get too, too far in before I hit a snag – in the third tutorial on the page, the HL7 Processing tutorial. The solution is very, very simple, and is given at the very end of this post, though finding the solution took me on a very instructive tour through the platform and a bunch of embedded packages. Fortunately, I had the benefit of time (the boys went to my son’s homecoming game last night) and absorbed a lot on the scenic route. Come along…Following the tutorial instructions to the letter resulted in an error when I tried to run it (unit testing run either from within eclipse or by running mvn test at the command line):SEVERE: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@3bfc47] to prepare test instance [org.openehealth.tutorial.SampleRouteTest@2f996f]java.lang.IllegalStateException: Failed to load ApplicationContextat org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:201)...[snip - a big stack trace with some cascading "Caused by:..." messages the last of which was the root cause]...Caused by: ca.uhn.hl7v2.HL7Exception: No map found for version 2.2. Only the following are available: [2.5, 2.3.1, 2.4, 2.6, 2.1, 2.5.1, 2.0D, 2.0, 2.3, 2.2]at ca.uhn.hl7v2.parser.Parser.getMessageStructureForEvent(Parser.java:352)...[snip - a bunch more stack trace]This error was getting thrown at bean instantiation time – the init method for the validationContext was failing. Of course, this error message is puzzling in two respects. First, most obviously, an error message that says “nothing available for x, only x, y and z are available” is rather contradictory. Second, when we look into the code for initialization of the validationContext we see that what we are doing is starting with a DefaultValidationContext and then we fill it in with the rules that are defined in the beans declared in the context.xml file. The DefaultValidationContext has a map, initially empty, from the HL7v2 versions (i.e. 2.1, 2.2, etc.) to the set of rules that apply to that version. Put that together with the error message above and we are easily mislead into thinking the system is complaining about some problem with the ruleMap in the DefaultValidationContext. Yes, mislead. This is NOT the map that is causing the problem.What happens at bean initialization time starts out exactly as I describe in the previous paragraph – the validationContext bean is instantiated and during initialization a DefaultValidationContext is created at the rules specified in the context.xml file are added. As the rules are added the forContext Groovy method is called, a RuleBuilder is instantiated and the forVersion method is called on it – that is, the rules are basically parsed (more on this in a moment). The rules in the defaultTypeRules are not a problem and are loaded without issue. The difference between these and myCustomRules, which are not loading, is that the custom rules we’ve defined are using the abstractSyntax method (those in the defaultTypeRules are specifying rules using different approaches).And here is the key…What happens when you define a rule using abstractSyntax is that the rule is validated against the abstractsyntax of the designated HL7 message version. That’s right, the IPF is doing a bunch of work here to make sure you’ve specified rules that are relevant against the version of HL7v2 that you are targeting. So, for example, if you tried to define a rule against an ADT_A25 message and you targeted it forVersion(‘2.2’), you’re cool. If however you target it forVersion(‘2.1’) then the rule itself won’t validate because version 2.1 only has ADT messages up through ADT_A24. And it even does validation into the message formats. This is a huge value add, it’s a point of model governance that I wasn’t necessarily expecting to have in IPF.So, back to the error message. The exception is thrown in ca.uhn.hl7v2.parser.Parser.getMessageStructureForEvent, the Parser does, indeed, contain a map from version numbers to messageStructures and the exception occurs because, indeed, there is no entry for version 2.2 (or any other version number for that matter). The question then is from where and when are they supposed to have been loaded. We don’t have to look too far, the Parser class includes a method called loadMessageStructures() and looking at the code in there we see:for (int i = 0; i < versions.length; i++) {   String resource = "ca/uhn/hl7v2/parser/eventmap/" + versions[i] + ".properties";   InputStream in = Parser.class.getClassLoader().getResourceAsStream(resource);   ...That is, for each version (the list is hardcoded in a class variable) load up the structure from a properties file with the right name. I knew then that this had to be a packaging issue, and, assuming the tutorial once worked as written, a result of some recent change. Digging through jars, this specifically had to do with HAPI libraries, and vaguely remembering seeing something about HAPI versions, here:

As of IPF 1.7-m3, the underlying HAPI library has been updated. The HL7 version-dependent classes have to be included separately.

was the solution.All that is to say that the only thing you need to do beyond what is described in the tutorial is add the following lines in the dependencies section of the pom.xml:<dependency>    <groupid>ca.uhn.hapi</groupid>    <artifactid>hapi-structures-v22</artifactid>    <version>0.6</version></dependency>

Share Your Thoughts