From 4c0a923901b3375a0433f3e8ce31f0ae1b1d2498 Mon Sep 17 00:00:00 2001 From: Basilio Bogado <541149+basiliskus@users.noreply.github.com> Date: Mon, 23 Dec 2024 13:44:06 -0800 Subject: [PATCH] Removed HL7Parser and moved message parsing logic to HL7Message to avoid circular dependencies --- .../rse2e/hl7/HL7FileMatcher.java | 2 +- .../rse2e/hl7/HL7Message.java | 42 ++++++++++++++- .../rse2e/hl7/HL7Parser.java | 49 ----------------- .../hl7/HL7ExpressionEvaluatorTest.groovy | 2 +- .../rse2e/hl7/HL7MessageTest.groovy | 47 ++++++++++++++++- .../rse2e/hl7/HL7ParserTest.groovy | 52 ------------------- 6 files changed, 89 insertions(+), 105 deletions(-) delete mode 100644 rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7Parser.java delete mode 100644 rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7ParserTest.groovy diff --git a/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7FileMatcher.java b/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7FileMatcher.java index 4e207a44a..b640ae415 100644 --- a/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7FileMatcher.java +++ b/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7FileMatcher.java @@ -57,7 +57,7 @@ public Map parseAndMapMessageByControlId(List String fileName = hl7FileStream.fileName(); try (InputStream inputStream = hl7FileStream.inputStream()) { String content = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); - HL7Message message = HL7Parser.parseMessage(content); + HL7Message message = HL7Message.parse(content); String msh10 = message.getIdentifier(); if (msh10 == null || msh10.isEmpty()) { throw new HL7FileMatcherException( diff --git a/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7Message.java b/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7Message.java index b839b5498..f89cb0f78 100644 --- a/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7Message.java +++ b/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7Message.java @@ -1,7 +1,10 @@ package gov.hhs.cdc.trustedintermediary.rse2e.hl7; import gov.hhs.cdc.trustedintermediary.wrappers.HealthData; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.regex.Pattern; /** @@ -10,6 +13,9 @@ */ public class HL7Message implements HealthData { + static final String MSH_SEGMENT_NAME = "MSH"; + static final String NEWLINE_REGEX = "\\r?\\n|\\r"; + private final List segments; private final HL7Encoding encoding; @@ -37,10 +43,32 @@ public String toString() { return String.join( HL7Encoding.DEFAULT_SEGMENT_DELIMITER, getSegments().stream() - .map(segment -> HL7Parser.segmentToString(segment, this.encoding)) + .map(segment -> segmentToString(segment, this.encoding)) .toList()); } + public static HL7Message parse(String content) { + List segments = new ArrayList<>(); + String encodingCharactersField = null; + String[] lines = content.split(NEWLINE_REGEX); + for (String line : lines) { + if (line.trim().isEmpty()) continue; + String[] fields = + line.split( + Pattern.quote(String.valueOf(HL7Encoding.DEFAULT_FIELD_DELIMITER)), -1); + String segmentName = fields[0]; + List segmentFields = + new ArrayList<>(Arrays.asList(fields).subList(1, fields.length)); + if (Objects.equals(segmentName, MSH_SEGMENT_NAME)) { + encodingCharactersField = fields[1]; + segmentFields.add(0, String.valueOf(HL7Encoding.DEFAULT_FIELD_DELIMITER)); + } + segments.add(new HL7Segment(segmentName, segmentFields)); + } + + return new HL7Message(segments, HL7Encoding.fromEncodingField(encodingCharactersField)); + } + public List getSegments() { return this.segments; } @@ -98,4 +126,16 @@ public String getValue(String path) throws HL7MessageException { } return value; } + + protected static String segmentToString(HL7Segment segment, HL7Encoding encoding) { + String fieldSeparator = String.valueOf(encoding.getFieldDelimiter()); + + if (segment.name().equals(MSH_SEGMENT_NAME)) { + return segment.name() + + segment.fields().get(0) + + String.join( + fieldSeparator, segment.fields().subList(1, segment.fields().size())); + } + return segment.name() + fieldSeparator + String.join(fieldSeparator, segment.fields()); + } } diff --git a/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7Parser.java b/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7Parser.java deleted file mode 100644 index a4a6c5808..000000000 --- a/rs-e2e/src/main/java/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7Parser.java +++ /dev/null @@ -1,49 +0,0 @@ -package gov.hhs.cdc.trustedintermediary.rse2e.hl7; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.regex.Pattern; - -/** The HL7Parser class is responsible for parsing HL7 messages and extracting values from them. */ -public class HL7Parser { - static final String MSH_SEGMENT_NAME = "MSH"; - static final String NEWLINE_REGEX = "\\r?\\n|\\r"; - - private HL7Parser() {} - - public static HL7Message parseMessage(String content) { - List segments = new ArrayList<>(); - String encodingCharactersField = null; - String[] lines = content.split(NEWLINE_REGEX); - for (String line : lines) { - if (line.trim().isEmpty()) continue; - String[] fields = - line.split( - Pattern.quote(String.valueOf(HL7Encoding.DEFAULT_FIELD_DELIMITER)), -1); - String segmentName = fields[0]; - List segmentFields = - new ArrayList<>(Arrays.asList(fields).subList(1, fields.length)); - if (Objects.equals(segmentName, MSH_SEGMENT_NAME)) { - encodingCharactersField = fields[1]; - segmentFields.add(0, String.valueOf(HL7Encoding.DEFAULT_FIELD_DELIMITER)); - } - segments.add(new HL7Segment(segmentName, segmentFields)); - } - - return new HL7Message(segments, HL7Encoding.fromEncodingField(encodingCharactersField)); - } - - public static String segmentToString(HL7Segment segment, HL7Encoding encoding) { - String fieldSeparator = String.valueOf(encoding.getFieldDelimiter()); - - if (segment.name().equals(MSH_SEGMENT_NAME)) { - return segment.name() - + segment.fields().get(0) - + String.join( - fieldSeparator, segment.fields().subList(1, segment.fields().size())); - } - return segment.name() + fieldSeparator + String.join(fieldSeparator, segment.fields()); - } -} diff --git a/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7ExpressionEvaluatorTest.groovy b/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7ExpressionEvaluatorTest.groovy index 813a12fd0..c53c3e157 100644 --- a/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7ExpressionEvaluatorTest.groovy +++ b/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7ExpressionEvaluatorTest.groovy @@ -18,7 +18,7 @@ class HL7ExpressionEvaluatorTest extends Specification { messageContent = """MSH|^~\\&|Sender Application^sender.test.com^DNS|Sender Facility^0.0.0.0.0.0.0.0^ISO|Receiver Application^0.0.0.0.0.0.0.0^ISO|Receiver Facility^simulated-lab-id^DNS|20230101010000-0000||ORM^O01^ORM_O01|111111|T|2.5.1 PID|1||11102779^^^CR^MR||SMITH^BB SARAH^^^^^L""" - hl7Message = HL7Parser.parseMessage(messageContent) + hl7Message = HL7Message.parse(messageContent) TestApplicationContext.injectRegisteredImplementations() } diff --git a/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7MessageTest.groovy b/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7MessageTest.groovy index 5579c7f83..abddd47fd 100644 --- a/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7MessageTest.groovy +++ b/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7MessageTest.groovy @@ -15,7 +15,52 @@ ORC|NW|4560411583^ORDERID||||||||||12345^^^^^^^^NPI&2.16.840.1.113883.4.6&ISO^L| OBR|1|4560411583^ORDERID||54089-8^Newborn screening panel AHIC^LN|||202402221854-0500|||||||||12345^^^^^^^^NPI&2.16.840.1.113883.4.6&ISO^L|||||||| OBX|1|ST|57723-9^Unique bar code number of Current sample^LN||123456||||||F|||202402221854-0500 OBX|2|NM|||3122||||||F|||202402221854-0500||""" - message = HL7Parser.parseMessage(messageContent) + message = HL7Message.parse(messageContent) + } + + def "parse should handle basic HL7 message"() { + given: + def content = """MSH|^~\\&|sending_app|sending_facility +PID|||12345||Doe^John||19800101|M""" + + when: + def message = HL7Message.parse(content) + def segments = message.getSegments() + + then: + segments.size() == 2 + segments[0].name() == "MSH" + segments[0].fields().size() == 4 + segments[0].fields().get(0) == "|" + segments[0].fields().get(1) == "^~\\&" + segments[1].name() == "PID" + segments[1].fields().size() == 8 + segments[1].fields().get(2) == "12345" + segments[1].fields().get(4) == "Doe^John" + } + + def "parse should handle empty lines in message"() { + given: + def content = """MSH|^~\\&|sending_app + +PID|||12345""" + + when: + def result = HL7Message.parse(content) + + then: + result.getSegments().size() == 2 + } + + def "parse should preserve empty fields"() { + given: + def content = "MSH|^~\\&|sending_app||sending_facility" + + when: + def result = HL7Message.parse(content) + + then: + result.getSegments().get(0).fields().get(3) == "" } def "getUnderlyingData should correctly return itself"() { diff --git a/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7ParserTest.groovy b/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7ParserTest.groovy deleted file mode 100644 index 5432bfcdc..000000000 --- a/rs-e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/rse2e/hl7/HL7ParserTest.groovy +++ /dev/null @@ -1,52 +0,0 @@ -package gov.hhs.cdc.trustedintermediary.rse2e.hl7 - - -import spock.lang.Specification - -class HL7ParserTest extends Specification { - - def "parseMessage should handle basic HL7 message"() { - given: - def content = """MSH|^~\\&|sending_app|sending_facility -PID|||12345||Doe^John||19800101|M""" - - when: - def message = HL7Parser.parseMessage(content) - def segments = message.getSegments() - - then: - segments.size() == 2 - segments[0].name() == "MSH" - segments[0].fields().size() == 4 - segments[0].fields().get(0) == "|" - segments[0].fields().get(1) == "^~\\&" - segments[1].name() == "PID" - segments[1].fields().size() == 8 - segments[1].fields().get(2) == "12345" - segments[1].fields().get(4) == "Doe^John" - } - - def "parseMessage should handle empty lines in message"() { - given: - def content = """MSH|^~\\&|sending_app - -PID|||12345""" - - when: - def result = HL7Parser.parseMessage(content) - - then: - result.getSegments().size() == 2 - } - - def "parseMessage should preserve empty fields"() { - given: - def content = "MSH|^~\\&|sending_app||sending_facility" - - when: - def result = HL7Parser.parseMessage(content) - - then: - result.getSegments().get(0).fields().get(3) == "" - } -}