1 /*
2 Licensed under the Apache License, Version 2.0 (the "License");
3 you may not use this file except in compliance with the License.
4 You may obtain a copy of the License at
5
6 http://www.apache.org/licenses/LICENSE-2.0
7
8 Unless required by applicable law or agreed to in writing, software
9 distributed under the License is distributed on an "AS IS" BASIS,
10 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 See the License for the specific language governing permissions and
12 limitations under the License.
13 */
14 package uk.nhs.interoperability.infrastructure;
15
16 import java.util.Locale;
17 import java.util.UUID;
18
19 import uk.nhs.interoperability.transport.ITKTransportProperties;
20
21 /**
22 * Base exception for the ITK Messaging api. Has the capability to wrap
23 * standard java exceptions as well as being able to represent more structured
24 * errors such as SOAP Faults - e.g. by representing the
25 * <code><itk:ToolkitErrorInfo/></code> information elements
26 *
27 * @see ITKTransportTimeoutException
28 * @see ITKCommsException
29 *
30 * @author Michael Odling-Smee
31 * @author Nicholas Jones
32 * @since version 0.1
33 */
34 public class ITKMessagingException extends Exception {
35
36 private static final long serialVersionUID = -462421080532710296L;
37
38 /**
39 * This is the OID to represent the default code system when raising SOAP faults etc.
40 * OID is <code>2.16.840.1.1138883.2.1.3.2.4.17.268</code>
41 */
42 public static final String DEFAULT_ERROR_CODESYSTEM_OID = "2.16.840.1.113883.2.1.3.2.4.17.268";
43
44 /**
45 * Default error "code" that indicates that no
46 * error code is associated with this ITKMessagingException
47 */
48 public static final int NO_ERROR_CODE = -1;
49
50 /**
51 * Invalid Message - the message structure or content is unrecognised or incorrect
52 */
53 public static final int INVALID_MESSAGE_CODE = 1000;
54
55 /**
56 * Processing Error (retryable) - a recoverable processing error has been encountered
57 */
58 public static final int PROCESSING_ERROR_RETRYABLE_CODE = 2100;
59
60 /**
61 * Processing Error (not retryable) - a non-recoverable processing error has been encountered
62 */
63 public static final int PROCESSING_ERROR_NOT_RETRYABLE_CODE = 2200;
64
65 /**
66 * Access Denied
67 */
68 public static final int ACCESS_DENIED_CODE = 3000;
69
70 /**
71 * Standard text associated with the {@link #INVALID_MESSAGE_CODE}
72 */
73 public static final String INVALID_MESSAGE_TEXT = "Invalid Message - the message structure or content is unrecognised or incorrect";
74
75 /**
76 * Standard text associated with the {@link #PROCESSING_ERROR_RETRYABLE_CODE}
77 */
78 public static final String PROCESSING_ERROR_RETRYABLE_TEXT = "Processing Error (retryable) - a recoverable processing error has been encountered";
79
80 /**
81 * Standard text associated with the {@link #PROCESSING_ERROR_NOT_RETRYABLE_CODE}
82 */
83 public static final String PROCESSING_ERROR_NOT_RETRYABLE_TEXT = "Processing Error (not retryable) - a non-recoverable processing error has been encountered";
84
85 /**
86 * Standard text associated with the {@link #ACCESS_DENIED_CODE}
87 */
88 public static final String ACCESS_DENIED_TEXT = "Access Denied";
89
90 /**
91 * Unique error Id used in applications logs to be able to uniquely tie
92 * log messages / exception trace together to aid in diagnostics
93 */
94 private String errorId = UUID.randomUUID().toString().toUpperCase();
95
96 /**
97 * Error code initialised to {@link #NO_ERROR_CODE}
98 * to indicate that there is no error code
99 */
100 private int errorCode = NO_ERROR_CODE;
101
102 /**
103 * ITKMessageProperties associated with the exception
104 */
105 private ITKMessageProperties relatedMessageProperties;
106
107 /**
108 * Transport properties associated with the exception
109 */
110 private ITKTransportProperties relatedItkTransportProperties;
111
112 /**
113 * Initialise the errorCodeSystem to the {@link #DEFAULT_ERROR_CODESYSTEM_OID}
114 */
115 private String errorCodeSystem = DEFAULT_ERROR_CODESYSTEM_OID;
116
117
118 /**
119 * Creates an ITKMessagingException with any relevant diagnostic
120 * information about the error - such as the likely cause
121 *
122 * @param message The diagnostic message about the
123 * the error condition
124 */
125 public ITKMessagingException(String message) {
126 super(message);
127 }
128
129 /**
130 * Creates an ITKMessagingException that wraps an underlying
131 * <code>Throwable</code> which has been encountered
132 * when sending/receiving a message
133 *
134 * @param cause The <code>Throwable</code> containing
135 * the root cause
136 */
137 public ITKMessagingException(Throwable cause) {
138 super(cause);
139 }
140
141 /**
142 * Creates an ITKMessagingException with any relevant diagnostic
143 * information about the error - such as the likely cause. An
144 * error code associated with the exception indicates the
145 * characteristics of the underlying issue - e.g. whether or not
146 * it is retryable or not {@link #getErrorCode()}.<br/><br/>
147 *
148 * Note: by default the <code>errorCode</code> is assumed to be
149 * a code associated with the
150 * {@link #DEFAULT_ERROR_CODESYSTEM_OID} codeSystem
151 *
152 * @param errorCode The appropriate errorCode associated
153 * with the exception - {@link #INVALID_MESSAGE_CODE};
154 * {@link #PROCESSING_ERROR_RETRYABLE_CODE};
155 * {@link #PROCESSING_ERROR_NOT_RETRYABLE_CODE} and
156 * {@link #ACCESS_DENIED_CODE}
157 *
158 * @param message The diagnostic message about the
159 * the error condition
160 */
161 public ITKMessagingException(int errorCode, String message) {
162 super(message);
163 this.setErrorCode(errorCode);
164 }
165
166 /**
167 * Creates an ITKMessagingException that wraps an underlying
168 * <code>Throwable</code> which has been encountered
169 * when sending/receiving a message
170 *
171 * @param message The diagnostic message about the
172 * the error condition
173 *
174 * @param cause The <code>Throwable</code> containing
175 * the root cause
176 */
177 public ITKMessagingException(String message, Throwable cause) {
178 super(message, cause);
179 }
180
181 /**
182 * Creates an ITKMessagingException that wraps an underlying
183 * <code>Throwable</code> which has been encountered
184 * when sending/receiving a message<br/><br/>
185 *
186 * Note: by default the <code>errorCode</code> is assumed to be
187 * a code associated with the
188 * {@link #DEFAULT_ERROR_CODESYSTEM_OID} codeSystem
189 *
190 * @param errorCode The appropriate errorCode associated
191 * with the exception - {@link #INVALID_MESSAGE_CODE};
192 * {@link #PROCESSING_ERROR_RETRYABLE_CODE};
193 * {@link #PROCESSING_ERROR_NOT_RETRYABLE_CODE} and
194 * {@link #ACCESS_DENIED_CODE}
195 *
196 * @param message The diagnostic message about the
197 * the error condition
198 *
199 * @param cause The <code>Throwable</code> containing
200 * the root cause
201 */
202 public ITKMessagingException(int errorCode, String message, Throwable cause) {
203 super(message, cause);
204 this.setErrorCode(errorCode);
205 }
206
207 public ITKMessagingException(ITKTransportProperties itkTransportProperties, ITKMessageProperties itkMessageProperties, int errorCode, String message) {
208 super(message);
209 this.setRelatedMessageProperties(itkMessageProperties);
210 this.setErrorCode(errorCode);
211 this.setRelatedItkTransportProperties(itkTransportProperties);
212 }
213
214 public ITKMessagingException(ITKTransportProperties itkTransportProperties, ITKMessageProperties itkMessageProperties, int errorCode, String message, Throwable cause) {
215 super(message, cause);
216 this.setRelatedMessageProperties(itkMessageProperties);
217 this.setErrorCode(errorCode);
218 this.setRelatedItkTransportProperties(itkTransportProperties);
219 }
220
221 public ITKMessagingException(ITKMessageProperties itkMessageProperties, int errorCode, String arg0) {
222 super(arg0);
223 this.setRelatedMessageProperties(itkMessageProperties);
224 this.setErrorCode(errorCode);
225 }
226
227 public ITKMessagingException(ITKMessageProperties itkMessageProperties, int errorCode, String message, Throwable cause) {
228 super(message, cause);
229 this.setRelatedMessageProperties(itkMessageProperties);
230 this.setErrorCode(errorCode);
231 }
232
233 /**
234 * Obtains the <code>errorCode</code> associated with
235 * the ITKMessagingException.
236 *
237 * Note: by default the <code>errorCode</code> is assumed to be
238 * a code associated with the
239 * {@link #DEFAULT_ERROR_CODESYSTEM_OID} codeSystem
240 *
241 * @return the <code>errorCode</code> associated
242 * with the exception and appropriate to the
243 * {@link #getErrorCodeSystem()}}. If no error code
244 * has been defined {@link #NO_ERROR_CODE} (the int -1)
245 * is returned
246 */
247 public int getErrorCode() {
248 return errorCode;
249 }
250
251 /**
252 * Sets the <code>errorCode</code> associated with
253 * the ITKMessagingException.
254 *
255 * Note: by default the <code>errorCode</code> is assumed to be
256 * a code associated with the
257 * {@link #DEFAULT_ERROR_CODESYSTEM_OID} codeSystem. To use
258 * and alternative system set the <code>errorCodeSystem</code>
259 * via the {@link #setErrorCodeSystem(String)} method
260 *
261 * @param errorCode The appropriate errorCode associated
262 * with the exception - {@link #INVALID_MESSAGE_CODE};
263 * {@link #PROCESSING_ERROR_RETRYABLE_CODE};
264 * {@link #PROCESSING_ERROR_NOT_RETRYABLE_CODE} and
265 * {@link #ACCESS_DENIED_CODE}
266 */
267 public void setErrorCode(int errorCode) {
268 this.errorCode = errorCode;
269 }
270
271 /**
272 * Obtains the <code>errorCodeSystem</code> for any
273 * <code>errorCode</code> associated with the
274 * ITKMessagingException. This is only relevant if the
275 * {@link #getErrorCode()} returns anything other than
276 * {@link #NO_ERROR_CODE}
277 *
278 * @return The <code>errorCodeSystem</code> associated
279 * with the <code>errorCode</code> for with the
280 * ITKMessagingException. The default error code system
281 * is indicated by the
282 * {@link #DEFAULT_ERROR_CODESYSTEM_OID}
283 */
284 public String getErrorCodeSystem() {
285 return errorCodeSystem;
286 }
287
288 /**
289 * Sets the <code>errorCodeSystem</code> for any
290 * <code>errorCode</code> associated with the
291 * ITKMessagingException. This is only relevant if the
292 * {@link #setErrorCode(int)} (or an appropriate constructor)
293 * is used to set the <code>errorCode</code> to something
294 * other than {@link #NO_ERROR_CODE}
295 *
296 * @param errorCodeSystem The <code>errorCodeSystem</code> associated
297 * with the <code>errorCode</code> for with the
298 * ITKMessagingException. The default error code system
299 * is indicated by the
300 * {@link #DEFAULT_ERROR_CODESYSTEM_OID}
301 */
302 public void setErrorCodeSystem(String errorCodeSystem) {
303 this.errorCodeSystem = errorCodeSystem;
304 }
305
306 public ITKMessageProperties getRelatedMessageProperties() {
307 return relatedMessageProperties;
308 }
309
310 public void setRelatedMessageProperties(ITKMessageProperties relatedMessageProperties) {
311 this.relatedMessageProperties = relatedMessageProperties;
312 }
313
314 /**
315 * Obtains the unique errorId for the ITKMessagingException
316 * The <code>errorId</code> is typically expected to be
317 * used in applications logs to uniquely tie
318 * log messages / exception traces together to aid in diagnostics
319 *
320 * @return the <code>errorId</code> associated with this
321 * ITKMessagingException.
322 */
323 public String getErrorId() {
324 return errorId;
325 }
326
327 /**
328 * Obtains the unique errorId for the ITKMessagingException
329 * The <code>errorId</code> is typically expected to be
330 * used in applications logs to uniquely tie
331 * log messages / exception traces together to aid in diagnostics
332 *
333 * @param errorId the <code>errorId</code> associated with this
334 * ITKMessagingException.
335 */
336 public void setErrorId(String errorId) {
337 this.errorId = errorId;
338 }
339
340 /**
341 * Obtains the standard (human readable message) associated with the
342 * ITKMessagingException. The text also contains the <code>errorId</code>
343 * to ensure it is represented in logs/stack traces
344 */
345 @Override
346 public String getMessage() {
347 return super.getMessage().startsWith("[" + this.errorId) ? super.getMessage() : "[" + this.errorId + "] " + super.getMessage();
348 }
349
350 /**
351 * Obtains the standard (human readable message) associated with the
352 * ITKMessagingException in the language for the {@link Locale} where it
353 * localised messages are available.
354 *
355 * The text also contains the <code>errorId</code>
356 * to ensure it is represented in logs/stack traces
357 */
358 @Override
359 public String getLocalizedMessage() {
360 return super.getLocalizedMessage().startsWith("[" + this.errorId) ? super.getLocalizedMessage() : "[" + this.errorId + "] " + super.getLocalizedMessage();
361 }
362
363 /**
364 * Convenience method to decode any <code>errorCode</code>
365 * from the {@link #DEFAULT_ERROR_CODESYSTEM_OID}.
366 *
367 * @return The appropriate error text. If the <code>codeSystem</code>
368 * is not the {@link #DEFAULT_ERROR_CODESYSTEM_OID} returns the
369 * {@link #getMessage()} text.
370 */
371 public String decodeErrorCode() {
372 if (this.errorCodeSystem.equals(DEFAULT_ERROR_CODESYSTEM_OID)) {
373 switch (this.getErrorCode()) {
374 case INVALID_MESSAGE_CODE: return INVALID_MESSAGE_TEXT;
375 case PROCESSING_ERROR_RETRYABLE_CODE: return PROCESSING_ERROR_RETRYABLE_TEXT;
376 case PROCESSING_ERROR_NOT_RETRYABLE_CODE: return PROCESSING_ERROR_NOT_RETRYABLE_TEXT;
377 case ACCESS_DENIED_CODE: return ACCESS_DENIED_TEXT;
378 }
379 }
380 //By default return the description of the error
381 return "Error code system " + this.getErrorCodeSystem() + " not known - error text was " + getMessage();
382 }
383
384 public ITKTransportProperties getRelatedItkTransportProperties() {
385 return relatedItkTransportProperties;
386 }
387
388 public void setRelatedItkTransportProperties(
389 ITKTransportProperties relatedItkTransportProperties) {
390 this.relatedItkTransportProperties = relatedItkTransportProperties;
391 }
392
393 }