package ca.uhn.fhir.jaxrs.server.interceptor; /* * #%L * HAPI FHIR JAX-RS Server * %% * Copyright (C) 2014 - 2017 University Health Network * %% * 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. * #L% */ import java.io.IOException; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; import javax.servlet.ServletException; import javax.ws.rs.core.Response; import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider; import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor; /** * An interceptor that catches the jax-rs exceptions * * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare */ public class JaxRsExceptionInterceptor { /** the existing exception handler which is able to convert exception into responses*/ private final ExceptionHandlingInterceptor exceptionHandler; /** * The default constructor */ public JaxRsExceptionInterceptor() { this.exceptionHandler = new ExceptionHandlingInterceptor(); } /** * A utility constructor for unit testing * @param exceptionHandler the handler for the exception conversion */ JaxRsExceptionInterceptor(final ExceptionHandlingInterceptor exceptionHandler) { this.exceptionHandler = exceptionHandler; } /** * This interceptor will catch all exception and convert them using the exceptionhandler * @param ctx the invocation context * @return the result * @throws JaxRsResponseException an exception that can be handled by a jee container */ @AroundInvoke public Object intercept(final InvocationContext ctx) throws JaxRsResponseException { try { return ctx.proceed(); } catch (final Exception theException) { final AbstractJaxRsProvider theServer = (AbstractJaxRsProvider) ctx.getTarget(); throw convertException(theServer, theException); } } /** * This method convert an exception to a JaxRsResponseException * @param theServer the provider * @param theException the exception to convert * @return JaxRsResponseException */ public JaxRsResponseException convertException(final AbstractJaxRsProvider theServer, final Throwable theException) { if (theServer.withStackTrace()) { exceptionHandler.setReturnStackTracesForExceptionTypes(Throwable.class); } final JaxRsRequest requestDetails = theServer.getRequest(null, null).build(); final BaseServerResponseException convertedException = preprocessException(theException, requestDetails); return new JaxRsResponseException(convertedException); } /** * This method converts an exception into a response * @param theRequest the request * @param theException the thrown exception * @return the response describing the error * @throws IOException */ public Response convertExceptionIntoResponse(final JaxRsRequest theRequest, final JaxRsResponseException theException) throws IOException { return handleExceptionWithoutServletError(theRequest, theException); } private BaseServerResponseException preprocessException(final Throwable theException, final JaxRsRequest requestDetails) { try { Throwable theExceptionToConvert = theException; if (!(theException instanceof BaseServerResponseException) && (theException.getCause() instanceof BaseServerResponseException)) { theExceptionToConvert = theException.getCause(); } return exceptionHandler.preProcessOutgoingException(requestDetails, theExceptionToConvert, null); } catch (final ServletException e) { return new InternalErrorException(e); } } private Response handleExceptionWithoutServletError(final JaxRsRequest theRequest, final BaseServerResponseException theException) throws IOException { try { return (Response) exceptionHandler.handleException(theRequest, theException); } catch (final ServletException e) { final BaseServerResponseException newException = preprocessException(new InternalErrorException(e), theRequest); return handleExceptionWithoutServletError(theRequest, newException); } } }