001/*- 002 * #%L 003 * Smile CDR - CDR 004 * %% 005 * Copyright (C) 2016 - 2024 Smile CDR, Inc. 006 * %% 007 * All rights reserved. 008 * #L% 009 */ 010package ca.cdr.api.pub.hl7v2.model; 011 012import ca.cdr.api.model.json.IModelJson; 013import ca.uhn.hl7v2.HL7Exception; 014import ca.uhn.hl7v2.model.AbstractMessage; 015import ca.uhn.hl7v2.model.Message; 016import com.fasterxml.jackson.annotation.JsonCreator; 017import com.fasterxml.jackson.annotation.JsonProperty; 018import com.fasterxml.jackson.annotation.JsonPropertyOrder; 019import org.hl7.fhir.instance.model.api.IBaseBundle; 020import org.springframework.util.CollectionUtils; 021 022import java.util.ArrayList; 023import java.util.List; 024 025import static ca.cdr.api.pub.hl7v2.model.Hl7v2ToFhirConversionResultJson.BUNDLES; 026import static ca.cdr.api.pub.hl7v2.model.Hl7v2ToFhirConversionResultJson.DO_AUTO_CONVERT; 027import static ca.cdr.api.pub.hl7v2.model.Hl7v2ToFhirConversionResultJson.DO_PROCESS; 028import static ca.cdr.api.pub.hl7v2.model.Hl7v2ToFhirConversionResultJson.ISSUES; 029import static ca.cdr.api.pub.hl7v2.model.Hl7v2ToFhirConversionResultJson.MODIFIABLE_MESSAGE; 030import static ca.cdr.api.pub.hl7v2.model.Hl7v2ToFhirConversionResultJson.ORIGINAL_MESSAGE; 031 032/** 033 * Contains all relevant data involved in the conversion of an HL7 v2.x message to a list of IBaseBundle resources. 034 */ 035@JsonPropertyOrder({ORIGINAL_MESSAGE, MODIFIABLE_MESSAGE, BUNDLES, ISSUES, DO_PROCESS, DO_AUTO_CONVERT}) 036public class Hl7v2ToFhirConversionResultJson implements IModelJson { 037 038 public static final String ORIGINAL_MESSAGE = "originalMessage"; 039 public static final String MODIFIABLE_MESSAGE = "modifiableMessage"; 040 public static final String BUNDLES = "bundles"; 041 public static final String ISSUES = "issues"; 042 public static final String DO_PROCESS = "doProcess"; 043 public static final String DO_AUTO_CONVERT = "doAutoConvert"; 044 045 /** 046 * The original HL7 v2.x message before any customizations have been applied. 047 */ 048 @JsonProperty(ORIGINAL_MESSAGE) 049 private Message myOriginalMessage; 050 051 /** 052 * The HL7 v2.x message which customizations can be applied to. 053 */ 054 @JsonProperty(MODIFIABLE_MESSAGE) 055 private Message myModifiableMessage; 056 057 /** 058 * A list of Bundle resources that have been created from the modifiableMessage. 059 */ 060 @JsonProperty(BUNDLES) 061 private List<IBaseBundle> myBundles = new ArrayList<>(); 062 063 /** 064 * A list of issues that have occurred throughout the conversion process. 065 */ 066 @JsonProperty(ISSUES) 067 private List<MappingMessage> myIssues = new ArrayList<>(); 068 069 /** 070 * A flag to indicate whether a given message should be processed. 071 */ 072 @JsonProperty(DO_PROCESS) 073 private boolean myDoProcess; 074 075 /** 076 * A flag to indicate whether a given message should be passed through the Smile generic mapper. 077 * Set this to false in order to skip the Smile generic mapper entirely. 078 */ 079 @JsonProperty(DO_AUTO_CONVERT) 080 private boolean myDoAutoConvert; 081 082 /** 083 * Constructor 084 * @param theOriginalMessage The original message to be preserved during the HL7V2 to FHIR conversion 085 */ 086 @JsonCreator 087 public Hl7v2ToFhirConversionResultJson(@JsonProperty(ORIGINAL_MESSAGE) Message theOriginalMessage) 088 throws HL7Exception { 089 myOriginalMessage = theOriginalMessage; 090 myModifiableMessage = cloneMessage(theOriginalMessage); 091 myDoProcess = true; 092 myDoAutoConvert = true; 093 } 094 095 /** 096 * @deprecated Use {@link AbstractMessage#copy()} instead. 097 * <br/><br/> 098 * Clones the specified {@link Message} into a new {@link Message} with the same contents 099 * @param theMessage The message to clone 100 */ 101 @Deprecated(since = "2023.11.R01") 102 public static Message cloneMessage(Message theMessage) throws HL7Exception { 103 return ((AbstractMessage) theMessage).copy(); 104 } 105 106 /** 107 * Adds a bundle 108 * @param theBundle The bundle to add 109 */ 110 public void addBundle(IBaseBundle theBundle) { 111 myBundles.add(theBundle); 112 } 113 114 /** 115 * Adds a message to the conversion result. Acceptable message levels are `INFO`, `WARNING`, and `ERROR` 116 * 117 * @param thePath The path within the message where the issue was detected 118 * @param theMessageLevel The issue error level, e.g. 'INFO', 'WARNING', or 'ERROR'. 119 * @param theIssue The description of the issue 120 */ 121 public void addIssue(String thePath, MappingMessage.MessageLevel theMessageLevel, String theIssue) { 122 MappingMessage issue = new MappingMessage(thePath, MappingMessage.PathType.HL7V2, theMessageLevel, theIssue); 123 this.addIssue(issue); 124 } 125 126 /** 127 * Adds an issue 128 * @param theIssue The issue to add 129 */ 130 public void addIssue(MappingMessage theIssue) { 131 if (myIssues.isEmpty()) { 132 myIssues = new ArrayList<>(); 133 } 134 myIssues.add(theIssue); 135 } 136 137 /** 138 * Indicates whether there were any issues ({@link MappingMessage.MessageLevel#INFO}, 139 * {@link MappingMessage.MessageLevel#WARNING}, or {@link MappingMessage.MessageLevel#ERROR}) 140 * during the message conversion 141 * @return true if there are any issues 142 */ 143 public boolean hasIssues() { 144 return !CollectionUtils.isEmpty(myIssues); 145 } 146 147 /** 148 * Indicates whether there were any {@link MappingMessage.MessageLevel#INFO} issues 149 * during the message conversion 150 * @return true if there are any {@link MappingMessage.MessageLevel#INFO} issues 151 */ 152 public boolean hasInfoIssues() { 153 return hasIssueOfType(MappingMessage.MessageLevel.INFO); 154 } 155 156 /** 157 * Indicates whether there were any {@link MappingMessage.MessageLevel#WARNING} issues 158 * during the message conversion 159 * @return true if there are any {@link MappingMessage.MessageLevel#WARNING} issues 160 */ 161 public boolean hasWarningIssues() { 162 return hasIssueOfType(MappingMessage.MessageLevel.WARNING); 163 } 164 165 /** 166 * Indicates whether there were any {@link MappingMessage.MessageLevel#ERROR} issues 167 * during the message conversion 168 * @return true if there are any {@link MappingMessage.MessageLevel#ERROR} issues 169 */ 170 public boolean hasErrorIssues() { 171 return hasIssueOfType(MappingMessage.MessageLevel.ERROR); 172 } 173 174 private boolean hasIssueOfType(MappingMessage.MessageLevel theType) { 175 return myIssues.stream().anyMatch(m -> theType.equals(m.getLevel())); 176 } 177 178 /** 179 * @return A copy of the original HL7 v2.x message before any customizations have been applied. 180 */ 181 public Message getOriginalMessage() throws HL7Exception { 182 return cloneMessage(myOriginalMessage); 183 } 184 185 /** 186 * @return The HL7 v2.x message which customizations can be applied to. 187 */ 188 public Message getModifiableMessage() { 189 return myModifiableMessage; 190 } 191 192 /** 193 * Sets the HL7 v2.x message which customizations can be applied to. 194 * @param theModifiableMessage The modifiable Message 195 */ 196 public void setModifiableMessage(Message theModifiableMessage) { 197 myModifiableMessage = theModifiableMessage; 198 } 199 200 /** 201 * @return A list of Bundle resources that have been created from the modifiable Message. 202 */ 203 public List<IBaseBundle> getBundles() { 204 return myBundles; 205 } 206 207 /** 208 * Sets the list of Bundle resources that have been created from the modifiable Message. 209 * @param theBundles The Bundles 210 */ 211 public void setBundles(List<IBaseBundle> theBundles) { 212 myBundles = theBundles; 213 } 214 215 /** 216 * @return A list of issues that have occurred throughout the conversion process. 217 */ 218 public List<MappingMessage> getIssues() { 219 return myIssues; 220 } 221 222 /** 223 * Sets the list of issues that have occurred throughout the conversion process. 224 * @param theIssues The issues 225 */ 226 public void setIssues(List<MappingMessage> theIssues) { 227 myIssues = new ArrayList<>(); 228 addIssues(theIssues); 229 } 230 231 /** 232 * Adds the items in list of issues that have occurred throughout the conversion process. 233 * @param theIssues The issues 234 */ 235 public void addIssues(List<MappingMessage> theIssues) { 236 if (!theIssues.isEmpty()) { 237 myIssues.addAll(theIssues); 238 } 239 } 240 241 /** 242 * @return Whether the modifiable Message should be processed. 243 */ 244 public boolean isDoProcess() { 245 return myDoProcess; 246 } 247 248 /** 249 * Sets a flag to indicate whether the modifiable Message should be processed. 250 * @param theDoProcess The value of the flag 251 */ 252 public void setDoProcess(boolean theDoProcess) { 253 myDoProcess = theDoProcess; 254 } 255 256 /** 257 * @return Whether the modifiable Message should be passed through the Smile generic mapper. 258 */ 259 public boolean isDoAutoConvert() { 260 return myDoAutoConvert; 261 } 262 263 /** 264 * Sets a flag to indicate whether the modifiable Message should be passed through the Smile generic mapper. 265 * <br/> 266 * The Smile generic mapper will be skipped entirely if this flag is set to false. 267 * @param theDoAutoConvert The value of the flag 268 */ 269 public void setDoAutoConvert(boolean theDoAutoConvert) { 270 myDoAutoConvert = theDoAutoConvert; 271 } 272}