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

org.openbase.jul.communication.exception.RPCResolvedException Maven / Gradle / Ivy

The newest version!
package org.openbase.jul.communication.exception;

/*-
 * #%L
 * JUL Communication Default
 * %%
 * Copyright (C) 2015 - 2022 openbase.org
 * %%
 * This program 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 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import org.openbase.jul.exception.CouldNotPerformException;
import org.openbase.jul.exception.printer.ExceptionPrinter;
import org.openbase.jul.exception.printer.LogLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;

/**
 * This class represents an RPCException while the raw message is reconstructed as exception cause chain.
 * This allows a proper exception handling of remote calls.
 */
public class RPCResolvedException extends CouldNotPerformException {

    private final static Logger LOGGER = LoggerFactory.getLogger(RPCResolvedException.class);

    final RPCException rpcException;

    /**
     * Constructor creates a new RPCResolvedException which is than representing the given {@code rpcException} while the message is reconstructed as exception cause chain.
     *
     * @param message      an error description.
     * @param rpcException the RPCException to resolve.
     */
    public RPCResolvedException(final String message, final RPCException rpcException) {
        super(message, resolveRPCException(rpcException));
        this.rpcException = rpcException;
    }

    /**
     * Default constructor only used
     *
     * @param message an error description.
     * @param cause   the cause.
     */
    public RPCResolvedException(final String message, final Throwable cause) {
        super(message, cause);
        this.rpcException = null;
    }

    /**
     * Constructor creates a new RPCResolvedException which is than representing the given {@code rpcException} while the message is reconstructed as exception cause chain.
     *
     * @param rpcException the RPCException to resolve.
     */
    public RPCResolvedException(final RPCException rpcException) {
        this("", rpcException);
    }

    /**
     * Method parses the RPCException message and resolves the causes and messagen and use those to reconstruct the exception chain.
     *
     * @param rpcException the origin RPCException
     *
     * @return the reconstruced excetion cause chain.
     */
    public static Throwable resolveRPCException(final RPCException rpcException) {
        Throwable exception = null;

        // build stacktrace array where each line is stored as entry. entry is extract each line stacktrace into arr
        final String[] stacktrace = ("Caused by: " + rpcException.getMessage()).split("\n");

        // iterate in reverse order to build exception chain.
        for (int i = stacktrace.length - 1; i >= 0; i--) {
            try {
                // only parse cause lines containing the exception class and message.
                if (stacktrace[i].startsWith("Caused by:")) {
                    final String[] causes = stacktrace[i].split(":");
                    final String exceptionClassName = causes[1].substring(1);

                    // System.out.println("parse: " + stacktrace[i]);
                    // System.out.println("match: " + causes.length);

                    final String message = causes.length <= 2 ? "" : stacktrace[i].substring(stacktrace[i].lastIndexOf(exceptionClassName) + exceptionClassName.length() + 2).trim();

                    // detect exception class
                    final Class exceptionClass;
                    try {
                        exceptionClass = (Class) Class.forName(exceptionClassName);

                        // build exception
                        try {
                            // try default constructor
                            exception = exceptionClass.getConstructor(String.class, Throwable.class).newInstance(message, exception);
                        } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                                 NoSuchMethodException | ClassCastException | UnsupportedOperationException ex) {
                            try {
                                // try to handle missing fields
                                if (exception == null && message.isEmpty()) {
                                    exception = exceptionClass.getConstructor().newInstance();
                                } else if (exception == null && !message.isEmpty()) {
                                    exception = exceptionClass.getConstructor(String.class).newInstance(message);
                                } else if (exception != null && message.isEmpty()) {
                                    exception = exceptionClass.getConstructor(Throwable.class).newInstance(exception);
                                } else {
                                    throw ex;
                                }
                            } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                                     NoSuchMethodException exx) {
                                throw new CouldNotPerformException("No compatible constructor found!", exx);
                            }
                        }
                        //System.out.println("create "+ exception.getClass().getSimpleName() + ":" + exception.getMessage());
                    } catch (ClassNotFoundException | ClassCastException | CouldNotPerformException ex) {
                        ExceptionPrinter.printHistory(new CouldNotPerformException("Exception[" + exceptionClassName + "] could not be recovered because no compatible Constructor(String, Throwable) was available!", ex), LOGGER, LogLevel.WARN);

                        // apply fallback solution
                        exception = new CouldNotPerformException(message, exception);
                    }
                }
            } catch (IndexOutOfBoundsException | NullPointerException ex) {
                ExceptionPrinter.printHistory(new CouldNotPerformException("Could not extract exception cause or message out of Line[" + stacktrace[i] + "]!", ex), LOGGER, LogLevel.WARN);
            }
        }
        return exception;
    }

    /**
     * Method returns the raw RPCException.
     *
     * @return the raw RPCException
     */
    public RPCException getRpcException() {
        return rpcException;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy