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 * 
039 * Abstract base class for Exceptions that are able to create acknowledgement
040 * messages from their error code and location information
041 * 
042 * @author Christian Ohr
043 *
044 */
045@SuppressWarnings("serial")
046public abstract class AbstractHL7Exception extends Exception {
047
048        private Location location;
049        private ErrorCode errorCode = ErrorCode.APPLICATION_INTERNAL_ERROR;
050    private Severity severity = Severity.ERROR;
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.setField(pos);
080        }
081
082        public void setSegmentName(String segmentName) {
083                if (location == null)
084                        location = new Location();
085                location.setSegmentName(segmentName);
086        }
087
088        public void setSegmentRepetition(int segmentRepetition) {
089                if (location == null)
090                        location = new Location();
091                location.setSegmentRepetition(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    /**
119         * Populates the generated response based on this exception.
120         * 
121         * @param response response message
122     * @param acknowledgmentCode the acknowledgement code
123     * @return response message
124         * @throws HL7Exception if populating the response fails
125         */
126        public Message populateResponse(Message response, AcknowledgmentCode acknowledgmentCode, int repetition)
127                        throws HL7Exception {
128                if (acknowledgmentCode == null) acknowledgmentCode = AcknowledgmentCode.AA;
129                if (V25.isGreaterThan(versionOf(response.getVersion()))) {
130                        return populateResponseBefore25(response, acknowledgmentCode, repetition);
131                }
132                return populateResponseAsOf25(response, acknowledgmentCode, repetition);
133        }
134
135        /**
136         * Fill segments for HL7 versions 2.5 or newer.
137         * <p>
138         * HL7 versions before 2.5 require to set MSA-1. The ERR segment has various fields (ERR-2,
139         * ERR-3) containing details about the exception. ERR-1 is marked as obsolete.
140         * 
141         * @param response the raw response message
142     * @param acknowledgmentCode acknowledgmentCode
143         * @param repetition repetition of the ERR segment that shall be populated
144         * @throws HL7Exception
145         */
146        private Message populateResponseAsOf25(Message response, AcknowledgmentCode acknowledgmentCode,
147                        int repetition) throws HL7Exception {
148                // TODO define what should happen if there is no MSA or ERR
149                Segment msa = (Segment) response.get("MSA");
150                Terser.set(msa, 1, 0, 1, 1, acknowledgmentCode.name());
151                Segment err = (Segment) response.get("ERR", repetition);
152                if (location != null) {
153                        if (location.getSegmentName() != null)
154                                Terser.set(err, 2, 0, 1, 1, location.getSegmentName());
155                        if (location.getField() > 0)
156                                Terser.set(err, 2, 0, 3, 1, Integer.toString(location.getField()));
157                        if (location.getFieldRepetition() > 0)
158                                Terser.set(err, 2, 0, 4, 1, Integer.toString(location.getFieldRepetition()));
159                        if (location.getComponent() > 0)
160                                Terser.set(err, 2, 0, 5, 1, Integer.toString(location.getComponent()));
161                        if (location.getSubcomponent() > 0)
162                                Terser.set(err, 2, 0, 6, 1, Integer.toString(location.getSubcomponent()));
163                }
164                Terser.set(err, 3, 0, 1, 1, Integer.toString(errorCode.getCode()));
165                Terser.set(err, 3, 0, 2, 1, errorCode.getMessage());
166                Terser.set(err, 3, 0, 3, 1, ErrorCode.codeTable());
167                Terser.set(err, 3, 0, 9, 1, getMessage());
168                Terser.set(err, 4, 0, 1, 1, "E");
169                return response;
170        }
171
172        /**
173         * Fill segments for HL7 versions before 2.5.
174         * <p>
175         * HL7 versions before 2.5 require to set MSA-1 and MSA-3. The ERR segment only has one
176         * repeatable field (ERR-1) with components containing details about the exception.
177         * 
178         * @param response the raw response message
179         * @param acknowledgmentCode acknowledgment code
180     * @param repetition repetition of the ERR segment that shall be popualted
181         * @throws HL7Exception
182         */
183        private Message populateResponseBefore25(Message response, AcknowledgmentCode acknowledgmentCode,
184                        int repetition) throws HL7Exception {
185                // TODO define what should happen if there is no MSA or ERR
186                Segment msa = (Segment) response.get("MSA");
187                Terser.set(msa, 1, 0, 1, 1, acknowledgmentCode.name());
188                Terser.set(msa, 3, 0, 1, 1, errorCode.getMessage());
189                Segment err = (Segment) response.get("ERR");
190                if (location != null) {
191                        if (location.getSegmentName() != null)
192                                Terser.set(err, 1, repetition, 1, 1, location.getSegmentName());
193                        if (location.getField() > 0)
194                                Terser.set(err, 1, repetition, 3, 1, Integer.toString(location.getField()));
195                }
196                Terser.set(err, 1, repetition, 4, 1, Integer.toString(errorCode.getCode()));
197                Terser.set(err, 1, repetition, 4, 2, errorCode.getMessage());
198                Terser.set(err, 1, repetition, 4, 3, ErrorCode.codeTable());
199                Terser.set(err, 1, repetition, 4, 5, getMessage());
200                return response;
201        }
202
203        public String getMessage() {
204                String message = getMessageWithoutLocation();
205                StringBuilder msg = new StringBuilder(message);
206                if (getLocation() != null && !getLocation().isUnknown()) {
207                        msg.append(" at ").append(getLocation().toString());
208                }
209                return msg.toString();
210        }
211
212    public String getMessageWithoutLocation() {
213        String message = super.getMessage();
214        if (message == null) message = "Exception";
215        return message;
216    }
217
218}