#128 - pass RestfulServer into exception handlers so they don't need to use the possibly null RequestDetail to sort out the server and server base

This commit is contained in:
b.debeaubien 2015-03-19 10:05:29 -04:00
parent 75877c18eb
commit 5956ab75fd
5 changed files with 30 additions and 42 deletions

View File

@ -37,7 +37,6 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.hl7.fhir.instance.model.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
@ -45,8 +44,6 @@ import ca.uhn.fhir.context.ProvidedResourceScanner;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome.BaseIssue;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.Destroy;
import ca.uhn.fhir.rest.annotation.IdParam;
@ -54,12 +51,10 @@ import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.method.ConformanceMethodBinding;
import ca.uhn.fhir.rest.method.OtherOperationTypeEnum;
import ca.uhn.fhir.rest.method.Request;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.method.SearchMethodBinding;
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.NotModifiedException;
import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
@ -680,7 +675,7 @@ public class RestfulServer extends HttpServlet {
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = getInterceptors().get(i);
if (!next.handleException(requestDetails, e, theRequest, theResponse)) {
if (!next.handleException(this, requestDetails, e, theRequest, theResponse)) {
ourLog.debug("Interceptor {} returned false, not continuing processing");
return;
}
@ -691,7 +686,7 @@ public class RestfulServer extends HttpServlet {
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = getInterceptors().get(i);
if (!next.handleException(requestDetails, e, theRequest, theResponse)) {
if (!next.handleException(this, requestDetails, e, theRequest, theResponse)) {
ourLog.debug("Interceptor {} returned false, not continuing processing");
return;
}
@ -710,13 +705,13 @@ public class RestfulServer extends HttpServlet {
*/
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = getInterceptors().get(i);
if (!next.handleException(requestDetails, e, theRequest, theResponse)) {
if (!next.handleException(this, requestDetails, e, theRequest, theResponse)) {
ourLog.debug("Interceptor {} returned false, not continuing processing");
return;
}
}
new ExceptionHandlingInterceptor().handleException(requestDetails, e, theRequest, theResponse);
new ExceptionHandlingInterceptor().handleException(this, requestDetails, e, theRequest, theResponse);
}
}

View File

@ -59,12 +59,12 @@ public class ExceptionHandlingInterceptor extends InterceptorAdapter {
}
@Override
public boolean handleException(RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException {
public boolean handleException(RestfulServer theRestfulServer, RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException {
ourLog.error("AA", theException);
BaseOperationOutcome oo = null;
int statusCode = Constants.STATUS_HTTP_500_INTERNAL_ERROR;
FhirContext ctx = theRequestDetails.getServer().getFhirContext();
FhirContext ctx = theRestfulServer.getFhirContext();
if (theException instanceof BaseServerResponseException) {
oo = ((BaseServerResponseException) theException).getOperationOutcome();
@ -109,12 +109,13 @@ public class ExceptionHandlingInterceptor extends InterceptorAdapter {
}
boolean requestIsBrowser = RestfulServer.requestIsBrowser(theRequest);
String fhirServerBase = ((Request) theRequestDetails).getFhirServerBase();
RestfulServerUtils.streamResponseAsResource(theRequestDetails.getServer(), theResponse, oo, RestfulServerUtils.determineResponseEncodingNoDefault(theRequest), true, requestIsBrowser,
String fhirServerBase = theRestfulServer.getServerBaseForRequest(theRequest);
RestfulServerUtils.streamResponseAsResource(theRestfulServer, theResponse, oo, RestfulServerUtils.determineResponseEncodingNoDefault(theRequest), true, requestIsBrowser,
NarrativeModeEnum.NORMAL, statusCode, false, fhirServerBase);
theResponse.setStatus(statusCode);
theRequestDetails.getServer().addHeadersToResponse(theResponse);
theRestfulServer.addHeadersToResponse(theResponse);
theResponse.setContentType("text/plain");
theResponse.setCharacterEncoding("UTF-8");
theResponse.getWriter().append(theException.getMessage());

View File

@ -26,6 +26,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ca.uhn.fhir.rest.server.RestfulServer;
import org.hl7.fhir.instance.model.IBaseResource;
import ca.uhn.fhir.model.api.Bundle;
@ -178,23 +179,25 @@ public interface IServerInterceptor {
* they have handled the request and processing should stop.
* </p>
*
* @param theRequestDetails
* Contains either <code>null</code>, or a bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}. This parameter may be
* null if the request processing did not successfully parse the incoming request, but will generally not be null.
* @param theServletRequest
* The incoming request
* @param theServletResponse
* The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return
* <code>false</code>
* @return Return <code>true</code> if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the
*
* @param server
* @param theRequestDetails
* Contains either <code>null</code>, or a bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link javax.servlet.http.HttpServletRequest servlet request}. This parameter may be
* null if the request processing did not successfully parse the incoming request, but will generally not be null.
* @param theServletRequest
* The incoming request
* @param theServletResponse
* The response. Note that interceptors may choose to provide a response (i.e. by calling {@link javax.servlet.http.HttpServletResponse#getWriter()}) but in that case it is important to return
* <code>false</code>
* @return Return <code>true</code> if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the
* response normally, you must return <code>false</code>. In this case, no further processing will occur and no further interceptors will be called.
* @throws ServletException
* If this exception is thrown, it will be re-thrown up to the container for handling.
* @throws IOException
* If this exception is thrown, it will be re-thrown up to the container for handling.
*/
public boolean handleException(RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws ServletException,
public boolean handleException(RestfulServer server, RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws ServletException,
IOException;
}

View File

@ -26,6 +26,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ca.uhn.fhir.rest.server.RestfulServer;
import org.hl7.fhir.instance.model.IBaseResource;
import ca.uhn.fhir.model.api.Bundle;
@ -70,7 +71,7 @@ public class InterceptorAdapter implements IServerInterceptor {
}
@Override
public boolean handleException(RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws ServletException,
public boolean handleException(RestfulServer server, RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws ServletException,
IOException {
return true;
}

View File

@ -4,9 +4,7 @@ import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
@ -21,7 +19,6 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hamcrest.core.StringContains;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@ -29,17 +26,8 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.slf4j.Logger;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.IResourceProvider;
@ -61,7 +49,7 @@ public class ExceptionInterceptorMethodTest {
when(myInterceptor.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
when(myInterceptor.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
when(myInterceptor.handleException(any(RequestDetails.class), any(Throwable.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
when(myInterceptor.handleException(any(RestfulServer.class), any(RequestDetails.class), any(Throwable.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=throwUnprocessableEntityException");
HttpResponse status = ourClient.execute(httpGet);
@ -70,7 +58,7 @@ public class ExceptionInterceptorMethodTest {
IOUtils.closeQuietly(status.getEntity().getContent());
ArgumentCaptor<Throwable> captor = ArgumentCaptor.forClass(Throwable.class);
verify(myInterceptor, times(1)).handleException(any(RequestDetails.class), captor.capture(), any(HttpServletRequest.class), any(HttpServletResponse.class));
verify(myInterceptor, times(1)).handleException(any(RestfulServer.class), any(RequestDetails.class), captor.capture(), any(HttpServletRequest.class), any(HttpServletResponse.class));
assertEquals(UnprocessableEntityException.class, captor.getValue().getClass());
}
@ -82,10 +70,10 @@ public class ExceptionInterceptorMethodTest {
when(myInterceptor.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
when(myInterceptor.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
when(myInterceptor.handleException(any(RequestDetails.class), any(Throwable.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenAnswer(new Answer<Boolean>() {
when(myInterceptor.handleException(any(RestfulServer.class), any(RequestDetails.class), any(Throwable.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock theInvocation) throws Throwable {
HttpServletResponse resp = (HttpServletResponse) theInvocation.getArguments()[3];
HttpServletResponse resp = (HttpServletResponse) theInvocation.getArguments()[4];
resp.setStatus(405);
resp.setContentType("text/plain");
resp.getWriter().write("HELP IM A BUG");