use of org.opencds.cqf.cql.engine.execution.Context in project cqf-ruler by DBCG.
the class CdsHooksServlet method doPost.
@Override
@SuppressWarnings("deprecation")
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
logger.info(request.getRequestURI());
try {
// validate that we are dealing with JSON
if (request.getContentType() == null || !request.getContentType().startsWith("application/json")) {
throw new ServletException(String.format("Invalid content type %s. Please use application/json.", request.getContentType()));
}
String baseUrl = this.myAppProperties.getServer_address();
String service = request.getPathInfo().replace("/", "");
JsonParser parser = new JsonParser();
JsonObject requestJson = parser.parse(request.getReader()).getAsJsonObject();
logger.info(requestJson.toString());
Request cdsHooksRequest = new Request(service, requestJson, JsonHelper.getObjectRequired(getService(service), "prefetch"));
Hook hook = HookFactory.createHook(cdsHooksRequest);
String hookName = hook.getRequest().getHook();
logger.info("cds-hooks hook: {}", hookName);
logger.info("cds-hooks hook instance: {}", hook.getRequest().getHookInstance());
logger.info("cds-hooks maxCodesPerQuery: {}", this.getProviderConfiguration().getMaxCodesPerQuery());
logger.info("cds-hooks expandValueSets: {}", this.getProviderConfiguration().getExpandValueSets());
logger.info("cds-hooks searchStyle: {}", this.getProviderConfiguration().getSearchStyle());
logger.info("cds-hooks prefetch maxUriLength: {}", this.getProviderConfiguration().getMaxUriLength());
logger.info("cds-hooks local server address: {}", baseUrl);
logger.info("cds-hooks fhir server address: {}", hook.getRequest().getFhirServerUrl());
logger.info("cds-hooks cql_logging_enabled: {}", this.getProviderConfiguration().getCqlLoggingEnabled());
PlanDefinition planDefinition = read(Ids.newId(PlanDefinition.class, hook.getRequest().getServiceName()));
AtomicBoolean planDefinitionHookMatchesRequestHook = new AtomicBoolean(false);
planDefinition.getAction().forEach(action -> {
action.getTriggerDefinition().forEach(triggerDefn -> {
if (hookName.equals(triggerDefn.getEventName())) {
planDefinitionHookMatchesRequestHook.set(true);
return;
}
});
if (planDefinitionHookMatchesRequestHook.get()) {
return;
}
});
if (!planDefinitionHookMatchesRequestHook.get()) {
throw new ServletException("ERROR: Request hook does not match the service called.");
}
// No tenant information available, so create local system request
RequestDetails requestDetails = new SystemRequestDetails();
LibraryLoader libraryLoader = libraryLoaderFactory.create(Lists.newArrayList(jpaLibraryContentProviderFactory.create(requestDetails)));
Reference reference = planDefinition.getLibrary().get(0);
Library library = read(reference.getReferenceElement());
org.cqframework.cql.elm.execution.Library elm = libraryLoader.load(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);
// TODO make sure tooling handles remote
context.registerDataProvider("http://hl7.org/fhir", fhirRetrieveProviderFactory.create(requestDetails, serverTerminologyProvider));
context.registerTerminologyProvider(serverTerminologyProvider);
context.registerLibraryLoader(libraryLoader);
context.setContextValue("Patient", hook.getRequest().getContext().getPatientId().replace("Patient/", ""));
context.setExpressionCaching(true);
EvaluationContext<PlanDefinition> evaluationContext = new Stu3EvaluationContext(hook, FhirContext.forCached(FhirVersionEnum.DSTU3).newRestfulGenericClient(baseUrl), context, elm, planDefinition, this.getProviderConfiguration(), this.modelResolver);
this.setAccessControlHeaders(response);
response.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType());
Stu3HookEvaluator evaluator = new Stu3HookEvaluator(this.modelResolver);
String jsonResponse = toJsonResponse(evaluator.evaluate(evaluationContext));
logger.info(jsonResponse);
response.getWriter().println(jsonResponse);
} catch (BaseServerResponseException e) {
this.setAccessControlHeaders(response);
// This will be overwritten with the correct status code downstream if needed.
response.setStatus(500);
response.getWriter().println("ERROR: Exception connecting to remote server.");
this.printMessageAndCause(e, response);
this.handleServerResponseException(e, response);
this.printStackTrack(e, response);
logger.error(e.toString());
} catch (DataProviderException e) {
this.setAccessControlHeaders(response);
// This will be overwritten with the correct status code downstream if needed.
response.setStatus(500);
response.getWriter().println("ERROR: Exception in DataProvider.");
this.printMessageAndCause(e, response);
if (e.getCause() != null && (e.getCause() instanceof BaseServerResponseException)) {
this.handleServerResponseException((BaseServerResponseException) e.getCause(), response);
}
this.printStackTrack(e, response);
logger.error(e.toString());
} catch (CqlException e) {
this.setAccessControlHeaders(response);
// This will be overwritten with the correct status code downstream if needed.
response.setStatus(500);
response.getWriter().println("ERROR: Exception in CQL Execution.");
this.printMessageAndCause(e, response);
if (e.getCause() != null && (e.getCause() instanceof BaseServerResponseException)) {
this.handleServerResponseException((BaseServerResponseException) e.getCause(), response);
}
this.printStackTrack(e, response);
logger.error(e.toString());
} catch (Exception e) {
logger.error(e.toString());
throw new ServletException("ERROR: Exception in cds-hooks processing.", e);
}
}
use of org.opencds.cqf.cql.engine.execution.Context in project cqf-ruler by DBCG.
the class CdsHooksServlet method doPost.
@Override
@SuppressWarnings("deprecation")
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
logger.info(request.getRequestURI());
try {
// validate that we are dealing with JSON
if (request.getContentType() == null || !request.getContentType().startsWith("application/json")) {
throw new ServletException(String.format("Invalid content type %s. Please use application/json.", request.getContentType()));
}
String baseUrl = this.myAppProperties.getServer_address();
String service = request.getPathInfo().replace("/", "");
JsonParser parser = new JsonParser();
Request cdsHooksRequest = new Request(service, parser.parse(request.getReader()).getAsJsonObject(), JsonHelper.getObjectRequired(getService(service), "prefetch"));
logger.info(cdsHooksRequest.getRequestJson().toString());
Hook hook = HookFactory.createHook(cdsHooksRequest);
String hookName = hook.getRequest().getHook();
logger.info("cds-hooks hook: {}", hookName);
logger.info("cds-hooks hook instance: {}", hook.getRequest().getHookInstance());
logger.info("cds-hooks maxCodesPerQuery: {}", this.getProviderConfiguration().getMaxCodesPerQuery());
logger.info("cds-hooks expandValueSets: {}", this.getProviderConfiguration().getExpandValueSets());
logger.info("cds-hooks searchStyle: {}", this.getProviderConfiguration().getSearchStyle());
logger.info("cds-hooks prefetch maxUriLength: {}", this.getProviderConfiguration().getMaxUriLength());
logger.info("cds-hooks local server address: {}", baseUrl);
logger.info("cds-hooks fhir server address: {}", hook.getRequest().getFhirServerUrl());
logger.info("cds-hooks cql_logging_enabled: {}", this.getProviderConfiguration().getCqlLoggingEnabled());
PlanDefinition planDefinition = read(Ids.newId(PlanDefinition.class, hook.getRequest().getServiceName()));
AtomicBoolean planDefinitionHookMatchesRequestHook = new AtomicBoolean(false);
planDefinition.getAction().forEach(action -> {
action.getTrigger().forEach(trigger -> {
if (hookName.equals(trigger.getName())) {
planDefinitionHookMatchesRequestHook.set(true);
return;
}
});
if (planDefinitionHookMatchesRequestHook.get()) {
return;
}
});
if (!planDefinitionHookMatchesRequestHook.get()) {
throw new ServletException("ERROR: Request hook does not match the service called.");
}
// No tenant information available, so create local system request
RequestDetails requestDetails = new SystemRequestDetails();
LibraryLoader libraryLoader = libraryLoaderFactory.create(Lists.newArrayList(jpaLibraryContentProviderFactory.create(requestDetails)));
CanonicalType canonical = planDefinition.getLibrary().get(0);
Library library = search(Library.class, Searches.byCanonical(canonical)).single();
org.cqframework.cql.elm.execution.Library elm = libraryLoader.load(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", // TODO make sure tooling
fhirRetrieveProviderFactory.create(requestDetails, serverTerminologyProvider));
// handles remote
context.registerTerminologyProvider(serverTerminologyProvider);
context.registerLibraryLoader(libraryLoader);
context.setContextValue("Patient", hook.getRequest().getContext().getPatientId().replace("Patient/", ""));
context.setExpressionCaching(true);
EvaluationContext<PlanDefinition> evaluationContext = new R4EvaluationContext(hook, FhirContext.forCached(FhirVersionEnum.R4).newRestfulGenericClient(baseUrl), context, elm, 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);
// This will be overwritten with the correct status code downstream if needed.
response.setStatus(500);
response.getWriter().println("ERROR: Exception connecting to remote server.");
this.printMessageAndCause(e, response);
this.handleServerResponseException(e, response);
this.printStackTrack(e, response);
logger.error(e.toString());
} catch (DataProviderException e) {
this.setAccessControlHeaders(response);
// This will be overwritten with the correct status code downstream if needed.
response.setStatus(500);
response.getWriter().println("ERROR: Exception in DataProvider.");
this.printMessageAndCause(e, response);
if (e.getCause() != null && (e.getCause() instanceof BaseServerResponseException)) {
this.handleServerResponseException((BaseServerResponseException) e.getCause(), response);
}
this.printStackTrack(e, response);
logger.error(e.toString());
} catch (CqlException e) {
this.setAccessControlHeaders(response);
// This will be overwritten with the correct status code downstream if needed.
response.setStatus(500);
response.getWriter().println("ERROR: Exception in CQL Execution.");
this.printMessageAndCause(e, response);
if (e.getCause() != null && (e.getCause() instanceof BaseServerResponseException)) {
this.handleServerResponseException((BaseServerResponseException) e.getCause(), response);
}
this.printStackTrack(e, response);
logger.error(e.toString());
} catch (Exception e) {
logger.error(e.toString());
throw new ServletException("ERROR: Exception in cds-hooks processing.", e);
}
}
use of org.opencds.cqf.cql.engine.execution.Context in project quality-measure-and-cohort-service by Alvearie.
the class ShortCircuitEvaluatorTest method testShortCircuitOr.
@Test
public void testShortCircuitOr() {
Context context = new Context(library);
verifyOr(context, "TrueOrTrue", true, true);
verifyOr(context, "TrueOrFalse", true, true);
verifyOr(context, "TrueOrNull", true, true);
verifyOr(context, "FalseOrTrue", true, false);
verifyOr(context, "FalseOrFalse", false, false);
verifyOr(context, "FalseOrNull", null, false);
verifyOr(context, "NullOrTrue", true, false);
verifyOr(context, "NullOrFalse", null, false);
verifyOr(context, "NullOrNull", null, false);
}
use of org.opencds.cqf.cql.engine.execution.Context in project quality-measure-and-cohort-service by Alvearie.
the class CqlEvaluator method evaluate.
public CqlEvaluationResult evaluate(CqlVersionedIdentifier topLevelLibraryIdentifier, Map<String, Parameter> parameters, Pair<String, String> context, Set<String> expressions, CqlDebug debug, ZonedDateTime batchDateTime) throws CqlLibraryDeserializationException {
if (this.libraryProvider == null) {
throw new IllegalArgumentException("Missing libraryProvider");
} else if (this.dataProvider == null) {
throw new IllegalArgumentException("Missing dataProvider");
} else if (this.terminologyProvider == null) {
throw new IllegalArgumentException("Missing terminologyProvider");
} else if (topLevelLibraryIdentifier == null) {
throw new IllegalArgumentException("Missing library identifier");
}
CqlContextFactory contextFactory = new CqlContextFactory();
contextFactory.setExternalFunctionProvider(this.externalFunctionProvider);
contextFactory.setCacheContexts(cacheContexts);
Context cqlContext = contextFactory.createContext(libraryProvider, topLevelLibraryIdentifier, terminologyProvider, dataProvider, batchDateTime, context, parameters, debug);
if (expressions == null) {
expressions = cqlContext.getCurrentLibrary().getStatements().getDef().stream().map(ExpressionDef::getName).collect(Collectors.toCollection(LinkedHashSet::new));
}
Map<String, Object> results = new LinkedHashMap<>();
for (String expression : expressions) {
ExpressionDef expressionDef = cqlContext.resolveExpressionRef(expression);
// also explicitly skips over FunctionDefs.
if (!(expressionDef instanceof FunctionDef)) {
Object result = cqlContext.resolveExpressionRef(expression).evaluate(cqlContext);
results.put(expression, result);
}
}
if (context != null) {
cqlContext.setContextValue(context.getLeft(), context.getRight());
}
return new CqlEvaluationResult(results);
}
use of org.opencds.cqf.cql.engine.execution.Context in project quality-measure-and-cohort-service by Alvearie.
the class CqlContextFactory method createContext.
/**
* Initialize a CQL Engine Context object with the provided settings.
*
* @param libraryProvider Provider for CQL library resources
* @param topLevelLibraryIdentifier Identifier for the top level library
* @param terminologyProvider Provider for CQL terminology resources
* @param dataProvider Provider for data that underlies the evaluation
* @param evaluationDateTime Date and time that will be considered "now" during
* CQL evaluation. If null, then ZonedDateTime.now()
* will be used each time a context object is
* initialized.
* @param contextData Name-Value pair of context name + context value
* corresponding to the unique ID of an individual
* context that is being evaluated. In a Patient
* context, this would be the Patient ID, etc.
* @param parameters Optional input parameters for the CQL evaluation
* @param debug Debug configuration.
* @return initialized Context object
* @throws CqlLibraryDeserializationException if the specified library cannot be
* loaded
*/
public Context createContext(CqlLibraryProvider libraryProvider, CqlVersionedIdentifier topLevelLibraryIdentifier, CqlTerminologyProvider terminologyProvider, CqlDataProvider dataProvider, ZonedDateTime evaluationDateTime, Pair<String, String> contextData, Map<String, Parameter> parameters, CqlDebug debug) throws CqlLibraryDeserializationException {
ContextCacheKey key = new ContextCacheKey(libraryProvider, topLevelLibraryIdentifier, terminologyProvider, this.externalFunctionProvider, evaluationDateTime, parameters);
Context cqlContext;
if (cacheContexts) {
cqlContext = CONTEXT_CACHE.computeIfAbsent(key, this::createContext);
} else {
cqlContext = createContext(key);
}
// The following data elements need to be reset on every evaluation...
Set<String> uris = getModelUrisForLibrary(cqlContext.getCurrentLibrary());
for (String modelUri : uris) {
cqlContext.registerDataProvider(modelUri, dataProvider);
}
resetContextValues(cqlContext);
cqlContext.clearExpressions();
if (contextData != null) {
cqlContext.setContextValue(contextData.getKey(), contextData.getValue());
}
DebugMap debugMap = createDebugMap(debug);
cqlContext.setDebugMap(debugMap);
cqlContext.setExpressionCaching(this.cacheExpressions);
cqlContext.clearEvaluatedResources();
return cqlContext;
}
Aggregations