-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #360 from LinuxForHealth/Example-and-test-of-custo…
…m-messages Example and test of custom messages
- Loading branch information
Showing
4 changed files
with
401 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# This is path to custom HL7 message implementations so HL7 parser can validate them. | ||
org.foo.hl7.custom |
137 changes: 137 additions & 0 deletions
137
src/test/java/io/github/linuxforhealth/hl7/message/Hl7CustomMessageTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/* | ||
* (C) Copyright IBM Corp. 2020, 2021 | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.github.linuxforhealth.hl7.message; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.util.List; | ||
|
||
import java.io.FileOutputStream; | ||
import java.util.Properties; | ||
|
||
import org.junit.jupiter.api.AfterAll; | ||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.io.TempDir; | ||
|
||
import org.hl7.fhir.instance.model.api.IBaseResource; | ||
import org.hl7.fhir.r4.model.Bundle; | ||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; | ||
import org.hl7.fhir.r4.model.Resource; | ||
import org.hl7.fhir.r4.model.ResourceType; | ||
|
||
import io.github.linuxforhealth.core.config.ConverterConfiguration; | ||
import io.github.linuxforhealth.fhir.FHIRContext; | ||
import io.github.linuxforhealth.hl7.ConverterOptions; | ||
import io.github.linuxforhealth.hl7.ConverterOptions.Builder; | ||
import io.github.linuxforhealth.hl7.HL7ToFHIRConverter; | ||
import io.github.linuxforhealth.hl7.resource.ResourceReader; | ||
import io.github.linuxforhealth.hl7.segments.util.ResourceUtils; | ||
|
||
// This shows how and tests the ability to create a custom Hl7 class | ||
// Detailed documentation about how this works is found here: | ||
// http://javadox.com/ca.uhn.hapi/hapi-base/2.1/ca/uhn/hl7v2/parser/DefaultModelClassFactory.html#packageList(java.lang.String) | ||
// In this test, the custom class which HL7 uses for validation is placed in src/test/java/org/foo/hl7/custom/message/CUSTOM_PAT.java | ||
// The custom message is placed in src/test/resources/additional_custom_resources/hl7/message/CUSTOM_PAT.yml | ||
// The custom packages class is placed in src/test/java/custom_packages/2.6 and references the custom package /org/foo/hl7/custom/ | ||
|
||
public class Hl7CustomMessageTest { | ||
|
||
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | ||
// NOTE VALIDATION IS INTENTIONALLY NOT USED BECAUSE WE ARE CREATING RESOURCES THAT ARE NOT STANDARD | ||
private static final ConverterOptions OPTIONS = new Builder().withPrettyPrint().build(); | ||
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | ||
|
||
private static final String CONF_PROP_HOME = "hl7converter.config.home"; | ||
|
||
@TempDir | ||
static File folder; | ||
|
||
static String originalConfigHome; | ||
|
||
@BeforeAll | ||
public static void saveConfigHomeProperty() { | ||
originalConfigHome = System.getProperty(CONF_PROP_HOME); | ||
ConverterConfiguration.reset(); | ||
ResourceReader.reset(); | ||
} | ||
|
||
@AfterEach | ||
public void reset() { | ||
System.clearProperty(CONF_PROP_HOME); | ||
ConverterConfiguration.reset(); | ||
ResourceReader.reset(); | ||
} | ||
|
||
@AfterAll | ||
public static void reloadPreviousConfigurations() { | ||
if (originalConfigHome != null) | ||
System.setProperty(CONF_PROP_HOME, originalConfigHome); | ||
else | ||
System.clearProperty(CONF_PROP_HOME); | ||
} | ||
|
||
@Test | ||
public void testCustomPatMessage() throws IOException { | ||
|
||
// Set up the config file | ||
commonConfigFileSetup(); | ||
|
||
String hl7message = | ||
"MSH|^~\\&|||||20211005105125||CUSTOM^PAT|1a3952f1-38fe-4d55-95c6-ce58ebfc7f10|P|2.6\n" | ||
+ "PID|1|100009^^^FAC^MR|100009^^^FAC^MR||DOE^JANE||195001010000|M|||||5734421788|||U\n" | ||
+ "PRB|1|20211005|10281^LYMPHOID LEUKEMIA NEC^ICD9||||201208061011||201208061011|||||||201208061011\n" | ||
+ "PRB|2|20211005|11334^ABNORMALITIES OF HAIR^ICD9||||201208071000||201208071000|||||||201208071000\n" | ||
+ "AL1|50|DA|penicillin|MO||20210629\n" | ||
+ "AL1|50|MA|cat dander|SV|hives\\R\\ difficult breathing|20210629\n" | ||
; | ||
|
||
List<BundleEntryComponent> e = getBundleEntryFromHL7Message(hl7message); | ||
|
||
// Check for the expected resources 1 patient, 2 conditions, 2 allergies | ||
List<Resource> patientResource = ResourceUtils.getResourceList(e, ResourceType.Patient); | ||
assertThat(patientResource).hasSize(1); // From PID | ||
|
||
List<Resource> conditionResource = ResourceUtils.getResourceList(e, ResourceType.Condition); | ||
assertThat(conditionResource).hasSize(2); // From 2x PRB | ||
|
||
List<Resource> allergyIntoleranceResource = ResourceUtils.getResourceList(e, ResourceType.AllergyIntolerance); | ||
assertThat(allergyIntoleranceResource).hasSize(2); // From 2x AL1 | ||
|
||
// Confirm that no extra resources are created | ||
assertThat(e.size()).isEqualTo(5); | ||
} | ||
|
||
private static void commonConfigFileSetup() throws IOException { | ||
File configFile = new File(folder, "config.properties"); | ||
Properties prop = new Properties(); | ||
prop.put("base.path.resource", "src/main/resources"); | ||
prop.put("supported.hl7.messages", "*"); // Must use wild card so the custom resources are found. | ||
prop.put("default.zoneid", "+08:00"); | ||
prop.put("additional.resources.location", "src/test/resources/additional_custom_resources"); // Location of custom resources | ||
prop.store(new FileOutputStream(configFile), null); | ||
System.setProperty(CONF_PROP_HOME, configFile.getParent()); | ||
} | ||
|
||
// Need custom convert sequence with options that turn off FHIR validation. | ||
private static List<BundleEntryComponent> getBundleEntryFromHL7Message(String hl7message) { | ||
HL7ToFHIRConverter ftv = new HL7ToFHIRConverter(); | ||
String json = ftv.convert(hl7message, OPTIONS); // Need custom options that turn off FHIR validation. | ||
assertThat(json).isNotNull(); | ||
FHIRContext context = new FHIRContext(); | ||
IBaseResource bundleResource = context.getParser().parseResource(json); | ||
assertThat(bundleResource).isNotNull(); | ||
Bundle b = (Bundle) bundleResource; | ||
return b.getEntry(); | ||
} | ||
|
||
} | ||
|
||
|
220 changes: 220 additions & 0 deletions
220
src/test/java/org/foo/hl7/custom/message/CUSTOM_PAT.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
/* | ||
* (C) Copyright IBM Corp. 2020, 2021 | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
//######################################################################## | ||
// Used for testing only. Not used in production. | ||
//######################################################################## | ||
|
||
package org.foo.hl7.custom.message; | ||
|
||
import ca.uhn.hl7v2.model.v26.segment.*; | ||
|
||
import ca.uhn.hl7v2.HL7Exception; | ||
import ca.uhn.hl7v2.parser.ModelClassFactory; | ||
import ca.uhn.hl7v2.parser.DefaultModelClassFactory; | ||
import ca.uhn.hl7v2.model.*; | ||
|
||
/** | ||
* <p> | ||
* Represents a CUSTOM_PAT message structure. This structure | ||
* contains the following elements: | ||
* </p> | ||
* <ul> | ||
* <li>MSH (Message Header) <b> </b></li> | ||
* <li>PID (Patient Identification) <b> </b></li> | ||
* <li>PRB (Problem Details) <b>optional repeating</b></li> | ||
* <li>AL1 (Allergy) <b>optional repeating</b></li> | ||
* </ul> | ||
* | ||
* Sample Message: | ||
* MSH|^~\\&|||||20210709162149||HIST^PAT|20210709162149|P|2.6 | ||
* PID|1|100021^^^FAC|100021^^^FAC||DOE^JANE||196705270000|F|||||5733551967|||U | ||
* PRB|1|20210726|11334^ABNORMALITIES OF HAIR^ICD9||||201208070948||201208070948|||||||201208070948 | ||
* AL1|90|MA|dog|MO|itch|20210629 | ||
*/ | ||
|
||
public class CUSTOM_PAT extends AbstractMessage { | ||
|
||
/** | ||
* Creates a new CUSTOM_PAT message with DefaultModelClassFactory. | ||
*/ | ||
public CUSTOM_PAT() { | ||
this(new DefaultModelClassFactory()); | ||
} | ||
|
||
/** | ||
* Creates a new CUSTOM_PAT message with custom ModelClassFactory. | ||
*/ | ||
public CUSTOM_PAT(ModelClassFactory factory) { | ||
super(factory); | ||
init(factory); | ||
} | ||
|
||
private void init(ModelClassFactory factory) { | ||
try { | ||
// parms: ClassName, required, repeats | ||
this.add(MSH.class, true, false); | ||
this.add(PID.class, true, false); | ||
this.add(PRB.class, false, true); | ||
this.add(AL1.class, false, true); | ||
} catch (HL7Exception e) { | ||
log.error("Unexpected error creating CUSTOM_PAT - this is probably a bug in the source code generator."); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the version. | ||
*/ | ||
public String getVersion() { | ||
return "2.6"; | ||
} | ||
|
||
/** | ||
* Returns MSH (Message Header) - creates it if necessary | ||
*/ | ||
public MSH getMSH() { | ||
return getTyped("MSH", MSH.class); | ||
} | ||
|
||
/** | ||
* Returns PID (Patient Identification) - creates it if necessary | ||
*/ | ||
public PID getPID() { | ||
return getTyped("PID", PID.class); | ||
} | ||
|
||
/** | ||
* Returns the first repetition of PRB (Problem Details) - creates it if | ||
* necessary | ||
*/ | ||
public PRB getPRB() { | ||
return getTyped("PRB", PRB.class); | ||
} | ||
|
||
/** | ||
* Returns a specific repetition of PRB (Problem Details) - creates it if | ||
* necessary | ||
* | ||
* @param rep The repetition index (0-indexed, i.e. the first repetition is at | ||
* index 0) | ||
* @throws HL7Exception if the repetition requested is more than one greater | ||
* than the number of existing repetitions. | ||
*/ | ||
public PRB getPRB(int rep) { | ||
return getTyped("PRB", rep, PRB.class); | ||
} | ||
|
||
/** | ||
* Returns the number of existing repetitions of PRB | ||
*/ | ||
public int getPRBReps() { | ||
return getReps("PRB"); | ||
} | ||
|
||
/** | ||
* Returns a non-modifiable List containing all current existing repetitions of | ||
* PRB. | ||
* Note that unlike {@link #getPRB()}, this method will not create any reps if | ||
* none are already present, so an empty list may be returned. | ||
*/ | ||
public java.util.List<PRB> getPRBAll() throws HL7Exception { | ||
return getAllAsList("PRB", PRB.class); | ||
} | ||
|
||
/** | ||
* Inserts a specific repetition of PRB (Problem Details) | ||
* * | ||
* @see AbstractGroup#insertRepetition(Structure, int) | ||
*/ | ||
public void insertPRB(PRB structure, int rep) throws HL7Exception { | ||
super.insertRepetition("PRB", structure, rep); | ||
} | ||
|
||
/** | ||
* Inserts a specific repetition of PRB (Problem Details) | ||
* | ||
* @see AbstractGroup#insertRepetition(Structure, int) | ||
*/ | ||
public PRB insertPRB(int rep) throws HL7Exception { | ||
return (PRB) super.insertRepetition("PRB", rep); | ||
} | ||
|
||
/** | ||
* Removes a specific repetition of PRB (Problem Details) | ||
* | ||
* @see AbstractGroup#removeRepetition(String, int) | ||
*/ | ||
public PRB removePRB(int rep) throws HL7Exception { | ||
return (PRB) super.removeRepetition("PRB", rep); | ||
} | ||
|
||
/** | ||
* Returns the first repetition of AL1 (Patient Allergy Information) - creates | ||
* it if necessary | ||
*/ | ||
public AL1 getAL1() { | ||
return getTyped("AL1", AL1.class); | ||
} | ||
|
||
/** | ||
* Returns a specific repetition of AL1 (Patient Allergy Information) - creates | ||
* it if necessary | ||
* @param rep The repetition index (0-indexed, i.e. the first repetition is at | ||
* index 0) | ||
* @throws HL7Exception if the repetition requested is more than one greater | ||
* than the number of existing repetitions. | ||
*/ | ||
public AL1 getAL1(int rep) { | ||
return getTyped("AL1", rep, AL1.class); | ||
} | ||
|
||
/** | ||
* Returns the number of existing repetitions of AL1 | ||
*/ | ||
public int getAL1Reps() { | ||
return getReps("AL1"); | ||
} | ||
|
||
/** | ||
* Returns a non-modifiable List containing all current existing repetitions of | ||
* AL1. | ||
* | ||
* Note that unlike {@link #getAL1()}, this method will not create any reps if | ||
* none are already present, so an empty list may be returned. | ||
* | ||
*/ | ||
public java.util.List<AL1> getAL1All() throws HL7Exception { | ||
return getAllAsList("AL1", AL1.class); | ||
} | ||
|
||
/** | ||
* Inserts a specific repetition of AL1 (Patient Allergy Information) | ||
* | ||
* @see AbstractGroup#insertRepetition(Structure, int) | ||
*/ | ||
public void insertAL1(AL1 structure, int rep) throws HL7Exception { | ||
super.insertRepetition("AL1", structure, rep); | ||
} | ||
|
||
/** | ||
* Inserts a specific repetition of AL1 (Patient Allergy Information) | ||
* | ||
* @see AbstractGroup#insertRepetition(Structure, int) | ||
*/ | ||
public AL1 insertAL1(int rep) throws HL7Exception { | ||
return (AL1) super.insertRepetition("AL1", rep); | ||
} | ||
|
||
/** | ||
* Removes a specific repetition of AL1 (Patient Allergy Information) | ||
* | ||
* @see AbstractGroup#removeRepetition(String, int) | ||
*/ | ||
public AL1 removeAL1(int rep) throws HL7Exception { | ||
return (AL1) super.removeRepetition("AL1", rep); | ||
} | ||
|
||
} |
Oops, something went wrong.