Skip to content
This repository has been archived by the owner on Apr 8, 2024. It is now read-only.

3. Add new mapping

BirgitSaalfeld edited this page Feb 15, 2021 · 74 revisions

After seting up and running the FHIR-Bridge (as explained here) a mapping can be added by following the steps explained beyond. All steps are explained following the example of implementing a mapping for body temperature.

1. Create a new branch

Each change to the FHIR bridge should have a ticket created, explaining the change. Create a new feature branch with ticket number like: feature/123_mapping_body_temperature, where 123 stands for the issue number

    # optional: make a new checkout
    #git clone https://github.com/ehrbase/fhir-bridge.git
    git clone [email protected]:ehrbase/fhir-bridge.git
    # default:
    cd fhir-bridge
    git checkout -b feature/123_mapping_body_temperature
    # At the first push:
    git push -u origin feature/123_mapping_body_temperature
    # For later pushes:
    git push

    # start docker, if it is not already running (analog to readme)
    cd fhir-bridge/docker
    docker-compose -f docker-compose-light.yml  up

    # build everything initially
    cd fhir-bridge # bzw. 'cd ..' , wenn der vorherige Befehl ausgeführt wurde
    mvn clean install


2. Add the operational template and FHIR profile for the mapping

2a. Operational template (OPT format)

  1. visit http://88.198.146.13/ckm/projects/1246.152.26/resourcecentre
  2. download the Körpertemperatur.opt by clicking on it
  3. add the file to the directory fhir-bridge/src/main/resources/opt
  • Optional: Check the OPT in Pablos Tool: toolkit.cabolabs.com

2b. Generate the openEHR Composition classes

  1. leave the fhir-bridge folder
  2. clone the following project with git clone https://github.com/ehrbase/openEHR_SDK
  3. enter the directory and execute mvn clean install
  4. execute java -jar YOUR_OPENEHR-SDK_PATH/generator/target/generator-1.0.0.jar -opt YOUR_FHIR-BRIDGE_PATH/src/main/resources/opt/Körpertemperatur.opt -out YOUR_FHIR-BRIDGE_PATH/src/main/java/ -package org.ehrbase.fhirbridge.ehr.opt This serializes Java classes for the Body temp Composition.
  5. Make class fhir-bridge/src/main/java/org/ehrbase/fhirbridge/ehr/opt/YOUR-COMP/YOUR-COMP-Composition implement the Composition interface. Troubleshooting: In case IntelliJ can not resolve basic imports anymore, e.g. java.xxxx, close the project. Delete the ".idea" folder and open project again.

2c. FHIR profile

  1. visit https://simplifier.net/ForschungsnetzCovid-19/~resources?fhirVersion=R4&sortBy=RankScore_desc
  2. search for Body Temperature (Profile)
  3. click on the Profile and Download a Snapshot as XML
  4. move the Downloaded XML into the directory fhir-bridge/src/main/resources/profiles

Note: If your Profile includes extensions, don't forget to download and add them, too.

2d. FHIR profile example

To later test the implemented mapping, an example of the profile also needs to be provided

  1. visit https://simplifier.net/ForschungsnetzCovid-19/~resources?fhirVersion=R4&sortBy=RankScore_desc
  2. search for Body Temperature (Example)
  3. click on the Example and Download it as JSON
  4. open the JSON and search for the value of the field ¨resourceType¨, in this case it is an Observation
  5. move it to fhir-bridge/src/test/resources/Observation
  6. rename it to create-body-temp.json
  7. open the file and replace the JSON object subject with the following lines:
"subject": {
    "identifier": {
      "system": "urn:ietf:rfc:4122",
      "value": "{{patientId}}"
    }
  },

Note: Step 7 depends on the resource type, e.g. for Patient it's just the identifier part that needs to be included.

3. Add the routing for the mapping

To add a mapping to the fhir-bridge, the routing for the input has to be defined. Since the basic functionality is already provided only two classes need to be edited.

3a. Adding the fhir profile to the profile Enum

  1. open fhir-bridge/src/main/java/org/ehrbase/fhir-bridge/fhir/common/Profile.java
  2. add the line
BODY_TEMP(Observation.class, "https://www.netzwerk-universitaetsmedizin.de/fhir/StructureDefinition/body-temperature"),

to the enum class e.g.:

public enum Profile {
    PATIENT(Patient.class, "https://www.netzwerk-universitaetsmedizin.de/fhir/StructureDefinition/Patient"),
    BODY_TEMP(Observation.class, "https://www.netzwerk-universitaetsmedizin.de/fhir/StructureDefinition/body-temperature"),
    BODY_WEIGHT(Observation.class, "https://www.netzwerk-universitaetsmedizin.de/fhir/StructureDefinition/body-weight");

The values entered here derive from your fhir resource you want to map. In case of our example, body temperature is a Observation. This may vary depending on the resourceType of your fhir resource! The URL contained as the second parameter is found in your fhir JSON example within the JSON object meta e.g.:

"meta": {
        "profile":  [
            "https://www.netzwerk-universitaetsmedizin.de/fhir/StructureDefinition/body-temperature"
        ]
    },

3b. Adding the profile to the routing of camel

  1. open fhir-bridge/src/main/org/ehrbase/fhirbridge/ehr/converter/CompositionConverterResolver.java
  2. go to the method afterPropertiesSet()
  3. add
 profiles.put(Profile.BODY_TEMP, new BodyTemperatureCompositionConverter());

to the method. Result should look like that :

   @Override
    public void afterPropertiesSet() {
        profiles.put(Profile.DIAGNOSTIC_REPORT_LAB, new DiagnosticReportLabCompositionConverter());
        profiles.put(Profile.BODY_HEIGHT, new BodyHeightCompositionConverter());
        profiles.put(Profile.BLOOD_PRESSURE, new BloodPressureCompositionConverter());
        profiles.put(Profile.BODY_TEMP, new BodyTemperatureCompositionConverter());

Hereby camel can route the input of an BodyTemp to the BodyTemperatureCompositionConverter where the mapping logic is to be contained.

3c. Creating the CompositionConverter class containing the mapping logic

  1. create the class BodyTemperatureCompositionConverter in fhir-bridge/src/main/java/org/ehrbase/fhirbridge/ehr/converter/ (for example with pressing Alt + Enter while your cursor is in IntelliJ on the red highlighted converter class name, you just wrote)
  2. this class needs to implement the CompositionConverter interface using the KoerpertermperaturComposition and Observation (remember body temp is an Observation). Example:
public class BodyTemperatureCompositionConverter implements CompositionConverter<KoerpertemperaturComposition, Observation>
  1. the CompositionConverter interface has two methods that needs to be set for each mappings that is done, the toComposition and fromComposition methods. The first one maps fhir into the openEHR composition, the latter one the composition into fhir. In our example, the method toComposition would look something like that:
@Override
    public KoerpertemperaturComposition toComposition(Observation observation) { 
     // your mapping code
    // return the mapped KoerpertemperaturComposition of Koerpertemperatur
   }

and fromComposition:

   @Override
    public Observation fromComposition(KoerpertemperaturComposition composition) {
     //your mapping code
    // return the mapped Observation of body temp
  }

4. Designing the mapping

  1. download the following graphic
  2. open draw.io
  3. import the graphic (file -> open from -> device)
  4. Go to Simplifier and open the resource you want to map (not the example !) e.g. body temp
  5. compare the fields with the ones of the template, to do so open this link, search your template and click "View template"
  6. add this value mappings to the grapic (see examples, also in the left top corner is a legend)

(Final file can be added to the Wiki under "Fertige Dokus")

To see all fields of the template you can use better designer instead of ckm. Therefore, you have to:

  1. Open the "Gecco Core Project" in ckm
  2. Export the project as zip
  3. Sign in with github-Account (https://tools.openehr.org/designer/#/)[https://tools.openehr.org/designer/#/]
  4. Create a new repository
  5. Import the zip into the repositry ("import", "upload", wait, "close")

5. Programming your mappings

In the next step the mapping needs to be implemented in your new CompositionConverter, in our case BodyTemperatureCompositionConverter.

To run what you implemented:

  1. Be sure, docker is running
(base) birgit@birgit-Latitude-7390:~$ docker ps
CONTAINER ID        IMAGE                             COMMAND                  CREATED             STATUS              PORTS                    NAMES
308cf2833064        ehrbase/ehrbase:next              "/bin/sh -c ./docker…"   2 minutes ago       Up 2 minutes        0.0.0.0:8080->8080/tcp   docker_ehrbase_1
71abf5d575ae        ehrbase/ehrbase-postgres:latest   "docker-entrypoint.s…"   3 minutes ago       Up 2 minutes        0.0.0.0:5432->5432/tcp   docker_ehrbase-db_1
  1. Start your local fhir-bridge by clicking 'Maven' in the upper right corner of IntelliJ. Then navigate to 'FHIR Bridge | Plugins | spring-boot ' und start the 'spring-boot:run' command
  2. Run the Junit tests of interest. If you just implemented your mapping you probably want to continue reading first ;-)

Troubleshooting for Windows user in IntelliJ: If "command line command is to long" error occurs. IntelliJ will already propose how to fix it (first option). If not: Run, Edit Configurations, testclass-name (e.g. ObservationIT). If you don't see the "Shorten command line". Click on arrow next to Modify options on right side and activate "Shorten command line". Now select "@argfile ...". Now it should run.

Postman

Afterwards POST the example fhir json to the fhir-bridge ({base_url/fhir/Observation}). Within the log of the fhir-bridge server, the composition version uid is returned. Copy this uid and send an request to ehrbase to return this composition. Retrieve related composition from ehrbase via an AQL query, i.e.

POST {{ehrbase_url}}/query/aql
Content-Type: application/json
Authorization: Basic bXl1c2VyOm15UGFzc3dvcmQ0MzI=

# body/payload
{
  "q": "SELECT c FROM EHR e [ehr_id/value='{{ehr_id}}'] CONTAINS COMPOSITION c"
}

#or

{
  "q": "SELECT c FROM EHR e CONTAINS COMPOSITION c ORDER BY c/context/start_time DESC"
}

Check if the composition contains all the values as intended.

Preparing steps

  • open Postman
  • import config/postman/fhir-bridge.postman_collection.json
  • check, that the fhir-bridge environment exists Issue 113
  • run Ehrbase -> Create EHR
  • run Patient -> Create Patient
  • then post your composition

6. Test your mappings

Tests shall cover the following cases:

  1. In fhir-bridge/src/test/java/org/ehrbase/fhirbridge/fhir create a new testfile for your mapping within the proper package, e.g. observation. The new class itself must end with IT, e.g. observation/BodyTempIT.java.
  • Make it extends AbstractMappingTestSetupIT
  • Add the constructor,the executeMappingUnprocessableEntityException()-method and the getJavers()-method.
  • In the getJavers()-method: add every openEHR Observation, Composition, Element etc. included in your mapping as a ValueObject.
  • The Composition has to include a location string, used to ignore the location when comparing object (example).
  • Implementation hint: When running the mapping that uses javers, the class that is not comparable will be thrown in the error stack, copy this class name and add it to the getJavers()-method.
  1. In test/resources/yourPackage create a package for your mapping
  2. In order to provide an object that the mapping test can be validated against, the output of your current one is to be used. It is crucial that you manually check this Composition and ensure its validity (your latest mapping can be found in src/main/resources/MappingOutput.json).
  • Copy this json and add it to the package you just created. Suggested name prefix:paragon-
  1. Write the mapping test using this file for the specific fhir input, do the same for all other valid testfiles. //BSa soll das Beispiel hier so bleiben? Im Telefonat meintest du, es sei zu kompliziert! Example:
    @Test
    void mapBodyTemp() throws IOException, IntrospectionException, InvocationTargetException, IllegalAccessException {
        String resource = IOUtils.toString(new ClassPathResource("observation/create-body-temp.json").getInputStream(), StandardCharsets.UTF_8);

        IParser parser = context.newJsonParser();
        BodyTempResource bodyTempResource = parser.parseResource(BodyTempFhirProfile.class, resource);
        BodyTempCompositionConverter bodyTempCompositionConverter = new BodyTempCompositionConverter();
        BodyTempComposition mappedBodyTempComposition = bodyTempCompositionConverter.toComposition(bodyTempResource);

        Diff diff = compareCompositions(getJavers(), "observation/BodyTempComposition.json", mappedBodyTempComposition);
        assertEquals(diff.getChanges().size(), 0);
    }
  1. Add one more test that map a resource and send it to the ehrbase (entire workflow). //BSa -> which test do you mean
  2. If there are some exceptions you added that are not covered yet, add tests for those.

7. Wait for the CI

8. Refactor your Code

9. Submit Pull Request

Clone this wiki locally