
001package ca.uhn.fhir.jaxrs.server.interceptor; 002 003/* 004 * #%L 005 * HAPI FHIR JAX-RS Server 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import java.io.IOException; 024 025import javax.interceptor.AroundInvoke; 026import javax.interceptor.InvocationContext; 027import javax.servlet.ServletException; 028import javax.ws.rs.core.Response; 029 030import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider; 031import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest; 032import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; 033import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 034import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor; 035 036/** 037 * An interceptor that catches the jax-rs exceptions 038 * 039 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare 040 */ 041public class JaxRsExceptionInterceptor { 042 043 /** the existing exception handler which is able to convert exception into responses*/ 044 private final ExceptionHandlingInterceptor exceptionHandler; 045 046 /** 047 * The default constructor 048 */ 049 public JaxRsExceptionInterceptor() { 050 this.exceptionHandler = new ExceptionHandlingInterceptor(); 051 } 052 053 /** 054 * A utility constructor for unit testing 055 * @param exceptionHandler the handler for the exception conversion 056 */ 057 JaxRsExceptionInterceptor(final ExceptionHandlingInterceptor exceptionHandler) { 058 this.exceptionHandler = exceptionHandler; 059 } 060 061 /** 062 * This interceptor will catch all exception and convert them using the exceptionhandler 063 * @param ctx the invocation context 064 * @return the result 065 * @throws JaxRsResponseException an exception that can be handled by a jee container 066 */ 067 @AroundInvoke 068 public Object intercept(final InvocationContext ctx) 069 throws JaxRsResponseException { 070 try { 071 return ctx.proceed(); 072 } 073 catch (final Exception theException) { 074 final AbstractJaxRsProvider theServer = (AbstractJaxRsProvider) ctx.getTarget(); 075 throw convertException(theServer, theException); 076 } 077 } 078 079 /** 080 * This method convert an exception to a JaxRsResponseException 081 * @param theServer the provider 082 * @param theException the exception to convert 083 * @return JaxRsResponseException 084 */ 085 public JaxRsResponseException convertException(final AbstractJaxRsProvider theServer, final Throwable theException) { 086 if (theServer.withStackTrace()) { 087 exceptionHandler.setReturnStackTracesForExceptionTypes(Throwable.class); 088 } 089 final JaxRsRequest requestDetails = theServer.getRequest(null, null).build(); 090 final BaseServerResponseException convertedException = preprocessException(theException, requestDetails); 091 return new JaxRsResponseException(convertedException); 092 } 093 094 /** 095 * This method converts an exception into a response 096 * @param theRequest the request 097 * @param theException the thrown exception 098 * @return the response describing the error 099 * @throws IOException 100 */ 101 public Response convertExceptionIntoResponse(final JaxRsRequest theRequest, final JaxRsResponseException theException) 102 throws IOException { 103 return handleExceptionWithoutServletError(theRequest, theException); 104 } 105 106 private BaseServerResponseException preprocessException(final Throwable theException, final JaxRsRequest requestDetails) { 107 try { 108 Throwable theExceptionToConvert = theException; 109 if (!(theException instanceof BaseServerResponseException) && (theException.getCause() instanceof BaseServerResponseException)) { 110 theExceptionToConvert = theException.getCause(); 111 } 112 return exceptionHandler.preProcessOutgoingException(requestDetails, theExceptionToConvert, null); 113 } 114 catch (final ServletException e) { 115 return new InternalErrorException(e); 116 } 117 } 118 119 private Response handleExceptionWithoutServletError(final JaxRsRequest theRequest, final BaseServerResponseException theException) 120 throws IOException { 121 try { 122 return (Response) exceptionHandler.handleException(theRequest, theException); 123 } 124 catch (final ServletException e) { 125 final BaseServerResponseException newException = preprocessException(new InternalErrorException(e), theRequest); 126 return handleExceptionWithoutServletError(theRequest, newException); 127 } 128 } 129}