From 1bb6e9e6104b98192faf88e7e4ea9acce9c90dc1 Mon Sep 17 00:00:00 2001 From: Justin McKelvy <60718638+Capt-Mac@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:53:32 -0600 Subject: [PATCH] updating to latest hapi, fixing cr tests --- pom.xml | 2 +- .../uhn/fhir/jpa/starter/AppProperties.java | 59 +---- .../cr/CrOperationProviderFactory.java | 103 -------- .../starter/cr/CrOperationProviderLoader.java | 54 ---- .../cr/PostInitProviderRegisterer.java | 51 ---- .../jpa/starter/cr/StarterCrDstu3Config.java | 211 ++++++++-------- .../jpa/starter/cr/StarterCrR4Config.java | 239 +++++++++--------- .../fhir/jpa/starter/ExampleServerR4IT.java | 30 ++- 8 files changed, 249 insertions(+), 500 deletions(-) delete mode 100644 src/main/java/ca/uhn/fhir/jpa/starter/cr/CrOperationProviderFactory.java delete mode 100644 src/main/java/ca/uhn/fhir/jpa/starter/cr/CrOperationProviderLoader.java delete mode 100644 src/main/java/ca/uhn/fhir/jpa/starter/cr/PostInitProviderRegisterer.java diff --git a/pom.xml b/pom.xml index ce13948..e38c38c 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.14-SNAPSHOT + 6.9.6-SNAPSHOT hapi-fhir-jpaserver-starter diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java b/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java index 1880b0e..22696a9 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java @@ -6,14 +6,12 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import ca.uhn.fhir.cr.config.CrProperties; + import org.cqframework.cql.cql2elm.CqlCompilerException; import org.cqframework.cql.cql2elm.CqlTranslator; import org.cqframework.cql.cql2elm.CqlTranslatorOptions; import org.cqframework.cql.cql2elm.LibraryBuilder; import org.hl7.fhir.r4.model.Bundle; -import org.opencds.cqf.cql.evaluator.CqlOptions; -import org.opencds.cqf.cql.evaluator.engine.CqlEngineOptions; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @@ -30,7 +28,6 @@ import ca.uhn.fhir.rest.api.EncodingEnum; @EnableConfigurationProperties public class AppProperties { //cql settings - private CqlEngineOptions cqlEngineOptions = CqlEngineOptions.defaultOptions(); private Boolean cql_use_embedded_libraries = true; private Boolean cql_runtime_debug_logging_enabled = false; private Boolean cql_runtime_enable_validation = false; @@ -385,50 +382,6 @@ public class AppProperties { this.cql_compiler_translator_format = cqlTranslatorFormat; } - private CqlTranslatorOptions cqlTranslatorOptions = new CqlTranslatorOptions( - getCqlTranslatorFormat(), - cql_compiler_enable_date_range_optimization, - cql_compiler_enable_annotations, - cql_compiler_enable_locators, - cql_compiler_enable_results_type, - isCqlCompilerVerifyOnly(), - cql_compiler_enable_detailed_errors, - getCqlCompilerErrorSeverityLevel(), - cql_compiler_disable_list_traversal, - cql_compiler_disable_list_demotion, - cql_compiler_disable_list_promotion, - cql_compiler_enable_interval_demotion, - cql_compiler_enable_interval_promotion, - cql_compiler_disable_method_invocation, - cql_compiler_require_from_keyword, - isCqlCompilerValidateUnits(), - cql_compiler_disable_default_model_info_load, - getCqlCompilerSignatureLevel(), - getCqlCompilerCompatibilityLevel()); - - public CqlTranslatorOptions getCqlTranslatorOptions() { - return this.cqlTranslatorOptions; - } - - public void setCqlTranslator(CqlTranslatorOptions translator) { - this.cqlTranslatorOptions = translator; - } - - public CqlEngineOptions getCqlEngineOptions() { - return this.cqlEngineOptions; - } - - public void setCqlEngineOptions(CqlEngineOptions engine) { - this.cqlEngineOptions = engine; - } - - public CqlOptions getCqlOptions() { - CqlOptions cqlOptions = new CqlOptions(); - cqlOptions.setUseEmbeddedLibraries(this.cql_use_embedded_libraries); - cqlOptions.setCqlEngineOptions(this.getCqlEngineOptions()); - cqlOptions.setCqlTranslatorOptions(this.getCqlTranslatorOptions()); - return cqlOptions; - } public Boolean getCr_enabled() { return cr_enabled; @@ -448,16 +401,6 @@ public class AppProperties { public void setCareGapsReporter(String theCareGapsReporter) { this.caregaps_reporter = theCareGapsReporter; } - public CrProperties.MeasureProperties getMeasureProperties(){ - var measureProperties = new CrProperties.MeasureProperties(); - var measureReportConfiguration = new CrProperties.MeasureProperties.MeasureReportConfiguration(); - measureReportConfiguration.setCareGapsReporter(this.getCareGapsReporter()); - measureReportConfiguration.setCareGapsCompositionSectionAuthor(this.getCareGapsSectionAuthor()); - - measureProperties.setMeasureReportConfiguration(measureReportConfiguration); - - return measureProperties; - } public Boolean getIps_enabled() { return ips_enabled; } diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cr/CrOperationProviderFactory.java b/src/main/java/ca/uhn/fhir/jpa/starter/cr/CrOperationProviderFactory.java deleted file mode 100644 index 4b75fe2..0000000 --- a/src/main/java/ca/uhn/fhir/jpa/starter/cr/CrOperationProviderFactory.java +++ /dev/null @@ -1,103 +0,0 @@ -package ca.uhn.fhir.jpa.starter.cr; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; - -import ca.uhn.fhir.context.ConfigurationException; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.cr.r4.measure.CareGapsOperationProvider; -import ca.uhn.fhir.cr.r4.measure.SubmitDataProvider; -import ca.uhn.fhir.cr.dstu3.activitydefinition.ActivityDefinitionOperationsProvider; -import ca.uhn.fhir.cr.dstu3.measure.MeasureOperationsProvider; -import ca.uhn.fhir.cr.dstu3.plandefinition.PlanDefinitionOperationsProvider; -import ca.uhn.fhir.cr.dstu3.questionnaire.QuestionnaireOperationsProvider; -import ca.uhn.fhir.cr.dstu3.questionnaireresponse.QuestionnaireResponseOperationsProvider; - -public class CrOperationProviderFactory { - @Autowired - private FhirContext myFhirContext; - - @Autowired - private ApplicationContext myApplicationContext; - - public Object getMeasureOperationsProvider() { - switch (myFhirContext.getVersion().getVersion()) { - case DSTU3: - return myApplicationContext.getBean(MeasureOperationsProvider.class); - case R4: - return myApplicationContext.getBean(ca.uhn.fhir.cr.r4.measure.MeasureOperationsProvider.class); - default: - throw new ConfigurationException("Measure operations are not supported for FHIR version " - + myFhirContext.getVersion().getVersion()); - } - } - - public Object getActivityDefinitionProvider() { - switch (myFhirContext.getVersion().getVersion()) { - case DSTU3: - return myApplicationContext.getBean(ActivityDefinitionOperationsProvider.class); - case R4: - return myApplicationContext - .getBean(ca.uhn.fhir.cr.r4.activitydefinition.ActivityDefinitionOperationsProvider.class); - default: - throw new ConfigurationException("ActivityDefinition operations are not supported for FHIR version " - + myFhirContext.getVersion().getVersion()); - } - } - - public Object getPlanDefinitionProvider() { - switch (myFhirContext.getVersion().getVersion()) { - case DSTU3: - return myApplicationContext.getBean(PlanDefinitionOperationsProvider.class); - case R4: - return myApplicationContext - .getBean(ca.uhn.fhir.cr.r4.plandefinition.PlanDefinitionOperationsProvider.class); - default: - throw new ConfigurationException("PlanDefinition operations are not supported for FHIR version " - + myFhirContext.getVersion().getVersion()); - } - } - - public Object getCareGapsProvider() { - switch (myFhirContext.getVersion().getVersion()) { - case R4: - return myApplicationContext.getBean(CareGapsOperationProvider.class); - default: - throw new ConfigurationException("PlanDefinition operations are not supported for FHIR version " - + myFhirContext.getVersion().getVersion()); - } - } - public Object getSubmitDataProvider() { - switch (myFhirContext.getVersion().getVersion()) { - case R4: - return myApplicationContext.getBean(SubmitDataProvider.class); - default: - throw new ConfigurationException("PlanDefinition operations are not supported for FHIR version " - + myFhirContext.getVersion().getVersion()); - } - } - public Object getQuestionnaireResponseOperationProvider() { - switch (myFhirContext.getVersion().getVersion()) { - case DSTU3: - return myApplicationContext.getBean(QuestionnaireResponseOperationsProvider.class); - case R4: - return myApplicationContext - .getBean(ca.uhn.fhir.cr.r4.questionnaireresponse.QuestionnaireResponseOperationsProvider.class); - default: - throw new ConfigurationException("PlanDefinition operations are not supported for FHIR version " - + myFhirContext.getVersion().getVersion()); - } - } - public Object getQuestionnaireOperationProvider() { - switch (myFhirContext.getVersion().getVersion()) { - case DSTU3: - return myApplicationContext.getBean(QuestionnaireOperationsProvider.class); - case R4: - return myApplicationContext - .getBean(ca.uhn.fhir.cr.r4.questionnaire.QuestionnaireOperationsProvider.class); - default: - throw new ConfigurationException("PlanDefinition operations are not supported for FHIR version " - + myFhirContext.getVersion().getVersion()); - } - } -} \ No newline at end of file diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cr/CrOperationProviderLoader.java b/src/main/java/ca/uhn/fhir/jpa/starter/cr/CrOperationProviderLoader.java deleted file mode 100644 index 4cc568d..0000000 --- a/src/main/java/ca/uhn/fhir/jpa/starter/cr/CrOperationProviderLoader.java +++ /dev/null @@ -1,54 +0,0 @@ -package ca.uhn.fhir.jpa.starter.cr; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.context.event.EventListener; - -import ca.uhn.fhir.context.ConfigurationException; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; - -public class CrOperationProviderLoader { - private static final Logger myLogger = LoggerFactory.getLogger(CrOperationProviderLoader.class); - private final FhirContext myFhirContext; - private final ResourceProviderFactory myResourceProviderFactory; - private final CrOperationProviderFactory myCrProviderFactory; - - private final PostInitProviderRegisterer myPostInitProviderRegister; - - public CrOperationProviderLoader(FhirContext theFhirContext, ResourceProviderFactory theResourceProviderFactory, - CrOperationProviderFactory theCrProviderFactory, PostInitProviderRegisterer thePostInitProviderRegister) { - myFhirContext = theFhirContext; - myResourceProviderFactory = theResourceProviderFactory; - myCrProviderFactory = theCrProviderFactory; - myPostInitProviderRegister = thePostInitProviderRegister; - loadProvider(); - } - - public void loadProvider() { - switch (myFhirContext.getVersion().getVersion()) { - case DSTU3: - myLogger.info("Registering DSTU3 Clinical Reasoning Providers"); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getMeasureOperationsProvider); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getActivityDefinitionProvider); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getPlanDefinitionProvider); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getQuestionnaireResponseOperationProvider); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getQuestionnaireOperationProvider); - break; - case R4: - myLogger.info("Registering R4 Clinical Reasoning Providers"); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getMeasureOperationsProvider); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getActivityDefinitionProvider); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getPlanDefinitionProvider); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getCareGapsProvider); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getSubmitDataProvider); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getQuestionnaireResponseOperationProvider); - myResourceProviderFactory.addSupplier(myCrProviderFactory::getQuestionnaireOperationProvider); - break; - default: - throw new ConfigurationException("Clinical Reasoning not supported for FHIR version " - + myFhirContext.getVersion().getVersion()); - } - } -} diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cr/PostInitProviderRegisterer.java b/src/main/java/ca/uhn/fhir/jpa/starter/cr/PostInitProviderRegisterer.java deleted file mode 100644 index 55e7e8f..0000000 --- a/src/main/java/ca/uhn/fhir/jpa/starter/cr/PostInitProviderRegisterer.java +++ /dev/null @@ -1,51 +0,0 @@ -package ca.uhn.fhir.jpa.starter.cr; - -import java.util.function.Supplier; - -import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.provider.IResourceProviderFactoryObserver; -import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; - -public class PostInitProviderRegisterer { - public PostInitProviderRegisterer(RestfulServer restfulServer, - ResourceProviderFactory resourceProviderFactory) { - resourceProviderFactory.attach(new Observer(restfulServer)); - } - - private class Observer implements IResourceProviderFactoryObserver { - private RestfulServer restfulServer; - - public Observer(RestfulServer restfulServer) { - this.restfulServer = restfulServer; - } - - public void update(Supplier theSupplier) { - if (theSupplier == null) { - return; - } - - var provider = theSupplier.get(); - if (provider == null) { - return; - } - - this.restfulServer.registerProvider(provider); - - } - - public void remove(Supplier theSupplier) { - if (theSupplier == null) { - return; - } - - var provider = theSupplier.get(); - if (provider == null) { - return; - } - - this.restfulServer.unregisterProvider(provider); - } - - } - -} diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrDstu3Config.java b/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrDstu3Config.java index ea3cde3..ce06c9b 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrDstu3Config.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrDstu3Config.java @@ -1,123 +1,126 @@ package ca.uhn.fhir.jpa.starter.cr; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; -import ca.uhn.fhir.cr.config.CrDstu3Config; -import ca.uhn.fhir.cr.config.CrProperties; -import ca.uhn.fhir.cr.dstu3.IActivityDefinitionProcessorFactory; -import ca.uhn.fhir.cr.dstu3.IPlanDefinitionProcessorFactory; -import ca.uhn.fhir.cr.dstu3.IQuestionnaireProcessorFactory; -import ca.uhn.fhir.cr.dstu3.IQuestionnaireResponseProcessorFactory; -import ca.uhn.fhir.cr.dstu3.activitydefinition.ActivityDefinitionOperationsProvider; -import ca.uhn.fhir.cr.dstu3.plandefinition.PlanDefinitionOperationsProvider; -import ca.uhn.fhir.cr.dstu3.questionnaire.QuestionnaireOperationsProvider; -import ca.uhn.fhir.cr.dstu3.questionnaireresponse.QuestionnaireResponseOperationsProvider; +import ca.uhn.fhir.cr.config.dstu3.CrDstu3Config; import ca.uhn.fhir.jpa.starter.AppProperties; import ca.uhn.fhir.jpa.starter.annotations.OnDSTU3Condition; -import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; -import org.cqframework.cql.cql2elm.CqlTranslatorOptions; -import org.opencds.cqf.cql.evaluator.CqlOptions; -import org.opencds.cqf.cql.evaluator.activitydefinition.dstu3.ActivityDefinitionProcessor; -import org.opencds.cqf.cql.evaluator.library.EvaluationSettings; -import org.opencds.cqf.cql.evaluator.plandefinition.dstu3.PlanDefinitionProcessor; -import org.opencds.cqf.cql.evaluator.questionnaire.dstu3.QuestionnaireProcessor; -import org.opencds.cqf.cql.evaluator.questionnaireresponse.dstu3.QuestionnaireResponseProcessor; +import org.cqframework.cql.cql2elm.CqlCompilerOptions; +import org.cqframework.cql.cql2elm.model.CompiledLibrary; +import org.cqframework.cql.cql2elm.model.Model; +import org.hl7.cql.model.ModelIdentifier; +import org.hl7.elm.r1.VersionedIdentifier; +import org.opencds.cqf.cql.engine.execution.CqlEngine; +import org.opencds.cqf.fhir.cql.EvaluationSettings; +import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; +import org.opencds.cqf.fhir.utility.ValidationProfile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.*; +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + @Configuration @Conditional({ OnDSTU3Condition.class, CrConfigCondition.class }) @Import({ CrDstu3Config.class }) public class StarterCrDstu3Config { private static final Logger ourLogger = LoggerFactory.getLogger(StarterCrDstu3Config.class); - @Bean - public PostInitProviderRegisterer postInitProviderRegisterer(RestfulServer theRestfulServer, - ResourceProviderFactory theResourceProviderFactory) { - return new PostInitProviderRegisterer(theRestfulServer, theResourceProviderFactory); - } @Bean - public CrOperationProviderFactory crOperationProviderFactory() { - return new CrOperationProviderFactory(); - } + MeasureEvaluationOptions measureEvaluationOptions(EvaluationSettings theEvaluationSettings, Map theValidationProfiles){ + MeasureEvaluationOptions measureEvalOptions = new MeasureEvaluationOptions(); + measureEvalOptions.setEvaluationSettings(theEvaluationSettings); - @Bean - public CrOperationProviderLoader crOperationProviderLoader(FhirContext theFhirContext, - ResourceProviderFactory theResourceProviderFactory, - CrOperationProviderFactory theCrOperationProviderFactory, - PostInitProviderRegisterer thePostInitProviderRegister) { - return new CrOperationProviderLoader(theFhirContext, theResourceProviderFactory, theCrOperationProviderFactory, - thePostInitProviderRegister); - } - - @Bean - public QuestionnaireOperationsProvider myR4QuestionnaireOperationsProvider() { - return new QuestionnaireOperationsProvider(); - } - - @Bean - public PlanDefinitionOperationsProvider r4PlanDefinitionOperationsProvider() { - return new PlanDefinitionOperationsProvider(); - } - - @Bean - public QuestionnaireResponseOperationsProvider myR4QuestionnaireResponseOperationsProvider() { - return new QuestionnaireResponseOperationsProvider(); - } - - @Bean - public ActivityDefinitionOperationsProvider myR4ActivityDefinitionOperationsProvider() { - return new ActivityDefinitionOperationsProvider(); - } - - @Bean - IActivityDefinitionProcessorFactory myR4ActivityDefinitionProcessorFactory( - EvaluationSettings theEvaluationSettings) { - return r -> new ActivityDefinitionProcessor(r, - theEvaluationSettings); - } - - @Bean - IQuestionnaireResponseProcessorFactory myR4QuestionnaireResponseProcessorFactory() { - return r -> new QuestionnaireResponseProcessor(r); - } - - @Bean - IQuestionnaireProcessorFactory myR4QuestionnaireProcessorFactory() { - return r -> new QuestionnaireProcessor(r); - } - - @Bean - IPlanDefinitionProcessorFactory myR4PlanDefinitionProcessorFactory( - EvaluationSettings theEvaluationSettings) { - return r -> new PlanDefinitionProcessor(r, theEvaluationSettings); - } - @Primary - @Bean - public CqlOptions cqlOptions(AppProperties theAppProperties) { - return theAppProperties.getCqlOptions(); - } - - @Primary - @Bean - public CrProperties.MeasureProperties measureProperties(AppProperties theAppProperties) { - return theAppProperties.getMeasureProperties(); - } - @Primary - @Bean - public CqlTranslatorOptions cqlTranslatorOptions(FhirContext theFhirContext, AppProperties theAppProperties) { - CqlTranslatorOptions options = theAppProperties.getCqlTranslatorOptions(); - - if (theFhirContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.R4) - && (options.getCompatibilityLevel().equals("1.5") || options.getCompatibilityLevel().equals("1.4"))) { - ourLogger.warn("{} {} {}", - "This server is configured to use CQL version > 1.4 and FHIR version <= DSTU3.", - "Most available CQL content for DSTU3 and below is for CQL versions 1.3.", - "If your CQL content causes translation errors, try setting the CQL compatibility level to 1.3"); + if(measureEvalOptions.isValidationEnabled()) { + measureEvalOptions.setValidationProfiles(theValidationProfiles); } - - return options; + return measureEvalOptions; } + + @Bean + public EvaluationSettings evaluationSettings( + AppProperties theAppProperties, + Map theGlobalLibraryCache, + Map theGlobalModelCache) { + var evaluationSettings = EvaluationSettings.getDefault(); + var cqlOptions = evaluationSettings.getCqlOptions(); + + var cqlEngineOptions = cqlOptions.getCqlEngineOptions(); + Set options = EnumSet.noneOf(CqlEngine.Options.class); + if (theAppProperties.isCqlRuntimeEnableExpressionCaching()) { + options.add(CqlEngine.Options.EnableExpressionCaching); + } + if (theAppProperties.isCqlRuntimeEnableValidation()) { + options.add(CqlEngine.Options.EnableValidation); + } + cqlEngineOptions.setOptions(options); + cqlOptions.setCqlEngineOptions(cqlEngineOptions); + + var cqlCompilerOptions = new CqlCompilerOptions(); + + if (theAppProperties.isEnableDateRangeOptimization() + ) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDateRangeOptimization); + } + if (theAppProperties.isEnableAnnotations()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableAnnotations); + } + if (theAppProperties.isEnableLocators()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableLocators); + } + if (theAppProperties.isEnableResultsType()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableResultTypes); + } + cqlCompilerOptions.setVerifyOnly(theAppProperties.isCqlCompilerVerifyOnly()); + if (theAppProperties.isEnableDetailedErrors()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDetailedErrors); + } + cqlCompilerOptions.setErrorLevel(theAppProperties.getCqlCompilerErrorSeverityLevel()); + if (theAppProperties.isDisableListTraversal()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListTraversal); + } + if (theAppProperties.isDisableListDemotion()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListDemotion); + } + if (theAppProperties.isDisableListPromotion()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListPromotion); + } + if (theAppProperties.isEnableIntervalDemotion()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalDemotion); + } + if (theAppProperties.isEnableIntervalPromotion()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalPromotion); + } + if (theAppProperties.isDisableMethodInvocation()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableMethodInvocation); + } + if (theAppProperties.isRequireFromKeyword()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.RequireFromKeyword); + } + cqlCompilerOptions.setValidateUnits(theAppProperties.isCqlCompilerValidateUnits()); + if (theAppProperties.isDisableDefaultModelInfoLoad()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableDefaultModelInfoLoad); + } + cqlCompilerOptions.setSignatureLevel(theAppProperties.getCqlCompilerSignatureLevel()); + cqlCompilerOptions.setCompatibilityLevel(theAppProperties.getCqlCompilerCompatibilityLevel()); + cqlCompilerOptions.setAnalyzeDataRequirements(theAppProperties.isCqlCompilerAnalyzeDataRequirements()); + cqlCompilerOptions.setCollapseDataRequirements(theAppProperties.isCqlCompilerCollapseDataRequirements()); + + cqlOptions.setCqlCompilerOptions(cqlCompilerOptions); + evaluationSettings.setLibraryCache(theGlobalLibraryCache); + evaluationSettings.setModelCache(theGlobalModelCache); + return evaluationSettings; + } + + @Bean + public Map globalLibraryCache() { + return new ConcurrentHashMap<>(); + } + + @Bean + public Map globalModelCache() { + return new ConcurrentHashMap<>(); + } + } diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrR4Config.java b/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrR4Config.java index 9c77e73..190f534 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrR4Config.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrR4Config.java @@ -1,151 +1,148 @@ package ca.uhn.fhir.jpa.starter.cr; -import ca.uhn.fhir.IHapiBootOrder; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; -import ca.uhn.fhir.cr.config.CrProperties; -import ca.uhn.fhir.cr.config.CrR4Config; -import ca.uhn.fhir.cr.r4.IActivityDefinitionProcessorFactory; -import ca.uhn.fhir.cr.r4.IPlanDefinitionProcessorFactory; -import ca.uhn.fhir.cr.r4.IQuestionnaireProcessorFactory; -import ca.uhn.fhir.cr.r4.IQuestionnaireResponseProcessorFactory; -import ca.uhn.fhir.cr.r4.activitydefinition.ActivityDefinitionOperationsProvider; -import ca.uhn.fhir.cr.r4.measure.CareGapsOperationProvider; -import ca.uhn.fhir.cr.r4.measure.CareGapsService; -import ca.uhn.fhir.cr.r4.plandefinition.PlanDefinitionOperationsProvider; -import ca.uhn.fhir.cr.r4.questionnaire.QuestionnaireOperationsProvider; -import ca.uhn.fhir.cr.r4.questionnaireresponse.QuestionnaireResponseOperationsProvider; +import ca.uhn.fhir.cr.common.CqlThreadFactory; +import ca.uhn.fhir.cr.config.ApplyOperationConfig; +import ca.uhn.fhir.cr.config.ExtractOperationConfig; +import ca.uhn.fhir.cr.config.PackageOperationConfig; +import ca.uhn.fhir.cr.config.PopulateOperationConfig; +import ca.uhn.fhir.cr.config.r4.CrR4Config; import ca.uhn.fhir.jpa.starter.AppProperties; import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition; -import ca.uhn.fhir.rest.api.server.RequestDetails; -import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; -import org.apache.commons.lang3.StringUtils; -import org.cqframework.cql.cql2elm.CqlTranslatorOptions; -import org.opencds.cqf.cql.evaluator.CqlOptions; -import org.opencds.cqf.cql.evaluator.activitydefinition.r4.ActivityDefinitionProcessor; -import org.opencds.cqf.cql.evaluator.library.EvaluationSettings; -import org.opencds.cqf.cql.evaluator.plandefinition.r4.PlanDefinitionProcessor; -import org.opencds.cqf.cql.evaluator.questionnaire.r4.QuestionnaireProcessor; -import org.opencds.cqf.cql.evaluator.questionnaireresponse.r4.QuestionnaireResponseProcessor; +import org.cqframework.cql.cql2elm.CqlCompilerOptions; +import org.cqframework.cql.cql2elm.model.CompiledLibrary; +import org.cqframework.cql.cql2elm.model.Model; +import org.hl7.cql.model.ModelIdentifier; +import org.hl7.elm.r1.VersionedIdentifier; +import org.opencds.cqf.cql.engine.execution.CqlEngine; +import org.opencds.cqf.fhir.cql.EvaluationSettings; +import org.opencds.cqf.fhir.cr.measure.CareGapsProperties; +import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; +import org.opencds.cqf.fhir.utility.ValidationProfile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.*; +import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService; +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.function.Function; @Configuration @Conditional({ OnR4Condition.class, CrConfigCondition.class }) -@Import({ CrR4Config.class }) +@Import({ CrR4Config.class, + ApplyOperationConfig.class, + ExtractOperationConfig.class, + PackageOperationConfig.class, + PopulateOperationConfig.class}) public class StarterCrR4Config { private static final Logger ourLogger = LoggerFactory.getLogger(StarterCrR4Config.class); - @Bean - public PostInitProviderRegisterer postInitProviderRegisterer(RestfulServer theRestfulServer, - ResourceProviderFactory theResourceProviderFactory) { - return new PostInitProviderRegisterer(theRestfulServer, theResourceProviderFactory); - } - - @Bean - public CrOperationProviderFactory crOperationProviderFactory() { - return new CrOperationProviderFactory(); - } - - @Bean - public CrOperationProviderLoader crOperationProviderLoader(FhirContext theFhirContext, - ResourceProviderFactory theResourceProviderFactory, - CrOperationProviderFactory theCrOperationProviderFactory, - PostInitProviderRegisterer thePostInitProviderRegister) { - return new CrOperationProviderLoader(theFhirContext, theResourceProviderFactory, theCrOperationProviderFactory, - thePostInitProviderRegister); - } - - @Bean - public QuestionnaireOperationsProvider myR4QuestionnaireOperationsProvider() { - return new QuestionnaireOperationsProvider(); - } - - @Bean - public PlanDefinitionOperationsProvider r4PlanDefinitionOperationsProvider() { - return new PlanDefinitionOperationsProvider(); - } - - @Bean - public QuestionnaireResponseOperationsProvider myR4QuestionnaireResponseOperationsProvider() { - return new QuestionnaireResponseOperationsProvider(); - } - - @Bean - public ActivityDefinitionOperationsProvider myR4ActivityDefinitionOperationsProvider() { - return new ActivityDefinitionOperationsProvider(); - } - - @Bean - IActivityDefinitionProcessorFactory myR4ActivityDefinitionProcessorFactory( - EvaluationSettings theEvaluationSettings) { - return r -> new ActivityDefinitionProcessor(r, - theEvaluationSettings); - } - - @Bean - IQuestionnaireResponseProcessorFactory myR4QuestionnaireResponseProcessorFactory() { - return r -> new QuestionnaireResponseProcessor(r); - } - - @Bean - IQuestionnaireProcessorFactory myR4QuestionnaireProcessorFactory() { - return r -> new QuestionnaireProcessor(r); - } - - @Bean - IPlanDefinitionProcessorFactory myR4PlanDefinitionProcessorFactory( - EvaluationSettings theEvaluationSettings) { - return r -> new PlanDefinitionProcessor(r, theEvaluationSettings); - } @Primary @Bean - public CqlOptions cqlOptions(AppProperties theAppProperties) { - return theAppProperties.getCqlOptions(); + public ExecutorService cqlExecutor() { + CqlThreadFactory factory = new CqlThreadFactory(); + ExecutorService executor = Executors. + newFixedThreadPool(2 + , factory); + executor = new DelegatingSecurityContextExecutorService(executor); + + return executor; + } + @Bean + CareGapsProperties careGapsProperties(AppProperties theAppProperties) { + var careGapsProperties = new CareGapsProperties(); + careGapsProperties.setThreadedCareGapsEnabled(false); + careGapsProperties.setCareGapsReporter(theAppProperties.getCareGapsReporter()); + careGapsProperties.setCareGapsCompositionSectionAuthor(theAppProperties.getCareGapsSectionAuthor()); + return careGapsProperties; } - @Primary @Bean - public CrProperties.MeasureProperties measureProperties(AppProperties theAppProperties) { - return theAppProperties.getMeasureProperties(); - } - - @Primary - @Bean - CareGapsOperationProvider careGapsOperationProvider(Function r4CareGapsServiceFactory, AppProperties theAppProperties) { - if(StringUtils.isBlank(theAppProperties.getCareGapsReporter()) || StringUtils.isBlank(theAppProperties.getCareGapsSectionAuthor())){ - throw new RuntimeException("Configuration failed to register reporter or author properties for running care gaps functionality"); + MeasureEvaluationOptions measureEvaluationOptions(EvaluationSettings theEvaluationSettings, Map theValidationProfiles){ + MeasureEvaluationOptions measureEvalOptions = new MeasureEvaluationOptions(); + measureEvalOptions.setEvaluationSettings(theEvaluationSettings); + if(measureEvalOptions.isValidationEnabled()) { + measureEvalOptions.setValidationProfiles(theValidationProfiles); } - Function careGapsServiceFunction = r4CareGapsServiceFactory.andThen(careGapsService -> { - var measureReportConfiguration = new CrProperties.MeasureProperties.MeasureReportConfiguration(); - measureReportConfiguration.setCareGapsReporter(theAppProperties.getCareGapsReporter()); - measureReportConfiguration.setCareGapsCompositionSectionAuthor(theAppProperties.getCareGapsSectionAuthor()); - careGapsService.getCrProperties().getMeasureProperties().setMeasureReportConfiguration(measureReportConfiguration); - return careGapsService; - }); - CareGapsOperationProvider careGapsOperationProvider = new CareGapsOperationProvider(careGapsServiceFunction); - return careGapsOperationProvider; + return measureEvalOptions; } - - @Primary @Bean - public CqlTranslatorOptions cqlTranslatorOptions(FhirContext theFhirContext, AppProperties theAppProperties) { - CqlTranslatorOptions options = theAppProperties.getCqlTranslatorOptions(); + public EvaluationSettings evaluationSettings( + AppProperties theAppProperties, + Map theGlobalLibraryCache, + Map theGlobalModelCache) { + var evaluationSettings = EvaluationSettings.getDefault(); + var cqlOptions = evaluationSettings.getCqlOptions(); - if (theFhirContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.R4) - && (options.getCompatibilityLevel().equals("1.5") || options.getCompatibilityLevel().equals("1.4"))) { - ourLogger.warn("{} {} {}", - "This server is configured to use CQL version > 1.4 and FHIR version <= DSTU3.", - "Most available CQL content for DSTU3 and below is for CQL versions 1.3.", - "If your CQL content causes translation errors, try setting the CQL compatibility level to 1.3"); + var cqlEngineOptions = cqlOptions.getCqlEngineOptions(); + Set options = EnumSet.noneOf(CqlEngine.Options.class); + if (theAppProperties.isCqlRuntimeEnableExpressionCaching()) { + options.add(CqlEngine.Options.EnableExpressionCaching); } + if (theAppProperties.isCqlRuntimeEnableValidation()) { + options.add(CqlEngine.Options.EnableValidation); + } + cqlEngineOptions.setOptions(options); + cqlOptions.setCqlEngineOptions(cqlEngineOptions); - return options; + var cqlCompilerOptions = new CqlCompilerOptions(); + + if (theAppProperties.isEnableDateRangeOptimization() + ) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDateRangeOptimization); + } + if (theAppProperties.isEnableAnnotations()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableAnnotations); + } + if (theAppProperties.isEnableLocators()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableLocators); + } + if (theAppProperties.isEnableResultsType()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableResultTypes); + } + cqlCompilerOptions.setVerifyOnly(theAppProperties.isCqlCompilerVerifyOnly()); + if (theAppProperties.isEnableDetailedErrors()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDetailedErrors); + } + cqlCompilerOptions.setErrorLevel(theAppProperties.getCqlCompilerErrorSeverityLevel()); + if (theAppProperties.isDisableListTraversal()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListTraversal); + } + if (theAppProperties.isDisableListDemotion()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListDemotion); + } + if (theAppProperties.isDisableListPromotion()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListPromotion); + } + if (theAppProperties.isEnableIntervalDemotion()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalDemotion); + } + if (theAppProperties.isEnableIntervalPromotion()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalPromotion); + } + if (theAppProperties.isDisableMethodInvocation()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableMethodInvocation); + } + if (theAppProperties.isRequireFromKeyword()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.RequireFromKeyword); + } + cqlCompilerOptions.setValidateUnits(theAppProperties.isCqlCompilerValidateUnits()); + if (theAppProperties.isDisableDefaultModelInfoLoad()) { + cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableDefaultModelInfoLoad); + } + cqlCompilerOptions.setSignatureLevel(theAppProperties.getCqlCompilerSignatureLevel()); + cqlCompilerOptions.setCompatibilityLevel(theAppProperties.getCqlCompilerCompatibilityLevel()); + cqlCompilerOptions.setAnalyzeDataRequirements(theAppProperties.isCqlCompilerAnalyzeDataRequirements()); + cqlCompilerOptions.setCollapseDataRequirements(theAppProperties.isCqlCompilerCollapseDataRequirements()); + + cqlOptions.setCqlCompilerOptions(cqlCompilerOptions); + evaluationSettings.setLibraryCache(theGlobalLibraryCache); + evaluationSettings.setModelCache(theGlobalModelCache); + return evaluationSettings; } } diff --git a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4IT.java b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4IT.java index 3c89932..be3473f 100644 --- a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4IT.java +++ b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4IT.java @@ -18,10 +18,8 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.context.ApplicationContext; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -33,10 +31,11 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import static ca.uhn.fhir.util.TestUtil.waitForSize; -import static java.lang.Thread.sleep; import static org.awaitility.Awaitility.await; import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.opencds.cqf.fhir.utility.r4.Parameters.parameters; +import static org.opencds.cqf.fhir.utility.r4.Parameters.stringPart; @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, @@ -113,7 +112,7 @@ class ExampleServerR4IT implements IServerSupport{ Parameters.ParametersParameterComponent component = response.get(0); assertTrue(component.getResource() instanceof MeasureReport); MeasureReport report = (MeasureReport) component.getResource(); - assertEquals(measureUrl, report.getMeasure()); + assertEquals(measureUrl + "|0.0.003", report.getMeasure()); } private org.hl7.fhir.r4.model.Bundle loadBundle(String theLocation, FhirContext theCtx, IGenericClient theClient) throws IOException { @@ -123,6 +122,21 @@ class ExampleServerR4IT implements IServerSupport{ return result; } + public Parameters runCqlExecution(Parameters parameters){ + + var results = ourClient.operation().onServer() + .named("$cql") + .withParameters(parameters) + .execute(); + return results; + } + @Test + void testSimpleDateCqlExecutionProvider() { + Parameters params = parameters(stringPart("expression", "Interval[Today() - 2 years, Today())")); + Parameters results = runCqlExecution(params); + assertTrue(results.getParameter("return").getValue() instanceof Period); + } + private IBaseResource loadRec(String theLocation, FhirContext theCtx, IGenericClient theClient) throws IOException { String json = stringFromResource(theLocation); List resList = new ArrayList<>(); @@ -260,10 +274,10 @@ class ExampleServerR4IT implements IServerSupport{ Parameters params = new Parameters(); params.addParameter().setName("periodStart").setValue(new DateType(periodStartValid)); - params.addParameter().setName("subject").setValue(new DateType(periodEndValid)); - params.addParameter().setName("status").setValue(new StringType(subjectPatientValid)); - params.addParameter().setName("measureId").setValue(new StringType(statusValid)); - params.addParameter().setName("").setValue(new StringType(measureIdValid)); + params.addParameter().setName("periodEnd").setValue(new DateType(periodEndValid)); + params.addParameter().setName("subject").setValue(new StringType(subjectPatientValid)); + params.addParameter().setName("status").setValue(new StringType(statusValid)); + params.addParameter().setName("measureId").setValue(new IdType(measureIdValid)); assertDoesNotThrow(() -> {