/**
* Copyright (C) 2015 Valkyrie RCP
*
* 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.
*/
package org.valkyriercp.application.exceptionhandling;
import org.valkyriercp.application.ApplicationWindow;
import org.valkyriercp.command.support.ApplicationWindowAwareCommand;
import org.valkyriercp.util.ValkyrieRepository;
import javax.swing.*;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
/**
* A development command used to test the exception handler configuration.
* Pops up a dialog and allows the user to type in the full classname of an exception to throw.
* <p/>
* It is usually not used in production and therefor configured with this property:
* <property name="visible" value="${development.mode}" />
* @author gds
*/
public class ThrowExceptionCommand extends ApplicationWindowAwareCommand
{
private static final String THROWABLE_MESSAGE = "Throwable message made by ThrowExceptionCommand";
private final static String ID = "throwExceptionCommand";
public ThrowExceptionCommand() {
super(ID);
}
@Override
protected void doExecuteCommand()
{
List<Class<? extends Throwable>> throwableClassList = askUserThrowableClassList();
if (throwableClassList != null) {
throwThrowable(throwableClassList);
}
}
private List<Class<? extends Throwable>> askUserThrowableClassList()
{
String throwableClassListString = (String) JOptionPane.showInputDialog(resolveParentFrame(),
"Please fill in the full classname of the exception to throw:\n"
+ "Causes can optionally be appended by semicolons(;). For example:\n"
+ " org.springframework.remoting.RemoteLookupFailureException;"
+ "java.rmi.ConnectException;java.net.ConnectException",
"Which exception do you want to throw?",
JOptionPane.INFORMATION_MESSAGE, null, null, "java.lang.IllegalStateException");
if (throwableClassListString == null) {
// User cancelled
return null;
}
List<Class<? extends Throwable>> throwableClassList = new ArrayList<Class<? extends Throwable>>();
String[] throwableClassListStringTokens = throwableClassListString.split(";");
for (String throwableClassListStringToken : throwableClassListStringTokens)
{
Class<? extends Throwable> throwableClass;
try
{
throwableClass = (Class<? extends Throwable>) Class.forName(throwableClassListStringToken);
}
catch (ClassNotFoundException e)
{
throw new IllegalArgumentException(
"ThrowExceptionCommand failure: Class (" + throwableClassListStringToken
+ ") does not exist.", e);
}
throwableClassList.add(throwableClass);
}
return throwableClassList;
}
private JFrame resolveParentFrame() {
ApplicationWindow activeWindow = ValkyrieRepository.getInstance().getApplicationConfig().windowManager().getActiveWindow();
return (activeWindow == null) ? null : activeWindow.getControl();
}
private void throwThrowable(List<Class<? extends Throwable>> throwableClassList)
{
Class<? extends Throwable> throwableClass = throwableClassList.remove(0);
Throwable throwable;
try
{
throwable = buildThrowable(throwableClassList, throwableClass);
}
catch (InstantiationException e)
{
throw new IllegalArgumentException(
"ThrowExceptionCommand failure: Could not build throwable chain.", e);
}
catch (IllegalAccessException e)
{
throw new IllegalArgumentException(
"ThrowExceptionCommand failure: Could not build throwable chain.", e);
}
catch (NoSuchMethodException e)
{
throw new IllegalArgumentException(
"ThrowExceptionCommand failure: Could not build throwable chain.", e);
}
catch (InvocationTargetException e)
{
throw new IllegalArgumentException(
"ThrowExceptionCommand failure: Could not build throwable chain.", e);
}
if (throwable instanceof RuntimeException) {
throw (RuntimeException) throwable;
} else if (throwable instanceof Error) {
throw (Error) throwable;
} else {
throw new IllegalArgumentException("ThrowExceptionCommand failure: The root throwable ("
+ throwableClass + ") should extend RuntimeException or Error.");
}
}
private Throwable buildThrowable(List<Class<? extends Throwable>> throwableClassList,
Class<? extends Throwable> throwableClass)
throws InstantiationException, IllegalAccessException, InvocationTargetException,
NoSuchMethodException
{
Throwable throwable;
if (throwableClassList.isEmpty()) {
try {
throwable = throwableClass.getDeclaredConstructor(String.class).newInstance(
THROWABLE_MESSAGE);
} catch (NoSuchMethodException e) {
throwable = throwableClass.newInstance();
}
} else {
Throwable cause = buildThrowAndCatch(throwableClassList);
try {
throwable = throwableClass.getDeclaredConstructor(String.class, Throwable.class)
.newInstance(THROWABLE_MESSAGE, cause);
} catch (NoSuchMethodException e) {
try {
throwable = throwableClass.getDeclaredConstructor(String.class, Exception.class)
.newInstance(THROWABLE_MESSAGE, cause);
} catch (NoSuchMethodException e2) {
try {
throwable = throwableClass.getDeclaredConstructor(Throwable.class).newInstance(cause);
} catch (NoSuchMethodException e3) {
throwable = throwableClass.getDeclaredConstructor(Exception.class).newInstance(cause);
}
}
}
}
return throwable;
}
private Throwable buildThrowAndCatch(List<Class<? extends Throwable>> throwableClassList)
throws IllegalAccessException, InstantiationException,
NoSuchMethodException, InvocationTargetException
{
Class<? extends Throwable> throwableClass = throwableClassList.remove(0);
Throwable throwable = buildThrowable(throwableClassList, throwableClass);
try {
throw throwable;
} catch (Throwable catchedThrowable) {
return catchedThrowable;
}
}
}