/*
* Copyright (c) 2012 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.server.webapp.pages;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.request.http.WebResponse;
import org.apache.wicket.request.http.flow.AbortWithHttpErrorCodeException;
import org.springframework.security.access.AccessDeniedException;
import de.fhg.igd.slf4jplus.ALogger;
import de.fhg.igd.slf4jplus.ALoggerFactory;
import eu.esdihumboldt.hale.server.webapp.util.PageDescription;
/**
* Page for informing the user about runtime exceptions.
*
* @author Simon Templer
*/
@PageDescription(title = "Error")
public class ExceptionPage extends BasePage {
private static final ALogger log = ALoggerFactory.getLogger(ExceptionPage.class);
private static final long serialVersionUID = 6090567597067611331L;
private final Map<Class<? extends Exception>, ExceptionInfo<?>> infos = new LinkedHashMap<Class<? extends Exception>, ExceptionInfo<?>>();
private Exception exception;
@SuppressWarnings("rawtypes")
private final ExceptionInfo info;
private static final ExceptionInfo<Exception> DEFAULT = new ExceptionInfo<Exception>() {
private static final long serialVersionUID = 6127547839449215497L;
@Override
public int getHttpErrorCode(Exception exception) {
return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
}
@Override
public Class<Exception> getExceptionType() {
return Exception.class;
}
@Override
public String getErrorTitle(Exception exception) {
return "Internal Error";
}
@Override
public String getErrorMessage(Exception exception) {
return "An internal error occurred during this operation.";
}
};
/**
* Create an error page based on the given exception.
*
* @param e the exception
*/
@SuppressWarnings("unchecked")
public ExceptionPage(Exception e) {
this.exception = e;
// log exception
log.error("Wicket internal error: " + e.getMessage(), e);
// custom exception handling
// TODO make this extendable/configurable?
// Spring Access Denied
ExceptionInfo<?> accessDenied = new ExceptionInfo<AccessDeniedException>() {
private static final long serialVersionUID = -3440057330226741496L;
@Override
public Class<AccessDeniedException> getExceptionType() {
return AccessDeniedException.class;
}
@Override
public String getErrorTitle(AccessDeniedException exception) {
return "Access Denied";
}
@Override
public String getErrorMessage(AccessDeniedException exception) {
return "You don't have the necessary permissions to perform this operation.";
}
@Override
public int getHttpErrorCode(AccessDeniedException exception) {
return HttpServletResponse.SC_FORBIDDEN;
}
};
infos.put(accessDenied.getExceptionType(), accessDenied);
ExceptionInfo<?> abortWithErrorCode = new ExceptionInfo<AbortWithHttpErrorCodeException>() {
private static final long serialVersionUID = -3440057330226741496L;
@Override
public Class<AbortWithHttpErrorCodeException> getExceptionType() {
return AbortWithHttpErrorCodeException.class;
}
@Override
public String getErrorTitle(AbortWithHttpErrorCodeException exception) {
return "Error " + exception.getErrorCode();
}
@Override
public String getErrorMessage(AbortWithHttpErrorCodeException exception) {
return exception.getMessage();
}
@Override
public int getHttpErrorCode(AbortWithHttpErrorCodeException exception) {
return exception.getErrorCode();
}
};
infos.put(abortWithErrorCode.getExceptionType(), abortWithErrorCode);
// determine exception info and assign exception variable
info = determineExceptionInfo(e);
add(new Label("title", info.getErrorTitle(exception)));
add(new Label("message", info.getErrorMessage(exception)));
}
private ExceptionInfo<?> determineExceptionInfo(Exception e) {
// first, try map key
ExceptionInfo<?> info = infos.get(e.getClass());
if (info != null) {
this.exception = e;
return info;
}
// then, try in order (test compatibility)
for (ExceptionInfo<?> candidate : infos.values()) {
if (candidate.getExceptionType().isAssignableFrom(e.getClass())) {
this.exception = e;
return candidate;
}
}
// then try cause
Throwable cause = e.getCause();
if (cause != null && cause != e && cause instanceof Exception) {
return determineExceptionInfo((Exception) cause);
}
this.exception = e;
return DEFAULT;
}
/**
* Get the HTTP status code for this error. Default is
* {@link HttpServletResponse#SC_INTERNAL_SERVER_ERROR}.
*
* @param exception the exception
* @return the status code
*/
@SuppressWarnings("unchecked")
protected int getStatus(Exception exception) {
return info.getHttpErrorCode(exception);
}
/**
* @see org.apache.wicket.markup.html.WebPage#configureResponse(WebResponse)
*/
@Override
protected void configureResponse(WebResponse webResponse) {
super.configureResponse(webResponse);
webResponse.setStatus(getStatus(exception));
}
/**
* @see org.apache.wicket.Page#isErrorPage()
*/
@Override
public boolean isErrorPage() {
return true;
}
}