Translation between FHIR and HL7 v2 message models
IPF provides utilities for translation between FHIR and HL7v2, thus giving the possibility to implement FHIR-based IHE transactions on top ot their HL7 v2 counterparts and to avoid redundancy in that way.
Currently supported transaction pairs are
Dependencies
In a Maven-based environment, the following dependencies should be registered in pom.xml:
<dependency>
<groupId>org.openehealth.ipf.commons</groupId>
<artifactId>ipf-commons-spring</artifactId>
<version>${ipf-version}</version>
</dependency>
<dependency>
<groupId>org.openehealth.ipf.platform-camel</groupId>
<artifactId>ipf-platform-camel-ihe-fhir-stu3-pixpdq</artifactId>
<version>${ipf-version}</version>
</dependency>
This depends transitively on the required module:
<dependency>
<groupId>org.openehealth.ipf.commons</groupId>
<artifactId>ipf-commons-ihe-fhir-stu3-pixpdq</artifactId>
<version>${ipf-version}</version>
</dependency>
Configuring the URI Mapper
For translation of FHIR messages, an instance of org.openehealth.ipf.commons.ihe.fhir.translation.UriMapper is required in order to map FHIR URIs into OIDs and vice versa. IPF provides an implementation (org.openehealth.ipf.commons.ihe.fhir.translation.NamingSystemUriMapper) that uses an instance of org.openehealth.ipf.commons.ihe.fhir.NamingSystemService under the hood.
The default implementation is org.openehealth.ipf.commons.ihe.fhir.DefaultNamingSystemServiceImpl, which expects a Bundle of FHIR NamingSystem resources. In addition, for code system mapping, a Mapping Service bean must be available. Here is a snippet of the required Spring-based configuration:
<bean id="fhirContext" class="ca.uhn.fhir.context.FhirContext" factory-method="forDstu2Hl7Org"/>
<bean id="mappingService" class="org.openehealth.ipf.commons.spring.map.SpringBidiMappingService">
<property name="mappingResources">
<list>
<value>classpath:META-INF/map/fhir-hl7v2-translation.map</value>
</list>
</property>
</bean>
<!-- Use NamingSystemService for the URI Mapper -->
<bean id="namingSystemService" class="org.openehealth.ipf.commons.ihe.fhir.DefaultNamingSystemServiceImpl">
<constructor-arg ref="fhirContext"/>
<property name="namingSystemsFromXml" value="classpath:identifiers.xml"/>
</bean>
<bean id="uriMapper" class="org.openehealth.ipf.commons.ihe.fhir.translation.NamingSystemUriMapper">
<constructor-arg ref="namingSystemService"/>
<constructor-arg value="identifiers"/>
</bean>
Note that Spring Boot applications can depend on ipf-fhir-spring-boot-starter, which already auto-configures these beans for you.
An example for a bundle of NamingSystem resources (referenced to be contained in the identifiers.xml file in the example above) looks like this:
<Bundle xmlns="http://hl7.org/fhir" >
<id value="identifiers"/>
<type value="collection"/>
<entry>
<resource>
<NamingSystem>
<id value="fhir1"/>
<name value="FHIR1 Patient Identifier Namespace"/>
<status value="active"/>
<kind value="identifier"/>
<date value="2015-07-31"/>
<type>
<coding>
<system value="http://hl7.org/fhir/identifier-type"/>
<code value="PI"/>
</coding>
</type>
<uniqueId>
<type value="oid"/>
<value value="1.2.3.4"/>
</uniqueId>
<uniqueId>
<type value="other"/>
<value value="fhir1"/>
</uniqueId>
<uniqueId>
<type value="uri"/>
<value value="http://org.openehealth/ipf/commons/ihe/fhir/1"/>
<preferred value="true"/>
</uniqueId>
</NamingSystem>
</resource>
</entry>
<entry>
<resource>
<NamingSystem>
<id value="fhir2"/>
<name value="FHIR2 Patient Identifier Namespace"/>
<status value="active"/>
<kind value="identifier"/>
<date value="2015-07-31"/>
<type>
<coding>
<system value="http://hl7.org/fhir/identifier-type"/>
<code value="PI"/>
</coding>
</type>
<uniqueId>
<type value="oid"/>
<value value="1.2.3.4.5.6"/>
</uniqueId>
<uniqueId>
<type value="other"/>
<value value="fhir2"/>
</uniqueId>
<uniqueId>
<type value="uri"/>
<value value="http://org.openehealth/ipf/commons/ihe/fhir/2"/>
<preferred value="true"/>
</uniqueId>
</NamingSystem>
</resource>
</entry>
</Bundle>
Of course you are free to include your own implementations of UriMapper and/or MappingService.
Translators
The package org.openehealth.ipf.commons.ihe.fhir.translation... contains the set of translators that is able to translate between corresponding IHE transactions.
From a Patient identity Cross Reference Manager ’s perspective, there are inbound translators:
| FHIR transaction | FHIR-to-HL7v2 request | HL7v2-Transaction | HL7v2-to-FHIR response |
|---|---|---|---|
| PDQm ITI-78 | iti78.PdqmRequestToPdqQueryTranslator | PDQ ITI-21 | iti78.PdqResponseToPdqmResponseTranslator |
| PIXm ITI-83 | iti83.PixmRequestToPixQueryTranslator | PIX Query ITI-9 | iti83.PixQueryResponseToPixmResponseTranslator |
Each translator has a set of configurable properties. Their descriptions can be taken from javadoc of the corresponding classes. Below there’s an example of a Spring application context defining translator beans:
<!-- Example for PIXm Query -->
<bean name="pixmRequestTranslator"
class="org.openehealth.ipf.commons.ihe.fhir.translation.iti83.PixmRequestToPixQueryTranslator">
<property name="uriMapper" ref="uriMapper" />
</bean>
<bean name="pixmResposneTranslator"
class="org.openehealth.ipf.commons.ihe.fhir.translation.iti83.PixQueryResponseToPixmResponseTranslator">
<property name="uriMapper" ref="uriMapper" />
</bean>
<!-- Example for PDQm -->
<bean name="pdqmRequestTranslator"
class="org.openehealth.ipf.commons.ihe.fhir.translation.iti78.PdqmRequestToPdqQueryTranslator">
<property name="uriMapper" ref="uriMapper" />
</bean>
<bean name="pdqmResponseTranslator"
class="org.openehealth.ipf.commons.ihe.fhir.translation.iti78.PdqResponseToPdqmResponseTranslator">
<property name="uriMapper" ref="uriMapper" />
</bean>
Using the translators
A translator instance can be used two ways:
- directly from a Java or Groovy application (not discussed here)
- from a Camel route using ´.process()`
The module ipf-platform-camel-ihe-fhir-pixpdq, being the basis for the PIXm/PDQm FHIR transactions’ implementation, provides processors that can be used to embed HL7 translation functionality into a Camel route.
There are two processor implementations, each taking a translator instance as parameter for the desired translation:
- FhirCamelTranslators.translatorFhirToHL7v2(translator)
- FhirCamelTranslators.translatorHL7v2ToFhir(translator)
Example
Here is a sample Camel route that bridges PIXm requests (ITI-83) to an HL7 v2-based Patient Identifier Cross-Reference Manager (ITI-9), and does the same in reverse direction for responses.
import org.apache.camel.builder.RouteBuilder;
import org.openehealth.ipf.commons.ihe.fhir.translation.FhirTranslator;
import org.openehealth.ipf.commons.ihe.fhir.translation.ToFhirTranslator;
import static org.openehealth.ipf.platform.camel.ihe.fhir.core.FhirCamelTranslators.translateFhir;
import static org.openehealth.ipf.platform.camel.ihe.fhir.core.FhirCamelTranslators.translateToFhir;
public class Iti83TestRouteBuilder extends RouteBuilder {
private final FhirTranslator<Message> requestTranslator;
private final ToFhirTranslator<Message> responseTranslator;
public Iti83TestRouteBuilder(FhirTranslator<Message> requestTranslator,
ToFhirTranslator<Message> responseTranslator) {
super();
this.requestTranslator = requestTranslator;
this.responseTranslator = responseTranslator;
}
@Override
public void configure() throws Exception {
from("pixm-iti83:translation?audit=true")
// Translate into ITI-9
.process(translatorFhir(requestTranslator))
// Create some static response
.to("pix-iti9://${pixManagerUri}")
// Translate back into FHIR
.process(translatorToFhir(responseTranslator, Message.class));
}
}