Merge remote-tracking branch 'origin/master' into rel_7_3_tracking
This commit is contained in:
13
.vscode/launch.json
vendored
13
.vscode/launch.json
vendored
@@ -7,7 +7,18 @@
|
|||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"mainClass": "ca.uhn.fhir.jpa.starter.Application",
|
"mainClass": "ca.uhn.fhir.jpa.starter.Application",
|
||||||
"projectName": "hapi-fhir-jpaserver-starter",
|
"projectName": "hapi-fhir-jpaserver-starter",
|
||||||
"args": "",
|
"vmArgs": [
|
||||||
|
"-XX:TieredStopAtLevel=1",
|
||||||
|
// "-Ddebug=true",
|
||||||
|
// "-Dloader.debug=true",
|
||||||
|
"-Dhapi.fhir.bulk_export_enabled=false",
|
||||||
|
"-Dspring.batch.job.enabled=false",
|
||||||
|
"-Dspring.main.allow-bean-definition-overriding=true",
|
||||||
|
"-Dhapi.fhir.cdshooks.enabled=true",
|
||||||
|
"-Dhapi.fhir.cr.enabled=true",
|
||||||
|
"-Dspring.main.allow-bean-definition-overriding=true"
|
||||||
|
|
||||||
|
],
|
||||||
"envFile": "${workspaceFolder}/.env"
|
"envFile": "${workspaceFolder}/.env"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -5,5 +5,6 @@
|
|||||||
"**/.settings": true,
|
"**/.settings": true,
|
||||||
"**/.factorypath": true
|
"**/.factorypath": true
|
||||||
},
|
},
|
||||||
"java.compile.nullAnalysis.mode": "disabled"
|
"java.compile.nullAnalysis.mode": "disabled",
|
||||||
|
"java.configuration.updateBuildConfiguration": "automatic"
|
||||||
}
|
}
|
||||||
@@ -483,7 +483,11 @@ The server may be configured with subscription support by enabling properties in
|
|||||||
|
|
||||||
## Enabling Clinical Reasoning
|
## Enabling Clinical Reasoning
|
||||||
|
|
||||||
Set `hapi.fhir.cr_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable [Clinical Quality Language](https://cql.hl7.org/) on this server.
|
Set `hapi.fhir.cr_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable [Clinical Quality Language](https://cql.hl7.org/) on this server. An alternate settings file, [cds.application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/cds.application.yaml), exists with the Clinical Reasoning module enabled and default settings that have been found to work with most CDS and dQM test cases.
|
||||||
|
|
||||||
|
## Enabling CDS Hooks
|
||||||
|
|
||||||
|
Set `hapi.fhir.cdshooks.enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable [CDS Hooks](https://cds-hooks.org/) on this server. The Clinical Reasoning module must also be enabled because this implementation of CDS Hooks includes [CDS on FHIR](https://build.fhir.org/clinicalreasoning-cds-on-fhir.html). An example CDS Service using CDS on FHIR is available in the CdsHooksServletIT test class.
|
||||||
|
|
||||||
## Enabling MDM (EMPI)
|
## Enabling MDM (EMPI)
|
||||||
|
|
||||||
|
|||||||
9
pom.xml
9
pom.xml
@@ -42,6 +42,15 @@
|
|||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- Temporarily override CR depedencies for debugging -->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.opencds.cqf.fhir</groupId>-->
|
||||||
|
<!-- <artifactId>cqf-fhir-bom</artifactId>-->
|
||||||
|
<!-- <version>3.4.0</version>-->
|
||||||
|
<!-- <type>pom</type>-->
|
||||||
|
<!-- <scope>import</scope>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.glassfish.jaxb</groupId>
|
<groupId>org.glassfish.jaxb</groupId>
|
||||||
<artifactId>jaxb-runtime</artifactId>
|
<artifactId>jaxb-runtime</artifactId>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -3,10 +3,6 @@ package ca.uhn.fhir.jpa.starter.cdshooks;
|
|||||||
import ca.uhn.fhir.jpa.starter.cr.CrProperties;
|
import ca.uhn.fhir.jpa.starter.cr.CrProperties;
|
||||||
|
|
||||||
public class ProviderConfiguration {
|
public class ProviderConfiguration {
|
||||||
|
|
||||||
public static final ProviderConfiguration DEFAULT_PROVIDER_CONFIGURATION =
|
|
||||||
new ProviderConfiguration(false, "client_id");
|
|
||||||
|
|
||||||
private final String clientIdHeaderName;
|
private final String clientIdHeaderName;
|
||||||
private final boolean cqlLoggingEnabled;
|
private final boolean cqlLoggingEnabled;
|
||||||
|
|
||||||
@@ -16,8 +12,7 @@ public class ProviderConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ProviderConfiguration(CdsHooksProperties cdsProperties, CrProperties crProperties) {
|
public ProviderConfiguration(CdsHooksProperties cdsProperties, CrProperties crProperties) {
|
||||||
this.clientIdHeaderName = cdsProperties.getClientIdHeaderName();
|
this(crProperties.getCql().getRuntime().isDebugLoggingEnabled(), cdsProperties.getClientIdHeaderName());
|
||||||
this.cqlLoggingEnabled = crProperties.isCqlRuntimeDebugLoggingEnabled();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getClientIdHeaderName() {
|
public String getClientIdHeaderName() {
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
package ca.uhn.fhir.jpa.starter.cdshooks;
|
package ca.uhn.fhir.jpa.starter.cdshooks;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.starter.cr.CrCommonConfig;
|
||||||
import ca.uhn.fhir.jpa.starter.cr.CrConfigCondition;
|
import ca.uhn.fhir.jpa.starter.cr.CrConfigCondition;
|
||||||
import ca.uhn.fhir.jpa.starter.cr.CrProperties;
|
import ca.uhn.fhir.jpa.starter.cr.CrProperties;
|
||||||
import ca.uhn.hapi.fhir.cdshooks.api.ICdsHooksDaoAuthorizationSvc;
|
import ca.uhn.hapi.fhir.cdshooks.api.ICdsHooksDaoAuthorizationSvc;
|
||||||
import ca.uhn.hapi.fhir.cdshooks.config.CdsHooksConfig;
|
import ca.uhn.hapi.fhir.cdshooks.config.CdsHooksConfig;
|
||||||
import ca.uhn.hapi.fhir.cdshooks.svc.CdsHooksContextBooter;
|
import ca.uhn.hapi.fhir.cdshooks.svc.CdsHooksContextBooter;
|
||||||
import ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrSettings;
|
import ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrSettings;
|
||||||
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrServiceRegistry;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.svc.cr.ICdsCrServiceRegistry;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.svc.cr.discovery.CdsCrDiscoveryServiceRegistry;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.svc.cr.discovery.ICdsCrDiscoveryServiceRegistry;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.svc.prefetch.CdsPrefetchDaoSvc;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.svc.prefetch.CdsPrefetchFhirClientSvc;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.svc.prefetch.CdsPrefetchSvc;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.svc.prefetch.CdsResolutionStrategySvc;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||||
@@ -16,8 +26,38 @@ import org.springframework.context.annotation.Import;
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Conditional({CdsHooksConfigCondition.class, CrConfigCondition.class})
|
@Conditional({CdsHooksConfigCondition.class, CrConfigCondition.class})
|
||||||
@Import(CdsHooksConfig.class)
|
@Import({CdsHooksConfig.class, CrCommonConfig.class})
|
||||||
public class StarterCdsHooksConfig {
|
public class StarterCdsHooksConfig {
|
||||||
|
|
||||||
|
// @Bean
|
||||||
|
// CdsPrefetchSvc cdsPrefetchSvc(
|
||||||
|
// CdsResolutionStrategySvc theCdsResolutionStrategySvc,
|
||||||
|
// CdsPrefetchDaoSvc theResourcePrefetchDao,
|
||||||
|
// CdsPrefetchFhirClientSvc theResourcePrefetchFhirClient,
|
||||||
|
// ICdsHooksDaoAuthorizationSvc theCdsHooksDaoAuthorizationSvc) {
|
||||||
|
// return new ModuleConfigurationPrefetchSvc(
|
||||||
|
// theCdsResolutionStrategySvc,
|
||||||
|
// theResourcePrefetchDao,
|
||||||
|
// theResourcePrefetchFhirClient,
|
||||||
|
// theCdsHooksDaoAuthorizationSvc);
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ICdsCrDiscoveryServiceRegistry cdsCrDiscoveryServiceRegistry() {
|
||||||
|
CdsCrDiscoveryServiceRegistry registry = new CdsCrDiscoveryServiceRegistry();
|
||||||
|
registry.unregister(FhirVersionEnum.R4);
|
||||||
|
registry.register(FhirVersionEnum.R4, UpdatedCrDiscoveryServiceR4.class);
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ICdsCrServiceRegistry cdsCrServiceRegistry() {
|
||||||
|
CdsCrServiceRegistry registry = new CdsCrServiceRegistry();
|
||||||
|
registry.unregister(FhirVersionEnum.R4);
|
||||||
|
registry.register(FhirVersionEnum.R4, UpdatedCdsCrServiceR4.class);
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CdsHooksProperties cdsHooksProperties() {
|
public CdsHooksProperties cdsHooksProperties() {
|
||||||
return new CdsHooksProperties();
|
return new CdsHooksProperties();
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter.cdshooks;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.api.ICdsConfigService;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestJson;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrServiceR4;
|
||||||
|
import org.hl7.fhir.r4.model.BooleanType;
|
||||||
|
import org.hl7.fhir.r4.model.Parameters;
|
||||||
|
import org.opencds.cqf.fhir.api.Repository;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA;
|
||||||
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA_ENDPOINT;
|
||||||
|
import static org.opencds.cqf.fhir.utility.r4.Parameters.part;
|
||||||
|
|
||||||
|
public class UpdatedCdsCrServiceR4 extends CdsCrServiceR4 {
|
||||||
|
public UpdatedCdsCrServiceR4(RequestDetails theRequestDetails, Repository theRepository, ICdsConfigService theCdsConfigService) {
|
||||||
|
super(theRequestDetails, theRepository, theCdsConfigService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Parameters encodeParams(CdsServiceRequestJson theJson) {
|
||||||
|
Parameters parameters = super.encodeParams(theJson);
|
||||||
|
if (parameters.hasParameter(APPLY_PARAMETER_DATA)) {
|
||||||
|
parameters.addParameter(part("useServerData", new BooleanType(false)));
|
||||||
|
}
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter.cdshooks;
|
||||||
|
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.svc.cr.discovery.CrDiscoveryServiceR4;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.opencds.cqf.fhir.api.Repository;
|
||||||
|
|
||||||
|
public class UpdatedCrDiscoveryServiceR4 extends CrDiscoveryServiceR4 {
|
||||||
|
public UpdatedCrDiscoveryServiceR4(IIdType thePlanDefinitionId, Repository theRepository) {
|
||||||
|
super(thePlanDefinitionId, theRepository);
|
||||||
|
myMaxUriLength = 6000;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter.cr;
|
||||||
|
|
||||||
|
public class CareGapsProperties {
|
||||||
|
private String reporter = "default";
|
||||||
|
private String section_author = "default";
|
||||||
|
|
||||||
|
public String getReporter() {
|
||||||
|
return reporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReporter(String reporter) {
|
||||||
|
this.reporter = reporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSection_author() {
|
||||||
|
return section_author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSection_author(String section_author) {
|
||||||
|
this.section_author = section_author;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter.cr;
|
||||||
|
|
||||||
|
import org.cqframework.cql.cql2elm.CqlCompilerException;
|
||||||
|
import org.cqframework.cql.cql2elm.CqlTranslator;
|
||||||
|
import org.cqframework.cql.cql2elm.LibraryBuilder;
|
||||||
|
|
||||||
|
public class CqlCompilerProperties {
|
||||||
|
private Boolean validate_units = true;
|
||||||
|
private Boolean verify_only = false;
|
||||||
|
private String compatibility_level = "1.5";
|
||||||
|
private CqlCompilerException.ErrorSeverity error_level = CqlCompilerException.ErrorSeverity.Info;
|
||||||
|
private LibraryBuilder.SignatureLevel signature_level = LibraryBuilder.SignatureLevel.All;
|
||||||
|
private Boolean analyze_data_requirements = false;
|
||||||
|
private Boolean collapse_data_requirements = false;
|
||||||
|
private CqlTranslator.Format translator_format = CqlTranslator.Format.JSON;
|
||||||
|
private Boolean enable_date_range_optimization = true;
|
||||||
|
private Boolean enable_annotations = true;
|
||||||
|
private Boolean enable_locators = true;
|
||||||
|
private Boolean enable_results_type = true;
|
||||||
|
private Boolean enable_detailed_errors = true;
|
||||||
|
private Boolean disable_list_traversal = false;
|
||||||
|
private Boolean disable_list_demotion = false;
|
||||||
|
private Boolean disable_list_promotion = false;
|
||||||
|
private Boolean enable_interval_demotion = false;
|
||||||
|
private Boolean enable_interval_promotion = false;
|
||||||
|
private Boolean disable_method_invocation = false;
|
||||||
|
private Boolean require_from_keyword = false;
|
||||||
|
private Boolean disable_default_model_info_load = false;
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isValidateUnits() {
|
||||||
|
return validate_units;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValidateUnits(boolean validateUnits) {
|
||||||
|
this.validate_units = validateUnits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVerifyOnly() {
|
||||||
|
return verify_only;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVerifyOnly(boolean verifyOnly) {
|
||||||
|
this.verify_only = verifyOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCompatibilityLevel() {
|
||||||
|
return compatibility_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompatibilityLevel(String compatibilityLevel) {
|
||||||
|
this.compatibility_level = compatibilityLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CqlCompilerException.ErrorSeverity getErrorSeverityLevel() {
|
||||||
|
return error_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrorSeverityLevel(CqlCompilerException.ErrorSeverity errorSeverityLevel) {
|
||||||
|
this.error_level = errorSeverityLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LibraryBuilder.SignatureLevel getSignatureLevel() {
|
||||||
|
return signature_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSignatureLevel(LibraryBuilder.SignatureLevel signatureLevel) {
|
||||||
|
this.signature_level = signatureLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAnalyzeDataRequirements() {
|
||||||
|
return analyze_data_requirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnalyzeDataRequirements(boolean analyzeDataRequirements) {
|
||||||
|
this.analyze_data_requirements = analyzeDataRequirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCollapseDataRequirements() {
|
||||||
|
return collapse_data_requirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCollapseDataRequirements(boolean collapseDataRequirements) {
|
||||||
|
this.collapse_data_requirements = collapseDataRequirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnableDateRangeOptimization() {
|
||||||
|
return enable_date_range_optimization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableDateRangeOptimization(boolean enableDateRangeOptimization) {
|
||||||
|
this.enable_date_range_optimization = enableDateRangeOptimization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnableAnnotations() {
|
||||||
|
return enable_annotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableAnnotations(boolean enableAnnotations) {
|
||||||
|
this.enable_annotations = enableAnnotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnableLocators() {
|
||||||
|
return enable_locators;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableLocators(boolean enableLocators) {
|
||||||
|
this.enable_locators = enableLocators;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnableResultsType() {
|
||||||
|
return enable_results_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableResultsType(boolean enableResultsType) {
|
||||||
|
this.enable_results_type = enableResultsType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnableDetailedErrors() {
|
||||||
|
return enable_detailed_errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableDetailedErrors(boolean enableDetailedErrors) {
|
||||||
|
this.enable_detailed_errors = enableDetailedErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDisableListTraversal() {
|
||||||
|
return disable_list_traversal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisableListTraversal(boolean disableListTraversal) {
|
||||||
|
this.disable_list_traversal = disableListTraversal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDisableListDemotion() {
|
||||||
|
return disable_list_demotion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisableListDemotion(boolean disableListDemotion) {
|
||||||
|
this.disable_list_demotion = disableListDemotion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDisableListPromotion() {
|
||||||
|
return disable_list_promotion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisableListPromotion(boolean disableListPromotion) {
|
||||||
|
this.disable_list_promotion = disableListPromotion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnableIntervalPromotion() {
|
||||||
|
return enable_interval_promotion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableIntervalPromotion(boolean enableIntervalPromotion) {
|
||||||
|
this.enable_interval_promotion = enableIntervalPromotion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnableIntervalDemotion() {
|
||||||
|
return enable_interval_demotion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableIntervalDemotion(boolean enableIntervalDemotion) {
|
||||||
|
this.enable_interval_demotion = enableIntervalDemotion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDisableMethodInvocation() {
|
||||||
|
return disable_method_invocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisableMethodInvocation(boolean disableMethodInvocation) {
|
||||||
|
this.disable_method_invocation = disableMethodInvocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRequireFromKeyword() {
|
||||||
|
return require_from_keyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequireFromKeyword(boolean requireFromKeyword) {
|
||||||
|
this.require_from_keyword = requireFromKeyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDisableDefaultModelInfoLoad() {
|
||||||
|
return disable_default_model_info_load;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisableDefaultModelInfoLoad(boolean disableDefaultModelInfoLoad) {
|
||||||
|
this.disable_default_model_info_load = disableDefaultModelInfoLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CqlTranslator.Format getTranslatorFormat() {
|
||||||
|
return translator_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTranslatorFormat(CqlTranslator.Format translatorFormat) {
|
||||||
|
this.translator_format = translatorFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/main/java/ca/uhn/fhir/jpa/starter/cr/CqlProperties.java
Normal file
53
src/main/java/ca/uhn/fhir/jpa/starter/cr/CqlProperties.java
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter.cr;
|
||||||
|
|
||||||
|
import org.opencds.cqf.fhir.cql.engine.retrieve.RetrieveSettings;
|
||||||
|
import org.opencds.cqf.fhir.cql.engine.terminology.TerminologySettings;
|
||||||
|
|
||||||
|
public class CqlProperties {
|
||||||
|
|
||||||
|
private Boolean use_embedded_libraries = true;
|
||||||
|
private CqlCompilerProperties compiler = new CqlCompilerProperties();
|
||||||
|
private CqlRuntimeProperties runtime = new CqlRuntimeProperties();
|
||||||
|
private TerminologySettings terminology = new TerminologySettings();
|
||||||
|
private RetrieveSettings data = new RetrieveSettings();
|
||||||
|
|
||||||
|
public Boolean getUse_embedded_libraries() {
|
||||||
|
return use_embedded_libraries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUse_embedded_libraries(Boolean use_embedded_libraries) {
|
||||||
|
this.use_embedded_libraries = use_embedded_libraries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CqlCompilerProperties getCompiler() {
|
||||||
|
return compiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompiler(CqlCompilerProperties compiler) {
|
||||||
|
this.compiler = compiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CqlRuntimeProperties getRuntime() {
|
||||||
|
return runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRuntime(CqlRuntimeProperties runtime) {
|
||||||
|
this.runtime = runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TerminologySettings getTerminology() {
|
||||||
|
return terminology;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTerminology(TerminologySettings terminology) {
|
||||||
|
this.terminology = terminology;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RetrieveSettings getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(RetrieveSettings data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter.cr;
|
||||||
|
|
||||||
|
public class CqlRuntimeProperties {
|
||||||
|
|
||||||
|
private Boolean debug_logging_enabled = false;
|
||||||
|
private Boolean enable_validation = false;
|
||||||
|
private Boolean enable_expression_caching = true;
|
||||||
|
|
||||||
|
public boolean isDebugLoggingEnabled() {
|
||||||
|
return debug_logging_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDebugLoggingEnabled(boolean debug_logging_enabled) {
|
||||||
|
this.debug_logging_enabled = debug_logging_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isEnableExpressionCaching() {
|
||||||
|
return enable_expression_caching;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableExpressionCaching(boolean enable_expression_caching) {
|
||||||
|
this.enable_expression_caching = enable_expression_caching;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnableValidation() {
|
||||||
|
return enable_validation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnableValidation(boolean enable_validation) {
|
||||||
|
this.enable_validation = enable_validation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
228
src/main/java/ca/uhn/fhir/jpa/starter/cr/CrCommonConfig.java
Normal file
228
src/main/java/ca/uhn/fhir/jpa/starter/cr/CrCommonConfig.java
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter.cr;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
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.cql.engine.runtime.Code;
|
||||||
|
import org.opencds.cqf.fhir.cql.EvaluationSettings;
|
||||||
|
import org.opencds.cqf.fhir.cql.engine.retrieve.RetrieveSettings;
|
||||||
|
import org.opencds.cqf.fhir.cql.engine.terminology.TerminologySettings;
|
||||||
|
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.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.cr.common.CodeCacheResourceChangeListener;
|
||||||
|
import ca.uhn.fhir.cr.common.CqlThreadFactory;
|
||||||
|
import ca.uhn.fhir.cr.common.ElmCacheResourceChangeListener;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerRegistryInterceptor;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
|
import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Conditional({CrConfigCondition.class})
|
||||||
|
public class CrCommonConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConfigurationProperties(prefix = "hapi.fhir.cr")
|
||||||
|
CrProperties crProperties() {
|
||||||
|
return new CrProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
RetrieveSettings retrieveSettings(CrProperties theCrProperties) {
|
||||||
|
return theCrProperties.getCql().getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
TerminologySettings terminologySettings(CrProperties theCrProperties) {
|
||||||
|
return theCrProperties.getCql().getTerminology();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public EvaluationSettings evaluationSettings(
|
||||||
|
CrProperties theCrProperties,
|
||||||
|
RetrieveSettings theRetrieveSettings,
|
||||||
|
TerminologySettings theTerminologySettings,
|
||||||
|
Map<VersionedIdentifier, CompiledLibrary> theGlobalLibraryCache,
|
||||||
|
Map<ModelIdentifier, Model> theGlobalModelCache,
|
||||||
|
Map<String, List<Code>> theGlobalValueSetCache) {
|
||||||
|
var evaluationSettings = EvaluationSettings.getDefault();
|
||||||
|
var cqlOptions = evaluationSettings.getCqlOptions();
|
||||||
|
|
||||||
|
var cqlEngineOptions = cqlOptions.getCqlEngineOptions();
|
||||||
|
Set<CqlEngine.Options> options = EnumSet.noneOf(CqlEngine.Options.class);
|
||||||
|
var cqlRuntimeProperties = theCrProperties.getCql().getRuntime();
|
||||||
|
if (cqlRuntimeProperties.isEnableExpressionCaching()) {
|
||||||
|
options.add(CqlEngine.Options.EnableExpressionCaching);
|
||||||
|
}
|
||||||
|
if (cqlRuntimeProperties.isEnableValidation()) {
|
||||||
|
options.add(CqlEngine.Options.EnableValidation);
|
||||||
|
}
|
||||||
|
cqlEngineOptions.setOptions(options);
|
||||||
|
if (cqlRuntimeProperties.isDebugLoggingEnabled()) {
|
||||||
|
cqlEngineOptions.setDebugLoggingEnabled(true);
|
||||||
|
}
|
||||||
|
cqlOptions.setCqlEngineOptions(cqlEngineOptions);
|
||||||
|
|
||||||
|
var cqlCompilerOptions = new CqlCompilerOptions();
|
||||||
|
|
||||||
|
var cqlCompilerProperties = theCrProperties.getCql().getCompiler();
|
||||||
|
|
||||||
|
if (cqlCompilerProperties.isEnableDateRangeOptimization()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDateRangeOptimization);
|
||||||
|
}
|
||||||
|
if (cqlCompilerProperties.isEnableAnnotations()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableAnnotations);
|
||||||
|
}
|
||||||
|
if (cqlCompilerProperties.isEnableLocators()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableLocators);
|
||||||
|
}
|
||||||
|
if (cqlCompilerProperties.isEnableResultsType()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableResultTypes);
|
||||||
|
}
|
||||||
|
cqlCompilerOptions.setVerifyOnly(cqlCompilerProperties.isVerifyOnly());
|
||||||
|
if (cqlCompilerProperties.isEnableDetailedErrors()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDetailedErrors);
|
||||||
|
}
|
||||||
|
cqlCompilerOptions.setErrorLevel(cqlCompilerProperties.getErrorSeverityLevel());
|
||||||
|
if (cqlCompilerProperties.isDisableListTraversal()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListTraversal);
|
||||||
|
}
|
||||||
|
if (cqlCompilerProperties.isDisableListDemotion()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListDemotion);
|
||||||
|
}
|
||||||
|
if (cqlCompilerProperties.isDisableListPromotion()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListPromotion);
|
||||||
|
}
|
||||||
|
if (cqlCompilerProperties.isEnableIntervalDemotion()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalDemotion);
|
||||||
|
}
|
||||||
|
if (cqlCompilerProperties.isEnableIntervalPromotion()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalPromotion);
|
||||||
|
}
|
||||||
|
if (cqlCompilerProperties.isDisableMethodInvocation()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableMethodInvocation);
|
||||||
|
}
|
||||||
|
if (cqlCompilerProperties.isRequireFromKeyword()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.RequireFromKeyword);
|
||||||
|
}
|
||||||
|
cqlCompilerOptions.setValidateUnits(cqlCompilerProperties.isValidateUnits());
|
||||||
|
if (cqlCompilerProperties.isDisableDefaultModelInfoLoad()) {
|
||||||
|
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableDefaultModelInfoLoad);
|
||||||
|
}
|
||||||
|
cqlCompilerOptions.setSignatureLevel(cqlCompilerProperties.getSignatureLevel());
|
||||||
|
cqlCompilerOptions.setCompatibilityLevel(cqlCompilerProperties.getCompatibilityLevel());
|
||||||
|
cqlCompilerOptions.setAnalyzeDataRequirements(cqlCompilerProperties.isAnalyzeDataRequirements());
|
||||||
|
cqlCompilerOptions.setCollapseDataRequirements(cqlCompilerProperties.isCollapseDataRequirements());
|
||||||
|
|
||||||
|
cqlOptions.setCqlCompilerOptions(cqlCompilerOptions);
|
||||||
|
evaluationSettings.setLibraryCache(theGlobalLibraryCache);
|
||||||
|
evaluationSettings.setModelCache(theGlobalModelCache);
|
||||||
|
evaluationSettings.setValueSetCache(theGlobalValueSetCache);
|
||||||
|
evaluationSettings.setRetrieveSettings(theRetrieveSettings);
|
||||||
|
evaluationSettings.setTerminologySettings(theTerminologySettings);
|
||||||
|
return evaluationSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
@Bean
|
||||||
|
public ExecutorService cqlExecutor() {
|
||||||
|
CqlThreadFactory factory = new CqlThreadFactory();
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(2, factory);
|
||||||
|
executor = new DelegatingSecurityContextExecutorService(executor);
|
||||||
|
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
CareGapsProperties careGapsProperties(CrProperties theCrProperties) {
|
||||||
|
var careGapsProperties = new CareGapsProperties();
|
||||||
|
careGapsProperties.setCareGapsReporter(theCrProperties.getCareGaps().getReporter());
|
||||||
|
careGapsProperties.setCareGapsCompositionSectionAuthor(theCrProperties.getCareGaps().getSection_author());
|
||||||
|
return careGapsProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
MeasureEvaluationOptions measureEvaluationOptions(
|
||||||
|
EvaluationSettings theEvaluationSettings, Map<String, ValidationProfile> theValidationProfiles) {
|
||||||
|
MeasureEvaluationOptions measureEvalOptions = new MeasureEvaluationOptions();
|
||||||
|
measureEvalOptions.setEvaluationSettings(theEvaluationSettings);
|
||||||
|
if (measureEvalOptions.isValidationEnabled()) {
|
||||||
|
measureEvalOptions.setValidationProfiles(theValidationProfiles);
|
||||||
|
}
|
||||||
|
return measureEvalOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PostInitProviderRegisterer postInitProviderRegisterer(
|
||||||
|
RestfulServer theRestfulServer, ResourceProviderFactory theResourceProviderFactory) {
|
||||||
|
return new PostInitProviderRegisterer(theRestfulServer, theResourceProviderFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Map<VersionedIdentifier, CompiledLibrary> globalLibraryCache() {
|
||||||
|
return new ConcurrentHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Map<ModelIdentifier, Model> globalModelCache() {
|
||||||
|
return new ConcurrentHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Map<String, List<Code>> globalValueSetCache() {
|
||||||
|
return new ConcurrentHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ElmCacheResourceChangeListener elmCacheResourceChangeListener(
|
||||||
|
IResourceChangeListenerRegistry theResourceChangeListenerRegistry,
|
||||||
|
DaoRegistry theDaoRegistry,
|
||||||
|
EvaluationSettings theEvaluationSettings) {
|
||||||
|
ElmCacheResourceChangeListener listener =
|
||||||
|
new ElmCacheResourceChangeListener(theDaoRegistry, theEvaluationSettings.getLibraryCache());
|
||||||
|
theResourceChangeListenerRegistry.registerResourceResourceChangeListener(
|
||||||
|
"Library", SearchParameterMap.newSynchronous(), listener, 1000);
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CodeCacheResourceChangeListener codeCacheResourceChangeListener(
|
||||||
|
IResourceChangeListenerRegistry theResourceChangeListenerRegistry,
|
||||||
|
EvaluationSettings theEvaluationSettings,
|
||||||
|
DaoRegistry theDaoRegistry) {
|
||||||
|
|
||||||
|
CodeCacheResourceChangeListener listener =
|
||||||
|
new CodeCacheResourceChangeListener(theDaoRegistry, theEvaluationSettings.getValueSetCache());
|
||||||
|
// registry
|
||||||
|
theResourceChangeListenerRegistry.registerResourceResourceChangeListener(
|
||||||
|
"ValueSet", SearchParameterMap.newSynchronous(), listener, 1000);
|
||||||
|
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ResourceChangeListenerRegistryInterceptor resourceChangeListenerRegistryInterceptor() {
|
||||||
|
return new ResourceChangeListenerRegistryInterceptor();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,40 +3,12 @@ package ca.uhn.fhir.jpa.starter.cr;
|
|||||||
import org.cqframework.cql.cql2elm.CqlCompilerException;
|
import org.cqframework.cql.cql2elm.CqlCompilerException;
|
||||||
import org.cqframework.cql.cql2elm.CqlTranslator;
|
import org.cqframework.cql.cql2elm.CqlTranslator;
|
||||||
import org.cqframework.cql.cql2elm.LibraryBuilder;
|
import org.cqframework.cql.cql2elm.LibraryBuilder;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "hapi.fhir.cr")
|
|
||||||
public class CrProperties {
|
public class CrProperties {
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
// cql settings
|
|
||||||
private Boolean cql_use_embedded_libraries = true;
|
private CareGapsProperties careGaps = new CareGapsProperties();
|
||||||
private Boolean cql_runtime_debug_logging_enabled = false;
|
private CqlProperties cql = new CqlProperties();
|
||||||
private Boolean cql_runtime_enable_validation = false;
|
|
||||||
private Boolean cql_runtime_enable_expression_caching = false;
|
|
||||||
private Boolean cql_compiler_validate_units = true;
|
|
||||||
private Boolean cql_compiler_verify_only = false;
|
|
||||||
private String cql_compiler_compatibility_level = "1.5";
|
|
||||||
private CqlCompilerException.ErrorSeverity cql_compiler_error_level = CqlCompilerException.ErrorSeverity.Info;
|
|
||||||
private LibraryBuilder.SignatureLevel cql_compiler_signature_level = LibraryBuilder.SignatureLevel.All;
|
|
||||||
private Boolean cql_compiler_analyze_data_requirements = false;
|
|
||||||
private Boolean cql_compiler_collapse_data_requirements = false;
|
|
||||||
private CqlTranslator.Format cql_compiler_translator_format = CqlTranslator.Format.JSON;
|
|
||||||
private Boolean cql_compiler_enable_date_range_optimization = false;
|
|
||||||
private Boolean cql_compiler_enable_annotations = false;
|
|
||||||
private Boolean cql_compiler_enable_locators = false;
|
|
||||||
private Boolean cql_compiler_enable_results_type = false;
|
|
||||||
private Boolean cql_compiler_enable_detailed_errors = false;
|
|
||||||
private Boolean cql_compiler_disable_list_traversal = false;
|
|
||||||
private Boolean cql_compiler_disable_list_demotion = false;
|
|
||||||
private Boolean cql_compiler_disable_list_promotion = false;
|
|
||||||
private Boolean cql_compiler_enable_interval_demotion = false;
|
|
||||||
private Boolean cql_compiler_enable_interval_promotion = false;
|
|
||||||
private Boolean cql_compiler_disable_method_invocation = false;
|
|
||||||
private Boolean cql_compiler_require_from_keyword = false;
|
|
||||||
private Boolean cql_compiler_disable_default_model_info_load = false;
|
|
||||||
// Care-gaps Settings
|
|
||||||
private String caregaps_reporter = "default";
|
|
||||||
private String caregaps_section_author = "default";
|
|
||||||
|
|
||||||
public Boolean getEnabled() {
|
public Boolean getEnabled() {
|
||||||
return enabled;
|
return enabled;
|
||||||
@@ -46,219 +18,19 @@ public class CrProperties {
|
|||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCqlUseEmbeddedLibraries() {
|
public CareGapsProperties getCareGaps() {
|
||||||
return cql_use_embedded_libraries;
|
return careGaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCqlUseEmbeddedLibraries(boolean cql_use_embedded_libraries) {
|
public void setCareGaps(CareGapsProperties careGaps) {
|
||||||
this.cql_use_embedded_libraries = cql_use_embedded_libraries;
|
this.careGaps = careGaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCqlRuntimeDebugLoggingEnabled() {
|
public CqlProperties getCql() {
|
||||||
return cql_runtime_debug_logging_enabled;
|
return cql;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCqlRuntimeDebugLoggingEnabled(boolean cqlRuntimeDebugLoggingEnabled) {
|
public void setCql(CqlProperties cql) {
|
||||||
this.cql_runtime_debug_logging_enabled = cqlRuntimeDebugLoggingEnabled;
|
this.cql = cql;
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCqlCompilerValidateUnits() {
|
|
||||||
return cql_compiler_validate_units;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCqlCompilerValidateUnits(boolean cqlCompilerValidateUnits) {
|
|
||||||
this.cql_compiler_validate_units = cqlCompilerValidateUnits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCqlCompilerVerifyOnly() {
|
|
||||||
return cql_compiler_verify_only;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCqlCompilerVerifyOnly(boolean cqlCompilerVerifyOnly) {
|
|
||||||
this.cql_compiler_verify_only = cqlCompilerVerifyOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCqlCompilerCompatibilityLevel() {
|
|
||||||
return cql_compiler_compatibility_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCqlCompilerCompatibilityLevel(String cqlCompilerCompatibilityLevel) {
|
|
||||||
this.cql_compiler_compatibility_level = cqlCompilerCompatibilityLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CqlCompilerException.ErrorSeverity getCqlCompilerErrorSeverityLevel() {
|
|
||||||
return cql_compiler_error_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCqlCompilerErrorSeverityLevel(CqlCompilerException.ErrorSeverity cqlCompilerErrorSeverityLevel) {
|
|
||||||
this.cql_compiler_error_level = cqlCompilerErrorSeverityLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryBuilder.SignatureLevel getCqlCompilerSignatureLevel() {
|
|
||||||
return cql_compiler_signature_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCqlCompilerSignatureLevel(LibraryBuilder.SignatureLevel cqlCompilerSignatureLevel) {
|
|
||||||
this.cql_compiler_signature_level = cqlCompilerSignatureLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCqlCompilerAnalyzeDataRequirements() {
|
|
||||||
return cql_compiler_analyze_data_requirements;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCqlCompilerAnalyzeDataRequirements(boolean cqlCompilerAnalyzeDataRequirements) {
|
|
||||||
this.cql_compiler_analyze_data_requirements = cqlCompilerAnalyzeDataRequirements;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCqlCompilerCollapseDataRequirements() {
|
|
||||||
return cql_compiler_collapse_data_requirements;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCqlCompilerCollapseDataRequirements(boolean cqlCompilerCollapseDataRequirements) {
|
|
||||||
this.cql_compiler_collapse_data_requirements = cqlCompilerCollapseDataRequirements;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnableDateRangeOptimization() {
|
|
||||||
return cql_compiler_enable_date_range_optimization;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnableDateRangeOptimization(boolean enableDateRangeOptimization) {
|
|
||||||
this.cql_compiler_enable_date_range_optimization = enableDateRangeOptimization;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnableAnnotations() {
|
|
||||||
return cql_compiler_enable_annotations;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnableAnnotations(boolean enableAnnotations) {
|
|
||||||
this.cql_compiler_enable_annotations = enableAnnotations;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnableLocators() {
|
|
||||||
return cql_compiler_enable_locators;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnableLocators(boolean enableLocators) {
|
|
||||||
this.cql_compiler_enable_locators = enableLocators;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnableResultsType() {
|
|
||||||
return cql_compiler_enable_results_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnableResultsType(boolean enableResultsType) {
|
|
||||||
this.cql_compiler_enable_results_type = enableResultsType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnableDetailedErrors() {
|
|
||||||
return cql_compiler_enable_detailed_errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnableDetailedErrors(boolean enableDetailedErrors) {
|
|
||||||
this.cql_compiler_enable_detailed_errors = enableDetailedErrors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisableListTraversal() {
|
|
||||||
return cql_compiler_disable_list_traversal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDisableListTraversal(boolean disableListTraversal) {
|
|
||||||
this.cql_compiler_disable_list_traversal = disableListTraversal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisableListDemotion() {
|
|
||||||
return cql_compiler_disable_list_demotion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDisableListDemotion(boolean disableListDemotion) {
|
|
||||||
this.cql_compiler_disable_list_demotion = disableListDemotion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisableListPromotion() {
|
|
||||||
return cql_compiler_disable_list_promotion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDisableListPromotion(boolean disableListPromotion) {
|
|
||||||
this.cql_compiler_disable_list_promotion = disableListPromotion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnableIntervalPromotion() {
|
|
||||||
return cql_compiler_enable_interval_promotion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnableIntervalPromotion(boolean enableIntervalPromotion) {
|
|
||||||
this.cql_compiler_enable_interval_promotion = enableIntervalPromotion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnableIntervalDemotion() {
|
|
||||||
return cql_compiler_enable_interval_demotion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnableIntervalDemotion(boolean enableIntervalDemotion) {
|
|
||||||
this.cql_compiler_enable_interval_demotion = enableIntervalDemotion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisableMethodInvocation() {
|
|
||||||
return cql_compiler_disable_method_invocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDisableMethodInvocation(boolean disableMethodInvocation) {
|
|
||||||
this.cql_compiler_disable_method_invocation = disableMethodInvocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRequireFromKeyword() {
|
|
||||||
return cql_compiler_require_from_keyword;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRequireFromKeyword(boolean requireFromKeyword) {
|
|
||||||
this.cql_compiler_require_from_keyword = requireFromKeyword;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisableDefaultModelInfoLoad() {
|
|
||||||
return cql_compiler_disable_default_model_info_load;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDisableDefaultModelInfoLoad(boolean disableDefaultModelInfoLoad) {
|
|
||||||
this.cql_compiler_disable_default_model_info_load = disableDefaultModelInfoLoad;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCqlRuntimeEnableExpressionCaching() {
|
|
||||||
return cql_runtime_enable_expression_caching;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCqlRuntimeEnableExpressionCaching(boolean cqlRuntimeEnableExpressionCaching) {
|
|
||||||
this.cql_runtime_enable_expression_caching = cqlRuntimeEnableExpressionCaching;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCqlRuntimeEnableValidation() {
|
|
||||||
return cql_runtime_enable_validation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCqlRuntimeEnableValidation(boolean cqlRuntimeEnableValidation) {
|
|
||||||
this.cql_runtime_enable_validation = cqlRuntimeEnableValidation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CqlTranslator.Format getCqlTranslatorFormat() {
|
|
||||||
return cql_compiler_translator_format;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCqlTranslatorFormat(CqlTranslator.Format cqlTranslatorFormat) {
|
|
||||||
this.cql_compiler_translator_format = cqlTranslatorFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCareGapsReporter() {
|
|
||||||
return caregaps_reporter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCareGapsSectionAuthor() {
|
|
||||||
return caregaps_section_author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCareGapsSectionAuthor(String theCareGapsSectionAuthor) {
|
|
||||||
this.caregaps_section_author = theCareGapsSectionAuthor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCareGapsReporter(String theCareGapsReporter) {
|
|
||||||
this.caregaps_reporter = theCareGapsReporter;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,195 +1,25 @@
|
|||||||
package ca.uhn.fhir.jpa.starter.cr;
|
package ca.uhn.fhir.jpa.starter.cr;
|
||||||
|
|
||||||
import ca.uhn.fhir.cr.common.CodeCacheResourceChangeListener;
|
|
||||||
import ca.uhn.fhir.cr.common.ElmCacheResourceChangeListener;
|
|
||||||
import ca.uhn.fhir.cr.config.dstu3.ApplyOperationConfig;
|
import ca.uhn.fhir.cr.config.dstu3.ApplyOperationConfig;
|
||||||
import ca.uhn.fhir.cr.config.dstu3.CrDstu3Config;
|
import ca.uhn.fhir.cr.config.dstu3.CrDstu3Config;
|
||||||
import ca.uhn.fhir.cr.config.dstu3.ExtractOperationConfig;
|
import ca.uhn.fhir.cr.config.dstu3.ExtractOperationConfig;
|
||||||
import ca.uhn.fhir.cr.config.dstu3.PackageOperationConfig;
|
import ca.uhn.fhir.cr.config.dstu3.PackageOperationConfig;
|
||||||
import ca.uhn.fhir.cr.config.dstu3.PopulateOperationConfig;
|
import ca.uhn.fhir.cr.config.dstu3.PopulateOperationConfig;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.cr.config.dstu3.QuestionnaireOperationConfig;
|
||||||
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
|
|
||||||
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerRegistryInterceptor;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
|
||||||
import ca.uhn.fhir.jpa.starter.annotations.OnDSTU3Condition;
|
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.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.cql.engine.runtime.Code;
|
|
||||||
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 org.springframework.context.annotation.*;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Conditional({OnDSTU3Condition.class, CrConfigCondition.class})
|
@Conditional({OnDSTU3Condition.class, CrConfigCondition.class})
|
||||||
@Import({
|
@Import({
|
||||||
// BaseCrConfig.class,
|
CrCommonConfig.class,
|
||||||
CrDstu3Config.class,
|
CrDstu3Config.class,
|
||||||
ApplyOperationConfig.class,
|
ApplyOperationConfig.class,
|
||||||
ExtractOperationConfig.class,
|
ExtractOperationConfig.class,
|
||||||
PackageOperationConfig.class,
|
PackageOperationConfig.class,
|
||||||
PopulateOperationConfig.class
|
PopulateOperationConfig.class,
|
||||||
|
QuestionnaireOperationConfig.class
|
||||||
})
|
})
|
||||||
public class StarterCrDstu3Config {
|
public class StarterCrDstu3Config {
|
||||||
private static final Logger ourLogger = LoggerFactory.getLogger(StarterCrDstu3Config.class);
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
MeasureEvaluationOptions measureEvaluationOptions(
|
|
||||||
EvaluationSettings theEvaluationSettings, Map<String, ValidationProfile> theValidationProfiles) {
|
|
||||||
MeasureEvaluationOptions measureEvalOptions = new MeasureEvaluationOptions();
|
|
||||||
measureEvalOptions.setEvaluationSettings(theEvaluationSettings);
|
|
||||||
|
|
||||||
if (measureEvalOptions.isValidationEnabled()) {
|
|
||||||
measureEvalOptions.setValidationProfiles(theValidationProfiles);
|
|
||||||
}
|
|
||||||
return measureEvalOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public EvaluationSettings evaluationSettings(
|
|
||||||
CrProperties theCrProperties,
|
|
||||||
Map<VersionedIdentifier, CompiledLibrary> theGlobalLibraryCache,
|
|
||||||
Map<ModelIdentifier, Model> theGlobalModelCache,
|
|
||||||
Map<String, List<Code>> theGlobalValueSetCache) {
|
|
||||||
var evaluationSettings = EvaluationSettings.getDefault();
|
|
||||||
var cqlOptions = evaluationSettings.getCqlOptions();
|
|
||||||
|
|
||||||
var cqlEngineOptions = cqlOptions.getCqlEngineOptions();
|
|
||||||
Set<CqlEngine.Options> options = EnumSet.noneOf(CqlEngine.Options.class);
|
|
||||||
if (theCrProperties.isCqlRuntimeEnableExpressionCaching()) {
|
|
||||||
options.add(CqlEngine.Options.EnableExpressionCaching);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isCqlRuntimeEnableValidation()) {
|
|
||||||
options.add(CqlEngine.Options.EnableValidation);
|
|
||||||
}
|
|
||||||
cqlEngineOptions.setOptions(options);
|
|
||||||
cqlOptions.setCqlEngineOptions(cqlEngineOptions);
|
|
||||||
|
|
||||||
var cqlCompilerOptions = new CqlCompilerOptions();
|
|
||||||
|
|
||||||
if (theCrProperties.isEnableDateRangeOptimization()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDateRangeOptimization);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isEnableAnnotations()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableAnnotations);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isEnableLocators()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableLocators);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isEnableResultsType()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableResultTypes);
|
|
||||||
}
|
|
||||||
cqlCompilerOptions.setVerifyOnly(theCrProperties.isCqlCompilerVerifyOnly());
|
|
||||||
if (theCrProperties.isEnableDetailedErrors()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDetailedErrors);
|
|
||||||
}
|
|
||||||
cqlCompilerOptions.setErrorLevel(theCrProperties.getCqlCompilerErrorSeverityLevel());
|
|
||||||
if (theCrProperties.isDisableListTraversal()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListTraversal);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isDisableListDemotion()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListDemotion);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isDisableListPromotion()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListPromotion);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isEnableIntervalDemotion()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalDemotion);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isEnableIntervalPromotion()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalPromotion);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isDisableMethodInvocation()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableMethodInvocation);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isRequireFromKeyword()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.RequireFromKeyword);
|
|
||||||
}
|
|
||||||
cqlCompilerOptions.setValidateUnits(theCrProperties.isCqlCompilerValidateUnits());
|
|
||||||
if (theCrProperties.isDisableDefaultModelInfoLoad()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableDefaultModelInfoLoad);
|
|
||||||
}
|
|
||||||
cqlCompilerOptions.setSignatureLevel(theCrProperties.getCqlCompilerSignatureLevel());
|
|
||||||
cqlCompilerOptions.setCompatibilityLevel(theCrProperties.getCqlCompilerCompatibilityLevel());
|
|
||||||
cqlCompilerOptions.setAnalyzeDataRequirements(theCrProperties.isCqlCompilerAnalyzeDataRequirements());
|
|
||||||
cqlCompilerOptions.setCollapseDataRequirements(theCrProperties.isCqlCompilerCollapseDataRequirements());
|
|
||||||
|
|
||||||
cqlOptions.setCqlCompilerOptions(cqlCompilerOptions);
|
|
||||||
evaluationSettings.setLibraryCache(theGlobalLibraryCache);
|
|
||||||
evaluationSettings.setModelCache(theGlobalModelCache);
|
|
||||||
evaluationSettings.setValueSetCache(theGlobalValueSetCache);
|
|
||||||
return evaluationSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public PostInitProviderRegisterer postInitProviderRegisterer(
|
|
||||||
RestfulServer theRestfulServer, ResourceProviderFactory theResourceProviderFactory) {
|
|
||||||
return new PostInitProviderRegisterer(theRestfulServer, theResourceProviderFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public CrProperties crProperties() {
|
|
||||||
return new CrProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Map<VersionedIdentifier, CompiledLibrary> globalLibraryCache() {
|
|
||||||
return new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Map<ModelIdentifier, Model> globalModelCache() {
|
|
||||||
return new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Map<String, List<Code>> globalValueSetCache() {
|
|
||||||
return new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ElmCacheResourceChangeListener elmCacheResourceChangeListener(
|
|
||||||
IResourceChangeListenerRegistry theResourceChangeListenerRegistry,
|
|
||||||
DaoRegistry theDaoRegistry,
|
|
||||||
EvaluationSettings theEvaluationSettings) {
|
|
||||||
ElmCacheResourceChangeListener listener =
|
|
||||||
new ElmCacheResourceChangeListener(theDaoRegistry, theEvaluationSettings.getLibraryCache());
|
|
||||||
theResourceChangeListenerRegistry.registerResourceResourceChangeListener(
|
|
||||||
"Library", SearchParameterMap.newSynchronous(), listener, 1000);
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public CodeCacheResourceChangeListener codeCacheResourceChangeListener(
|
|
||||||
IResourceChangeListenerRegistry theResourceChangeListenerRegistry,
|
|
||||||
EvaluationSettings theEvaluationSettings,
|
|
||||||
DaoRegistry theDaoRegistry) {
|
|
||||||
|
|
||||||
CodeCacheResourceChangeListener listener =
|
|
||||||
new CodeCacheResourceChangeListener(theDaoRegistry, theEvaluationSettings.getValueSetCache());
|
|
||||||
// registry
|
|
||||||
theResourceChangeListenerRegistry.registerResourceResourceChangeListener(
|
|
||||||
"ValueSet", SearchParameterMap.newSynchronous(), listener, 1000);
|
|
||||||
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ResourceChangeListenerRegistryInterceptor resourceChangeListenerRegistryInterceptor() {
|
|
||||||
return new ResourceChangeListenerRegistryInterceptor();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,220 +1,27 @@
|
|||||||
package ca.uhn.fhir.jpa.starter.cr;
|
package ca.uhn.fhir.jpa.starter.cr;
|
||||||
|
|
||||||
import ca.uhn.fhir.cr.common.CodeCacheResourceChangeListener;
|
|
||||||
import ca.uhn.fhir.cr.common.CqlThreadFactory;
|
|
||||||
import ca.uhn.fhir.cr.common.ElmCacheResourceChangeListener;
|
|
||||||
import ca.uhn.fhir.cr.config.r4.ApplyOperationConfig;
|
import ca.uhn.fhir.cr.config.r4.ApplyOperationConfig;
|
||||||
import ca.uhn.fhir.cr.config.r4.CrR4Config;
|
import ca.uhn.fhir.cr.config.r4.CrR4Config;
|
||||||
import ca.uhn.fhir.cr.config.r4.ExtractOperationConfig;
|
import ca.uhn.fhir.cr.config.r4.ExtractOperationConfig;
|
||||||
import ca.uhn.fhir.cr.config.r4.PackageOperationConfig;
|
import ca.uhn.fhir.cr.config.r4.PackageOperationConfig;
|
||||||
import ca.uhn.fhir.cr.config.r4.PopulateOperationConfig;
|
import ca.uhn.fhir.cr.config.r4.PopulateOperationConfig;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.cr.config.r4.QuestionnaireOperationConfig;
|
||||||
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
|
|
||||||
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerRegistryInterceptor;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
|
||||||
import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition;
|
import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition;
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
|
||||||
import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
|
|
||||||
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.cql.engine.runtime.Code;
|
|
||||||
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.Bean;
|
|
||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.Primary;
|
|
||||||
import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService;
|
|
||||||
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Conditional({OnR4Condition.class, CrConfigCondition.class})
|
@Conditional({OnR4Condition.class, CrConfigCondition.class})
|
||||||
@Import({
|
@Import({
|
||||||
|
CrCommonConfig.class,
|
||||||
CrR4Config.class,
|
CrR4Config.class,
|
||||||
ApplyOperationConfig.class,
|
ApplyOperationConfig.class,
|
||||||
ExtractOperationConfig.class,
|
ExtractOperationConfig.class,
|
||||||
PackageOperationConfig.class,
|
PackageOperationConfig.class,
|
||||||
PopulateOperationConfig.class
|
PopulateOperationConfig.class,
|
||||||
|
QuestionnaireOperationConfig.class
|
||||||
})
|
})
|
||||||
public class StarterCrR4Config {
|
public class StarterCrR4Config {
|
||||||
private static final Logger ourLogger = LoggerFactory.getLogger(StarterCrR4Config.class);
|
|
||||||
|
|
||||||
@Primary
|
|
||||||
@Bean
|
|
||||||
public ExecutorService cqlExecutor() {
|
|
||||||
CqlThreadFactory factory = new CqlThreadFactory();
|
|
||||||
ExecutorService executor = Executors.newFixedThreadPool(2, factory);
|
|
||||||
executor = new DelegatingSecurityContextExecutorService(executor);
|
|
||||||
|
|
||||||
return executor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
CareGapsProperties careGapsProperties(CrProperties theCrProperties) {
|
|
||||||
var careGapsProperties = new CareGapsProperties();
|
|
||||||
careGapsProperties.setCareGapsReporter(theCrProperties.getCareGapsReporter());
|
|
||||||
careGapsProperties.setCareGapsCompositionSectionAuthor(theCrProperties.getCareGapsSectionAuthor());
|
|
||||||
return careGapsProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
MeasureEvaluationOptions measureEvaluationOptions(
|
|
||||||
EvaluationSettings theEvaluationSettings, Map<String, ValidationProfile> theValidationProfiles) {
|
|
||||||
MeasureEvaluationOptions measureEvalOptions = new MeasureEvaluationOptions();
|
|
||||||
measureEvalOptions.setEvaluationSettings(theEvaluationSettings);
|
|
||||||
if (measureEvalOptions.isValidationEnabled()) {
|
|
||||||
measureEvalOptions.setValidationProfiles(theValidationProfiles);
|
|
||||||
}
|
|
||||||
return measureEvalOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public EvaluationSettings evaluationSettings(
|
|
||||||
CrProperties theCrProperties,
|
|
||||||
Map<VersionedIdentifier, CompiledLibrary> theGlobalLibraryCache,
|
|
||||||
Map<ModelIdentifier, Model> theGlobalModelCache,
|
|
||||||
Map<String, List<Code>> theGlobalValueSetCache) {
|
|
||||||
var evaluationSettings = EvaluationSettings.getDefault();
|
|
||||||
var cqlOptions = evaluationSettings.getCqlOptions();
|
|
||||||
|
|
||||||
var cqlEngineOptions = cqlOptions.getCqlEngineOptions();
|
|
||||||
Set<CqlEngine.Options> options = EnumSet.noneOf(CqlEngine.Options.class);
|
|
||||||
if (theCrProperties.isCqlRuntimeEnableExpressionCaching()) {
|
|
||||||
options.add(CqlEngine.Options.EnableExpressionCaching);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isCqlRuntimeEnableValidation()) {
|
|
||||||
options.add(CqlEngine.Options.EnableValidation);
|
|
||||||
}
|
|
||||||
cqlEngineOptions.setOptions(options);
|
|
||||||
cqlOptions.setCqlEngineOptions(cqlEngineOptions);
|
|
||||||
|
|
||||||
var cqlCompilerOptions = new CqlCompilerOptions();
|
|
||||||
|
|
||||||
if (theCrProperties.isEnableDateRangeOptimization()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDateRangeOptimization);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isEnableAnnotations()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableAnnotations);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isEnableLocators()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableLocators);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isEnableResultsType()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableResultTypes);
|
|
||||||
}
|
|
||||||
cqlCompilerOptions.setVerifyOnly(theCrProperties.isCqlCompilerVerifyOnly());
|
|
||||||
if (theCrProperties.isEnableDetailedErrors()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDetailedErrors);
|
|
||||||
}
|
|
||||||
cqlCompilerOptions.setErrorLevel(theCrProperties.getCqlCompilerErrorSeverityLevel());
|
|
||||||
if (theCrProperties.isDisableListTraversal()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListTraversal);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isDisableListDemotion()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListDemotion);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isDisableListPromotion()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListPromotion);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isEnableIntervalDemotion()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalDemotion);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isEnableIntervalPromotion()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalPromotion);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isDisableMethodInvocation()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableMethodInvocation);
|
|
||||||
}
|
|
||||||
if (theCrProperties.isRequireFromKeyword()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.RequireFromKeyword);
|
|
||||||
}
|
|
||||||
cqlCompilerOptions.setValidateUnits(theCrProperties.isCqlCompilerValidateUnits());
|
|
||||||
if (theCrProperties.isDisableDefaultModelInfoLoad()) {
|
|
||||||
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableDefaultModelInfoLoad);
|
|
||||||
}
|
|
||||||
cqlCompilerOptions.setSignatureLevel(theCrProperties.getCqlCompilerSignatureLevel());
|
|
||||||
cqlCompilerOptions.setCompatibilityLevel(theCrProperties.getCqlCompilerCompatibilityLevel());
|
|
||||||
cqlCompilerOptions.setAnalyzeDataRequirements(theCrProperties.isCqlCompilerAnalyzeDataRequirements());
|
|
||||||
cqlCompilerOptions.setCollapseDataRequirements(theCrProperties.isCqlCompilerCollapseDataRequirements());
|
|
||||||
|
|
||||||
cqlOptions.setCqlCompilerOptions(cqlCompilerOptions);
|
|
||||||
evaluationSettings.setLibraryCache(theGlobalLibraryCache);
|
|
||||||
evaluationSettings.setModelCache(theGlobalModelCache);
|
|
||||||
evaluationSettings.setValueSetCache(theGlobalValueSetCache);
|
|
||||||
return evaluationSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public PostInitProviderRegisterer postInitProviderRegisterer(
|
|
||||||
RestfulServer theRestfulServer, ResourceProviderFactory theResourceProviderFactory) {
|
|
||||||
return new PostInitProviderRegisterer(theRestfulServer, theResourceProviderFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public CrProperties crProperties() {
|
|
||||||
return new CrProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Map<VersionedIdentifier, CompiledLibrary> globalLibraryCache() {
|
|
||||||
return new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Map<ModelIdentifier, Model> globalModelCache() {
|
|
||||||
return new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Map<String, List<Code>> globalValueSetCache() {
|
|
||||||
return new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ElmCacheResourceChangeListener elmCacheResourceChangeListener(
|
|
||||||
IResourceChangeListenerRegistry theResourceChangeListenerRegistry,
|
|
||||||
DaoRegistry theDaoRegistry,
|
|
||||||
EvaluationSettings theEvaluationSettings) {
|
|
||||||
ElmCacheResourceChangeListener listener =
|
|
||||||
new ElmCacheResourceChangeListener(theDaoRegistry, theEvaluationSettings.getLibraryCache());
|
|
||||||
theResourceChangeListenerRegistry.registerResourceResourceChangeListener(
|
|
||||||
"Library", SearchParameterMap.newSynchronous(), listener, 1000);
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public CodeCacheResourceChangeListener codeCacheResourceChangeListener(
|
|
||||||
IResourceChangeListenerRegistry theResourceChangeListenerRegistry,
|
|
||||||
EvaluationSettings theEvaluationSettings,
|
|
||||||
DaoRegistry theDaoRegistry) {
|
|
||||||
|
|
||||||
CodeCacheResourceChangeListener listener =
|
|
||||||
new CodeCacheResourceChangeListener(theDaoRegistry, theEvaluationSettings.getValueSetCache());
|
|
||||||
// registry
|
|
||||||
theResourceChangeListenerRegistry.registerResourceResourceChangeListener(
|
|
||||||
"ValueSet", SearchParameterMap.newSynchronous(), listener, 1000);
|
|
||||||
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ResourceChangeListenerRegistryInterceptor resourceChangeListenerRegistryInterceptor() {
|
|
||||||
return new ResourceChangeListenerRegistryInterceptor();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import ca.uhn.fhir.jpa.ips.generator.IIpsGeneratorSvc;
|
|||||||
import ca.uhn.fhir.jpa.ips.generator.IpsGeneratorSvcImpl;
|
import ca.uhn.fhir.jpa.ips.generator.IpsGeneratorSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.ips.jpa.DefaultJpaIpsGenerationStrategy;
|
import ca.uhn.fhir.jpa.ips.jpa.DefaultJpaIpsGenerationStrategy;
|
||||||
import ca.uhn.fhir.jpa.ips.provider.IpsOperationProvider;
|
import ca.uhn.fhir.jpa.ips.provider.IpsOperationProvider;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ management:
|
|||||||
spring:
|
spring:
|
||||||
main:
|
main:
|
||||||
allow-circular-references: true
|
allow-circular-references: true
|
||||||
#allow-bean-definition-overriding: true
|
|
||||||
flyway:
|
flyway:
|
||||||
enabled: false
|
enabled: false
|
||||||
baselineOnMigrate: true
|
baselineOnMigrate: true
|
||||||
@@ -78,9 +77,50 @@ hapi:
|
|||||||
### Flag is false by default, can be passed as command line argument to override.
|
### Flag is false by default, can be passed as command line argument to override.
|
||||||
cr:
|
cr:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
caregaps:
|
||||||
|
reporter: "default"
|
||||||
|
section_author: "default"
|
||||||
|
cql:
|
||||||
|
use_embedded_libraries: true
|
||||||
|
compiler:
|
||||||
|
### These are low-level compiler options.
|
||||||
|
### They are not typically needed by most users.
|
||||||
|
# validate_units: true
|
||||||
|
# verify_only: false
|
||||||
|
# compatibility_level: "1.5"
|
||||||
|
error_level: Info
|
||||||
|
signature_level: All
|
||||||
|
# analyze_data_requirements: false
|
||||||
|
# collapse_data_requirements: false
|
||||||
|
# translator_format: JSON
|
||||||
|
# enable_date_range_optimization: true
|
||||||
|
enable_annotations: true
|
||||||
|
enable_locators: true
|
||||||
|
enable_results_type: true
|
||||||
|
enable_detailed_errors: true
|
||||||
|
# disable_list_traversal: false
|
||||||
|
# disable_list_demotion: false
|
||||||
|
# enable_interval_demotion: false
|
||||||
|
# enable_interval_promotion: false
|
||||||
|
# disable_method_invocation: false
|
||||||
|
# require_from_keyword: false
|
||||||
|
# disable_default_model_info_load: false
|
||||||
|
runtime:
|
||||||
|
debug_logging_enabled: false
|
||||||
|
# enable_validation: false
|
||||||
|
# enable_expression_caching: true
|
||||||
|
terminology:
|
||||||
|
valueset_preexpansion_mode: REQUIRE # USE_IF_PRESENT, REQUIRE, IGNORE
|
||||||
|
valueset_expansion_mode: PERFORM_NAIVE_EXPANSION # AUTO, USE_EXPANSION_OPERATION, PERFORM_NAIVE_EXPANSION
|
||||||
|
valueset_membership_mode: USE_EXPANSION # AUTO, USE_VALIDATE_CODE_OPERATION, USE_EXPANSION
|
||||||
|
code_lookup_mode: USE_VALIDATE_CODE_OPERATION # AUTO, USE_VALIDATE_CODE_OPERATION, USE_CODESYSTEM_URL
|
||||||
|
data:
|
||||||
|
search_parameter_mode: FILTER_IN_MEMORY # AUTO, USE_SEARCH_PARAMETERS, FILTER_IN_MEMORY
|
||||||
|
terminology_parameter_mode: FILTER_IN_MEMORY # AUTO, USE_VALUE_SET_URL, USE_INLINE_CODES, FILTER_IN_MEMORY
|
||||||
|
profile_mode: DECLARED # ENFORCED, DECLARED, OPTIONAL, TRUST, OFF
|
||||||
|
|
||||||
cdshooks:
|
cdshooks:
|
||||||
enabled: true
|
enabled: false
|
||||||
clientIdHeaderName: client_id
|
clientIdHeaderName: client_id
|
||||||
|
|
||||||
### This enables the swagger-ui at /fhir/swagger-ui/index.html as well as the /fhir/api-docs (see https://hapifhir.io/hapi-fhir/docs/server_plain/openapi.html)
|
### This enables the swagger-ui at /fhir/swagger-ui/index.html as well as the /fhir/api-docs (see https://hapifhir.io/hapi-fhir/docs/server_plain/openapi.html)
|
||||||
|
|||||||
294
src/main/resources/cds.application.yaml
Normal file
294
src/main/resources/cds.application.yaml
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
#Uncomment the "servlet" and "context-path" lines below to make the fhir endpoint available at /example/path/fhir instead of the default value of /fhir
|
||||||
|
server:
|
||||||
|
# servlet:
|
||||||
|
# context-path: /example/path
|
||||||
|
port: 8080
|
||||||
|
#Adds the option to go to eg. http://localhost:8080/actuator/health for seeing the running configuration
|
||||||
|
#see https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints
|
||||||
|
management:
|
||||||
|
endpoints:
|
||||||
|
web:
|
||||||
|
exposure:
|
||||||
|
include: "health,prometheus"
|
||||||
|
spring:
|
||||||
|
main:
|
||||||
|
allow-circular-references: true
|
||||||
|
allow-bean-definition-overriding: true
|
||||||
|
flyway:
|
||||||
|
enabled: false
|
||||||
|
baselineOnMigrate: true
|
||||||
|
fail-on-missing-locations: false
|
||||||
|
datasource:
|
||||||
|
#url: 'jdbc:h2:file:./target/database/h2'
|
||||||
|
url: jdbc:h2:mem:test_mem
|
||||||
|
username: sa
|
||||||
|
password: null
|
||||||
|
driverClassName: org.h2.Driver
|
||||||
|
max-active: 15
|
||||||
|
|
||||||
|
# database connection pool size
|
||||||
|
hikari:
|
||||||
|
maximum-pool-size: 10
|
||||||
|
jpa:
|
||||||
|
properties:
|
||||||
|
hibernate.format_sql: false
|
||||||
|
hibernate.show_sql: false
|
||||||
|
|
||||||
|
#Hibernate dialect is automatically detected except Postgres and H2.
|
||||||
|
#If using H2, then supply the value of ca.uhn.fhir.jpa.model.dialect.HapiFhirH2Dialect
|
||||||
|
#If using postgres, then supply the value of ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect
|
||||||
|
hibernate.dialect: ca.uhn.fhir.jpa.model.dialect.HapiFhirH2Dialect
|
||||||
|
# hibernate.hbm2ddl.auto: update
|
||||||
|
# hibernate.jdbc.batch_size: 20
|
||||||
|
# hibernate.cache.use_query_cache: false
|
||||||
|
# hibernate.cache.use_second_level_cache: false
|
||||||
|
# hibernate.cache.use_structured_entries: false
|
||||||
|
# hibernate.cache.use_minimal_puts: false
|
||||||
|
|
||||||
|
### These settings will enable fulltext search with lucene or elastic
|
||||||
|
hibernate.search.enabled: true
|
||||||
|
### lucene parameters
|
||||||
|
# hibernate.search.backend.type: lucene
|
||||||
|
# hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiHSearchAnalysisConfigurers$HapiLuceneAnalysisConfigurer
|
||||||
|
# hibernate.search.backend.directory.type: local-filesystem
|
||||||
|
# hibernate.search.backend.directory.root: target/lucenefiles
|
||||||
|
# hibernate.search.backend.lucene_version: lucene_current
|
||||||
|
### elastic parameters ===> see also elasticsearch section below <===
|
||||||
|
# hibernate.search.backend.type: elasticsearch
|
||||||
|
# hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiHSearchAnalysisConfigurers$HapiElasticAnalysisConfigurer
|
||||||
|
hapi:
|
||||||
|
fhir:
|
||||||
|
### This flag when enabled to true, will avail evaluate measure operations from CR Module.
|
||||||
|
### Flag is false by default, can be passed as command line argument to override.
|
||||||
|
cr:
|
||||||
|
enabled: true
|
||||||
|
caregaps:
|
||||||
|
reporter: "default"
|
||||||
|
section_author: "default"
|
||||||
|
cql:
|
||||||
|
use_embedded_libraries: true
|
||||||
|
compiler:
|
||||||
|
### These are low-level compiler options.
|
||||||
|
### They are not typically needed by most users.
|
||||||
|
# validate_units: true
|
||||||
|
# verify_only: false
|
||||||
|
# compatibility_level: "1.5"
|
||||||
|
error_level: Info
|
||||||
|
signature_level: All
|
||||||
|
# analyze_data_requirements: false
|
||||||
|
# collapse_data_requirements: false
|
||||||
|
# translator_format: JSON
|
||||||
|
# enable_date_range_optimization: true
|
||||||
|
enable_annotations: true
|
||||||
|
enable_locators: true
|
||||||
|
enable_results_type: true
|
||||||
|
enable_detailed_errors: true
|
||||||
|
# disable_list_traversal: false
|
||||||
|
# disable_list_demotion: false
|
||||||
|
# enable_interval_demotion: false
|
||||||
|
# enable_interval_promotion: false
|
||||||
|
# disable_method_invocation: false
|
||||||
|
# require_from_keyword: false
|
||||||
|
# disable_default_model_info_load: false
|
||||||
|
runtime:
|
||||||
|
debug_logging_enabled: false
|
||||||
|
# enable_validation: false
|
||||||
|
# enable_expression_caching: true
|
||||||
|
terminology:
|
||||||
|
valueset_preexpansion_mode: REQUIRE # USE_IF_PRESENT, REQUIRE, IGNORE
|
||||||
|
valueset_expansion_mode: PERFORM_NAIVE_EXPANSION # AUTO, USE_EXPANSION_OPERATION, PERFORM_NAIVE_EXPANSION
|
||||||
|
valueset_membership_mode: USE_EXPANSION # AUTO, USE_VALIDATE_CODE_OPERATION, USE_EXPANSION
|
||||||
|
code_lookup_mode: USE_CODESYSTEM_URL # AUTO, USE_VALIDATE_CODE_OPERATION, USE_CODESYSTEM_URL
|
||||||
|
data:
|
||||||
|
search_parameter_mode: USE_SEARCH_PARAMETERS # AUTO, USE_SEARCH_PARAMETERS, FILTER_IN_MEMORY
|
||||||
|
terminology_parameter_mode: FILTER_IN_MEMORY # AUTO, USE_VALUE_SET_URL, USE_INLINE_CODES, FILTER_IN_MEMORY
|
||||||
|
profile_mode: OFF # ENFORCED, DECLARED, OPTIONAL, TRUST, OFF
|
||||||
|
|
||||||
|
cdshooks:
|
||||||
|
enabled: true
|
||||||
|
clientIdHeaderName: client_id
|
||||||
|
|
||||||
|
### This enables the swagger-ui at /fhir/swagger-ui/index.html as well as the /fhir/api-docs (see https://hapifhir.io/hapi-fhir/docs/server_plain/openapi.html)
|
||||||
|
openapi_enabled: true
|
||||||
|
### This is the FHIR version. Choose between, DSTU2, DSTU3, R4 or R5
|
||||||
|
fhir_version: R4
|
||||||
|
### Flag is false by default. This flag enables runtime installation of IG's.
|
||||||
|
ig_runtime_upload_enabled: false
|
||||||
|
### This flag when enabled to true, will avail evaluate measure operations from CR Module.
|
||||||
|
|
||||||
|
### enable to use the ApacheProxyAddressStrategy which uses X-Forwarded-* headers
|
||||||
|
### to determine the FHIR server address
|
||||||
|
# use_apache_address_strategy: false
|
||||||
|
### forces the use of the https:// protocol for the returned server address.
|
||||||
|
### alternatively, it may be set using the X-Forwarded-Proto header.
|
||||||
|
# use_apache_address_strategy_https: false
|
||||||
|
### enables the server to overwrite defaults on HTML, css, etc. under the url pattern of eg. /content/custom **
|
||||||
|
### Folder with custom content MUST be named custom. If omitted then default content applies
|
||||||
|
#custom_content_path: ./custom
|
||||||
|
### enables the server host custom content. If e.g. the value ./configs/app is supplied then the content
|
||||||
|
### will be served under /web/app
|
||||||
|
#app_content_path: ./configs/app
|
||||||
|
### enable to set the Server URL
|
||||||
|
# server_address: http://hapi.fhir.org/baseR4
|
||||||
|
# defer_indexing_for_codesystems_of_size: 101
|
||||||
|
# install_transitive_ig_dependencies: true
|
||||||
|
#implementationguides:
|
||||||
|
### example from registry (packages.fhir.org)
|
||||||
|
# swiss:
|
||||||
|
# name: swiss.mednet.fhir
|
||||||
|
# version: 0.8.0
|
||||||
|
# reloadExisting: false
|
||||||
|
# installMode: STORE_AND_INSTALL
|
||||||
|
# example not from registry
|
||||||
|
# ips_1_0_0:
|
||||||
|
# packageUrl: https://build.fhir.org/ig/HL7/fhir-ips/package.tgz
|
||||||
|
# name: hl7.fhir.uv.ips
|
||||||
|
# version: 1.0.0
|
||||||
|
# supported_resource_types:
|
||||||
|
# - Patient
|
||||||
|
# - Observation
|
||||||
|
##################################################
|
||||||
|
# Allowed Bundle Types for persistence (defaults are: COLLECTION,DOCUMENT,MESSAGE)
|
||||||
|
##################################################
|
||||||
|
# allowed_bundle_types: COLLECTION,DOCUMENT,MESSAGE,TRANSACTION,TRANSACTIONRESPONSE,BATCH,BATCHRESPONSE,HISTORY,SEARCHSET
|
||||||
|
# allow_cascading_deletes: true
|
||||||
|
# allow_contains_searches: true
|
||||||
|
# allow_external_references: true
|
||||||
|
# allow_multiple_delete: true
|
||||||
|
# allow_override_default_search_params: true
|
||||||
|
# auto_create_placeholder_reference_targets: false
|
||||||
|
### tells the server to automatically append the current version of the target resource to references at these paths
|
||||||
|
# auto_version_reference_at_paths: Device.patient, Device.location, Device.parent, DeviceMetric.parent, DeviceMetric.source, Observation.device, Observation.subject
|
||||||
|
# ips_enabled: false
|
||||||
|
# default_encoding: JSON
|
||||||
|
# default_pretty_print: true
|
||||||
|
# default_page_size: 20
|
||||||
|
# delete_expunge_enabled: true
|
||||||
|
# enable_repository_validating_interceptor: true
|
||||||
|
# enable_index_missing_fields: false
|
||||||
|
# enable_index_of_type: true
|
||||||
|
# enable_index_contained_resource: false
|
||||||
|
# resource_dbhistory_enabled: false
|
||||||
|
### !!Extended Lucene/Elasticsearch Indexing is still a experimental feature, expect some features (e.g. _total=accurate) to not work as expected!!
|
||||||
|
### more information here: https://hapifhir.io/hapi-fhir/docs/server_jpa/elastic.html
|
||||||
|
advanced_lucene_indexing: false
|
||||||
|
bulk_export_enabled: false
|
||||||
|
bulk_import_enabled: false
|
||||||
|
# language_search_parameter_enabled: true
|
||||||
|
# enforce_referential_integrity_on_delete: false
|
||||||
|
# This is an experimental feature, and does not fully support _total and other FHIR features.
|
||||||
|
# enforce_referential_integrity_on_delete: false
|
||||||
|
# enforce_referential_integrity_on_write: false
|
||||||
|
# etag_support_enabled: true
|
||||||
|
# expunge_enabled: true
|
||||||
|
# client_id_strategy: ALPHANUMERIC
|
||||||
|
# server_id_strategy: SEQUENTIAL_NUMERIC
|
||||||
|
# fhirpath_interceptor_enabled: false
|
||||||
|
# filter_search_enabled: true
|
||||||
|
# graphql_enabled: true
|
||||||
|
narrative_enabled: false
|
||||||
|
mdm_enabled: false
|
||||||
|
mdm_rules_json_location: "mdm-rules.json"
|
||||||
|
# local_base_urls:
|
||||||
|
# - https://hapi.fhir.org/baseR4
|
||||||
|
logical_urls:
|
||||||
|
- http://terminology.hl7.org/*
|
||||||
|
- https://terminology.hl7.org/*
|
||||||
|
- http://snomed.info/*
|
||||||
|
- https://snomed.info/*
|
||||||
|
- http://unitsofmeasure.org/*
|
||||||
|
- https://unitsofmeasure.org/*
|
||||||
|
- http://loinc.org/*
|
||||||
|
- https://loinc.org/*
|
||||||
|
# partitioning:
|
||||||
|
# allow_references_across_partitions: false
|
||||||
|
# partitioning_include_in_search_hashes: false
|
||||||
|
cors:
|
||||||
|
allow_Credentials: true
|
||||||
|
# These are allowed_origin patterns, see: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/cors/CorsConfiguration.html#setAllowedOriginPatterns-java.util.List-
|
||||||
|
allowed_origin:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
# Search coordinator thread pool sizes
|
||||||
|
search-coord-core-pool-size: 20
|
||||||
|
search-coord-max-pool-size: 100
|
||||||
|
search-coord-queue-capacity: 200
|
||||||
|
|
||||||
|
# comma-separated package names, will be @ComponentScan'ed by Spring to allow for creating custom Spring beans
|
||||||
|
#custom-bean-packages:
|
||||||
|
|
||||||
|
# comma-separated list of fully qualified interceptor classes.
|
||||||
|
# classes listed here will be fetched from the Spring context when combined with 'custom-bean-packages',
|
||||||
|
# or will be instantiated via reflection using an no-arg contructor; then registered with the server
|
||||||
|
#custom-interceptor-classes:
|
||||||
|
|
||||||
|
# comma-separated list of fully qualified provider classes.
|
||||||
|
# classes listed here will be fetched from the Spring context when combined with 'custom-bean-packages',
|
||||||
|
# or will be instantiated via reflection using an no-arg contructor; then registered with the server
|
||||||
|
#custom-provider-classes:
|
||||||
|
|
||||||
|
# Threadpool size for BATCH'ed GETs in a bundle.
|
||||||
|
# bundle_batch_pool_size: 10
|
||||||
|
# bundle_batch_pool_max_size: 50
|
||||||
|
|
||||||
|
# logger:
|
||||||
|
# error_format: 'ERROR - ${requestVerb} ${requestUrl}'
|
||||||
|
# format: >-
|
||||||
|
# Path[${servletPath}] Source[${requestHeader.x-forwarded-for}]
|
||||||
|
# Operation[${operationType} ${operationName} ${idOrResourceName}]
|
||||||
|
# UA[${requestHeader.user-agent}] Params[${requestParameters}]
|
||||||
|
# ResponseEncoding[${responseEncodingNoDefault}]
|
||||||
|
# log_exceptions: true
|
||||||
|
# name: fhirtest.access
|
||||||
|
# max_binary_size: 104857600
|
||||||
|
# max_page_size: 200
|
||||||
|
# retain_cached_searches_mins: 60
|
||||||
|
# reuse_cached_search_results_millis: 60000
|
||||||
|
tester:
|
||||||
|
home:
|
||||||
|
name: Local Tester
|
||||||
|
server_address: 'http://localhost:8080/fhir'
|
||||||
|
refuse_to_fetch_third_party_urls: false
|
||||||
|
fhir_version: R4
|
||||||
|
global:
|
||||||
|
name: Global Tester
|
||||||
|
server_address: "http://hapi.fhir.org/baseR4"
|
||||||
|
refuse_to_fetch_third_party_urls: false
|
||||||
|
fhir_version: R4
|
||||||
|
# validation:
|
||||||
|
# requests_enabled: true
|
||||||
|
# responses_enabled: true
|
||||||
|
# binary_storage_enabled: true
|
||||||
|
inline_resource_storage_below_size: 4000
|
||||||
|
# bulk_export_enabled: true
|
||||||
|
# subscription:
|
||||||
|
# resthook_enabled: true
|
||||||
|
# websocket_enabled: false
|
||||||
|
# email:
|
||||||
|
# from: some@test.com
|
||||||
|
# host: google.com
|
||||||
|
# port:
|
||||||
|
# username:
|
||||||
|
# password:
|
||||||
|
# auth:
|
||||||
|
# startTlsEnable:
|
||||||
|
# startTlsRequired:
|
||||||
|
# quitWait:
|
||||||
|
# lastn_enabled: true
|
||||||
|
# store_resource_in_lucene_index_enabled: true
|
||||||
|
### This is configuration for normalized quantity search level default is 0
|
||||||
|
### 0: NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED - default
|
||||||
|
### 1: NORMALIZED_QUANTITY_STORAGE_SUPPORTED
|
||||||
|
### 2: NORMALIZED_QUANTITY_SEARCH_SUPPORTED
|
||||||
|
# normalized_quantity_search_level: 2
|
||||||
|
#elasticsearch:
|
||||||
|
# debug:
|
||||||
|
# pretty_print_json_log: false
|
||||||
|
# refresh_after_write: false
|
||||||
|
# enabled: false
|
||||||
|
# password: SomePassword
|
||||||
|
# required_index_status: YELLOW
|
||||||
|
# rest_url: 'localhost:9200'
|
||||||
|
# protocol: 'http'
|
||||||
|
# schema_management_strategy: CREATE
|
||||||
|
# username: SomeUsername
|
||||||
@@ -1,23 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration scan="true" scanPeriod="30 seconds">
|
<configuration scan="true" scanPeriod="30 seconds">
|
||||||
|
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
|
||||||
<level>INFO</level>
|
|
||||||
</filter>
|
|
||||||
<encoder>
|
|
||||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] %msg%n</pattern>
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<logger name="org.springframework.beans" level="INFO">
|
|
||||||
<appender-ref ref="STDOUT" />
|
|
||||||
</logger>
|
|
||||||
<logger name="org.springframework.core" level="INFO">
|
|
||||||
<appender-ref ref="STDOUT" />
|
|
||||||
</logger>
|
|
||||||
|
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="CONSOLE" />
|
||||||
</root>
|
</root>
|
||||||
|
<logger name = "org.opencds.cqf.cql.engine.debug" level="DEBUG"/>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
242
src/test/java/ca/uhn/fhir/jpa/starter/CdsHooksServletIT.java
Normal file
242
src/test/java/ca/uhn/fhir/jpa/starter/CdsHooksServletIT.java
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.cr.config.RepositoryConfig;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.config.NicknameServiceConfig;
|
||||||
|
import ca.uhn.fhir.jpa.starter.cdshooks.StarterCdsHooksConfig;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||||
|
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.api.ICdsServiceRegistry;
|
||||||
|
import ca.uhn.hapi.fhir.cdshooks.config.CdsHooksConfig;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.awaitility.Awaitility.await;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||||
|
classes = {
|
||||||
|
Application.class,
|
||||||
|
NicknameServiceConfig.class,
|
||||||
|
RepositoryConfig.class,
|
||||||
|
CdsHooksConfig.class,
|
||||||
|
StarterCdsHooksConfig.class
|
||||||
|
}, properties = {
|
||||||
|
"spring.profiles.include=storageSettingsTest",
|
||||||
|
"spring.datasource.url=jdbc:h2:mem:dbr4",
|
||||||
|
"hapi.fhir.enable_repository_validating_interceptor=true",
|
||||||
|
"hapi.fhir.fhir_version=r4",
|
||||||
|
"hapi.fhir.cr.enabled=true",
|
||||||
|
"hapi.fhir.cr.caregaps.section_author=Organization/alphora-author",
|
||||||
|
"hapi.fhir.cr.caregaps.reporter=Organization/alphora",
|
||||||
|
"hapi.fhir.cdshooks.enabled=true",
|
||||||
|
"spring.main.allow-bean-definition-overriding=true"})
|
||||||
|
class CdsHooksServletIT implements IServerSupport {
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CdsHooksServletIT.class);
|
||||||
|
private final FhirContext ourCtx = FhirContext.forR4Cached();
|
||||||
|
private final IParser ourParser = ourCtx.newJsonParser();
|
||||||
|
private IGenericClient ourClient;
|
||||||
|
private String ourCdsBase;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DaoRegistry myDaoRegistry;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ICdsServiceRegistry myCdsServiceRegistry;
|
||||||
|
|
||||||
|
@LocalServerPort
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
private String ourServerBase;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void beforeEach() {
|
||||||
|
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||||
|
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||||
|
ourServerBase = "http://localhost:" + port + "/fhir/";
|
||||||
|
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||||
|
ourCdsBase = "http://localhost:" + port + "/cds-services";
|
||||||
|
|
||||||
|
var cdsServicesJson = myCdsServiceRegistry.getCdsServicesJson();
|
||||||
|
if (cdsServicesJson != null && cdsServicesJson.getServices() != null && !cdsServicesJson.getServices().isEmpty()) {
|
||||||
|
var services = cdsServicesJson.getServices();
|
||||||
|
for (int i = 0; i < services.size(); i++) {
|
||||||
|
myCdsServiceRegistry.unregisterService(services.get(i).getId(), "CR");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean hasCdsServices() throws IOException {
|
||||||
|
var response = callCdsServicesDiscovery();
|
||||||
|
return response.getEntity().getContentLength() > 21 || response.getEntity().isChunked();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CloseableHttpResponse callCdsServicesDiscovery() {
|
||||||
|
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||||
|
HttpGet request = new HttpGet(ourCdsBase);
|
||||||
|
request.addHeader("Content-Type", "application/json");
|
||||||
|
return httpClient.execute(request);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
fail(ioe.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetCdsServices() {
|
||||||
|
var response = callCdsServicesDiscovery();
|
||||||
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCdsHooks() throws IOException, InterruptedException {
|
||||||
|
loadBundle("r4/HelloWorld-Bundle.json", ourCtx, ourClient);
|
||||||
|
await().atMost(10000, TimeUnit.MILLISECONDS).until(() -> hasCdsServices());
|
||||||
|
var cdsRequest = "{\n" +
|
||||||
|
" \"hookInstance\": \"12345\",\n" +
|
||||||
|
" \"hook\": \"patient-view\",\n" +
|
||||||
|
" \"context\": {\n" +
|
||||||
|
" \"userId\": \"Practitioner/example\",\n" +
|
||||||
|
" \"patientId\": \"Patient/example-hello-world\"\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"prefetch\": {\n" +
|
||||||
|
" \"item1\": {\n" +
|
||||||
|
" \"resourceType\": \"Patient\",\n" +
|
||||||
|
" \"id\": \"example-hello-world\",\n" +
|
||||||
|
" \"gender\": \"male\",\n" +
|
||||||
|
" \"birthDate\": \"2000-01-01\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}";
|
||||||
|
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||||
|
HttpPost request = new HttpPost(ourCdsBase + "/hello-world");
|
||||||
|
request.setEntity(new StringEntity(cdsRequest));
|
||||||
|
request.addHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
CloseableHttpResponse httpResponse = httpClient.execute(request);
|
||||||
|
String result = EntityUtils.toString(httpResponse.getEntity());
|
||||||
|
Gson gsonResponse = new Gson();
|
||||||
|
JsonObject response = gsonResponse.fromJson(result, JsonObject.class);
|
||||||
|
assertNotNull(response);
|
||||||
|
JsonArray cards = response.getAsJsonArray("cards");
|
||||||
|
assertEquals(1, cards.size());
|
||||||
|
assertEquals("\"Hello World!\"", cards.get(0).getAsJsonObject().get("summary").toString());
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
fail(ioe.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRec10() throws IOException {
|
||||||
|
loadBundle("r4/opioidcds-10-order-sign-bundle.json", ourCtx, ourClient);
|
||||||
|
await().atMost(20000, TimeUnit.MILLISECONDS).until(() -> hasCdsServices());
|
||||||
|
var fhirServer = " \"fhirServer\": " + "\"" + ourServerBase + "\"" + ",\n";
|
||||||
|
var cdsRequest = "{\n" +
|
||||||
|
" \"hookInstance\": \"055b009c-4a7d-4db4-a35e-0e5198918ed1\",\n" +
|
||||||
|
" \"hook\": \"order-sign\",\n" +
|
||||||
|
fhirServer +
|
||||||
|
" \"context\": {\n" +
|
||||||
|
" \"patientId\": \"example-rec-10-order-sign-illicit-POS-Cocaine-drugs\",\n" +
|
||||||
|
" \"userId\": \"COREPRACTITIONER1\",\n" +
|
||||||
|
" \"draftOrders\": {\n" +
|
||||||
|
" \"resourceType\": \"Bundle\",\n" +
|
||||||
|
" \"entry\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"resource\": {\n" +
|
||||||
|
" \"resourceType\": \"MedicationRequest\",\n" +
|
||||||
|
" \"id\": \"request-123\",\n" +
|
||||||
|
" \"status\": \"draft\",\n" +
|
||||||
|
" \"subject\": {\n" +
|
||||||
|
" \"reference\": \"Patient/example-rec-10-order-sign-illicit-POS-Cocaine-drugs\"\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"authoredOn\": \"2024-03-27\",\n" +
|
||||||
|
" \"dosageInstruction\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"timing\": {\n" +
|
||||||
|
" \"repeat\": {\n" +
|
||||||
|
" \"frequency\": 1,\n" +
|
||||||
|
" \"period\": 1,\n" +
|
||||||
|
" \"periodUnit\": \"d\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"doseAndRate\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"doseQuantity\": {\n" +
|
||||||
|
" \"value\": 1,\n" +
|
||||||
|
" \"system\": \"http://unitsofmeasure.org\",\n" +
|
||||||
|
" \"code\": \"{pill}\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ],\n" +
|
||||||
|
" \"dispenseRequest\": {\n" +
|
||||||
|
" \"expectedSupplyDuration\": {\n" +
|
||||||
|
" \"value\": 90,\n" +
|
||||||
|
" \"unit\": \"days\",\n" +
|
||||||
|
" \"system\": \"http://unitsofmeasure.org\",\n" +
|
||||||
|
" \"code\": \"d\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"intent\": \"order\",\n" +
|
||||||
|
" \"category\": {\n" +
|
||||||
|
" \"coding\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"system\": \"http://terminology.hl7.org/CodeSystem/medicationrequest-category\",\n" +
|
||||||
|
" \"code\": \"community\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"medicationCodeableConcept\": {\n" +
|
||||||
|
" \"coding\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"system\": \"http://www.nlm.nih.gov/research/umls/rxnorm\",\n" +
|
||||||
|
" \"code\": \"1049502\",\n" +
|
||||||
|
" \"display\": \"12 HR oxycodone hydrochloride 10 MG Extended Release Oral Tablet\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}";
|
||||||
|
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||||
|
HttpPost request = new HttpPost(ourCdsBase + "/opioidcds-10-order-sign");
|
||||||
|
request.setEntity(new StringEntity(cdsRequest));
|
||||||
|
request.addHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
CloseableHttpResponse httpResponse = httpClient.execute(request);
|
||||||
|
String result = EntityUtils.toString(httpResponse.getEntity());
|
||||||
|
Gson gsonResponse = new Gson();
|
||||||
|
JsonObject response = gsonResponse.fromJson(result, JsonObject.class);
|
||||||
|
assertNotNull(response);
|
||||||
|
JsonArray cards = response.getAsJsonArray("cards");
|
||||||
|
assertEquals(0, cards.size());
|
||||||
|
// assertEquals("\"Hello World!\"", cards.get(0).getAsJsonObject().get("summary").toString());
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
fail(ioe.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -151,13 +151,6 @@ class ExampleServerDstu3IT implements IServerSupport {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bundle loadBundle(String theLocation, FhirContext theCtx, IGenericClient theClient) throws IOException {
|
|
||||||
String json = stringFromResource(theLocation);
|
|
||||||
Bundle bundle = (Bundle) theCtx.newJsonParser().parseResource(json);
|
|
||||||
Bundle result = theClient.transaction().withBundle(bundle).execute();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testWebsocketSubscription() throws Exception {
|
void testWebsocketSubscription() throws Exception {
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ import static org.opencds.cqf.fhir.utility.r4.Parameters.stringPart;
|
|||||||
"hapi.fhir.subscription.websocket_enabled=true",
|
"hapi.fhir.subscription.websocket_enabled=true",
|
||||||
//"hapi.fhir.mdm_enabled=true",
|
//"hapi.fhir.mdm_enabled=true",
|
||||||
"hapi.fhir.cr.enabled=true",
|
"hapi.fhir.cr.enabled=true",
|
||||||
"hapi.fhir.cr.caregaps_section_author=Organization/alphora-author",
|
"hapi.fhir.cr.caregaps.section_author=Organization/alphora-author",
|
||||||
"hapi.fhir.cr.caregaps_reporter=Organization/alphora",
|
"hapi.fhir.cr.caregaps.reporter=Organization/alphora",
|
||||||
"hapi.fhir.implementationguides.dk-core.name=hl7.fhir.dk.core",
|
"hapi.fhir.implementationguides.dk-core.name=hl7.fhir.dk.core",
|
||||||
"hapi.fhir.implementationguides.dk-core.version=1.1.0",
|
"hapi.fhir.implementationguides.dk-core.version=1.1.0",
|
||||||
"hapi.fhir.auto_create_placeholder_reference_targets=true",
|
"hapi.fhir.auto_create_placeholder_reference_targets=true",
|
||||||
@@ -130,13 +130,6 @@ class ExampleServerR4IT implements IServerSupport {
|
|||||||
assertEquals(measureUrl + "|0.0.003", 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 {
|
|
||||||
String json = stringFromResource(theLocation);
|
|
||||||
org.hl7.fhir.r4.model.Bundle bundle = (org.hl7.fhir.r4.model.Bundle) theCtx.newJsonParser().parseResource(json);
|
|
||||||
org.hl7.fhir.r4.model.Bundle result = theClient.transaction().withBundle(bundle).execute();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Parameters runCqlExecution(Parameters parameters) {
|
public Parameters runCqlExecution(Parameters parameters) {
|
||||||
|
|
||||||
var results = ourClient.operation().onServer()
|
var results = ourClient.operation().onServer()
|
||||||
@@ -274,8 +267,8 @@ class ExampleServerR4IT implements IServerSupport {
|
|||||||
@Test
|
@Test
|
||||||
void testCareGaps() throws IOException {
|
void testCareGaps() throws IOException {
|
||||||
|
|
||||||
var reporter = crProperties.getCareGapsReporter();
|
var reporter = crProperties.getCareGaps().getReporter();
|
||||||
var author = crProperties.getCareGapsSectionAuthor();
|
var author = crProperties.getCareGaps().getSection_author();
|
||||||
|
|
||||||
assertTrue(reporter.equals("Organization/alphora"));
|
assertTrue(reporter.equals("Organization/alphora"));
|
||||||
assertTrue(author.equals("Organization/alphora-author"));
|
assertTrue(author.equals("Organization/alphora-author"));
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package ca.uhn.fhir.jpa.starter;
|
|||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
|
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.springframework.core.io.DefaultResourceLoader;
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
@@ -28,6 +30,12 @@ public interface IServerSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default IBaseBundle loadBundle(String theLocation, FhirContext theFhirContext, IGenericClient theClient) throws IOException {
|
||||||
|
String json = stringFromResource(theLocation);
|
||||||
|
IBaseBundle bundle = (IBaseBundle) theFhirContext.newJsonParser().parseResource(json);
|
||||||
|
return theClient.transaction().withBundle(bundle).execute();
|
||||||
|
}
|
||||||
|
|
||||||
default String stringFromResource(String theLocation) throws IOException {
|
default String stringFromResource(String theLocation) throws IOException {
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
if (theLocation.startsWith(File.separator)) {
|
if (theLocation.startsWith(File.separator)) {
|
||||||
|
|||||||
309
src/test/resources/r4/HelloWorld-Bundle.json
Normal file
309
src/test/resources/r4/HelloWorld-Bundle.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user