diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/CdsHooksServlet.java b/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/CdsHooksServlet.java index 9c19a18..cfb035c 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/CdsHooksServlet.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/CdsHooksServlet.java @@ -44,7 +44,7 @@ public class CdsHooksServlet extends HttpServlet { // CORS Pre-flight @Override protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - //ErrorHandling.setAccessControlHeaders(resp, appProperties); + ErrorHandling.setAccessControlHeaders(resp, appProperties); resp.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType()); resp.setHeader("X-Content-Type-Options", "nosniff"); resp.setStatus(HttpServletResponse.SC_OK); @@ -59,7 +59,7 @@ public class CdsHooksServlet extends HttpServlet { logger.error(request.getRequestURI()); throw new ServletException("This servlet is not configured to handle GET requests."); } - //ErrorHandling.setAccessControlHeaders(response, myAppProperties); + ErrorHandling.setAccessControlHeaders(response, appProperties); response.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType()); response.getWriter().println(new GsonBuilder().setPrettyPrinting().create().toJson(getServices())); } @@ -90,7 +90,7 @@ public class CdsHooksServlet extends HttpServlet { response.setContentType("text/json;charset=UTF-8"); response.getWriter().println(jsonResponse); } catch (BaseServerResponseException e) { - // ErrorHandling.handleError(response, "ERROR: Exception connecting to remote server.", e, myAppProperties); + ErrorHandling.handleError(response, "ERROR: Exception connecting to remote server.", e, appProperties); logger.error(e.toString()); } catch (Exception e) { logger.error(e.toString()); diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/ErrorHandling.java b/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/ErrorHandling.java new file mode 100644 index 0000000..203a1ef --- /dev/null +++ b/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/ErrorHandling.java @@ -0,0 +1,91 @@ +package ca.uhn.fhir.jpa.starter.cdshooks; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; + +import javax.servlet.http.HttpServletResponse; + +import ca.uhn.fhir.jpa.starter.AppProperties; +import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; + +public class ErrorHandling { + + private ErrorHandling() {} + + public static void handleError(HttpServletResponse response, String message, + Exception e, AppProperties myAppProperties) + throws IOException { + setAccessControlHeaders(response, myAppProperties); + response.setStatus(500); // This will be overwritten with the correct status code downstream if needed. + response.getWriter().println(message); + printMessageAndCause(e, response); + if (e instanceof BaseServerResponseException) { + handleServerResponseException((BaseServerResponseException) e, response); + } else if (e.getCause() instanceof BaseServerResponseException) { + handleServerResponseException((BaseServerResponseException) e.getCause(), response); + } + printStackTrack(e, response); + } + + private static void handleServerResponseException(BaseServerResponseException e, HttpServletResponse response) + throws IOException { + switch (e.getStatusCode()) { + case 401: + case 403: + response.getWriter().println("Precondition Failed. Remote FHIR server returned: " + e.getStatusCode()); + response.getWriter().println( + "Ensure that the fhirAuthorization token is set or that the remote server allows unauthenticated access."); + response.setStatus(412); + break; + case 404: + response.getWriter().println("Precondition Failed. Remote FHIR server returned: " + e.getStatusCode()); + response.getWriter().println("Ensure the resource exists on the remote server."); + response.setStatus(412); + break; + default: + response.getWriter().println("Unhandled Error in Remote FHIR server: " + e.getStatusCode()); + } + } + + private static void printMessageAndCause(Exception e, HttpServletResponse response) throws IOException { + if (e.getMessage() != null) { + response.getWriter().println(e.getMessage()); + } + + if (e.getCause() != null && e.getCause().getMessage() != null) { + response.getWriter().println(e.getCause().getMessage()); + } + } + + private static void printStackTrack(Exception e, HttpServletResponse response) throws IOException { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + String exceptionAsString = sw.toString(); + response.getWriter().println(exceptionAsString); + } + + public static void setAccessControlHeaders(HttpServletResponse resp, AppProperties myAppProperties) { + if (myAppProperties.getCors() != null) { + if (myAppProperties.getCors().getAllow_Credentials()) { + resp.setHeader("Access-Control-Allow-Origin", + myAppProperties.getCors().getAllowed_origin().stream().findFirst().get()); + resp.setHeader("Access-Control-Allow-Methods", + String.join(", ", Arrays.asList("GET", "HEAD", "POST", "OPTIONS"))); + resp.setHeader("Access-Control-Allow-Headers", + String.join(", ", Arrays.asList("x-fhir-starter", "Origin", + "Accept", "X-Requested-With", "Content-Type", "Authorization", "Cache-Control"))); + resp.setHeader("Access-Control-Expose-Headers", + String.join(", ", Arrays.asList("Location", "Content-Location"))); + resp.setHeader("Access-Control-Max-Age", "86400"); + } + } + } + + public static class CdsHooksError extends RuntimeException { + public CdsHooksError(String message) { + super(message); + } + } +} diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/StarterCdsHooksConfig.java b/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/StarterCdsHooksConfig.java index f732257..cd5a078 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/StarterCdsHooksConfig.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/StarterCdsHooksConfig.java @@ -1,16 +1,12 @@ package ca.uhn.fhir.jpa.starter.cdshooks; import org.hl7.fhir.instance.model.api.IBaseResource; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry; -import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.hapi.fhir.cdshooks.api.ICdsHooksDaoAuthorizationSvc; import ca.uhn.hapi.fhir.cdshooks.config.CdsHooksConfig; import ca.uhn.hapi.fhir.cdshooks.svc.CdsHooksContextBooter;