Add CdsHooksServlet

This commit is contained in:
Brenin Rhodes
2023-09-28 20:10:20 -06:00
parent 6379e8ae60
commit 68b83d0c8e
2 changed files with 175 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
package ca.uhn.fhir.jpa.starter.cdshooks;
import java.io.IOException;
import java.util.stream.Collectors;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import ca.uhn.fhir.jpa.starter.AppProperties;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.hapi.fhir.cdshooks.api.ICdsServiceRegistry;
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestJson;
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseJson;
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServicesJson;
@Configurable
public class CdsHooksServlet extends HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(CdsHooksServlet.class);
private static final long serialVersionUID = 1L;
@Autowired
private AppProperties appProperties;
@Autowired
ICdsServiceRegistry cdsServiceRegistry;
@Autowired
RestfulServer restfulServer;
// private final ServletRequestDetails requestDetails = new ServletRequestDetails();
// CORS Pre-flight
@Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//ErrorHandling.setAccessControlHeaders(resp, appProperties);
resp.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType());
resp.setHeader("X-Content-Type-Options", "nosniff");
resp.setStatus(HttpServletResponse.SC_OK);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
logger.info(request.getRequestURI());
if (!request.getRequestURL().toString().endsWith("/cds-services")
&& !request.getRequestURL().toString().endsWith("/cds-services/")) {
logger.error(request.getRequestURI());
throw new ServletException("This servlet is not configured to handle GET requests.");
}
//ErrorHandling.setAccessControlHeaders(response, myAppProperties);
response.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType());
response.getWriter().println(new GsonBuilder().setPrettyPrinting().create().toJson(getServices()));
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
if (request.getContentType() == null || !request.getContentType().startsWith("application/json")) {
throw new ServletException(String.format("Invalid content type %s. Please use application/json.",
request.getContentType()));
}
logger.info(request.getRequestURI());
String service = request.getPathInfo().replace("/", "");
ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
String requestJson = request.getReader().lines().collect(Collectors.joining());
CdsServiceRequestJson cdsHooksRequest = mapper.readValue(requestJson, CdsServiceRequestJson.class);
logRequestInfo(cdsHooksRequest, requestJson);
CdsServiceResponseJson serviceResponseJson = cdsServiceRegistry.callService(service, cdsHooksRequest);
// Using GSON pretty print format as Jackson's is ugly
String jsonResponse = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create()
.toJson(JsonParser.parseString(mapper.writeValueAsString(serviceResponseJson)));
logger.info(jsonResponse);
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);
logger.error(e.toString());
} catch (Exception e) {
logger.error(e.toString());
throw new ServletException("ERROR: Exception in cds-hooks processing.", e);
}
}
private void logRequestInfo(CdsServiceRequestJson request, String jsonRequest) {
logger.info(jsonRequest);
logger.info("cds-hooks hook instance: {}", request.getHookInstance());
// logger.info("cds-hooks maxCodesPerQuery: {}", this.getProviderConfiguration().getMaxCodesPerQuery());
// logger.info("cds-hooks expandValueSets: {}", this.getProviderConfiguration().getExpandValueSets());
// logger.info("cds-hooks queryBatchThreshold: {}", this.getProviderConfiguration().getQueryBatchThreshold());
// logger.info("cds-hooks searchStyle: {}", this.getProviderConfiguration().getSearchStyle());
// logger.info("cds-hooks prefetch maxUriLength: {}", this.getProviderConfiguration().getMaxUriLength());
logger.info("cds-hooks local server address: {}", appProperties.getServer_address());
logger.info("cds-hooks fhir server address: {}", request.getFhirServer());
// logger.info("cds-hooks cql_logging_enabled: {}", this.getProviderConfiguration().getCqlLoggingEnabled());
}
private CdsServicesJson getServices() {
return cdsServiceRegistry.getCdsServicesJson();
}
// public DebugMap getDebugMap() {
// DebugMap debugMap = new DebugMap();
// if (cqlProperties.getCqlRuntimeOptions().isDebugLoggingEnabled()) {
// // getOptions().getCqlEngineOptions().isDebugLoggingEnabled()) {
// debugMap.setIsLoggingEnabled(true);
// }
// return debugMap;
// }
}

View File

@@ -0,0 +1,49 @@
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;
@Configuration
@Import(CdsHooksConfig.class)
public class StarterCdsHooksConfig {
@Bean
public CdsHooksContextBooter cdsHooksContextBooter() {
// ourLog.info("No Spring Context provided. Assuming all CDS Services will be registered dynamically.");
return new CdsHooksContextBooter();
}
public static class CdsHooksDaoAuthorizationSvc implements ICdsHooksDaoAuthorizationSvc {
@Override
public void authorizePreShow(IBaseResource theResource) {}
}
@Bean
ICdsHooksDaoAuthorizationSvc cdsHooksDaoAuthorizationSvc() {
return new CdsHooksDaoAuthorizationSvc();
}
@Bean
public ServletRegistrationBean<CdsHooksServlet> cdsHooksRegistrationBean(AutowireCapableBeanFactory beanFactory) {
CdsHooksServlet cdsHooksServlet = new CdsHooksServlet();
beanFactory.autowireBean(cdsHooksServlet);
ServletRegistrationBean<CdsHooksServlet> registrationBean = new ServletRegistrationBean<>();
registrationBean.setName("cds-hooks servlet");
registrationBean.setServlet(cdsHooksServlet);
registrationBean.addUrlMappings("/cds-services/*");
registrationBean.setLoadOnStartup(1);
return registrationBean;
}
}