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}