001
002/*
003 The contents of this file are subject to the Mozilla Public License Version 1.1
004 (the "License"); you may not use this file except in compliance with the License.
005 You may obtain a copy of the License at http://www.mozilla.org/MPL/
006 Software distributed under the License is distributed on an "AS IS" basis,
007 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
008 specific language governing rights and limitations under the License.
009
010 The Original Code is "AbstractHL7Exception.java".  Description:
011 "Exception containing a Location and Error Code"
012
013 The Initial Developer of the Original Code is University Health Network. Copyright (C)
014 2012.  All Rights Reserved.
015
016 Contributor(s): ______________________________________.
017
018 Alternatively, the contents of this file may be used under the terms of the
019 GNU General Public License (the "GPL"), in which case the provisions of the GPL are
020 applicable instead of those above.  If you wish to allow use of your version of this
021 file only under the terms of the GPL and not to allow others to use your version
022 of this file under the MPL, indicate your decision by deleting  the provisions above
023 and replace  them with the notice and other provisions required by the GPL License.
024 If you do not delete the provisions above, a recipient may use your version of
025 this file under either the MPL or the GPL.
026 */
027
028package ca.uhn.hl7v2;
029
030import static ca.uhn.hl7v2.Version.V25;
031import static ca.uhn.hl7v2.Version.versionOf;
032
033import ca.uhn.hl7v2.model.Message;
034import ca.uhn.hl7v2.model.Segment;
035import ca.uhn.hl7v2.util.Terser;
036
037/**
038 * Abstract base class for Exceptions that are able to create acknowledgement
039 * messages from their error code and location information
040 *
041 * @author Christian Ohr
042 */
043@SuppressWarnings("serial")
044public abstract class AbstractHL7Exception extends Exception {
045
046    private Location location;
047    private ErrorCode errorCode = ErrorCode.APPLICATION_INTERNAL_ERROR;
048    private Severity severity = Severity.ERROR;
049    private Message responseMessage;
050
051
052    public AbstractHL7Exception() {
053        super();
054    }
055
056    public AbstractHL7Exception(String message, Throwable cause) {
057        super(message, cause);
058    }
059
060    public AbstractHL7Exception(String message) {
061        super(message);
062    }
063
064    public AbstractHL7Exception(Throwable cause) {
065        super(cause);
066    }
067
068    public Location getLocation() {
069        return location;
070    }
071
072    public void setLocation(Location location) {
073        this.location = location;
074    }
075
076    public void setFieldPosition(int pos) {
077        if (location == null)
078            location = new Location();
079        location.withField(pos);
080    }
081
082    public void setSegmentName(String segmentName) {
083        if (location == null)
084            location = new Location();
085        location.withSegmentName(segmentName);
086    }
087
088    public void setSegmentRepetition(int segmentRepetition) {
089        if (location == null)
090            location = new Location();
091        location.withSegmentRepetition(segmentRepetition);
092    }
093
094    public int getErrorCode() {
095        return errorCode.getCode();
096    }
097
098    public void setErrorCode(int errorCode) {
099        this.errorCode = ErrorCode.errorCodeFor(errorCode);
100    }
101
102    public ErrorCode getError() {
103        return errorCode;
104    }
105
106    public void setError(ErrorCode errorCode) {
107        this.errorCode = errorCode;
108    }
109
110    public Severity getSeverity() {
111        return severity;
112    }
113
114    public void setSeverity(Severity severity) {
115        this.severity = severity;
116    }
117
118    public Message getResponseMessage() {
119        return responseMessage;
120    }
121
122    public void setResponseMessage(Message responseMessage) {
123        this.responseMessage = responseMessage;
124    }
125
126    /**
127     * Populates the generated response based on this exception.
128     *
129     * @param emptyResponse empty response message
130     * @param acknowledgmentCode the acknowledgement code
131     * @return response message
132     * @throws HL7Exception if populating the response fails
133     */
134    public Message populateResponse(Message emptyResponse, AcknowledgmentCode acknowledgmentCode, int repetition)
135            throws HL7Exception {
136        if (responseMessage == null) {
137            if (acknowledgmentCode == null) acknowledgmentCode = AcknowledgmentCode.AA;
138            if (V25.isGreaterThan(versionOf(emptyResponse.getVersion()))) {
139                responseMessage = populateResponseBefore25(emptyResponse, acknowledgmentCode, repetition);
140            } else {
141                responseMessage = populateResponseAsOf25(emptyResponse, acknowledgmentCode, repetition);
142            }
143        }
144        return responseMessage;
145    }
146
147    /**
148     * Fill segments for HL7 versions 2.5 or newer.
149     * <p/>
150     * HL7 versions before 2.5 require to set MSA-1. The ERR segment has various fields (ERR-2,
151     * ERR-3) containing details about the exception. ERR-1 is marked as obsolete.
152     *
153     * @param response           the raw response message
154     * @param acknowledgmentCode acknowledgmentCode
155     * @param repetition         repetition of the ERR segment that shall be populated
156     * @throws HL7Exception
157     */
158    private Message populateResponseAsOf25(Message response, AcknowledgmentCode acknowledgmentCode,
159                                           int repetition) throws HL7Exception {
160        // TODO define what should happen if there is no MSA or ERR
161        Segment msa = (Segment) response.get("MSA");
162        Terser.set(msa, 1, 0, 1, 1, acknowledgmentCode.name());
163        Segment err = (Segment) response.get("ERR", repetition);
164        if (location != null) {
165            if (location.getSegmentName() != null)
166                Terser.set(err, 2, 0, 1, 1, location.getSegmentName());
167            if (location.getSegmentRepetition() > 0)
168                Terser.set(err, 2, 0, 2, 1, Integer.toString(location.getSegmentRepetition()));
169            if (location.getField() > 0)
170                Terser.set(err, 2, 0, 3, 1, Integer.toString(location.getField()));
171            if (location.getFieldRepetition() > 0)
172                Terser.set(err, 2, 0, 4, 1, Integer.toString(location.getFieldRepetition()));
173            if (location.getComponent() > 0)
174                Terser.set(err, 2, 0, 5, 1, Integer.toString(location.getComponent()));
175            if (location.getSubcomponent() > 0)
176                Terser.set(err, 2, 0, 6, 1, Integer.toString(location.getSubcomponent()));
177        }
178        Terser.set(err, 3, 0, 1, 1, Integer.toString(errorCode.getCode()));
179        Terser.set(err, 3, 0, 2, 1, errorCode.getMessage());
180        Terser.set(err, 3, 0, 3, 1, ErrorCode.codeTable());
181        Terser.set(err, 3, 0, 9, 1, getMessage());
182        Terser.set(err, 4, 0, 1, 1, "E");
183        return response;
184    }
185
186    /**
187     * Fill segments for HL7 versions before 2.5.
188     * <p/>
189     * HL7 versions before 2.5 require to set MSA-1 and MSA-3. The ERR segment only has one
190     * repeatable field (ERR-1) with components containing details about the exception.
191     *
192     * @param response           the raw response message
193     * @param acknowledgmentCode acknowledgment code
194     * @param repetition         repetition of the ERR segment that shall be popualted
195     * @throws HL7Exception
196     */
197    private Message populateResponseBefore25(Message response, AcknowledgmentCode acknowledgmentCode,
198                                             int repetition) throws HL7Exception {
199        // TODO define what should happen if there is no MSA or ERR
200        Segment msa = (Segment) response.get("MSA");
201        Terser.set(msa, 1, 0, 1, 1, acknowledgmentCode.name());
202        Terser.set(msa, 3, 0, 1, 1, errorCode.getMessage());
203        Segment err = (Segment) response.get("ERR");
204        if (location != null) {
205            if (location.getSegmentName() != null)
206                Terser.set(err, 1, repetition, 1, 1, location.getSegmentName());
207            if (location.getField() > 0)
208                Terser.set(err, 1, repetition, 3, 1, Integer.toString(location.getField()));
209        }
210        Terser.set(err, 1, repetition, 4, 1, Integer.toString(errorCode.getCode()));
211        Terser.set(err, 1, repetition, 4, 2, errorCode.getMessage());
212        Terser.set(err, 1, repetition, 4, 3, ErrorCode.codeTable());
213        Terser.set(err, 1, repetition, 4, 5, getMessage());
214        return response;
215    }
216
217    public String getMessage() {
218        String message = getMessageWithoutLocation();
219        StringBuilder msg = new StringBuilder(message);
220        if (getLocation() != null && !getLocation().isUnknown()) {
221            msg.append(" at ").append(getLocation().toString());
222        }
223        return msg.toString();
224    }
225
226    public String getMessageWithoutLocation() {
227        String message = super.getMessage();
228        if (message == null) message = "Exception";
229        return message;
230    }
231
232}