All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.schlichtherle.io.ChainableIOException Maven / Gradle / Ivy

Go to download

TrueZIP is a Java based Virtual File System (VFS) to enable transparent, multi-threaded read/write access to archive files (ZIP, TAR etc.) as if they were directories. Archive files may be arbitrarily nested and the nesting level is only limited by heap and file system size.

The newest version!
/*
 * Copyright (C) 2005-2010 Schlichtherle IT Services
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.schlichtherle.io;

import java.io.*;
import java.util.*;

/**
 * Represents a chain of {@link IOException}s.
 * This class supports chaining exceptions for reasons other than causes
 * (which is a functionality already provided by J2SE 1.4 and later).
 * A {@code ChainableIOException} can be used to implement an algorithm
 * which must be able to continue with some work although one or more
 * {@code IOException}s have occured.
 * 

* For example, when looping through a list of files, an algorithm might * encounter an {@code IOException} when processing a file element in the list. * However, it may still be required to process the remaining files in the list * before actually throwing the corresponding {@code IOException}. * Hence, whenever this algorithm encounters an {@code IOException}, * it would catch the {@code IOException}, create a * {@code ChainableIOException} for it and continue processing the * remainder of the list. * Finally, at the end of the algorithm, if any {@code IOException}s * have occured, the {@code ChainableIOException} chain would get sorted * according to priority (see {@link #getPriority()} and * {@link #sortPriority()}) and finally thrown. * This would allow a client application to filter the exceptions by priority * with a simple try-catch statement, ensuring that no other exception of * higher priority is in the catched exception chain. *

* Note: This is not related to the cause concept of exceptions in * J2SE 1.4 and higher. Exceptions chained by this class are not * causes of each other, but have just been merely collected over time * and then thrown as one exception (list). * * @see File#update * @see File#umount * * @author Christian Schlichtherle * @version $Id: ChainableIOException.java,v 1.4 2010/08/20 13:09:41 christian_schlichtherle Exp $ * @since TrueZIP 6.0 (generalized from the former * {@code ArchiveControllerException}). */ public class ChainableIOException extends IOException implements Cloneable { /** * Compares two ZIP controller exceptions in descending order of their * priority. * If the priority is equal, the elements are compared in descending * order of their appearance. */ // Note: Not private for unit testing purposes only! static final Comparator PRIORITY_COMP = new Comparator() { public int compare(Object o1, Object o2) { final int cmp = ((ChainableIOException) o1).getPriority() - ((ChainableIOException) o2).getPriority(); return cmp != 0 ? cmp : APPEARANCE_COMP.compare(o1, o2); } }; /** * Compares two ZIP controller exceptions in descending order of their * appearance. */ // Note: Not private for unit testing purposes only! static final Comparator APPEARANCE_COMP = new Comparator() { public int compare(Object o1, Object o2) { return ((ChainableIOException) o1).getAppearance() - ((ChainableIOException) o2).getAppearance(); } }; private static int maxPrintExceptions = 3; /** * The tail chain of this exception chain. * Maybe {@code null} if there are no more exceptions. * If this exception chain has not been reordered, * the head of the tail is either {@code null} or an exception which * occured before this exception was created. *

* Please note that this is totally unrelated to a possible cause for * this exception! */ private ChainableIOException prior; private final int appearance; int maxAppearance; /** * Constructs a new exception with the specified prior exception. * * @param priorException An exception that happened before and that was * caught - may be {@code null}. * * @see ChainableIOException */ public ChainableIOException(ChainableIOException priorException) { this(priorException, null, null); } /** * Constructs a new exception with the specified prior exception * and a message. * * @param priorException An exception that happened before and that was * caught - may be {@code null}. * @param message The message for this exception. * * @see ChainableIOException */ public ChainableIOException( ChainableIOException priorException, String message) { this(priorException, message, null); } /** * Constructs a new exception with the specified prior exception and the * cause. * * @param priorException An exception that happened before and that was * caught - may be {@code null}. * @param cause The cause (which is saved for later retrieval by the * {@link #getCause()} method). (A {@code null} value is * permitted, and indicates that the cause is nonexistent or * unknown.). * * @see ChainableIOException */ public ChainableIOException( ChainableIOException priorException, IOException cause) { this(priorException, null, cause); } /** * Constructs a new exception with the specified prior exception, * a message and a cause. * * @param priorException An exception that happened before and that was * caught - may be {@code null}. * @param message The message for this exception. * @param cause The cause (which is saved for later retrieval by the * {@link #getCause()} method). (A {@code null} value is * permitted, and indicates that the cause is nonexistent or * unknown.). * * @see ChainableIOException */ public ChainableIOException( final ChainableIOException priorException, final String message, final IOException cause) { super(message); this.prior = priorException; if (cause != null) super.initCause(cause); if (priorException != null) maxAppearance = priorException.maxAppearance + 1; else maxAppearance = 0; appearance = maxAppearance; } /** * Returns a shallow clone of this exception. */ public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException cannotHappen) { throw new AssertionError(cannotHappen); } } /** * Returns the priority for this class of exception. * This should always return the same value for all instances of a * particular class. * * @return 0 for all instances of this class. */ public int getPriority() { return 0; } /** * @return The order of appearance for this ZIP exception. */ public final int getAppearance() { return appearance; } /** * @return The exception chain represented by the prior exception, * or {@code null} if no prior exception exists. */ public ChainableIOException getPrior() { return prior; } /** * Sorts the elements of this exception chain in descending order * of their priority. * If the priority of two elements is equal, they are sorted in descending * order of their appearance. * * @return The sorted exception chain, consisting of cloned elements where * required to enforce the immutability of this class. * This is a non-destructive sort, i.e. elements already in order * are guaranteed not to get rearranged. * If and only if all elements are in order, this exception chain * is returned and no elements are cloned. */ public ChainableIOException sortPriority() { return sort(PRIORITY_COMP); } /** * Sorts the elements of this exception chain in descending order * of their appearance. * * @return The sorted exception chain, consisting of cloned elements where * required to enforce the immutability of this class. * This is a non-destructive sort, i.e. elements already in order * are guaranteed not to get rearranged. * If and only if all elements are in order, this exception chain * is returned and no elements are cloned. */ public ChainableIOException sortAppearance() { return sort(APPEARANCE_COMP); } private ChainableIOException sort(final Comparator comp) { if (prior != null) { final ChainableIOException sortedPrior = prior.sort(comp); if (sortedPrior == prior && comp.compare(this, prior) >= 0) return this; else return sortedPrior.insert((ChainableIOException) clone(), comp); } else { return this; } } private ChainableIOException insert( final ChainableIOException element, final Comparator comp) { if (comp.compare(element, this) >= 0) { // Prepend to chain. element.prior = this; element.maxAppearance = Math.max(element.appearance, maxAppearance); return element; } else { // Insert element in the prior exception chain. final ChainableIOException clone = (ChainableIOException) clone(); if (prior != null) { clone.prior = prior.insert(element, comp); clone.maxAppearance = Math.max(clone.appearance, clone.prior.maxAppearance); } else { element.prior = null; clone.prior = element; clone.maxAppearance = element.maxAppearance; } return clone; } } /** * Calls {@link #initCause(IOException) initCause((IOException) cause)}. * * @throws ClassCastException If {@code cause} is not an instance * of {@link IOException}. */ /*public final Throwable initCause(final Throwable cause) { return initCause((IOException) cause); }*/ public Throwable initCause(final IOException cause) { return super.initCause(cause); } /** * Prints up to {@link #getMaxPrintExceptions()} exceptions in this * chain to the provided {@link PrintStream}. *

* Exceptions are printed in ascending order of this chain. * If this chain has not been sorted, this results in the exceptions being * printed in order of their appearance. *

* If more exceptions are in this chain than are allowed to be printed, * then the printed message starts with a line indicating the number of * exceptions which have been omitted from the beginning of this chain. * Thus, this exception is always printed as the last exception in the * list. */ public void printStackTrace(PrintStream s) { printStackTrace(s, getMaxPrintExceptions()); } /** * Prints up to {@code maxExceptions()} exceptions in this * chain to the provided {@link PrintStream}. *

* Exceptions are printed in ascending order of this chain. * If this chain has not been sorted, this results in the exceptions being * printed in order of their appearance. *

* If more exceptions are in this chain than are allowed to be printed, * then the printed message starts with a line indicating the number of * exceptions which have been omitted from the beginning of this chain. * Thus, this exception is always printed as the last exception in the * list. */ public void printStackTrace(final PrintStream s, int maxExceptions) { maxExceptions--; if (prior != null) { if (maxExceptions > 0) { prior.printStackTrace(s, maxExceptions); s.println("Followed, but not caused by:"); } else { s.println("(Omitting " + prior.getNumExceptions() + " exception(s) at the start of this list)"); } } super.printStackTrace(s); } private int getNumExceptions() { return prior != null ? prior.getNumExceptions() + 1 : 1; } /** * Prints up to {@link #getMaxPrintExceptions()} exceptions in this * chain to the provided {@link PrintStream}. *

* Exceptions are printed in ascending order of this chain. * If this chain has not been sorted, this results in the exceptions being * printed in order of their appearance. *

* If more exceptions are in this chain than are allowed to be printed, * then the printed message starts with a line indicating the number of * exceptions which have been omitted from the beginning of this chain. * Thus, this exception is always printed as the last exception in the * list. */ public void printStackTrace(PrintWriter s) { printStackTrace(s, getMaxPrintExceptions()); } /** * Prints up to {@code maxExceptions()} exceptions in this * chain to the provided {@link PrintStream}. *

* Exceptions are printed in ascending order of this chain. * If this chain has not been sorted, this results in the exceptions being * printed in order of their appearance. *

* If more exceptions are in this chain than are allowed to be printed, * then the printed message starts with a line indicating the number of * exceptions which have been omitted from the beginning of this chain. * Thus, this exception is always printed as the last exception in the * list. */ public void printStackTrace(final PrintWriter s, int maxExceptions) { maxExceptions--; if (prior != null) { if (maxExceptions > 0) { prior.printStackTrace(s, maxExceptions); s.println("Followed, but not caused by:"); } else { s.println("(Omitting " + prior.getNumExceptions() + " exception(s) at the start of this list)"); } } super.printStackTrace(s); } /** * @see #printStackTrace(PrintStream) * @see #printStackTrace(PrintWriter) */ public static int getMaxPrintExceptions() { return maxPrintExceptions; } /** * @see #printStackTrace(PrintStream) * @see #printStackTrace(PrintWriter) */ public static void setMaxPrintExceptions(int maxPrintExcepions) { ChainableIOException.maxPrintExceptions = maxPrintExcepions; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy