/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.everrest.core.impl; import org.everrest.core.ApplicationContext; import org.everrest.core.ExtHttpHeaders; import org.everrest.core.GenericContainerRequest; import org.everrest.core.GenericContainerResponse; import org.everrest.core.RequestFilter; import org.everrest.core.RequestHandler; import org.everrest.core.ResourceBinder; import org.everrest.core.ResponseFilter; import org.everrest.core.UnhandledException; import org.everrest.core.tools.ErrorPages; import org.everrest.core.util.Tracer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.ext.ExceptionMapper; import java.io.IOException; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Strings.isNullOrEmpty; /** * @author andrew00x */ public class RequestHandlerImpl implements RequestHandler { private static final Logger LOG = LoggerFactory.getLogger(RequestHandlerImpl.class); private final RequestDispatcher dispatcher; private final ProviderBinder providers; public RequestHandlerImpl(RequestDispatcher dispatcher, ProviderBinder providers) { checkNotNull(dispatcher); checkNotNull(providers); this.dispatcher = dispatcher; this.providers = providers; } @Override public void handleRequest(GenericContainerRequest request, GenericContainerResponse response) throws IOException { final ApplicationContext context = ApplicationContext.getCurrent(); try { for (RequestFilter filter : providers.getRequestFilters(context.getPath())) { filter.doFilter(request); } dispatcher.dispatch(request, response); setupInternalResponseHeaders(response.getStatus(), response.getHttpHeaders()); for (ResponseFilter filter : providers.getResponseFilters(context.getPath())) { filter.doFilter(response); } } catch (Exception e) { if (e instanceof WebApplicationException) { handleWebApplicationException((WebApplicationException)e, response); } else if (e instanceof InternalException) { handleInternalException((InternalException)e, response); } else { throw new UnhandledException(e); } } response.writeResponse(); } @SuppressWarnings({"unchecked"}) private void handleWebApplicationException(WebApplicationException webApplicationException, GenericContainerResponse response) { LOG.debug("WebApplicationException occurs", webApplicationException); ErrorPages errorPages = (ErrorPages)EnvironmentContext.getCurrent().get(ErrorPages.class); Response errorResponse = webApplicationException.getResponse(); int errorStatus = errorResponse.getStatus(); Throwable cause = webApplicationException.getCause(); propagateErrorIfHaveErrorPage(webApplicationException, errorPages); propagateErrorIfHaveErrorPage(cause, errorPages); propagateErrorIfHaveErrorPage(errorStatus, errorPages); if (Tracer.isTracingEnabled()) { Tracer.trace("WebApplicationException occurs, cause = (%s)", cause); } if (errorResponse.hasEntity()) { setupInternalResponseHeaders(errorStatus, errorResponse.getMetadata()); } else { ExceptionMapper exceptionMapper = providers.getExceptionMapper(WebApplicationException.class); if (exceptionMapper != null) { if (Tracer.isTracingEnabled()) { Tracer.trace("Found ExceptionMapper for WebApplicationException = (%s)", exceptionMapper); } errorResponse = exceptionMapper.toResponse(webApplicationException); } else if (cause != null) { if (isNullOrEmpty(cause.getMessage())) { errorResponse = createErrorResponse(errorStatus, cause.toString()); } else { errorResponse = createErrorResponse(errorStatus, cause.getMessage()); } } else if (!isNullOrEmpty(webApplicationException.getMessage())) { errorResponse = createErrorResponse(errorStatus, webApplicationException.getMessage()); } } response.setResponse(errorResponse); } @SuppressWarnings({"unchecked"}) private void handleInternalException(InternalException internalException, GenericContainerResponse response) { LOG.debug("InternalException occurs", internalException); ErrorPages errorPages = (ErrorPages)EnvironmentContext.getCurrent().get(ErrorPages.class); Throwable cause = internalException.getCause(); propagateErrorIfHaveErrorPage(internalException, errorPages); propagateErrorIfHaveErrorPage(cause, errorPages); if (Tracer.isTracingEnabled()) { Tracer.trace("InternalException occurs, cause = (%s)", cause); } ExceptionMapper exceptionMapper = providers.getExceptionMapper(cause.getClass()); if (exceptionMapper != null) { if (Tracer.isTracingEnabled()) { Tracer.trace("Found ExceptionMapper for %s = (%s)", cause.getClass(), exceptionMapper); } response.setResponse(exceptionMapper.toResponse(cause)); } else { throw new UnhandledException(cause); } } private void propagateErrorIfHaveErrorPage(Throwable error, ErrorPages errorPages) { if (errorPages != null && error != null && errorPages.hasErrorPage(error)) { throw new UnhandledException(error); } } private void propagateErrorIfHaveErrorPage(int errorStatus, ErrorPages errorPages) { if (errorPages != null && errorPages.hasErrorPage(errorStatus)) { throw new UnhandledException(errorStatus); } } @Deprecated private void setupInternalResponseHeaders(int status, MultivaluedMap<String, Object> responseHeaders) { if (responseHeaders.getFirst(ExtHttpHeaders.JAXRS_BODY_PROVIDED) == null) { String jaxrsHeader = getJaxrsHeader(status); if (jaxrsHeader != null) { responseHeaders.putSingle(ExtHttpHeaders.JAXRS_BODY_PROVIDED, jaxrsHeader); } } } @Override public ProviderBinder getProviders() { return providers; } @Override public ResourceBinder getResources() { return dispatcher.getResources(); } /** * Create error response with specified status and body message. * * @param status * response status * @param message * response message * @return response */ private Response createErrorResponse(int status, String message) { ResponseBuilder responseBuilder = Response.status(status); responseBuilder.entity(message).type(MediaType.TEXT_PLAIN); String jaxrsHeader = getJaxrsHeader(status); if (jaxrsHeader != null) { responseBuilder.header(ExtHttpHeaders.JAXRS_BODY_PROVIDED, jaxrsHeader); } return responseBuilder.build(); } private String getJaxrsHeader(int status) { if (status >= 400) { return "Error-Message"; } return null; } }