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.util.ArrayList;
026import java.util.List;
027
028/**
029 * Helps with Throwable objects.
030 */
031public final class Throwables {
032
033    private Throwables() {
034    }
035
036    /**
037     * Returns the deepest cause of the given {@code throwable}.
038     *
039     * @param throwable the throwable to navigate
040     * @return the deepest throwable or the given throwable
041     */
042    public static Throwable getRootCause(final Throwable throwable) {
043        Throwable cause;
044        Throwable root = throwable;
045        while ((cause = root.getCause()) != null) {
046            root = cause;
047        }
048        return root;
049    }
050
051    /**
052     * Converts a Throwable stack trace into a List of Strings.
053     *
054     * @param throwable the Throwable
055     * @return a List of Strings
056     */
057    public static List<String> toStringList(final Throwable throwable) {
058        final StringWriter sw = new StringWriter();
059        final PrintWriter pw = new PrintWriter(sw);
060        try {
061            throwable.printStackTrace(pw);
062        } catch (final RuntimeException ex) {
063            // Ignore any exceptions.
064        }
065        pw.flush();
066        final List<String> lines = new ArrayList<>();
067        final LineNumberReader reader = new LineNumberReader(new StringReader(sw.toString()));
068        try {
069            String line = reader.readLine();
070            while (line != null) {
071                lines.add(line);
072                line = reader.readLine();
073            }
074        } catch (final IOException ex) {
075            if (ex instanceof InterruptedIOException) {
076                Thread.currentThread().interrupt();
077            }
078            lines.add(ex.toString());
079        } finally {
080            Closer.closeSilently(reader);
081        }
082        return lines;
083    }
084
085    /**
086     * Rethrows a {@link Throwable}.
087     *
088     * @param t the Throwable to throw.
089     * @since 2.1
090     */
091    public static void rethrow(final Throwable t) {
092        Throwables.<RuntimeException>rethrow0(t);
093    }
094
095    @SuppressWarnings("unchecked")
096    private static <T extends Throwable> void rethrow0(final Throwable t) throws T {
097        throw (T) t;
098    }
099}