/*
* This file is part of LibrePlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.web.common;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang3.Validate;
public class ExceptionCatcherProxy<T> {
public interface IExceptionHandler<T extends Exception> {
public void onException(T exception);
}
public static <T> ExceptionCatcherProxy<T> doCatchFor(
Class<T> interfaceKlass) {
return new ExceptionCatcherProxy<T>(interfaceKlass);
}
private static class RegisteredHandler<T extends Exception> {
private final Class<T> exceptionClass;
private final IExceptionHandler<T> handler;
RegisteredHandler(Class<T> exceptionClass, IExceptionHandler<T> handler) {
this.exceptionClass = exceptionClass;
this.handler = handler;
}
void invoke(Exception e) {
handler.onException(exceptionClass.cast(e));
}
boolean isAppyable(Throwable cause) {
return exceptionClass.isInstance(cause);
}
public boolean isMoreSpecificThan(RegisteredHandler<?> r) {
return r.exceptionClass.isAssignableFrom(this.exceptionClass);
}
}
private List<RegisteredHandler<?>> handlers = new LinkedList<RegisteredHandler<?>>();
private final Class<T> interfaceKlass;
private ExceptionCatcherProxy(Class<T> interfaceKlass) {
this.interfaceKlass = interfaceKlass;
Validate.isTrue(interfaceKlass.isInterface());
}
public T applyTo(final T instance) {
return interfaceKlass.cast(Proxy.newProxyInstance(instance.getClass()
.getClassLoader(), new Class[] { interfaceKlass },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
Object result;
try {
result = method.invoke(instance, args);
return result;
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (!handled(cause)) {
throw cause;
}
// we don't know what would be the result, so we
// return null
return null;
}
}
}));
}
private boolean handled(Throwable cause) {
if (!(cause instanceof Exception)) {
return false;
}
Exception exception = (Exception) cause;
for (RegisteredHandler<?> registeredHandler : handlers) {
if (registeredHandler.isAppyable(cause)) {
registeredHandler.invoke(exception);
return true;
}
}
return false;
}
public <E extends Exception> ExceptionCatcherProxy<T> when(
Class<E> exception, IExceptionHandler<E> handler) {
RegisteredHandler<E> registered = new RegisteredHandler<E>(exception,
handler);
insertAtRightPosition(registered);
return this;
}
private void insertAtRightPosition(RegisteredHandler<?> handler) {
int i = 0;
for (RegisteredHandler<?> r : handlers) {
if (handler.isMoreSpecificThan(r)) {
break;
}
i++;
}
handlers.add(i, handler);
}
}