/**
* 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 com.google.common.collect.Lists;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.List;
/**
* An exception handler that selects an appropriate exception handler from a list
* based on the thrown exception and delegates the handling of the exception to it.
* <p/>
* This class works very similar to catch statements:
* the first delegate which can handle the exception will handle it.
* For example, consider 3 simple delegates for the following classes in this order:
* NullPointerException (1), RuntimeException (2), IllegalArgumentException (3).
* A thrown IllegalArgumentException will be handled by the (2) handler. The (3) handler is useless.
*
* @see ExceptionHandlerDelegate
* @see SimpleExceptionHandlerDelegate
* @author Geoffrey De Smet
* @since 0.3.0
*/
public class DelegatingExceptionHandler<SELF extends DelegatingExceptionHandler<SELF>> extends AbstractRegisterableExceptionHandler<SELF> implements InitializingBean {
protected final transient Log logger = LogFactory.getLog(getClass());
protected List<ExceptionHandlerDelegate> delegateList;
protected ExceptionPurger exceptionPurger = null;
/**
* Sets the list of delegates.
* This is not a map because the order is important
* and delegate selection is not a simple key based selector.
* @param delegateList a list of DelegatingExceptionHandlerDelegate
*/
public void setDelegateList(List<ExceptionHandlerDelegate> delegateList) {
this.delegateList = delegateList;
}
public SELF delegatingInOrderTo(ExceptionHandlerDelegate... delegateList) {
setDelegateList(Lists.newArrayList(delegateList));
return self();
}
public void addDelegateToList(ExceptionHandlerDelegate... delegateList) {
getDelegateList().addAll(Lists.newArrayList(delegateList));
}
public List<ExceptionHandlerDelegate> getDelegateList() {
if(delegateList == null)
delegateList = new ArrayList<ExceptionHandlerDelegate>();
return delegateList;
}
/**
* If set the throwable will first be purged before handling it.
* @param exceptionPurger
*/
public void setExceptionPurger(ExceptionPurger exceptionPurger) {
this.exceptionPurger = exceptionPurger;
}
public SELF purgedBy(ExceptionPurger exceptionPurger) {
setExceptionPurger(exceptionPurger);
return self();
}
public void afterPropertiesSet() throws Exception {
Assert.notEmpty(delegateList, "The delegate list must contains at least one entry.");
}
/**
* Delegates the throwable to the appropriate delegate exception handler.
* @param thread the thread in which the throwable occurred
* @param throwable the thrown throwable
*/
public void uncaughtException(Thread thread, Throwable throwable) {
if (exceptionPurger != null) {
throwable = exceptionPurger.purge(throwable);
}
for (ExceptionHandlerDelegate delegate : delegateList) {
if (delegate.hasAppropriateHandler(throwable)) {
delegate.uncaughtException(thread, throwable);
return;
}
}
// A silent exception handler should be configured if it needs to be silent
logger.error("No exception handler found for throwable", throwable);
}
}