package com.googlecode.totallylazy; import com.googlecode.totallylazy.functions.Block; import com.googlecode.totallylazy.functions.Function1; import com.googlecode.totallylazy.predicates.Predicate; import java.io.PrintWriter; import static com.googlecode.totallylazy.Left.left; import static com.googlecode.totallylazy.Option.none; import static com.googlecode.totallylazy.predicates.Predicates.instanceOf; import static com.googlecode.totallylazy.predicates.Predicates.notNullValue; import static com.googlecode.totallylazy.Right.right; import static com.googlecode.totallylazy.Sequences.iterate; import static com.googlecode.totallylazy.Sequences.sequence; public class Exceptions { public static Exception toException(Throwable throwable) throws Exception { if (throwable instanceof Error) { throw (Error) throwable; } return (Exception) throwable; } public static <T extends Throwable> Option<T> find(final Throwable throwable, final Class<T> aClass) { return causes(throwable). safeCast(aClass). headOption(); } public static Sequence<Throwable> causes(Throwable throwable) { return iterate(getCause(), throwable). takeWhile(notNullValue()); } public static Function1<Throwable, Throwable> getCause() { return throwable -> throwable.getCause(); } public static final Function1<Exception,String> message = e -> e.getMessage(); public static Function1<Exception, String> message() { return message; } public static <T, S> Function1<T, Option<S>> ignoringException(final Function1<? super T, ? extends S> callable) { return optional(callable); } @SafeVarargs public static <T, S> Function1<T, Option<S>> handleException(final Function1<? super T, ? extends S> callable, final Class<? extends Exception>... exceptionClasses) { return handleException(callable, sequence(exceptionClasses).map(asInstanceOf())); } private static <T> Function1<Class<? extends T>, Predicate<? super T>> asInstanceOf() { return aClass -> instanceOf(aClass); } public static <T, S> Function1<T, Option<S>> handleException(final Function1<? super T, ? extends S> callable, final Predicate<? super Exception> first) { return handleException(callable, sequence(first)); } @SafeVarargs public static <T, S> Function1<T, Option<S>> handleException(final Function1<? super T, ? extends S> callable, final Predicate<? super Exception>... exceptionClasses) { return handleException(callable, sequence(exceptionClasses)); } public static <T, S> Function1<T, Option<S>> handleException(final Function1<? super T, ? extends S> callable, final Iterable<? extends Predicate<? super Exception>> predicates) { return t -> { try { return Option.some(callable.call(t)); } catch (Exception e) { if (sequence(predicates).exists(matches(e))) { return none(); } throw e; } }; } public static String asString(Exception e) { StringPrintStream stream = new StringPrintStream(); e.printStackTrace(stream); return stream.toString(); } private static <T> Predicate<? super Predicate<? super T>> matches(final T instance) { return other -> other.matches(instance); } public static <T, S> Function1<T, Either<S, Throwable>> captureException(final Function1<? super T, ? extends S> callable) { return input -> { try { return left(callable.call(input)); } catch (Throwable e) { return right(e); } }; } public static Block<PrintWriter> printStackTrace(final Throwable e) { return e::printStackTrace; } public static <A, B> Function1<A, Either<Exception, B>> either(final Function1<? super A, ? extends B> callable) { return a -> Either.either(() -> callable.call(a)); } public static <A, B> Function1<A, B> orElse(final Function1<? super A, ? extends B> callable, final B result) { return a -> { try { return callable.call(a); } catch (Exception e) { return result; } }; } public static <T, S> Function1<T, Option<S>> optional(final Function1<? super T, ? extends S> callable) { return t -> Option.option(() -> callable.call(t)); } }