View Javadoc

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>&lt;itk:ToolkitErrorInfo/&gt;</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 }