KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > schlichtherle > io > ChainableIOException


1 /*
2  * ChainableIOException.java
3  *
4  * Created on 30. Oktober 2004, 03:08
5  */

6 /*
7  * Copyright 2005 Schlichtherle IT Services
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */

21
22 package de.schlichtherle.io;
23
24 import java.io.IOException JavaDoc;
25 import java.io.OutputStreamWriter JavaDoc;
26 import java.io.PrintStream JavaDoc;
27 import java.io.PrintWriter JavaDoc;
28 import java.util.Comparator JavaDoc;
29
30 /**
31  * Represents a chain of {@link IOException}s.
32  * This class supports chaining exceptions for reasons other than causes
33  * (which is a functionality already provided by J2SE 1.4 and later).
34  * A <code>ChainableIOException</code> can be used to implement an algorithm
35  * which must be able to continue with some work although one or more
36  * <code>IOException</code>s have occured.
37  * <p>
38  * For example, when looping through a list of files, an algorithm might
39  * encounter an <code>IOException</code> when processing a file element in the list.
40  * However, it may still be required to process the remaining files in the list
41  * before actually throwing the corresponding <code>IOException</code>.
42  * Hence, whenever this algorithm encounters an <code>IOException</code>,
43  * it would catch the <code>IOException</code>, create a
44  * <code>ChainableIOException</code> for it and continue processing the
45  * remainder of the list.
46  * Finally, at the end of the algorithm, if any <code>IOException</code>s
47  * have occured, the <code>ChainableIOException</code> chain would get sorted
48  * according to priority (see {@link #getPriority()} and
49  * {@link #sortPriority()}) and finally thrown.
50  * This would allow a client application to filter the exceptions by priority
51  * with a simple try-catch statement, ensuring that no other exception of
52  * higher priority is in the catched exception chain.
53  * <p>
54  * <b>Note:</b> This is not related to the cause concept of exceptions in
55  * J2SE 1.4 and higher. Exceptions chained by this class are <b>not</b>
56  * causes of each other, but have just been merely collected over time
57  * and then thrown as one exception (list).
58  *
59  * @see File#update()
60  * @see File#umount()
61  *
62  * @author Christian Schlichtherle
63  * @version @version@
64  * @since TrueZIP 6.0 (generalized from the former
65  * <code>ArchiveControllerException</code>).
66  */

67 public class ChainableIOException extends IOException JavaDoc implements Cloneable JavaDoc {
68
69     /**
70      * Compares two ZIP controller exceptions in descending order of their
71      * priority.
72      * If the priority is equal, the elements are compared in descending
73      * order of their appearance.
74      */

75     // Note: Not private for unit testing purposes only!
76
static final Comparator JavaDoc PRIORITY_COMP = new Comparator JavaDoc() {
77         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
78             final int cmp = ((ChainableIOException) o1).getPriority()
79                           - ((ChainableIOException) o2).getPriority();
80             return cmp != 0 ? cmp : APPEARANCE_COMP.compare(o1, o2);
81         }
82     };
83     
84     /**
85      * Compares two ZIP controller exceptions in descending order of their
86      * appearance.
87      */

88     // Note: Not private for unit testing purposes only!
89
static final Comparator JavaDoc APPEARANCE_COMP = new Comparator JavaDoc() {
90         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
91             return ((ChainableIOException) o1).getAppearance()
92                  - ((ChainableIOException) o2).getAppearance();
93         }
94     };
95
96     private static int maxPrintExceptions = 5;
97
98     /**
99      * @see #printStackTrace(PrintStream)
100      * @see #printStackTrace(PrintWriter)
101      */

102     public static int getMaxPrintExceptions() {
103         return maxPrintExceptions;
104     }
105     
106     /**
107      * @see #printStackTrace(PrintStream)
108      * @see #printStackTrace(PrintWriter)
109      */

110     public static void setMaxPrintExceptions(int maxPrintExcepions) {
111         ChainableIOException.maxPrintExceptions = maxPrintExcepions;
112     }
113     
114     /**
115      * The tail chain of this exception chain.
116      * Maybe <tt>null</tt> if there are no more exceptions.
117      * If this exception chain has not been reordered,
118      * the head of the tail is either <tt>null</tt> or an exception which
119      * occured before this exception was created.
120      * <p>
121      * Please note that this is totally unrelated to a possible cause for
122      * this exception!
123      */

124     private ChainableIOException prior;
125
126     private final int appearance;
127
128     int maxAppearance;
129
130     /**
131      * Constructs a new exception with the specified prior exception.
132      *
133      * @param priorException An exception that happened before and that was
134      * caught - may be <tt>null</tt>.
135      *
136      * @see ChainableIOException
137      */

138     public ChainableIOException(ChainableIOException priorException) {
139         this(priorException, null, null);
140     }
141
142     /**
143      * Constructs a new exception with the specified prior exception
144      * and a message.
145      *
146      * @param priorException An exception that happened before and that was
147      * caught - may be <tt>null</tt>.
148      * @param message The message for this exception.
149      *
150      * @see ChainableIOException
151      */

152     public ChainableIOException(
153             ChainableIOException priorException,
154             String JavaDoc message) {
155         this(priorException, message, null);
156     }
157     
158     /**
159      * Constructs a new exception with the specified prior exception and the
160      * cause.
161      *
162      * @param priorException An exception that happened before and that was
163      * caught - may be <tt>null</tt>.
164      * @param cause The cause (which is saved for later retrieval by the
165      * {@link #getCause()} method). (A <tt>null</tt> value is
166      * permitted, and indicates that the cause is nonexistent or
167      * unknown.).
168      *
169      * @see ChainableIOException
170      */

171     public ChainableIOException(
172             ChainableIOException priorException,
173             IOException JavaDoc cause) {
174         this(priorException, null, cause);
175     }
176
177     /**
178      * Constructs a new exception with the specified prior exception,
179      * a message and a cause.
180      *
181      * @param priorException An exception that happened before and that was
182      * caught - may be <tt>null</tt>.
183      * @param message The message for this exception.
184      * @param cause The cause (which is saved for later retrieval by the
185      * {@link #getCause()} method). (A <tt>null</tt> value is
186      * permitted, and indicates that the cause is nonexistent or
187      * unknown.).
188      *
189      * @see ChainableIOException
190      */

191     public ChainableIOException(
192             ChainableIOException priorException,
193             String JavaDoc message,
194             IOException JavaDoc cause) {
195         super(message);
196         this.prior = priorException;
197         if (cause != null)
198             initCause(cause);
199         if (priorException != null)
200             maxAppearance = priorException.maxAppearance + 1;
201         else
202             maxAppearance = 0;
203         appearance = maxAppearance;
204     }
205
206     /**
207      * Returns a <em>shallow</em> clone of this exception.
208      */

209     public Object JavaDoc clone() {
210         try {
211             return super.clone();
212         } catch (CloneNotSupportedException JavaDoc cannotHappen) {
213             throw new AssertionError JavaDoc(cannotHappen);
214         }
215     }
216
217     /**
218      * Returns the priority for this class of exception.
219      * This should always return the same value for all instances of a
220      * particular class.
221      *
222      * @return 0 for all instances of this class.
223      */

224     public int getPriority() {
225         return 0;
226     }
227
228     /**
229      * @return The order of appearance for this ZIP exception.
230      */

231     public final int getAppearance() {
232         return appearance;
233     }
234
235     /**
236      * @return The exception chain represented by the prior exception,
237      * or <code>null</code> if no prior exception exists.
238      */

239     public ChainableIOException getPrior() {
240         return prior;
241     }
242
243     /**
244      * Sorts the elements of this exception chain in descending order
245      * of their priority.
246      * If the priority of two elements is equal, they are sorted in descending
247      * order of their appearance.
248      *
249      * @return The sorted exception chain, consisting of cloned elements where
250      * required to enforce the immutability of this class.
251      * This is a non-destructive sort, i.e. elements already in order
252      * are guaranteed not to get rearranged.
253      * If and only if all elements are in order, this exception chain
254      * is returned and no elements are cloned.
255      */

256     public ChainableIOException sortPriority() {
257         return sort(PRIORITY_COMP);
258     }
259     
260     /**
261      * Sorts the elements of this exception chain in descending order
262      * of their appearance.
263      *
264      * @return The sorted exception chain, consisting of cloned elements where
265      * required to enforce the immutability of this class.
266      * This is a non-destructive sort, i.e. elements already in order
267      * are guaranteed not to get rearranged.
268      * If and only if all elements are in order, this exception chain
269      * is returned and no elements are cloned.
270      */

271     public ChainableIOException sortAppearance() {
272         return sort(APPEARANCE_COMP);
273     }
274     
275     private ChainableIOException sort(final Comparator JavaDoc comp) {
276         if (prior != null) {
277             final ChainableIOException sortedPrior = prior.sort(comp);
278             if (sortedPrior == prior && comp.compare(this, prior) >= 0)
279                 return this;
280             else
281                 return sortedPrior.insert((ChainableIOException) clone(), comp);
282         } else {
283             return this;
284         }
285     }
286
287     private ChainableIOException insert(
288             final ChainableIOException element,
289             final Comparator JavaDoc comp) {
290         if (comp.compare(element, this) >= 0) {
291             // Prepend to chain.
292
element.prior = this;
293             element.maxAppearance = Math.max(element.appearance, maxAppearance);
294             return element;
295         } else {
296             // Insert element in the prior exception chain.
297
final ChainableIOException clone
298                     = (ChainableIOException) clone();
299             if (prior != null) {
300                 clone.prior = prior.insert(element, comp);
301                 clone.maxAppearance = Math.max(clone.appearance, clone.prior.maxAppearance);
302             } else {
303                 element.prior = null;
304                 clone.prior = element;
305                 clone.maxAppearance = element.maxAppearance;
306             }
307             return clone;
308         }
309     }
310     
311     /**
312      * Prints up to {@link #getMaxPrintExceptions()} exceptions in this
313      * chain to the provided {@link PrintStream}.
314      * <p>
315      * Exceptions are printed in ascending order of this chain.
316      * If this chain has not been sorted, this results in the exceptions being
317      * printed in order of their appearance.
318      * <p>
319      * If more exceptions are in this chain than are allowed to be printed,
320      * then the printed message starts with a line indicating the number of
321      * exceptions which have been omitted from the beginning of this chain.
322      * Thus, this exception is always printed as the last exception in the
323      * list.
324      */

325     public void printStackTrace(PrintStream JavaDoc s) {
326         printStackTrace(s, getMaxPrintExceptions());
327     }
328
329     /**
330      * Prints up to <code>maxExceptions()</code> exceptions in this
331      * chain to the provided {@link PrintStream}.
332      * <p>
333      * Exceptions are printed in ascending order of this chain.
334      * If this chain has not been sorted, this results in the exceptions being
335      * printed in order of their appearance.
336      * <p>
337      * If more exceptions are in this chain than are allowed to be printed,
338      * then the printed message starts with a line indicating the number of
339      * exceptions which have been omitted from the beginning of this chain.
340      * Thus, this exception is always printed as the last exception in the
341      * list.
342      */

343     public void printStackTrace(PrintStream JavaDoc s, int maxExceptions) {
344         maxExceptions--;
345
346         if (prior != null) {
347             if (maxExceptions > 0) {
348                 prior.printStackTrace(s, maxExceptions);
349                 s.println("Followed, but not caused by:");
350             } else {
351                 s.println("(Omitting " + prior.getNumExceptions() + " exception(s) at the start of this list)");
352             }
353         }
354
355         super.printStackTrace(s);
356     }
357
358     private int getNumExceptions() {
359         return prior != null ? prior.getNumExceptions() + 1 : 1;
360     }
361
362     /**
363      * Prints up to {@link #getMaxPrintExceptions()} exceptions in this
364      * chain to the provided {@link PrintStream}.
365      * <p>
366      * Exceptions are printed in ascending order of this chain.
367      * If this chain has not been sorted, this results in the exceptions being
368      * printed in order of their appearance.
369      * <p>
370      * If more exceptions are in this chain than are allowed to be printed,
371      * then the printed message starts with a line indicating the number of
372      * exceptions which have been omitted from the beginning of this chain.
373      * Thus, this exception is always printed as the last exception in the
374      * list.
375      */

376     public void printStackTrace(PrintWriter JavaDoc s) {
377         printStackTrace(s, getMaxPrintExceptions());
378     }
379
380     /**
381      * Prints up to <code>maxExceptions()</code> exceptions in this
382      * chain to the provided {@link PrintStream}.
383      * <p>
384      * Exceptions are printed in ascending order of this chain.
385      * If this chain has not been sorted, this results in the exceptions being
386      * printed in order of their appearance.
387      * <p>
388      * If more exceptions are in this chain than are allowed to be printed,
389      * then the printed message starts with a line indicating the number of
390      * exceptions which have been omitted from the beginning of this chain.
391      * Thus, this exception is always printed as the last exception in the
392      * list.
393      */

394     public void printStackTrace(PrintWriter JavaDoc s, int maxExceptions) {
395         maxExceptions--;
396
397         if (prior != null) {
398             if (maxExceptions > 0) {
399                 prior.printStackTrace(s, maxExceptions);
400                 s.println("Followed, but not caused by:");
401             } else {
402                 s.println("(Omitting " + prior.getNumExceptions() + " exception(s) at the start of this list)");
403             }
404         }
405
406         super.printStackTrace(s);
407     }
408 }
409
Popular Tags