001: /*
002: * $Id: CallException.java,v 1.33 2007/03/15 17:08:27 agoubard Exp $
003: *
004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
005: * See the COPYRIGHT file for redistribution and use restrictions.
006: */
007: package org.xins.common.service;
008:
009: import org.xins.common.MandatoryArgumentChecker;
010:
011: import org.xins.logdoc.ExceptionUtils;
012:
013: /**
014: * Root class for all exceptions that indicate a <code>ServiceCaller</code>
015: * call failed. This exception is typically only thrown by class
016: * {@link ServiceCaller} and subclasses.
017: *
018: * <p>Call exceptions can be linked. The first exception is then actually
019: * thrown to the caller. The caller can get the linked exceptions using
020: * {@link #getNext()}.
021: *
022: * @version $Revision: 1.33 $ $Date: 2007/03/15 17:08:27 $
023: * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a>
024: *
025: * @since XINS 1.0.0
026: */
027: public abstract class CallException extends Exception {
028:
029: /**
030: * Short description of the reason. Cannot be <code>null</code>.
031: */
032: private final String _shortReason;
033:
034: /**
035: * The original request. Cannot be <code>null</code>.
036: */
037: private final CallRequest _request;
038:
039: /**
040: * Descriptor for the target that was attempted to be called. Cannot be
041: * <code>null</code>.
042: */
043: private final TargetDescriptor _target;
044:
045: /**
046: * The time elapsed between the time the call attempt was started and the
047: * time the call returned. The duration is in milliseconds and is always
048: * >= 0.
049: */
050: private final long _duration;
051:
052: /**
053: * A detailed description of the problem. Can be <code>null</code>.
054: */
055: private String _detail;
056:
057: /**
058: * The next linked <code>CallException</code>. Can be <code>null</code> if
059: * there is none or if it has not been set yet.
060: */
061: private CallException _next;
062:
063: /**
064: * The exception message. Is <code>null</code> if unset.
065: */
066: private String _message;
067:
068: /**
069: * Constructs a new <code>CallException</code> based on a short reason, the
070: * original request, target called, call duration, detail message and cause
071: * exception.
072: *
073: * @param shortReason
074: * the short reason, cannot be <code>null</code>.
075: *
076: * @param request
077: * the original request, cannot be <code>null</code>.
078: *
079: * @param target
080: * descriptor for the target that was attempted to be called, can be <code>null</code>.
081: *
082: * @param duration
083: * the call duration in milliseconds, must be >= 0.
084: *
085: * @param detail
086: * a detailed description of the problem, can be <code>null</code> if
087: * there is no more detail.
088: *
089: * @param cause
090: * the cause exception, can be <code>null</code>.
091: *
092: * @throws IllegalArgumentException
093: * if <code>shortReason == null
094: * || request == null
095: * || duration < 0</code>.
096: */
097: protected CallException(String shortReason, CallRequest request,
098: TargetDescriptor target, long duration, String detail,
099: Throwable cause) throws IllegalArgumentException {
100:
101: // Check preconditions
102: MandatoryArgumentChecker.check("shortReason", shortReason,
103: "request", request);
104: if (duration < 0) {
105: throw new IllegalArgumentException("duration (" + duration
106: + ") < 0");
107: }
108:
109: // Associate this exception with the root cause
110: if (cause != null) {
111: ExceptionUtils.setCause(this , cause);
112: }
113:
114: // Store information in fields
115: _shortReason = shortReason;
116: _request = request;
117: _target = target;
118: _duration = duration;
119: _detail = detail;
120: }
121:
122: /**
123: * Returns the detail message string of this exception.
124: *
125: * @return
126: * the detail message string of this exception, never <code>null</code>.
127: */
128: public String getMessage() {
129:
130: // Initialize the message if necessary
131: if (_message == null) {
132:
133: StringBuffer buffer = new StringBuffer(495);
134: buffer.append(_shortReason);
135: buffer.append(" in ");
136: buffer.append(_duration);
137: buffer.append(" ms while executing ");
138: buffer.append(_request.describe());
139: buffer.append(" at ");
140: buffer.append(_target.getURL());
141:
142: if (_detail == null) {
143: buffer.append('.');
144: } else {
145: buffer.append(": ");
146: buffer.append(_detail);
147: }
148:
149: _message = buffer.toString();
150: }
151:
152: if (_next != null) {
153: if (_message.endsWith(".")) {
154: return _message + " Followed by: " + _next.getMessage();
155: } else {
156: return _message + ". Followed by: "
157: + _next.getMessage();
158: }
159: } else {
160: return _message;
161: }
162: }
163:
164: /**
165: * Returns the original request.
166: *
167: * @return
168: * the original request, never <code>null</code>.
169: */
170: public final CallRequest getRequest() {
171: return _request;
172: }
173:
174: /**
175: * Returns the descriptor for the target that was attempted to be called.
176: *
177: * @return
178: * the target descriptor, can be <code>null</code>.
179: */
180: public final TargetDescriptor getTarget() {
181: return _target;
182: }
183:
184: /**
185: * Returns the call duration. This is defined as the time elapsed between
186: * the time the call attempt was started and the time the call returned.
187: * The duration is in milliseconds and is always >= 0.
188: *
189: * @return
190: * the call duration in milliseconds, always >= 0.
191: */
192: public final long getDuration() {
193: return _duration;
194: }
195:
196: /**
197: * Sets the next linked <code>CallException</code>. This method should be
198: * called either never or once during the lifetime of a
199: * <code>CallException</code> object.
200: *
201: * @param next
202: * the next linked <code>CallException</code>, not <code>null</code>.
203: *
204: * @throws IllegalStateException
205: * if the next linked <code>CallException</code> has already been set.
206: *
207: * @throws IllegalArgumentException
208: * if <code>next == null</code>.
209: */
210: final void setNext(CallException next)
211: throws IllegalStateException, IllegalArgumentException {
212:
213: // Check preconditions
214: if (_next != null) {
215: throw new IllegalStateException(
216: "Next linked CallException already set.");
217: }
218: MandatoryArgumentChecker.check("next", next);
219:
220: // Store the reference
221: _next = next;
222: }
223:
224: /**
225: * Gets the next linked <code>CallException</code>, if there is any.
226: *
227: * @return
228: * the next linked <code>CallException</code>, or <code>null</code> if
229: * there is none.
230: */
231: public final CallException getNext() {
232: return _next;
233: }
234:
235: /**
236: * Returns a detailed description of problem, if any.
237: *
238: * @return
239: * a detailed description, if available, otherwise <code>null</code>.
240: */
241: public String getDetail() {
242: return _detail;
243: }
244: }
|