Mapping Service
The org.openehealth.ipf.commons.map.MappingService
interface deals with the requirement that message processing often
involves mapping between code systems, i.e. from one set of codes into a corresponding set of codes.
For example, HL7 version 2 to HL7 version 3 use different code systems for most coded values like message type, gender,
clinical encounter type, marital status codes, address and telecommunication use codes, just to mention a few.
MappingService implementations provide the mapping logic, which can be a simple java.util.Map
, but can also be a facade for a
remote terminology service.
The ipf-commons-map
component extends the java.lang.String
and java.util.Collection
classes with methods targeted at mapping.
The ipf-commons-map library provides the MappingService implementation
(org.openehealth.ipf.commons.map.BidiMappingService
), which implements
- bidirectional mapping
- mapping of arbitrary objects
- definitions of mappings using external Groovy Scripts
Additionally there is org.openehealth.ipf.commons.spring.map.SpringBidiMappingService
that adds the possibility to configure mapping scripts as Spring Resource
s.
You are free to implement and use your own service as long as it implements the
org.openehealth.ipf.commons.map.MappingService
interface.
Dependencies
In a Maven-based environment, the following dependency must be registered in pom.xml
:
<dependency>
<groupId>org.openehealth.ipf.commons</groupId>
<artifactId>ipf-commons-map</artifactId>
<version>${ipf-version}</version>
</dependency>
When using Spring, you should also depend on:
<dependency>
<groupId>org.openehealth.ipf.commons</groupId>
<artifactId>ipf-commons-spring</artifactId>
<version>${ipf-version}</version>
</dependency>
Configuring the Mapping Service
Here is how to configure IPF’s SpringBidiMappingService
using Spring:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ipf="http://openehealth.org/schema/ipf-commons-core"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://openehealth.org/schema/ipf-commons-core
http://openehealth.org/schema/ipf-commons-core.xsd">
<!-- Register Spring as global registry -->
<ipf:globalContext id="globalContext"/>
...
<!-- Groovy class that provides the operations on the mappings -->
<bean id="myMappingService" class="org.openehealth.ipf.commons.spring.map.SpringBidiMappingService">
<property name="mappingResources">
<list>
<value>classpath:example.groovy"</value>
<!-- could add more mapping files -->
</list>
</property>
</bean>
...
Mapping scripts can also be dynamically appended to a global mapping service instance. See Custom Mappings for details.
Configuring the mappings
A mapping example (referenced above as example.groovy
) is displayed below.
The example maps a couple of codes from HL7-related code systems.
mappings = {
encounterType(['2.16.840.1.113883.12.4','2.16.840.1.113883.5.4'],
E : 'EMER',
I : 'IMP',
O : 'AMB'
)
vip(['2.16.840.1.113883.12.99','2.16.840.1.113883.5.1075'],
Y : 'VIP',
(ELSE) : { it }
)
messageType(
'ADT^A01' : 'PRPA_IN402001',
(ELSE) : { throw new HL7Exception("Invalid message type", 207) }
)
}
This defines three mappings (encounterType
, vip
, and messageType
), having an optional definition for
ISO Object Identifiers (OIDs) to identify key and value code systems.
The encounterType mapping has three entries, while the vip and messageType mappings have only one.
Using the Mapping Service
The Mapping Service can be used directly. By using the Groovy metaclass extension, however, the map
and
mapReverse
methods can be directly applied to strings and collections:
// using the service bean reference
def x = mappingService.get('encounterType', 'E')
// more concise: using the dynamic map method on a string instance
def y = 'E'.map('encounterType')
// x == y == 'EMER'
The ELSE
entry is called on MappingService#get
request with unknown keys. ELSE
can be
- a Closure, which takes the key as parameter and is then executed
- any other Object o, which will return o.toString().
In the mapping example above,
- for the
vip
mapping the key is returned, so that mappingService.get(‘vip’, ‘X’) == ‘X’ - for the
messageType
mapping, an Exception is thrown.
The Mapping Service also allows mapping in the backward direction. In case that a mapping definition maps more than one key to the same value (e.g. A->C and B->C), the backward mapping only contains the last entry, i.e. C->B.
// using the service bean reference
def x = mappingService.getKey('vip', 'VIP')
// more concise: using the dynamic map method on a string instance
def y = 'VIP'.mapReverse('vip')
// x == y == 'Y'
ELSE
is also allowed in mapping in the backward direction:
mappings = {
reverseMapping(
key : 'value',
(ELSE) : 'unknownKey',
'unknownValue' : (ELSE)
)
reverseMappingWithClosures(
key : 'value',
(ELSE) : 'unknownKey',
// backwards default mapping to an existing key without conflict:
({'key'}) : (ELSE)
)
}
Dynamic Custom Mappings
Custom mapping scripts can be added to a global mapping service instance.
Define a org.openehealth.ipf.commons.spring.map.config.CustomMappings
bean in a custom spring application context file which references
one or more mapping scripts that shall be picked up.
<bean id="customMapping1"
class="org.openehealth.ipf.commons.spring.map.config.CustomMappings">
<property name="mappingResources">
<list>
<value>classpath:config1.map</value>
<value>classpath:config2.map</value>
</list>
</property>
</bean>
<bean id="customMapping2"
class="org.openehealth.ipf.commons.spring.map.config.CustomMappings">
<property name="mappingResource" value="classpath:config3.map" />
</bean>
These mapping definitions will be picked up by the CustomMappingsConfigurer
and automatically added
to the shared MappingService.