001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.core.util;
018
019import java.io.IOException;
020import java.io.InterruptedIOException;
021import java.io.LineNumberReader;
022import java.io.PrintWriter;
023import java.io.StringReader;
024import java.io.StringWriter;
025import java.lang.reflect.UndeclaredThrowableException;
026import java.util.ArrayList;
027import java.util.List;
028
029/**
030 * Helps with Throwable objects.
031 */
032public final class Throwables {
033
034    private Throwables() {
035    }
036
037    /**
038     * Has no effect on Java 6 and below.
039     *
040     * @param throwable a Throwable
041     * @param suppressedThrowable a suppressed Throwable
042     * @see Throwable#addSuppressed(Throwable)
043     * @deprecated If compiling on Java 7 and above use {@link Throwable#addSuppressed(Throwable)}.
044     *             Marked as deprecated because Java 6 is deprecated. Will be removed in 2.5.
045     */
046    @Deprecated
047    public static void addSuppressed(final Throwable throwable, final Throwable suppressedThrowable) {
048        throwable.addSuppressed(suppressedThrowable);
049    }
050
051    /**
052     * Returns the deepest cause of the given {@code throwable}.
053     * 
054     * @param throwable the throwable to navigate
055     * @return the deepest throwable or the given throwable
056     */
057    public static Throwable getRootCause(final Throwable throwable) {
058        Throwable cause;
059        Throwable root = throwable;
060        while ((cause = root.getCause()) != null) {
061            root = cause;
062        }
063        return root;
064    }
065
066    /**
067     * Has no effect on Java 6 and below.
068     *
069     * @param throwable a Throwable
070     * @return see Java 7's {@link Throwable#getSuppressed()}
071     * @see Throwable#getSuppressed()
072     * @deprecated If compiling on Java 7 and above use {@link Throwable#getSuppressed()}. Marked as deprecated because
073     *             Java 6 is deprecated. Will be removed 2.5.
074     */
075    @Deprecated
076    public static Throwable[] getSuppressed(final Throwable throwable) {
077        return throwable.getSuppressed();
078    }
079
080    /**
081     * Returns true if the getSuppressed method is available.
082     * 
083     * @return True if getSuppressed is available. As of 2.4, always returns true.
084     * @deprecated Will be removed in 2.5. As of 2.4, always returns true.
085     */
086    @Deprecated
087    public static boolean isGetSuppressedAvailable() {
088        return true;
089    }
090
091    /**
092     * Converts a Throwable stack trace into a List of Strings.
093     *
094     * @param throwable the Throwable
095     * @return a List of Strings
096     */
097    public static List<String> toStringList(final Throwable throwable) {
098        final StringWriter sw = new StringWriter();
099        final PrintWriter pw = new PrintWriter(sw);
100        try {
101            throwable.printStackTrace(pw);
102        } catch (final RuntimeException ex) {
103            // Ignore any exceptions.
104        }
105        pw.flush();
106        final List<String> lines = new ArrayList<>();
107        final LineNumberReader reader = new LineNumberReader(new StringReader(sw.toString()));
108        try {
109            String line = reader.readLine();
110            while (line != null) {
111                lines.add(line);
112                line = reader.readLine();
113            }
114        } catch (final IOException ex) {
115            if (ex instanceof InterruptedIOException) {
116                Thread.currentThread().interrupt();
117            }
118            lines.add(ex.toString());
119        } finally {
120            Closer.closeSilently(reader);
121        }
122        return lines;
123    }
124
125    /**
126     * Rethrows a {@link Throwable}, wrapping checked exceptions into an {@link UndeclaredThrowableException}.
127     *
128     * @param t the Throwable to throw.
129     * @throws RuntimeException if {@code t} is a RuntimeException
130     * @throws Error if {@code t} is an Error
131     * @throws UndeclaredThrowableException if {@code t} is a checked Exception
132     * @since 2.1
133     */
134    public static void rethrow(final Throwable t) {
135        if (t instanceof RuntimeException) {
136            throw (RuntimeException) t;
137        }
138        if (t instanceof Error) {
139            throw (Error) t;
140        }
141        throw new UndeclaredThrowableException(t);
142    }
143}