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 }