mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-02-22 13:55:22 +00:00
#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:
parent
75877c18eb
commit
5956ab75fd
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user