/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2009 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id: ExceptionUtils.java 18362 2009-08-25 09:42:48Z sauthieg $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.commands.admin.util;

import java.util.Set;
import java.util.HashSet;

/**
 * Exception/Throwable related utility class.
 */
public class ExceptionUtils {

    /**
     * Private constructor for utility class.
     */
    private ExceptionUtils() {}

    /**
     * Get the root cause of an Exception.
     * @param throwable the top level exception.
     * @return the root cause of the given exception
     */
    public static Throwable getRootCause(final Throwable throwable) {
        if (throwable == null) {
            throw new IllegalStateException("Throwable parameter MUST not be null");
        }
        return getRootCause(throwable, new HashSet<Throwable>());
    }

    /**
     * Get the deeper cause of the given Throwable. Manage loops.
     * @param throwable Traversed item
     * @param throwableSet set of already traversed items
     * @return the deeper cause available.
     */
    private static Throwable getRootCause(final Throwable throwable,
                                          final Set<Throwable> throwableSet) {

        Throwable cause = throwable.getCause();

        if (cause == null) {
            // Return itself, the given throwable is the root cause
            return throwable;
        }

        if (throwableSet.contains(cause)) {
            // There is a loop in the chained Exceptions
            // Return the given throwable as it's the most deeper Exception we have
            return throwable;
        }

        // Add this exception in the list
        throwableSet.add(throwable);
        // Continue recursion
        return getRootCause(cause, throwableSet);
    }
}
