CallException.java |
/* * $Id: CallException.java,v 1.37 2011/03/19 09:11:18 agoubard Exp $ * * See the COPYRIGHT file for redistribution and use restrictions. */ package org.xins.common.service; import org.xins.common.MandatoryArgumentChecker; /** * Root class for all exceptions that indicate a <code>ServiceCaller</code> * call failed. This exception is typically only thrown by class * {@link ServiceCaller} and subclasses. * * <p>Call exceptions can be linked. The first exception is then actually * thrown to the caller. The caller can get the linked exceptions using * {@link #getNext()}. * * @version $Revision: 1.37 $ $Date: 2011/03/19 09:11:18 $ * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a> * * @since XINS 1.0.0 */ public abstract class CallException extends Exception { /** * Short description of the reason. Cannot be <code>null</code>. */ private final String _shortReason; /** * The original request. Cannot be <code>null</code>. */ private final CallRequest _request; /** * Descriptor for the target that was attempted to be called. Cannot be * <code>null</code>. */ private final TargetDescriptor _target; /** * The time elapsed between the time the call attempt was started and the * time the call returned. The duration is in milliseconds and is always * >= 0. */ private final long _duration; /** * A detailed description of the problem. Can be <code>null</code>. */ private String _detail; /** * The next linked <code>CallException</code>. Can be <code>null</code> if * there is none or if it has not been set yet. */ private CallException _next; /** * The exception message. Is <code>null</code> if unset. */ private String _message; /** * Constructs a new <code>CallException</code> based on a short reason, the * original request, target called, call duration, detail message and cause * exception. * * @param shortReason * the short reason, cannot be <code>null</code>. * * @param request * the original request, cannot be <code>null</code>. * * @param target * descriptor for the target that was attempted to be called, can be <code>null</code>. * * @param duration * the call duration in milliseconds, must be >= 0. * * @param detail * a detailed description of the problem, can be <code>null</code> if * there is no more detail. * * @param cause * the cause exception, can be <code>null</code>. * * @throws IllegalArgumentException * if <code>shortReason == null * || request == null * || duration < 0</code>. */ protected CallException(String shortReason, CallRequest request, TargetDescriptor target, long duration, String detail, Throwable cause) throws IllegalArgumentException { // Check preconditions MandatoryArgumentChecker.check("shortReason", shortReason, "request", request); if (duration < 0) { throw new IllegalArgumentException( "duration (" + duration + ") < 0"); } // Associate this exception with the root cause if (cause != null) { initCause(cause); } // Store information in fields _shortReason = shortReason; _request = request; _target = target; _duration = duration; _detail = detail; } /** * Returns the detail message string of this exception. * * @return * the detail message string of this exception, never <code>null</code>. */ public String getMessage() { // Initialize the message if necessary if (_message == null) { StringBuffer buffer = new StringBuffer(495); buffer.append(_shortReason); buffer.append(" in "); buffer.append(_duration); buffer.append(" ms while executing "); buffer.append(_request.describe()); buffer.append(" at "); buffer.append(_target.getURL()); if (_detail == null) { buffer.append('.'); } else { buffer.append(": "); buffer.append(_detail); } _message = buffer.toString(); } if (_next != null) { if (_message.endsWith(".")) { return _message + " Followed by: " + _next.getMessage(); } else { return _message + ". Followed by: " + _next.getMessage(); } } else { return _message; } } /** * Returns the original request. * * @return * the original request, never <code>null</code>. */ public final CallRequest getRequest() { return _request; } /** * Returns the descriptor for the target that was attempted to be called. * * @return * the target descriptor, can be <code>null</code>. */ public final TargetDescriptor getTarget() { return _target; } /** * Returns the call duration. This is defined as the time elapsed between * the time the call attempt was started and the time the call returned. * The duration is in milliseconds and is always >= 0. * * @return * the call duration in milliseconds, always >= 0. */ public final long getDuration() { return _duration; } /** * Sets the next linked <code>CallException</code>. This method should be * called either never or once during the lifetime of a * <code>CallException</code> object. * * @param next * the next linked <code>CallException</code>, not <code>null</code>. * * @throws IllegalStateException * if the next linked <code>CallException</code> has already been set. * * @throws IllegalArgumentException * if <code>next == null</code>. */ final void setNext(CallException next) throws IllegalStateException, IllegalArgumentException { // Check preconditions if (_next != null) { throw new IllegalStateException( "Next linked CallException already set."); } MandatoryArgumentChecker.check("next", next); // Store the reference _next = next; } /** * Gets the next linked <code>CallException</code>, if there is any. * * @return * the next linked <code>CallException</code>, or <code>null</code> if * there is none. */ public final CallException getNext() { return _next; } /** * Returns a detailed description of problem, if any. * * @return * a detailed description, if available, otherwise <code>null</code>. */ public String getDetail() { return _detail; } /** * Indicates whether this call exception allow for the ServiceCaller to * fail over another TargetDescriptor if available. * Note that when an exception doesn't know if the call (or part of the call) * has been executed, <code>false</code> should be returned. * * @return * <code>true</code> if the service can fail over, <code>false</code> otherwise. */ public boolean isFailOverAllowed() { return false; } }