/*
 * #%L
 * fujion
 * %%
 * Copyright (C) 2018 Fujion Framework
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * #L%
 */
package org.fujion.ancillary;

import java.lang.reflect.InvocationTargetException;

import org.apache.commons.lang.UnhandledException;
import org.fujion.component.BaseComponent;

/**
 * Run time exception related to a component operation.
 */
public class ComponentException extends UnhandledException {

    private static final long serialVersionUID = 1L;

    private final BaseComponent component;

    private final Class<? extends BaseComponent> componentClass;

    private final String message;
    
    private static String formatMessage(Class<?> componentClass, BaseComponent component, String message, Object... args) {
        Object object = component != null ? component : componentClass;
        return (object == null ? "" : object + ": ") + String.format(message, args);
    }
    
    private static Throwable getCause(Throwable cause) {
        return cause instanceof InvocationTargetException ? cause.getCause() : cause;
    }

    private ComponentException(Throwable cause, Class<? extends BaseComponent> componentClass, BaseComponent component,
                               String message, Object... args) {
        super(getCause(cause));
        this.message = formatMessage(componentClass, component, message, args);
        this.component = component;
        this.componentClass = component != null ? component.getClass() : componentClass;
    }
    
    public ComponentException(Throwable cause, String message, Object... args) {
        this(cause, null, null, message, args);
    }
    
    public ComponentException(Throwable cause, Class<? extends BaseComponent> componentClass, String message,
                              Object... args) {
        this(cause, componentClass, null, message, args);
    }
    
    public ComponentException(Throwable cause, BaseComponent component, String message, Object... args) {
        this(cause, null, component, message, args);
    }
    
    public ComponentException(String message, Object... args) {
        this(null, null, null, message, args);
    }

    public ComponentException(Class<? extends BaseComponent> componentClass, String message, Object... args) {
        this(null, componentClass, null, message, args);
    }

    public ComponentException(BaseComponent component, String message, Object... args) {
        this(null, null, component, message, args);
    }

    /**
     * Returns the component instance that caused the exception.
     *
     * @return Component instance that caused the exception. May be null.
     */
    public BaseComponent getComponent() {
        return component;
    }

    /**
     * Returns the class of the component that caused the exception. If a component instance is
     * associated with the exception, the class will be that of the component instance. However, if
     * the exception occurred while attempting to create an instance of a component, the component
     * instance will be null and only the component class will be set.
     *
     * @return Class of the component that caused the exception. May be null.
     */
    public Class<? extends BaseComponent> getComponentClass() {
        return componentClass;
    }

    /**
     * Override default behavior and simply prepend this exception's message to that of its
     * superclass.
     */
    @Override
    public String getMessage() {
        String message = super.getMessage();
        
        if (message == null) {
            message = this.message;
        } else if (this.message != null) {
            message = this.message + "\n" + message;
        }
        
        return message;
    }
}

@@ -716,16 +716,52 @@
 ception;
+%0Aimport java.util.function.Supplier;
 %0A%0Aimport
@@ -1174,24 +1174,839 @@
 ssage;%0A    %0A
+    /**%0A     * Asserts that a condition is true, throwing a ComponentException if it is not.%0A     *%0A     * @param condition Condition to test.%0A     * @param message The exception message.%0A     */%0A    public static void assertTrue(boolean condition, Supplier%3CString%3E message) %7B%0A        if (!condition) %7B%0A            throw new ComponentException(message.get());%0A        %7D%0A    %7D%0A    %0A    /**%0A     * Asserts that a condition is true, throwing a ComponentException if it is not.%0A     *%0A     * @param condition Condition to test.%0A     * @param message The exception message.%0A     * @param args Optional message parameters%0A     */%0A    public static void assertTrue(boolean condition, String message, Object... args) %7B%0A        if (!condition) %7B%0A            throw new ComponentException(message, args);%0A        %7D%0A    %7D%0A    %0A
     private 
@@ -2185,24 +2185,117 @@
 onentClass;%0A
+        message = args == null %7C%7C args.length == 0 ? message : String.format(message, args);%0A
         retu
@@ -2341,36 +2341,15 @@
 ) + 
-String.format(message, args)
+message
 ;%0A  

Add ComponentException.assertTrue static method.