From 9578cdb881047f526fdf75f27f9e88adc40da7f8 Mon Sep 17 00:00:00 2001 From: Clement Hennequin Date: Fri, 15 Nov 2024 16:46:03 -0500 Subject: [PATCH] Ack support for configurability by integrating and overriding MQEUtil ok --- .../kernal/logic/IncomingMessageHandler.java | 31 +- .../logic/IncomingMessageHandlerR4.java | 4 +- .../logic/IncomingMessageHandlerR5.java | 4 +- .../logic/ProcessingExceptionReportable.java | 66 ---- .../kernal/logic/{ => ack}/IisAckBuilder.java | 61 ++-- .../iis/kernal/logic/ack/IisAckData.java | 149 +++++++++ .../iis/kernal/logic/ack/IisHL7Util.java | 316 ++++++++++++++++++ .../IisReportable.java} | 84 +++-- .../logic/ack/IisReportableSeverity.java | 70 ++++ 9 files changed, 644 insertions(+), 141 deletions(-) delete mode 100644 src/main/java/org/immregistries/iis/kernal/logic/ProcessingExceptionReportable.java rename src/main/java/org/immregistries/iis/kernal/logic/{ => ack}/IisAckBuilder.java (66%) create mode 100644 src/main/java/org/immregistries/iis/kernal/logic/ack/IisAckData.java create mode 100644 src/main/java/org/immregistries/iis/kernal/logic/ack/IisHL7Util.java rename src/main/java/org/immregistries/iis/kernal/logic/{NISTReportable.java => ack/IisReportable.java} (66%) create mode 100644 src/main/java/org/immregistries/iis/kernal/logic/ack/IisReportableSeverity.java diff --git a/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandler.java b/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandler.java index 225c1f31..b8c72722 100644 --- a/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandler.java +++ b/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandler.java @@ -25,16 +25,15 @@ import org.immregistries.iis.kernal.SoftwareVersion; import org.immregistries.iis.kernal.fhir.interceptors.PartitionCreationInterceptor; import org.immregistries.iis.kernal.fhir.security.ServletHelper; +import org.immregistries.iis.kernal.logic.ack.*; import org.immregistries.iis.kernal.mapping.Interfaces.ImmunizationMapper; import org.immregistries.iis.kernal.mapping.Interfaces.LocationMapper; import org.immregistries.iis.kernal.mapping.Interfaces.ObservationMapper; import org.immregistries.iis.kernal.mapping.Interfaces.PatientMapper; import org.immregistries.iis.kernal.model.*; import org.immregistries.iis.kernal.servlet.PopServlet; -import org.immregistries.mqe.hl7util.Reportable; +import org.immregistries.mqe.hl7util.ReportableSource; import org.immregistries.mqe.hl7util.SeverityLevel; -import org.immregistries.mqe.hl7util.builder.AckData; -import org.immregistries.mqe.hl7util.builder.HL7Util; import org.immregistries.mqe.hl7util.model.CodedWithExceptions; import org.immregistries.mqe.hl7util.model.Hl7Location; import org.immregistries.mqe.validator.MqeMessageService; @@ -226,23 +225,23 @@ public String buildAck(HL7Reader reader, List processingExc sb.append("MSA|").append(overallStatus).append("|").append(sendersUniqueId).append("\r"); for (ProcessingException pe : processingExceptionList) { - sb.append(HL7Util.makeERRSegment(new ProcessingExceptionReportable(pe), false)); + sb.append(IisHL7Util.makeERRSegment(new IisReportable(pe), false)); } return sb.toString(); } - public String buildAckMqe(MqeMessageServiceResponse mqeMessageServiceResponse, List processingExceptionList, Set processingFlavorSet, List validatorReportables) { + public String buildAckMqe(MqeMessageServiceResponse mqeMessageServiceResponse, List processingExceptionList, Set processingFlavorSet, List validatorReportables) { IisAckBuilder ackBuilder = IisAckBuilder.INSTANCE; - AckData data = new AckData(); + IisAckData data = new IisAckData(); MqeMessageHeader header = mqeMessageServiceResponse.getMessageObjects().getMessageHeader(); data.setProfileId(Z23_ACKNOWLEDGEMENT); List resultList = mqeMessageServiceResponse.getValidationResults(); - List reportables = new ArrayList<>(validatorReportables); - reportables.addAll(processingExceptionList.stream().map(ProcessingExceptionReportable::new).collect(Collectors.toList())); + List reportables = new ArrayList<>(validatorReportables); + reportables.addAll(processingExceptionList.stream().map(IisReportable::new).collect(Collectors.toList())); /* This code needs to get put somewhere better. */ for (ValidationRuleResult result : resultList) { - reportables.addAll(result.getValidationDetections()); + reportables.addAll(result.getValidationDetections().stream().map(IisReportable::new).collect(Collectors.toList())); } // if processing flavor contains MEDLAR then all the non E errors have to removed from the processing list if (processingFlavorSet != null && processingFlavorSet.contains(ProcessingFlavor.MEDLAR)) { @@ -518,7 +517,7 @@ public String buildRSP(HL7Reader reader, String messageReceived, PatientMaster p sb.append("MSA|AA|").append(sendersUniqueId).append("\r"); } if (processingExceptionList.size() > 0) { - sb.append(HL7Util.makeERRSegment(new ProcessingExceptionReportable(processingExceptionList.get(processingExceptionList.size() - 1)), false)); + sb.append(IisHL7Util.makeERRSegment(new IisReportable(processingExceptionList.get(processingExceptionList.size() - 1)), false)); } } String profileName = "Request a Complete Immunization History"; @@ -904,9 +903,9 @@ public int readAndCreateObservations(HL7Reader reader, List public abstract ObservationReported readObservations(HL7Reader reader, List processingExceptionList, PatientReported patientReported, boolean strictDate, int obxCount, VaccinationReported vaccinationReported, VaccinationMaster vaccination, String identifierCode, String valueCode); - public List nistValidation(String message) throws Exception { + public List nistValidation(String message) throws Exception { String id = "aa72383a-7b48-46e5-a74a-82e019591fe7"; - List reportableList = new ArrayList(); + List reportableList = new ArrayList(); Report report = syncHL7Validator.check(message, id); logger.info(report.toText()); logger.info(report.toJson()); @@ -921,7 +920,9 @@ public List nistValidation(String message) throws Exception { } if (severityLevel != SeverityLevel.ACCEPT) { - NISTReportable reportable = new NISTReportable(); + IisReportable reportable = new IisReportable(); + reportable.setSource(ReportableSource.NIST); + reportable.setSeverity(IisReportableSeverity.WARN); reportableList.add(reportable); reportable.setReportedMessage(assertion.getDescription()); // reportable.setSeverity(severityLevel); @@ -944,7 +945,7 @@ public List nistValidation(String message) throws Exception { return reportableList; } - public void readErrorLocation(NISTReportable reportable, String path) { + public void readErrorLocation(IisReportable reportable, String path) { if (path != null && path.length() >= 3) { String segmentid = path.substring(0, 3); if (path.length() > 3) { @@ -953,7 +954,7 @@ public void readErrorLocation(NISTReportable reportable, String path) { path = ""; } - Hl7Location errorLocation = NISTReportable.readErrorLocation(path, segmentid); + Hl7Location errorLocation = IisReportable.readErrorLocation(path, segmentid); if (errorLocation != null) { reportable.getHl7LocationList().add(errorLocation); } diff --git a/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandlerR4.java b/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandlerR4.java index dc163f33..98791ddd 100644 --- a/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandlerR4.java +++ b/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandlerR4.java @@ -12,8 +12,8 @@ import org.immregistries.codebase.client.generated.Code; import org.immregistries.codebase.client.reference.CodesetType; import org.immregistries.iis.kernal.fhir.annotations.OnR4Condition; +import org.immregistries.iis.kernal.logic.ack.IisReportable; import org.immregistries.iis.kernal.model.*; -import org.immregistries.mqe.hl7util.Reportable; import org.immregistries.mqe.validator.MqeMessageServiceResponse; import org.immregistries.smm.tester.manager.HL7Reader; import org.springframework.context.annotation.Conditional; @@ -93,7 +93,7 @@ public String processVXU(Tenant tenant, HL7Reader reader, String message, Organi List processingExceptionList = new ArrayList<>(); Set processingFlavorSet = tenant.getProcessingFlavorSet(); MqeMessageServiceResponse mqeMessageServiceResponse = mqeMessageService.processMessage(message); - List nistReportables = nistValidation(message); + List nistReportables = nistValidation(message); try { CodeMap codeMap = CodeMapManager.getCodeMap(); diff --git a/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandlerR5.java b/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandlerR5.java index 49c48510..354d3afc 100644 --- a/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandlerR5.java +++ b/src/main/java/org/immregistries/iis/kernal/logic/IncomingMessageHandlerR5.java @@ -12,8 +12,8 @@ import org.immregistries.codebase.client.generated.Code; import org.immregistries.codebase.client.reference.CodesetType; import org.immregistries.iis.kernal.fhir.annotations.OnR5Condition; +import org.immregistries.iis.kernal.logic.ack.IisReportable; import org.immregistries.iis.kernal.model.*; -import org.immregistries.mqe.hl7util.Reportable; import org.immregistries.mqe.validator.MqeMessageServiceResponse; import org.immregistries.mqe.validator.engine.ValidationRuleResult; import org.immregistries.smm.tester.manager.HL7Reader; @@ -95,7 +95,7 @@ public String processVXU(Tenant tenant, HL7Reader reader, String message, Organi List processingExceptionList = new ArrayList<>(); Set processingFlavorSet = tenant.getProcessingFlavorSet(); MqeMessageServiceResponse mqeMessageServiceResponse = mqeMessageService.processMessage(message); - List nistReportables = nistValidation(message); + List nistReportables = nistValidation(message); try { CodeMap codeMap = CodeMapManager.getCodeMap(); diff --git a/src/main/java/org/immregistries/iis/kernal/logic/ProcessingExceptionReportable.java b/src/main/java/org/immregistries/iis/kernal/logic/ProcessingExceptionReportable.java deleted file mode 100644 index 1b2444dd..00000000 --- a/src/main/java/org/immregistries/iis/kernal/logic/ProcessingExceptionReportable.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.immregistries.iis.kernal.logic; - -import org.immregistries.mqe.hl7util.Reportable; -import org.immregistries.mqe.hl7util.ReportableSource; -import org.immregistries.mqe.hl7util.SeverityLevel; -import org.immregistries.mqe.hl7util.model.CodedWithExceptions; -import org.immregistries.mqe.hl7util.model.Hl7Location; - -import java.util.List; - -public class ProcessingExceptionReportable implements Reportable { - ProcessingException processingException; - - public ProcessingExceptionReportable(ProcessingException processingException) { - this.processingException = processingException; - } - - - @Override - public List getHl7LocationList() { - Hl7Location location = new Hl7Location(); - location.setSegmentId(processingException.getSegmentId()); - location.setFieldRepetition(processingException.getSegmentRepeat()); - location.setFieldPosition(processingException.getFieldPosition()); - return List.of(location); - } - - @Override - public CodedWithExceptions getHl7ErrorCode() { - CodedWithExceptions codedWithExceptions = new CodedWithExceptions(); - codedWithExceptions.setIdentifier("101"); - codedWithExceptions.setNameOfCodingSystem("HL70357"); - codedWithExceptions.setText("Required field missing"); - return codedWithExceptions; - } - - @Override - public SeverityLevel getSeverity() { - return SeverityLevel.findByCode(processingException.getErrorCode()); - } - - @Override - public CodedWithExceptions getApplicationErrorCode() { - CodedWithExceptions codedWithExceptions = new CodedWithExceptions(); -// codedWithExceptions.setIdentifier("101"); -// codedWithExceptions.setNameOfCodingSystem("HL70357"); -// codedWithExceptions.setText("Required field missing"); - return codedWithExceptions; - } - - @Override - public String getReportedMessage() { - return processingException.getLocalizedMessage(); - } - - @Override - public String getDiagnosticMessage() { - return processingException.getMessage(); - } - - - @Override - public ReportableSource getSource() { - return ReportableSource.IIS; - } -} diff --git a/src/main/java/org/immregistries/iis/kernal/logic/IisAckBuilder.java b/src/main/java/org/immregistries/iis/kernal/logic/ack/IisAckBuilder.java similarity index 66% rename from src/main/java/org/immregistries/iis/kernal/logic/IisAckBuilder.java rename to src/main/java/org/immregistries/iis/kernal/logic/ack/IisAckBuilder.java index 58a0bee8..d473fa12 100644 --- a/src/main/java/org/immregistries/iis/kernal/logic/IisAckBuilder.java +++ b/src/main/java/org/immregistries/iis/kernal/logic/ack/IisAckBuilder.java @@ -1,10 +1,6 @@ -package org.immregistries.iis.kernal.logic; +package org.immregistries.iis.kernal.logic.ack; -import org.immregistries.mqe.hl7util.Reportable; -import org.immregistries.mqe.hl7util.SeverityLevel; -import org.immregistries.mqe.hl7util.builder.AckData; import org.immregistries.mqe.hl7util.builder.AckResult; -import org.immregistries.mqe.hl7util.builder.HL7Util; import java.text.SimpleDateFormat; import java.util.Date; @@ -16,16 +12,16 @@ public enum IisAckBuilder { INSTANCE; public static final String PROCESSING_ID_DEBUG = "D"; - public String buildAckFrom(AckData ackDataIn) { + public String buildAckFrom(IisAckData ackDataIn) { String controlId = ackDataIn.getMessageControlId(); String processingId = ackDataIn.getProcessingControlId(); - String ackCode = AckResult.APP_ACCEPT.getCode(); + String ackCode; String hl7ErrorCode = "0"; - if (hasErrors(ackDataIn)) { + if (hasErrorSeverityType(ackDataIn, IisReportableSeverity.ERROR.getCode())) { ackCode = AckResult.APP_ERROR.getCode(); - for (Reportable r : ackDataIn.getReportables()) { - if (r.getSeverity() == SeverityLevel.ERROR && r.getHl7ErrorCode() != null + for (IisReportable r : ackDataIn.getReportables()) { + if (r.getSeverity() == IisReportableSeverity.ERROR && r.getHl7ErrorCode() != null && r.getHl7ErrorCode().getIdentifier() != null) { hl7ErrorCode = r.getHl7ErrorCode().getIdentifier(); if (hl7ErrorCode != null && hl7ErrorCode.startsWith("2")) { @@ -34,6 +30,12 @@ public String buildAckFrom(AckData ackDataIn) { } } } + } else if (hasErrorSeverityType(ackDataIn, IisReportableSeverity.WARN.getCode())) { + ackCode = "AW"; + } else if (hasErrorSeverityType(ackDataIn, "N")) { + ackCode = "AN"; + } else { + ackCode = AckResult.APP_ACCEPT.getCode(); } StringBuilder ack = new StringBuilder(); makeHeader(ack, ackDataIn, "Z23", null); @@ -42,25 +44,25 @@ public String buildAckFrom(AckData ackDataIn) { // SoftwareVersion.BINARY_ID // + "|\r"); ack.append("MSA|" + ackCode + "|" + controlId + "|\r"); - for (Reportable r : ackDataIn.getReportables()) { - if (r.getSeverity() == SeverityLevel.ERROR) { - ack.append(HL7Util.makeERRSegment(r, PROCESSING_ID_DEBUG.equals(processingId))); + for (IisReportable r : ackDataIn.getReportables()) { + if (r.getSeverity() == IisReportableSeverity.ERROR) { + ack.append(IisHL7Util.makeERRSegment(r, PROCESSING_ID_DEBUG.equals(processingId))); } } - for (Reportable r : ackDataIn.getReportables()) { - if (r.getSeverity() == SeverityLevel.WARN) { - ack.append(HL7Util.makeERRSegment(r, PROCESSING_ID_DEBUG.equals(processingId))); + for (IisReportable r : ackDataIn.getReportables()) { + if (r.getSeverity() == IisReportableSeverity.WARN) { + ack.append(IisHL7Util.makeERRSegment(r, PROCESSING_ID_DEBUG.equals(processingId))); } } - for (Reportable r : ackDataIn.getReportables()) { - if (r.getSeverity() == SeverityLevel.INFO) { - ack.append(HL7Util.makeERRSegment(r, PROCESSING_ID_DEBUG.equals(processingId))); + for (IisReportable r : ackDataIn.getReportables()) { + if (r.getSeverity() == IisReportableSeverity.INFO) { + ack.append(IisHL7Util.makeERRSegment(r, PROCESSING_ID_DEBUG.equals(processingId))); } } if (PROCESSING_ID_DEBUG.equals(processingId)) { - for (Reportable r : ackDataIn.getReportables()) { - if (r.getSeverity() == SeverityLevel.ACCEPT) { - ack.append(HL7Util.makeERRSegment(r, PROCESSING_ID_DEBUG.equals(processingId))); + for (IisReportable r : ackDataIn.getReportables()) { + if (r.getSeverity() == IisReportableSeverity.ACCEPT) { + ack.append(IisHL7Util.makeERRSegment(r, PROCESSING_ID_DEBUG.equals(processingId))); } } } @@ -78,35 +80,34 @@ public String buildAckFrom(AckData ackDataIn) { // // 2 Error Location // ack.append("|" + reportable.getHl7LocationList()); // // 3 HL7 Error Code -// HL7Util.appendErrorCode(ack, reportable.getHl7ErrorCode()); +// IisHL7Util.appendErrorCode(ack, reportable.getHl7ErrorCode()); // ack.append("|"); // // 4 Severity // ack.append(severity); // ack.append("|"); // // 5 Application Error Code -// HL7Util.appendAppErrorCode(ack, reportable); +// IisHL7Util.appendAppErrorCode(ack, reportable); // ack.append("|"); // // 6 Application Error Parameter // ack.append("|"); // // 7 Diagnostic Information // ack.append("|"); // // 8 User Message -// ack.append(HL7Util.escapeHL7Chars(reportable.getReportedMessage())); +// ack.append(IisHL7Util.escapeHL7Chars(reportable.getReportedMessage())); // ack.append("|\r"); // // } - private static boolean hasErrors(AckData ackDataIn) { - for (Reportable reportable : ackDataIn.getReportables()) { - if (reportable.getSeverity() == SeverityLevel.ERROR) { -// reportable.getSeverity() == SeverityLevel.WARN) { + private static boolean hasErrorSeverityType(IisAckData ackDataIn, String severityCode) { + for (IisReportable reportable : ackDataIn.getReportables()) { + if (reportable.getSeverity().getCode().equals(severityCode)) { return true; } } return false; } - public static void makeHeader(StringBuilder ack, AckData ackDataIn, String profileId, + public static void makeHeader(StringBuilder ack, IisAckData ackDataIn, String profileId, String responseType) { String receivingApplication = ackDataIn.getSendingApplication(); String receivingFacility = ackDataIn.getSendingFacility(); diff --git a/src/main/java/org/immregistries/iis/kernal/logic/ack/IisAckData.java b/src/main/java/org/immregistries/iis/kernal/logic/ack/IisAckData.java new file mode 100644 index 00000000..f3779012 --- /dev/null +++ b/src/main/java/org/immregistries/iis/kernal/logic/ack/IisAckData.java @@ -0,0 +1,149 @@ +package org.immregistries.iis.kernal.logic.ack; + +import org.immregistries.mqe.hl7util.builder.AckResult; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class IisAckData { + + private String messageProfileId = ""; + private String messageVersionId = ""; + private AckResult result = AckResult.APP_ERROR;// default is error??? + private List reportables = new ArrayList(); + private String messageControlId = ""; + private String processingControlId = ""; + private String receivingApplication = ""; + private String receivingFacility = ""; + private String sendingApplication = ""; + private String sendingFacility = ""; + private Date messageDate = new Date(); + private String responseType = ""; + private String profileId = ""; + + public IisAckData() { + } + + public IisAckData(String messageProfileId, String messageVersionId, + AckResult result, List list, String messageControlId, + String processingControlId, String receivingApplication, + String receivingFacility, String sendingApplication, + String sendingFacility, Date messageDate, String responseType, + String profileId) { + this.messageProfileId = messageProfileId; + this.messageVersionId = messageVersionId; + this.result = result; + this.reportables.addAll(list); + this.messageControlId = messageControlId; + this.processingControlId = processingControlId; + this.receivingApplication = receivingApplication; + this.receivingFacility = receivingFacility; + this.sendingApplication = sendingApplication; + this.sendingFacility = sendingFacility; + } + + public String getMessageProfileId() { + return messageProfileId; + } + + public void setMessageProfileId(String messageProfileId) { + this.messageProfileId = messageProfileId; + } + + public String getMessageVersionId() { + return messageVersionId; + } + + public void setMessageVersionId(String messageVersionId) { + this.messageVersionId = messageVersionId; + } + + public AckResult getResult() { + return result; + } + + public void setResult(AckResult result) { + this.result = result; + } + + public List getReportables() { + return reportables; + } + + public void setReportables(List reportables) { + this.reportables = reportables; + } + + public String getMessageControlId() { + return messageControlId; + } + + public void setMessageControlId(String messageControlId) { + this.messageControlId = messageControlId; + } + + public String getProcessingControlId() { + return processingControlId; + } + + public void setProcessingControlId(String processingControlId) { + this.processingControlId = processingControlId; + } + + public String getReceivingApplication() { + return receivingApplication; + } + + public void setReceivingApplication(String receivingApplication) { + this.receivingApplication = receivingApplication; + } + + public String getReceivingFacility() { + return receivingFacility; + } + + public void setReceivingFacility(String receivingFacility) { + this.receivingFacility = receivingFacility; + } + + public String getSendingApplication() { + return sendingApplication; + } + + public void setSendingApplication(String sendingApplication) { + this.sendingApplication = sendingApplication; + } + + public String getSendingFacility() { + return sendingFacility; + } + + public void setSendingFacility(String sendingFacility) { + this.sendingFacility = sendingFacility; + } + + public Date getMessageDate() { + return messageDate; + } + + public void setMessageDate(Date messageDate) { + this.messageDate = messageDate; + } + + public String getResponseType() { + return responseType; + } + + public void setResponseType(String responseType) { + this.responseType = responseType; + } + + public String getProfileId() { + return profileId; + } + + public void setProfileId(String profileId) { + this.profileId = profileId; + } +} diff --git a/src/main/java/org/immregistries/iis/kernal/logic/ack/IisHL7Util.java b/src/main/java/org/immregistries/iis/kernal/logic/ack/IisHL7Util.java new file mode 100644 index 00000000..66024768 --- /dev/null +++ b/src/main/java/org/immregistries/iis/kernal/logic/ack/IisHL7Util.java @@ -0,0 +1,316 @@ +package org.immregistries.iis.kernal.logic.ack; + +import org.apache.commons.lang3.StringUtils; +import org.immregistries.mqe.hl7util.ReportableSource; +import org.immregistries.mqe.hl7util.builder.AckERRCode; +import org.immregistries.mqe.hl7util.model.CodedWithExceptions; +import org.immregistries.mqe.hl7util.model.Hl7Location; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import static org.immregistries.mqe.vxu.parse.HL7ParsingUtil.escapeHL7Chars; + +public class IisHL7Util { + + public static final String MESSAGE_TYPE_VXU = "VXU"; + public static final String MESSAGE_TYPE_QBP = "QBP"; + + public static final String ACK_ERROR = "AE"; + public static final String ACK_ACCEPT = "AA"; + public static final String ACK_REJECT = "AR"; + + public static final String SEVERITY_ERROR = "E"; + public static final String SEVERITY_WARNING = "W"; + public static final String SEVERITY_INFORMATION = "I"; + + public static final String PROCESSING_ID_DEBUGGING = "D"; + public static final String PROCESSING_ID_PRODUCTION = "P"; + public static final String PROCESSING_ID_TRAINING = "T"; + + public static final String QUERY_RESULT_NO_MATCHES = "Z34"; + public static final String QUERY_RESULT_LIST_OF_CANDIDATES = "Z31"; + public static final String QUERY_RESULT_IMMUNIZATION_HISTORY = "Z32"; + + public static final String QUERY_RESPONSE_TYPE = "RSP^K11^RSP_K11"; + + public static final int BAR = 0; + public static final int CAR = 1; + public static final int TIL = 2; + public static final int SLA = 3; + public static final int AMP = 4; + + private static int ackCount = 1; + + public static synchronized int getNextAckCount() { + if (ackCount == Integer.MAX_VALUE) { + ackCount = 1; + } + return ackCount++; + } + + public static boolean setupSeparators(String messageText, char[] separators) { + if (messageText.startsWith("MSH") && messageText.length() > 10) { + separators[BAR] = messageText.charAt(BAR + 3); + separators[CAR] = messageText.charAt(CAR + 3); + separators[TIL] = messageText.charAt(TIL + 3); + separators[SLA] = messageText.charAt(SLA + 3); + separators[AMP] = messageText.charAt(AMP + 3); + return true; + } else { + setDefault(separators); + return false; + } + } + + public static void setDefault(char[] separators) { + separators[BAR] = '|'; + separators[CAR] = '^'; + separators[TIL] = '~'; + separators[SLA] = '\\'; + separators[AMP] = '&'; + } + + public static boolean checkSeparatorsAreValid(char[] separators) { + boolean unique = true; + // Make sure separators are unique for each other + for (int i = 0; i < separators.length; i++) { + for (int j = i + 1; j < separators.length; j++) { + if (separators[i] == separators[j]) { + unique = false; + break; + } + } + } + return unique; + } + + public static String makeAckMessage(String ackType, String severityLevel, String message, + IisAckData ackData, IisReportable reportable) { + StringBuilder ack = new StringBuilder(); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssZ"); + String messageDate = sdf.format(new Date()); + // MSH + ack.append("MSH|^~\\&"); + ack.append("|" + ackData.getSendingApplication()); // MSH-3 Sending + // Application + ack.append("|" + ackData.getSendingFacility()); // MSH-4 Sending Facility + ack.append("|" + ackData.getReceivingApplication()); // MSH-5 Receiving + // Application + ack.append("|" + ackData.getReceivingFacility()); // MSH-6 Receiving + // Facility + ack.append("|" + messageDate); // MSH-7 Date/Time of Message + ack.append("|"); // MSH-8 Security + ack.append("|ACK"); // MSH-9 + // Message + // Type + ack.append("|" + messageDate + "." + getNextAckCount()); // MSH-10 Message + // Control ID + ack.append("|P"); // MSH-11 Processing ID + ack.append("|2.5.1"); // MSH-12 Version ID + ack.append("|"); // MSH-13 + ack.append("|"); // MSH-14 + ack.append("|"); // MSH-15 + ack.append("|NE"); // MSH-16 + ack.append("|NE"); // MSH-17 + ack.append("|"); // MSH-18 + ack.append("|"); // MSH-19 + ack.append("|"); // MSH-20 + ack.append("|Z23^CDCPHINVS"); // MSH-21 + ack.append("|\r"); + // ack.append("SFT|" + SoftwareVersion.VENDOR + "|" + + // SoftwareVersion.VERSION + "|" + SoftwareVersion.PRODUCT + "|" + + // SoftwareVersion.BINARY_ID + // + "|\r"); + ack.append("MSA|" + ackType + "|" + ackData.getProcessingControlId() + "|\r"); + + ack.append(makeERRSegment(severityLevel, message, reportable)); + + return ack.toString(); + + } + + public static void appendErrorCode(StringBuilder ack, CodedWithExceptions cwe) { + if (cwe != null) { + AckERRCode code = AckERRCode.getFromString(cwe.getIdentifier()); + if (code == null) { + code = AckERRCode.CODE_0_MESSAGE_ACCEPTED; + } + cwe.setNameOfCodingSystem(AckERRCode.TABLE); + cwe.setText(code.text); + } + printCodedWithExceptions(ack, cwe); + } + + public static String makeERRSegment(IisReportable reportable, boolean debug) { + StringBuilder err = new StringBuilder(); + CodedWithExceptions hl7ErrorCode = reportable.getHl7ErrorCode(); + + err.append("ERR||"); + err.append(printErr3(reportable)); + // 2 Error Location + err.append("|"); + // 3 HL7 Error Code + if (hl7ErrorCode == null) { + hl7ErrorCode = new CodedWithExceptions(); + hl7ErrorCode.setIdentifier("0"); + } + IisHL7Util.appendErrorCode(err, reportable.getHl7ErrorCode()); + err.append("|"); + // 4 Severity + IisReportableSeverity level = reportable.getSeverity(); + err.append(level != null ? (level.getCode().equals("A") ? "I" : level.getCode()) : "E"); + + err.append("|"); + // 5 Application Error Code + appendAppErrorCode(err, reportable); + err.append("|"); + // 6 Application Error Parameter + err.append("|"); + // 7 Diagnostic Information + if (debug && reportable.getDiagnosticMessage() != null) { + err.append(escapeHL7Chars(reportable.getDiagnosticMessage())); + } + // 8 User Message + err.append("|"); + err.append(escapeHL7Chars(reportable.getReportedMessage())); + if (reportable.getSource() != ReportableSource.MQE) { + err.append(escapeHL7Chars(" (reported by " + reportable.getSource() + ")")); + } + err.append("|\r"); + return err.toString(); + } + + public static void appendAppErrorCode(StringBuilder ack, IisReportable reportable) { + if (reportable != null) { + CodedWithExceptions cwe = reportable.getApplicationErrorCode(); + if (cwe != null) { + if (StringUtils.isNotBlank(cwe.getIdentifier())) { + if (cwe.getIdentifier().startsWith("MQE")) { + cwe.setAlternateIdentifier(cwe.getIdentifier()); + cwe.setAlternateText(cwe.getText()); + cwe.setNameOfAlternateCodingSystem("L"); + cwe.setIdentifier(""); + cwe.setText(""); + cwe.setNameOfCodingSystem(""); + } + } + if (StringUtils.isNotBlank(cwe.getIdentifier())) { + if (cwe.getText() == null || cwe.getText().equals("")) { + cwe.setNameOfCodingSystem("HL70533"); + if (cwe.getIdentifier().equals("1")) { + cwe.setText("Illogical Date error"); + } else if (cwe.getIdentifier().equals("2")) { + cwe.setText("Invalid Date"); + } else if (cwe.getIdentifier().equals("3")) { + cwe.setText("Illogical Value error"); + } else if (cwe.getIdentifier().equals("4")) { + cwe.setText("Invalid value"); + } else if (cwe.getIdentifier().equals("5")) { + cwe.setText("Table value not found"); + } else if (cwe.getIdentifier().equals("6")) { + cwe.setText("Required observation missing"); + } else if (cwe.getIdentifier().equals("7")) { + cwe.setText("Required data missing"); + } else if (cwe.getIdentifier().equals("8")) { + cwe.setText("Data was ignored"); + } + } + } + } + printCodedWithExceptions(ack, cwe); + } + + } + + private static void printCodedWithExceptions(StringBuilder ack, CodedWithExceptions cwe) { + if (cwe != null) { + if (StringUtils.isNotBlank(cwe.getIdentifier())) { + ack.append(cwe.getIdentifier()); + ack.append("^"); + ack.append(cwe.getText()); + ack.append("^"); + ack.append(cwe.getNameOfCodingSystem()); + if (StringUtils.isNotBlank(cwe.getAlternateIdentifier())) { + ack.append("^"); + } + } + if (StringUtils.isNotBlank(cwe.getAlternateIdentifier())) { + ack.append(cwe.getAlternateIdentifier()); + ack.append("^"); + ack.append(cwe.getAlternateText()); + ack.append("^"); + ack.append(cwe.getNameOfAlternateCodingSystem()); + } + } + } + + private static String printErr3(IisReportable reportable) { + StringBuilder ack = new StringBuilder(); + boolean repeating = false; + if (reportable.getHl7LocationList() != null) { + for (Hl7Location hl7Location : reportable.getHl7LocationList()) { + if (hl7Location.hasSegmentId()) { + if (repeating) { + ack.append("~"); + } + repeating = true; + ack.append(hl7Location.getSegmentId()); + ack.append("^"); + if (hl7Location.getSegmentSequence() == 0) { + ack.append(1); + } else { + ack.append(hl7Location.getSegmentSequence()); + } + + if (hl7Location.hasFieldPosition()) { + ack.append("^"); + ack.append(hl7Location.getFieldPosition()); + ack.append("^"); + if (hl7Location.getFieldRepetition() == 0) { + ack.append(1); + } else { + ack.append(hl7Location.getFieldRepetition()); + } + if (hl7Location.hasComponentNumber()) { + ack.append("^"); + ack.append(hl7Location.getComponentNumber()); + if (hl7Location.hasSubComponentNumber()) { + ack.append("^"); + ack.append(hl7Location.getSubComponentNumber()); + } + } + } + } + } + } + return ack.toString(); + } + + public static String makeERRSegment(String severity, String textMessage, IisReportable reportable) { + StringBuilder ack = new StringBuilder(); + ack.append("ERR||"); + // 2 Error Location + ack.append(reportable.getHl7LocationList() != null && reportable.getHl7LocationList().size() > 0 + ? reportable.getHl7LocationList().get(0) : ""); + ack.append("|"); + // 3 HL7 Error Code + IisHL7Util.appendErrorCode(ack, reportable.getHl7ErrorCode()); + ack.append("|"); + // 4 Severity + ack.append(severity); + ack.append("|"); + // 5 Application Error Code + appendAppErrorCode(ack, reportable); + ack.append("|"); + // 6 Application Error Parameter + ack.append("|"); + // 7 Diagnostic Information + ack.append("|"); + // 8 User Message + ack.append(escapeHL7Chars(textMessage)); + ack.append("|\r"); + return ack.toString(); + } +} diff --git a/src/main/java/org/immregistries/iis/kernal/logic/NISTReportable.java b/src/main/java/org/immregistries/iis/kernal/logic/ack/IisReportable.java similarity index 66% rename from src/main/java/org/immregistries/iis/kernal/logic/NISTReportable.java rename to src/main/java/org/immregistries/iis/kernal/logic/ack/IisReportable.java index f03a6d25..c03235bc 100644 --- a/src/main/java/org/immregistries/iis/kernal/logic/NISTReportable.java +++ b/src/main/java/org/immregistries/iis/kernal/logic/ack/IisReportable.java @@ -1,75 +1,108 @@ -package org.immregistries.iis.kernal.logic; +package org.immregistries.iis.kernal.logic.ack; +import org.immregistries.iis.kernal.logic.ProcessingException; import org.immregistries.mqe.hl7util.Reportable; import org.immregistries.mqe.hl7util.ReportableSource; -import org.immregistries.mqe.hl7util.SeverityLevel; import org.immregistries.mqe.hl7util.model.CodedWithExceptions; import org.immregistries.mqe.hl7util.model.Hl7Location; import java.util.ArrayList; import java.util.List; -public class NISTReportable implements Reportable { +public class IisReportable { private CodedWithExceptions applicationErrorCode = new CodedWithExceptions(); private String diagnosticMessage = null; private CodedWithExceptions hl7ErrorCode = new CodedWithExceptions(); private List hl7LocationList = new ArrayList(); private String reportedMessage = null; - private SeverityLevel severity = null; + private IisReportableSeverity severity = null; private ReportableSource source; - public NISTReportable() { - this.source = ReportableSource.NIST; - this.severity = SeverityLevel.WARN; + public IisReportable() { } - public ReportableSource getSource() { - return this.source; + public IisReportable(Reportable reportable) { + applicationErrorCode = reportable.getApplicationErrorCode(); + diagnosticMessage = reportable.getDiagnosticMessage(); + hl7ErrorCode = reportable.getHl7ErrorCode(); + reportedMessage = reportable.getReportedMessage(); + severity = IisReportableSeverity.findByCode(reportable.getSeverity().getCode()); + source = reportable.getSource(); + } + + + public IisReportable(ProcessingException processingException) { + Hl7Location location = new Hl7Location(); + location.setSegmentId(processingException.getSegmentId()); + location.setFieldRepetition(processingException.getSegmentRepeat()); + location.setFieldPosition(processingException.getFieldPosition()); + hl7LocationList = List.of(location); + hl7ErrorCode = new CodedWithExceptions(); + hl7ErrorCode.setIdentifier("101"); + hl7ErrorCode.setNameOfCodingSystem("HL70357"); + hl7ErrorCode.setText("Required field missing"); + severity = IisReportableSeverity.findByCode(processingException.getErrorCode()); + applicationErrorCode = new CodedWithExceptions(); + reportedMessage = processingException.getLocalizedMessage(); + diagnosticMessage = processingException.getMessage(); + source = ReportableSource.IIS; + } + + public CodedWithExceptions getApplicationErrorCode() { + return applicationErrorCode; } public void setApplicationErrorCode(CodedWithExceptions applicationErrorCode) { this.applicationErrorCode = applicationErrorCode; } + public String getDiagnosticMessage() { + return diagnosticMessage; + } + public void setDiagnosticMessage(String diagnosticMessage) { this.diagnosticMessage = diagnosticMessage; } + public CodedWithExceptions getHl7ErrorCode() { + return hl7ErrorCode; + } + public void setHl7ErrorCode(CodedWithExceptions hl7ErrorCode) { this.hl7ErrorCode = hl7ErrorCode; } - public void setHl7LocationList(List hl7LocationList) { - this.hl7LocationList = hl7LocationList; + public List getHl7LocationList() { + return hl7LocationList; } - public void setReportedMessage(String reportedMessage) { - this.reportedMessage = reportedMessage; + public void setHl7LocationList(List hl7LocationList) { + this.hl7LocationList = hl7LocationList; } - public CodedWithExceptions getApplicationErrorCode() { - return this.applicationErrorCode; + public String getReportedMessage() { + return reportedMessage; } - public String getDiagnosticMessage() { - return this.diagnosticMessage; + public void setReportedMessage(String reportedMessage) { + this.reportedMessage = reportedMessage; } - public CodedWithExceptions getHl7ErrorCode() { - return this.hl7ErrorCode; + public IisReportableSeverity getSeverity() { + return severity; } - public List getHl7LocationList() { - return this.hl7LocationList; + public void setSeverity(IisReportableSeverity severity) { + this.severity = severity; } - public String getReportedMessage() { - return this.reportedMessage; + public ReportableSource getSource() { + return source; } - public SeverityLevel getSeverity() { - return this.severity; + public void setSource(ReportableSource source) { + this.source = source; } public static Hl7Location readErrorLocation(String path, String segmentid) { @@ -157,4 +190,3 @@ private static int parseBracketInt(String s) { } } - diff --git a/src/main/java/org/immregistries/iis/kernal/logic/ack/IisReportableSeverity.java b/src/main/java/org/immregistries/iis/kernal/logic/ack/IisReportableSeverity.java new file mode 100644 index 00000000..bdd097f0 --- /dev/null +++ b/src/main/java/org/immregistries/iis/kernal/logic/ack/IisReportableSeverity.java @@ -0,0 +1,70 @@ +package org.immregistries.iis.kernal.logic.ack; + + +public enum IisReportableSeverity { + + /** + * Data needs to be fixed, and the message should be resubmitted. + */ + ERROR("E", "Error", "Rejected with Errors") + /** + * Data needs to be fixed, but we can deal with it in this message. No need + * to resubmit. + */ + , + WARN("W", "Warn", "Accepted with Warnings") + /** + * This means an issue is acceptable, but we're not going to tell anyone + * about it, except maybe on a report. + */ + , + ACCEPT("A", "Accept", "Accepted") + /** + * This means an issues is acceptable, and we do want to tell people. + */ + , + INFO("I", "Info", "Informational"), + NOTICE("N", "Notice", "Notice"); + + private String severityCode = ""; + private String severityLabel = ""; + private String severityDescription = ""; + + private IisReportableSeverity(String actionCode, String actionLabel, + String actionDesc) { + this.severityCode = actionCode; + this.severityLabel = actionLabel; + this.severityDescription = actionDesc; + } + + public static IisReportableSeverity findByCode(String code) { + for (IisReportableSeverity s : IisReportableSeverity.values()) { + if (s.getCode() == code) { + return s; + } + } + return null; + } + + public static IisReportableSeverity findByLabel(String label) { + for (IisReportableSeverity s : IisReportableSeverity.values()) { + if (s.getLabel().equalsIgnoreCase(label)) { + return s; + } + } + return null; + } + + public String getLabel() { + return this.severityLabel; + } + + public String getCode() { + return severityCode; + } + + public String getDescription() { + return this.severityDescription; + } + +}