Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added cds hooks tests for requests with and without prefetch data #572

Merged
merged 2 commits into from
Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package org.opencds.cqf.ruler.cdshooks.evaluation;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import org.opencds.cqf.cql.engine.fhir.retrieve.Dstu3FhirQueryGenerator;
import org.opencds.cqf.cql.engine.fhir.retrieve.R4FhirQueryGenerator;
import org.opencds.cqf.cql.engine.retrieve.TerminologyAwareRetrieveProvider;
import org.opencds.cqf.cql.evaluator.engine.retrieve.PriorityRetrieveProvider;
import org.opencds.cqf.ruler.cdshooks.hooks.Hook;
import org.opencds.cqf.ruler.cdshooks.providers.PrefetchDataProviderDstu2;
import org.opencds.cqf.ruler.cdshooks.providers.PrefetchDataProviderR4;
import org.opencds.cqf.ruler.cdshooks.providers.PrefetchDataProviderStu3;
import org.opencds.cqf.ruler.cdshooks.providers.ProviderConfiguration;
import org.opencds.cqf.ruler.cdshooks.exceptions.NotImplementedException;

Expand All @@ -15,9 +22,6 @@
import org.opencds.cqf.cql.engine.model.ModelResolver;
import org.opencds.cqf.cql.engine.fhir.retrieve.RestFhirRetrieveProvider;
import org.opencds.cqf.cql.engine.fhir.searchparam.SearchParameterResolver;
import org.opencds.cqf.cql.engine.terminology.TerminologyProvider;
import org.opencds.cqf.cql.engine.fhir.terminology.Dstu3FhirTerminologyProvider;
import org.opencds.cqf.cql.engine.fhir.terminology.R4FhirTerminologyProvider;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
Expand All @@ -28,45 +32,37 @@
public abstract class EvaluationContext<T extends IBaseResource> {

// Provided
private Hook hook;
private FhirVersionEnum fhirVersion;
private FhirContext fhirContext;
private final Hook hook;
private final FhirVersionEnum fhirVersion;
private final FhirContext fhirContext;
private DataProvider systemProvider;
private Context context;
private T planDefinition;
private Library library;
private final Context context;
private final T planDefinition;
private final Library library;
private final IGenericClient client;
private final ProviderConfiguration providerConfiguration;
private final ModelResolver modelResolver;

// Requires resolution
private DataProvider remoteProvider;
private List<Object> contextResources;
private List<Object> prefetchResources;

private IGenericClient client;

private ProviderConfiguration providerConfiguration;

private ModelResolver modelResolver;

public EvaluationContext(Hook hook, FhirVersionEnum fhirVersion, IGenericClient fhirClient, Context context,
Library library, T planDefinition, ProviderConfiguration providerConfiguration, ModelResolver modelResolver) {

// How to determine if it's a local server?
// Local Server url?
// Need a DataRetriever for that.
// Otherwise, it's a remote data retriver.

this.hook = hook;
this.fhirVersion = fhirVersion;
this.fhirContext = FhirContext.forCached(fhirVersion);
this.context = context;
this.planDefinition = planDefinition;
this.library = library;

this.client = fhirClient;

this.providerConfiguration = providerConfiguration;
this.modelResolver = modelResolver;

context.registerDataProvider("http://hl7.org/fhir", getDataProvider());
}

Expand Down Expand Up @@ -102,33 +98,39 @@ public Library getLibrary() {

private DataProvider getDataProvider() {
if (remoteProvider == null) {
ModelResolver resolver = modelResolver;
TerminologyProvider terminologyProvider;
SearchParameterResolver srp = new SearchParameterResolver(fhirContext);
RestFhirRetrieveProvider remoteRetriever = new RestFhirRetrieveProvider(srp, modelResolver,
getHookFhirClient());
remoteRetriever.setTerminologyProvider(context.resolveTerminologyProvider());
remoteRetriever.setExpandValueSets(providerConfiguration.getExpandValueSets());
remoteRetriever.setMaxCodesPerQuery(providerConfiguration.getMaxCodesPerQuery());
remoteRetriever.setSearchStyle(providerConfiguration.getSearchStyle());
remoteRetriever.setModelResolver(modelResolver);
TerminologyAwareRetrieveProvider prefetchRetriever;
switch (fhirVersion) {
case DSTU2:
terminologyProvider = new Dstu3FhirTerminologyProvider(this.getSystemFhirClient());
// TODO: We need a dstu2 version remote data and terminology providers
prefetchRetriever = new PrefetchDataProviderDstu2(getPrefetchResources(), modelResolver);
break;
case DSTU3:
terminologyProvider = new Dstu3FhirTerminologyProvider(this.getSystemFhirClient());
prefetchRetriever = new PrefetchDataProviderStu3(getPrefetchResources(), modelResolver);
remoteRetriever.setFhirQueryGenerator(
new Dstu3FhirQueryGenerator(srp, context.resolveTerminologyProvider(), modelResolver));
break;
case R4:
terminologyProvider = new R4FhirTerminologyProvider(this.getSystemFhirClient());
prefetchRetriever = new PrefetchDataProviderR4(getPrefetchResources(), modelResolver);
remoteRetriever.setFhirQueryGenerator(
new R4FhirQueryGenerator(srp, context.resolveTerminologyProvider(), modelResolver));
break;
default:
throw new NotImplementedException(
"This CDS Hooks implementation is not configured for FHIR version: "
+ fhirVersion.getFhirVersionString());
}

RestFhirRetrieveProvider provider = new RestFhirRetrieveProvider(
new SearchParameterResolver(this.fhirContext), this.getHookFhirClient());
provider.setTerminologyProvider(terminologyProvider);

provider.setExpandValueSets(this.providerConfiguration.getExpandValueSets());
provider.setMaxCodesPerQuery(this.providerConfiguration.getMaxCodesPerQuery());
provider.setSearchStyle(this.providerConfiguration.getSearchStyle());

this.remoteProvider = new CompositeDataProvider(resolver, provider);
// TODO: Get the "system" terminology provider.
prefetchRetriever.setTerminologyProvider(context.resolveTerminologyProvider());
PriorityRetrieveProvider priorityRetrieveProvider = new PriorityRetrieveProvider(Arrays.asList(prefetchRetriever, remoteRetriever));
remoteProvider = new CompositeDataProvider(modelResolver, priorityRetrieveProvider);
}
return remoteProvider;
}
Expand All @@ -150,7 +152,7 @@ public List<Object> getContextResources() {
return contextResources;
}

public List<Object> getPrefetchResources() throws IOException {
public List<Object> getPrefetchResources() {
if (prefetchResources == null) {
prefetchResources = EvaluationHelper.resolvePrefetchResources(hook, fhirContext, this.getHookFhirClient(), this.providerConfiguration.getSearchStyle());
if (hook.getRequest().isApplyCql()) {
Expand Down Expand Up @@ -180,11 +182,9 @@ public IGenericClient getHookFhirClient() {
loggingInterceptor.setLogRequestSummary(true);
loggingInterceptor.setLogRequestHeaders(true);
loggingInterceptor.setLogRequestBody(true);

loggingInterceptor.setLogResponseSummary(true);
loggingInterceptor.setLogResponseHeaders(true);
loggingInterceptor.setLogResponseBody(true);

client.registerInterceptor(loggingInterceptor);

return client;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public static List<Object> resolveBundle(List<IBaseResource> bundles, FhirContex
return ret;
}

public static List<Object> resolvePrefetchResources(Hook hook, FhirContext fhirContext, IGenericClient client, SearchStyleEnum searchStyle) throws IOException {
public static List<Object> resolvePrefetchResources(Hook hook, FhirContext fhirContext, IGenericClient client, SearchStyleEnum searchStyle) {
List<Object> prefetchResources = new ArrayList<>();
List<String> prefetchElementsToFetch = new ArrayList<>();
Gson gson = new GsonBuilder().create();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,15 @@
package org.opencds.cqf.ruler.cdshooks.hooks;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import org.cqframework.cql.elm.execution.ListTypeSpecifier;
import org.cqframework.cql.elm.execution.ParameterDef;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.opencds.cqf.cql.engine.data.CompositeDataProvider;
import org.opencds.cqf.cql.engine.execution.Context;
import org.opencds.cqf.cql.engine.fhir.retrieve.Dstu3FhirQueryGenerator;
import org.opencds.cqf.cql.engine.fhir.retrieve.R4FhirQueryGenerator;
import org.opencds.cqf.cql.engine.fhir.retrieve.RestFhirRetrieveProvider;
import org.opencds.cqf.cql.engine.fhir.searchparam.SearchParameterResolver;
import org.opencds.cqf.cql.engine.model.ModelResolver;
import org.opencds.cqf.cql.engine.retrieve.TerminologyAwareRetrieveProvider;
import org.opencds.cqf.cql.evaluator.engine.retrieve.PriorityRetrieveProvider;
import org.opencds.cqf.ruler.cdshooks.evaluation.EvaluationContext;
import org.opencds.cqf.ruler.cdshooks.providers.PrefetchDataProviderDstu2;
import org.opencds.cqf.ruler.cdshooks.providers.PrefetchDataProviderR4;
import org.opencds.cqf.ruler.cdshooks.providers.PrefetchDataProviderStu3;
import org.opencds.cqf.ruler.cdshooks.response.CdsCard;

import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient;


Expand All @@ -34,8 +21,7 @@ protected BaseHookEvaluator(ModelResolver modelResolver) {
this.modelResolver = modelResolver;
}

public List<CdsCard> evaluate(EvaluationContext<P> context) throws IOException {

public List<CdsCard> evaluate(EvaluationContext<P> context) {
// resolve context resources parameter
// TODO - this will need some work for libraries with multiple parameters
if (context.getLibrary().getParameters() != null && !(context.getHook() instanceof PatientViewHook)) {
Expand All @@ -45,40 +31,6 @@ public List<CdsCard> evaluate(EvaluationContext<P> context) throws IOException {
}
}
}

SearchParameterResolver srp = new SearchParameterResolver(context.getFhirContext());
RestFhirRetrieveProvider remoteRetriever = new RestFhirRetrieveProvider(srp, modelResolver,
context.getHookFhirClient());

remoteRetriever.setTerminologyProvider(context.getContext().resolveTerminologyProvider());
remoteRetriever.setExpandValueSets(context.getProviderConfiguration().getExpandValueSets());
remoteRetriever.setMaxCodesPerQuery(context.getProviderConfiguration().getMaxCodesPerQuery());
remoteRetriever.setSearchStyle(context.getProviderConfiguration().getSearchStyle());
remoteRetriever.setModelResolver(modelResolver);

TerminologyAwareRetrieveProvider prefetchRetriever;
if (context.getFhirVersion() == FhirVersionEnum.DSTU3) {
prefetchRetriever = new PrefetchDataProviderStu3(context.getPrefetchResources(), modelResolver);
remoteRetriever.setFhirQueryGenerator(
new Dstu3FhirQueryGenerator(srp, context.getContext().resolveTerminologyProvider(), modelResolver));
} else if (context.getFhirVersion() == FhirVersionEnum.DSTU2) {
prefetchRetriever = new PrefetchDataProviderDstu2(context.getPrefetchResources(), modelResolver);
// TODO: We need a dstu2 version
}
else {
prefetchRetriever = new PrefetchDataProviderR4(context.getPrefetchResources(), modelResolver);
remoteRetriever.setFhirQueryGenerator(
new R4FhirQueryGenerator(srp, context.getContext().resolveTerminologyProvider(), modelResolver));
}

// TODO: Get the "system" terminology provider.
prefetchRetriever.setTerminologyProvider(context.getContext().resolveTerminologyProvider());

PriorityRetrieveProvider priorityRetrieveProvider = new PriorityRetrieveProvider(Arrays.asList(prefetchRetriever, remoteRetriever));
context.getContext().registerDataProvider("http://hl7.org/fhir",
new CompositeDataProvider(this.modelResolver, priorityRetrieveProvider));
context.getContext().registerTerminologyProvider(prefetchRetriever.getTerminologyProvider());

return evaluateCdsHooksPlanDefinition(context.getContext(), context.getPlanDefinition(),
context.getHook().getRequest().getContext().getPatientId(), context.getSystemFhirClient());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,31 +71,22 @@ public class CdsHooksServlet extends HttpServlet implements DaoRegistryUser {

@Autowired
private CqlProperties cqlProperties;

@Autowired
private DaoRegistry daoRegistry;

@Autowired
private AppProperties myAppProperties;

@Autowired
private LibraryLoaderFactory libraryLoaderFactory;

@Autowired
private JpaLibraryContentProviderFactory jpaLibraryContentProviderFactory;

@Autowired
private ProviderConfiguration providerConfiguration;

@Autowired
private JpaDataProviderFactory fhirRetrieveProviderFactory;

@Autowired
JpaTerminologyProviderFactory myJpaTerminologyProviderFactory;

@Autowired
private ModelResolver modelResolver;

@Autowired
CdsServicesCache cdsServicesCache;

Expand Down Expand Up @@ -196,17 +187,11 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion()));

Context context = new Context(elm);

context.setDebugMap(this.getDebugMap());

// provider case
// No tenant information available for cds-hooks
TerminologyProvider serverTerminologyProvider = myJpaTerminologyProviderFactory.create(requestDetails);

context.registerDataProvider("http://hl7.org/fhir",
fhirRetrieveProviderFactory.create(requestDetails, serverTerminologyProvider)); // TODO make sure tooling
// handles remote

context.registerTerminologyProvider(serverTerminologyProvider);
context.registerLibraryLoader(libraryLoader);
context.setContextValue("Patient", hook.getRequest().getContext().getPatientId().replace("Patient/", ""));
Expand All @@ -218,15 +203,10 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
planDefinition, this.getProviderConfiguration(), this.modelResolver);

this.setAccessControlHeaders(response);

response.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType());

R4HookEvaluator evaluator = new R4HookEvaluator(this.modelResolver);

String jsonResponse = toJsonResponse(evaluator.evaluate(evaluationContext));

logger.info(jsonResponse);

response.getWriter().println(jsonResponse);
} catch (BaseServerResponseException e) {
this.setAccessControlHeaders(response);
Expand Down
Loading