Hapi cr codecache (#5360)

* WIP code cache config

* WIP test

* Passing unit test

* cachelistener IT

* hardening cache listener tests

* cache listener fixes & tests, measureService migration, add reporter parameter to r4

* fix ELMCache listener to match on version, update test, remove reporter parameter

* edit inline notes

* changelog, version bump, spotless apply

---------

Co-authored-by: Jonathan Percival <jonathan.i.percival@gmail.com>
This commit is contained in:
Justin McKelvy 2023-10-11 12:47:52 -06:00 committed by GitHub
parent 88e9780004
commit c832cf0507
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
96 changed files with 6063 additions and 503 deletions

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<packaging>pom</packaging>
<name>HAPI FHIR BOM</name>
@ -12,7 +12,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -0,0 +1,4 @@
---
type: fix
issue: 5356
title: "Clinical reasoning bug that did not invalidate resources in repository api global caches for terminology and libraries when updates/deletes were made."

View File

@ -11,7 +11,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,7 @@
<parent>
<artifactId>hapi-fhir-serviceloaders</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,7 @@
<parent>
<artifactId>hapi-fhir-serviceloaders</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -21,7 +21,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-caching-api</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
</dependency>
<dependency>

View File

@ -7,7 +7,7 @@
<parent>
<artifactId>hapi-fhir-serviceloaders</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,7 @@
<parent>
<artifactId>hapi-fhir</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>hapi-deployable-pom</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -25,7 +25,6 @@ import ca.uhn.fhir.jpa.cache.IResourceChangeEvent;
import ca.uhn.fhir.jpa.cache.IResourceChangeListener;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import org.hl7.elm.r1.VersionedIdentifier;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.opencds.cqf.cql.engine.runtime.Code;
@ -45,14 +44,13 @@ public class CodeCacheResourceChangeListener implements IResourceChangeListener
org.slf4j.LoggerFactory.getLogger(CodeCacheResourceChangeListener.class);
private final IFhirResourceDao<?> myValueSetDao;
private final Map<VersionedIdentifier, List<Code>> myGlobalCodeCache;
private final Map<String, List<Code>> myGlobalValueSetCache;
private final Function<IBaseResource, String> myUrlFunction;
private final Function<IBaseResource, String> myVersionFunction;
public CodeCacheResourceChangeListener(
DaoRegistry theDaoRegistry, Map<VersionedIdentifier, List<Code>> theGlobalCodeCache) {
public CodeCacheResourceChangeListener(DaoRegistry theDaoRegistry, Map<String, List<Code>> theGlobalValueSetCache) {
this.myValueSetDao = theDaoRegistry.getResourceDao("ValueSet");
this.myGlobalCodeCache = theGlobalCodeCache;
this.myGlobalValueSetCache = theGlobalValueSetCache;
this.myUrlFunction = Reflections.getUrlFunction(myValueSetDao.getResourceType());
this.myVersionFunction = Reflections.getVersionFunction(myValueSetDao.getResourceType());
}
@ -89,7 +87,7 @@ public class CodeCacheResourceChangeListener implements IResourceChangeListener
IBaseResource valueSet;
try {
valueSet = this.myValueSetDao.read(theId);
valueSet = this.myValueSetDao.read(theId.toUnqualifiedVersionless());
}
// This happens when a Library is deleted entirely, so it's impossible to look up
// name and version.
@ -97,13 +95,20 @@ public class CodeCacheResourceChangeListener implements IResourceChangeListener
ourLog.debug(
"Failed to locate resource {} to look up url and version. Clearing all codes from cache.",
theId.getValueAsString());
this.myGlobalCodeCache.clear();
myGlobalValueSetCache.clear();
return;
}
String url = this.myUrlFunction.apply(valueSet);
String version = this.myVersionFunction.apply(valueSet);
this.myGlobalCodeCache.remove(new VersionedIdentifier().withId(url).withVersion(version));
var valuesets = myGlobalValueSetCache.keySet();
for (String key : valuesets) {
var urlKey = key;
if (urlKey.contains(url)) {
myGlobalValueSetCache.remove(key);
ourLog.warn("Successfully removed valueSet from ValueSetCache: " + url + " due to updated resource");
}
}
}
}

View File

@ -27,9 +27,9 @@ import ca.uhn.fhir.cr.config.ProviderSelector;
import ca.uhn.fhir.cr.config.RepositoryConfig;
import ca.uhn.fhir.cr.dstu3.IMeasureServiceFactory;
import ca.uhn.fhir.cr.dstu3.measure.MeasureOperationsProvider;
import ca.uhn.fhir.cr.dstu3.measure.MeasureService;
import ca.uhn.fhir.rest.server.RestfulServer;
import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions;
import org.opencds.cqf.fhir.cr.measure.dstu3.Dstu3MeasureService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -45,7 +45,7 @@ public class CrDstu3Config {
@Bean
IMeasureServiceFactory dstu3MeasureServiceFactory(
IRepositoryFactory theRepositoryFactory, MeasureEvaluationOptions theEvaluationOptions) {
return rd -> new MeasureService(theRepositoryFactory.create(rd), theEvaluationOptions);
return rd -> new Dstu3MeasureService(theRepositoryFactory.create(rd), theEvaluationOptions);
}
@Bean

View File

@ -32,7 +32,6 @@ import ca.uhn.fhir.cr.r4.ISubmitDataProcessorFactory;
import ca.uhn.fhir.cr.r4.cqlexecution.CqlExecutionOperationProvider;
import ca.uhn.fhir.cr.r4.measure.CareGapsOperationProvider;
import ca.uhn.fhir.cr.r4.measure.MeasureOperationsProvider;
import ca.uhn.fhir.cr.r4.measure.MeasureService;
import ca.uhn.fhir.cr.r4.measure.SubmitDataProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import org.opencds.cqf.fhir.cql.EvaluationSettings;
@ -40,6 +39,7 @@ import org.opencds.cqf.fhir.cr.cql.r4.R4CqlExecutionService;
import org.opencds.cqf.fhir.cr.measure.CareGapsProperties;
import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions;
import org.opencds.cqf.fhir.cr.measure.r4.R4CareGapsService;
import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureService;
import org.opencds.cqf.fhir.cr.measure.r4.R4SubmitDataService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
@ -58,7 +58,7 @@ public class CrR4Config {
@Bean
IMeasureServiceFactory r4MeasureServiceFactory(
IRepositoryFactory theRepositoryFactory, MeasureEvaluationOptions theEvaluationOptions) {
return rd -> new MeasureService(theRepositoryFactory.create(rd), theEvaluationOptions);
return rd -> new R4MeasureService(theRepositoryFactory.create(rd), theEvaluationOptions);
}
@Bean

View File

@ -19,10 +19,10 @@
*/
package ca.uhn.fhir.cr.dstu3;
import ca.uhn.fhir.cr.dstu3.measure.MeasureService;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.opencds.cqf.fhir.cr.measure.dstu3.Dstu3MeasureService;
@FunctionalInterface
public interface IMeasureServiceFactory {
MeasureService create(RequestDetails theRequestDetails);
Dstu3MeasureService create(RequestDetails theRequestDetails);
}

View File

@ -1,158 +0,0 @@
/*-
* #%L
* HAPI FHIR - Clinical Reasoning
* %%
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.cr.dstu3.measure;
import ca.uhn.fhir.util.BundleBuilder;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.ContactDetail;
import org.hl7.fhir.dstu3.model.ContactPoint;
import org.hl7.fhir.dstu3.model.Endpoint;
import org.hl7.fhir.dstu3.model.Enumerations;
import org.hl7.fhir.dstu3.model.Extension;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.MeasureReport;
import org.hl7.fhir.dstu3.model.SearchParameter;
import org.hl7.fhir.dstu3.model.StringType;
import org.opencds.cqf.fhir.api.Repository;
import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions;
import org.opencds.cqf.fhir.cr.measure.dstu3.Dstu3MeasureProcessor;
import java.util.Collections;
import java.util.List;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.COUNTRY_CODING_SYSTEM_CODE;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.MEASUREREPORT_MEASURE_SUPPLEMENTALDATA_EXTENSION;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_DEFINITION_DATE;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_URL;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_VERSION;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.US_COUNTRY_CODE;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.US_COUNTRY_DISPLAY;
public class MeasureService {
private final Repository myRepository;
private final MeasureEvaluationOptions myMeasureEvaluationOptions;
public MeasureService(Repository theRepository, MeasureEvaluationOptions theMeasureEvaluationOptions) {
myRepository = theRepository;
myMeasureEvaluationOptions = theMeasureEvaluationOptions;
}
public static final List<ContactDetail> CQI_CONTACT_DETAIL = Collections.singletonList(new ContactDetail()
.addTelecom(new ContactPoint()
.setSystem(ContactPoint.ContactPointSystem.URL)
.setValue("http://www.hl7.org/Special/committees/cqi/index.cfm")));
public static final List<CodeableConcept> US_JURISDICTION_CODING = Collections.singletonList(new CodeableConcept()
.addCoding(new Coding(COUNTRY_CODING_SYSTEM_CODE, US_COUNTRY_CODE, US_COUNTRY_DISPLAY)));
public static final SearchParameter SUPPLEMENTAL_DATA_SEARCHPARAMETER = (SearchParameter) new SearchParameter()
.setUrl(MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_URL)
.setVersion(MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_VERSION)
.setName("DEQMMeasureReportSupplementalData")
.setStatus(Enumerations.PublicationStatus.ACTIVE)
.setDate(MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_DEFINITION_DATE)
.setPublisher("HL7 International - Clinical Quality Information Work Group")
.setContact(CQI_CONTACT_DETAIL)
.setDescription(String.format(
"Returns resources (supplemental data) from references on extensions on the MeasureReport with urls matching %s.",
MEASUREREPORT_MEASURE_SUPPLEMENTALDATA_EXTENSION))
.setJurisdiction(US_JURISDICTION_CODING)
.addBase("MeasureReport")
.setCode("supplemental-data")
.setType(Enumerations.SearchParamType.REFERENCE)
.setExpression(String.format(
"MeasureReport.extension('%s').value", MEASUREREPORT_MEASURE_SUPPLEMENTALDATA_EXTENSION))
.setXpath(String.format(
"f:MeasureReport/f:extension[@url='%s'].value", MEASUREREPORT_MEASURE_SUPPLEMENTALDATA_EXTENSION))
.setXpathUsage(SearchParameter.XPathUsageType.NORMAL)
.setTitle("Supplemental Data")
.setId("deqm-measurereport-supplemental-data");
/**
* Get The details (such as tenant) of this request. Usually auto-populated HAPI.
*
*/
/**
* Implements the <a href=
* "https://www.hl7.org/fhir/operation-measure-evaluate-measure.html">$evaluate-measure</a>
* operation found in the
* <a href="http://www.hl7.org/fhir/clinicalreasoning-module.html">FHIR Clinical
* Reasoning Module</a>. This implementation aims to be compatible with the CQF
* IG.
*
* @param theId the Id of the Measure to evaluate
* @param thePeriodStart The start of the reporting period
* @param thePeriodEnd The end of the reporting period
* @param theReportType The type of MeasureReport to generate
* @param thePractitioner the practitioner to use for the evaluation
* @param theLastReceivedOn the date the results of this measure were last
* received.
* @param theProductLine the productLine (e.g. Medicare, Medicaid, etc) to use
* for the evaluation. This is a non-standard parameter.
* @param theAdditionalData the data bundle containing additional data
* @param theTerminologyEndpoint the endpoint of terminology services for your measure valuesets
* @return the calculated MeasureReport
*/
public MeasureReport evaluateMeasure(
IdType theId,
String thePeriodStart,
String thePeriodEnd,
String theReportType,
String theSubject,
String thePractitioner,
String theLastReceivedOn,
String theProductLine,
Bundle theAdditionalData,
Endpoint theTerminologyEndpoint) {
ensureSupplementalDataElementSearchParameter();
var dstu3MeasureProcessor = new Dstu3MeasureProcessor(myRepository, myMeasureEvaluationOptions);
MeasureReport report = dstu3MeasureProcessor.evaluateMeasure(
theId,
thePeriodStart,
thePeriodEnd,
theReportType,
Collections.singletonList(theSubject),
theAdditionalData);
if (theProductLine != null) {
Extension ext = new Extension();
ext.setUrl("http://hl7.org/fhir/us/cqframework/cqfmeasures/StructureDefinition/cqfm-productLine");
ext.setValue(new StringType(theProductLine));
report.addExtension(ext);
}
return report;
}
protected void ensureSupplementalDataElementSearchParameter() {
// create a transaction bundle
BundleBuilder builder = new BundleBuilder(myRepository.fhirContext());
// set the request to be condition on code == supplemental data
builder.addTransactionCreateEntry(SUPPLEMENTAL_DATA_SEARCHPARAMETER).conditional("code=supplemental-data");
myRepository.transaction(builder.getBundle());
}
}

View File

@ -19,10 +19,10 @@
*/
package ca.uhn.fhir.cr.r4;
import ca.uhn.fhir.cr.r4.measure.MeasureService;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureService;
@FunctionalInterface
public interface IMeasureServiceFactory {
MeasureService create(RequestDetails theRequestDetails);
R4MeasureService create(RequestDetails theRequestDetails);
}

View File

@ -32,6 +32,7 @@ import org.hl7.fhir.r4.model.Endpoint;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Measure;
import org.hl7.fhir.r4.model.MeasureReport;
import org.opencds.cqf.fhir.utility.monad.Eithers;
import org.springframework.beans.factory.annotation.Autowired;
public class MeasureOperationsProvider {
@ -77,16 +78,18 @@ public class MeasureOperationsProvider {
throws InternalErrorException, FHIRException {
return myR4MeasureServiceFactory
.create(theRequestDetails)
.evaluateMeasure(
theId,
.evaluate(
Eithers.forMiddle3(theId),
thePeriodStart,
thePeriodEnd,
theReportType,
theSubject,
thePractitioner,
theLastReceivedOn,
theProductLine,
null,
theTerminologyEndpoint,
null,
theAdditionalData,
theTerminologyEndpoint);
theProductLine,
thePractitioner);
}
}

View File

@ -1,216 +0,0 @@
/*-
* #%L
* HAPI FHIR - Clinical Reasoning
* %%
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.cr.r4.measure;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.util.BundleBuilder;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ContactDetail;
import org.hl7.fhir.r4.model.ContactPoint;
import org.hl7.fhir.r4.model.Endpoint;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.MeasureReport;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.SearchParameter;
import org.hl7.fhir.r4.model.StringType;
import org.opencds.cqf.fhir.api.Repository;
import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions;
import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureProcessor;
import org.opencds.cqf.fhir.cr.measure.r4.R4RepositorySubjectProvider;
import org.opencds.cqf.fhir.utility.iterable.BundleIterator;
import org.opencds.cqf.fhir.utility.monad.Eithers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.COUNTRY_CODING_SYSTEM_CODE;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.MEASUREREPORT_MEASURE_SUPPLEMENTALDATA_EXTENSION;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.MEASUREREPORT_PRODUCT_LINE_EXT_URL;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_DEFINITION_DATE;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_URL;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_VERSION;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.US_COUNTRY_CODE;
import static org.opencds.cqf.fhir.cr.measure.constant.MeasureReportConstants.US_COUNTRY_DISPLAY;
public class MeasureService {
private final Repository myRepository;
private final MeasureEvaluationOptions myMeasureEvaluationOptions;
private Logger ourLogger = LoggerFactory.getLogger(MeasureService.class);
public MeasureService(Repository theRepository, MeasureEvaluationOptions theMeasureEvaluationOptions) {
this.myRepository = theRepository;
this.myMeasureEvaluationOptions = theMeasureEvaluationOptions;
}
public static final List<ContactDetail> CQI_CONTACTDETAIL = Collections.singletonList(new ContactDetail()
.addTelecom(new ContactPoint()
.setSystem(ContactPoint.ContactPointSystem.URL)
.setValue("http://www.hl7.org/Special/committees/cqi/index.cfm")));
public static final List<CodeableConcept> US_JURISDICTION_CODING = Collections.singletonList(new CodeableConcept()
.addCoding(new Coding(COUNTRY_CODING_SYSTEM_CODE, US_COUNTRY_CODE, US_COUNTRY_DISPLAY)));
public static final SearchParameter SUPPLEMENTAL_DATA_SEARCHPARAMETER = (SearchParameter) new SearchParameter()
.setUrl(MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_URL)
.setVersion(MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_VERSION)
.setName("DEQMMeasureReportSupplementalData")
.setStatus(Enumerations.PublicationStatus.ACTIVE)
.setDate(MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_DEFINITION_DATE)
.setPublisher("HL7 International - Clinical Quality Information Work Group")
.setContact(CQI_CONTACTDETAIL)
.setDescription(String.format(
"Returns resources (supplemental data) from references on extensions on the MeasureReport with urls matching %s.",
MEASUREREPORT_MEASURE_SUPPLEMENTALDATA_EXTENSION))
.setJurisdiction(US_JURISDICTION_CODING)
.addBase("MeasureReport")
.setCode("supplemental-data")
.setType(Enumerations.SearchParamType.REFERENCE)
.setExpression(String.format(
"MeasureReport.extension('%s').value", MEASUREREPORT_MEASURE_SUPPLEMENTALDATA_EXTENSION))
.setXpath(String.format(
"f:MeasureReport/f:extension[@url='%s'].value", MEASUREREPORT_MEASURE_SUPPLEMENTALDATA_EXTENSION))
.setXpathUsage(SearchParameter.XPathUsageType.NORMAL)
.setTitle("Supplemental Data")
.setId("deqm-measurereport-supplemental-data");
/**
* Implements the <a href=
* "https://www.hl7.org/fhir/operation-measure-evaluate-measure.html">$evaluate-measure</a>
* operation found in the
* <a href="http://www.hl7.org/fhir/clinicalreasoning-module.html">FHIR Clinical
* Reasoning Module</a>. This implementation aims to be compatible with the CQF
* IG.
*
* @param theId the Id of the Measure to evaluate
* @param thePeriodStart The start of the reporting period
* @param thePeriodEnd The end of the reporting period
* @param theReportType The type of MeasureReport to generate
* @param thePractitioner the thePractitioner to use for the evaluation
* @param theLastReceivedOn the date the results of this measure were last
* received.
* @param theProductLine the theProductLine (e.g. Medicare, Medicaid, etc) to use
* for the evaluation. This is a non-standard parameter.
* @param theAdditionalData the data bundle containing additional data
* @param theTerminologyEndpoint the endpoint of terminology services for your measure valuesets
* @return the calculated MeasureReport
*/
public MeasureReport evaluateMeasure(
IdType theId,
String thePeriodStart,
String thePeriodEnd,
String theReportType,
String theSubject,
String thePractitioner,
String theLastReceivedOn,
String theProductLine,
Bundle theAdditionalData,
Endpoint theTerminologyEndpoint) {
ensureSupplementalDataElementSearchParameter();
var r4MeasureProcessor =
new R4MeasureProcessor(myRepository, myMeasureEvaluationOptions, new R4RepositorySubjectProvider());
MeasureReport measureReport = null;
// SUBJECT LIST SETTERS
if (StringUtils.isBlank(theSubject) && StringUtils.isNotBlank(thePractitioner)) {
List<String> subjectIds = getPractitionerPatients(thePractitioner, myRepository);
measureReport = r4MeasureProcessor.evaluateMeasure(
Eithers.forMiddle3(theId),
thePeriodStart,
thePeriodEnd,
theReportType,
subjectIds,
theAdditionalData);
} else if (StringUtils.isNotBlank(theSubject)) {
measureReport = r4MeasureProcessor.evaluateMeasure(
Eithers.forMiddle3(theId),
thePeriodStart,
thePeriodEnd,
theReportType,
Collections.singletonList(theSubject),
theAdditionalData);
} else if (StringUtils.isBlank(theSubject) && StringUtils.isBlank(thePractitioner)) {
measureReport = r4MeasureProcessor.evaluateMeasure(
Eithers.forMiddle3(theId), thePeriodStart, thePeriodEnd, theReportType, null, theAdditionalData);
}
// add ProductLine after report is generated
addProductLineExtension(measureReport, theProductLine);
return measureReport;
}
private List<String> getPractitionerPatients(String thePractitioner, Repository theRepository) {
List<String> patients = new ArrayList<>();
Map<String, List<IQueryParameterType>> map = new HashMap<>();
map.put(
"general-practitioner",
Collections.singletonList(new ReferenceParam(
thePractitioner.startsWith("Practitioner/")
? thePractitioner
: "Practitioner/" + thePractitioner)));
var bundle = theRepository.search(Bundle.class, Patient.class, map);
var iterator = new BundleIterator<>(theRepository, bundle);
while (iterator.hasNext()) {
var patient = iterator.next().getResource();
var refString = patient.getIdElement().getResourceType() + "/"
+ patient.getIdElement().getIdPart();
patients.add(refString);
}
return patients;
}
private void addProductLineExtension(MeasureReport theMeasureReport, String theProductLine) {
if (theProductLine != null) {
Extension ext = new Extension();
ext.setUrl(MEASUREREPORT_PRODUCT_LINE_EXT_URL);
ext.setValue(new StringType(theProductLine));
theMeasureReport.addExtension(ext);
}
}
protected void ensureSupplementalDataElementSearchParameter() {
// create a transaction bundle
BundleBuilder builder = new BundleBuilder(myRepository.fhirContext());
// set the request to be condition on code == supplemental data
builder.addTransactionCreateEntry(SUPPLEMENTAL_DATA_SEARCHPARAMETER).conditional("code=supplemental-data");
myRepository.transaction(builder.getBundle());
}
}

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.cr;
import ca.uhn.fhir.batch2.jobs.reindex.ReindexProvider;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.cr.common.CodeCacheResourceChangeListener;
@ -8,7 +9,15 @@ import ca.uhn.fhir.cr.common.ElmCacheResourceChangeListener;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.cache.IResourceChangeListener;
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerCacheRefresher;
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerCache;
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerCacheFactory;
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerCacheRefresherImpl;
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerRegistryImpl;
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerRegistryInterceptor;
import ca.uhn.fhir.jpa.cache.ResourceVersionMap;
import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
import ca.uhn.fhir.jpa.provider.DiffProvider;
import ca.uhn.fhir.jpa.provider.IJpaSystemProvider;
@ -16,6 +25,7 @@ import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.provider.ValueSetOperationProvider;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.matcher.InMemoryResourceMatcher;
import ca.uhn.fhir.jpa.subscription.channel.config.SubscriptionChannelConfig;
import ca.uhn.fhir.jpa.subscription.submit.config.SubscriptionSubmitterConfig;
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
@ -32,6 +42,9 @@ 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.runtime.Code;
import org.opencds.cqf.fhir.cql.EvaluationSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -39,10 +52,14 @@ import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Configuration
@Import({SubscriptionSubmitterConfig.class, SubscriptionChannelConfig.class})
@ -91,7 +108,6 @@ public class TestCrConfig {
}
@Bean
@Scope("prototype")
public ModelManager modelManager(Map<ModelIdentifier, Model> theGlobalModelCache) {
return new ModelManager(theGlobalModelCache);
}
@ -107,34 +123,49 @@ public class TestCrConfig {
}
@Bean
public Map<VersionedIdentifier, List<Code>> globalCodeCache() {
public Map<String, List<Code>> globalValueSetCache() {
return new ConcurrentHashMap<>();
}
@Bean
@Primary
public ElmCacheResourceChangeListener elmCacheResourceChangeListener(
IResourceChangeListenerRegistry theResourceChangeListenerRegistry,
DaoRegistry theDaoRegistry,
Map<VersionedIdentifier, CompiledLibrary> theGlobalLibraryCache) {
EvaluationSettings theEvaluationSettings) {
ElmCacheResourceChangeListener listener =
new ElmCacheResourceChangeListener(theDaoRegistry, theGlobalLibraryCache);
new ElmCacheResourceChangeListener(theDaoRegistry, theEvaluationSettings.getLibraryCache());
theResourceChangeListenerRegistry.registerResourceResourceChangeListener(
"Library", SearchParameterMap.newSynchronous(), listener, 1000);
return listener;
}
@Bean
@Primary
public CodeCacheResourceChangeListener codeCacheResourceChangeListener(
IResourceChangeListenerRegistry theResourceChangeListenerRegistry,
DaoRegistry theDaoRegistry,
Map<VersionedIdentifier, List<Code>> theGlobalCodeCache) {
CodeCacheResourceChangeListener listener =
new CodeCacheResourceChangeListener(theDaoRegistry, theGlobalCodeCache);
EvaluationSettings theEvaluationSettings,
DaoRegistry theDaoRegistry) {
CodeCacheResourceChangeListener listener = new CodeCacheResourceChangeListener(theDaoRegistry, theEvaluationSettings.getValueSetCache());
//registry
theResourceChangeListenerRegistry.registerResourceResourceChangeListener(
"ValueSet", SearchParameterMap.newSynchronous(), listener, 1000);
"ValueSet", SearchParameterMap.newSynchronous(), listener,1000);
return listener;
}
@Bean
public IResourceChangeListenerRegistry resourceChangeListenerRegistry(InMemoryResourceMatcher theInMemoryResourceMatcher, FhirContext theFhirContext, ResourceChangeListenerCacheFactory theResourceChangeListenerCacheFactory) {
return new ResourceChangeListenerRegistryImpl(theFhirContext, theResourceChangeListenerCacheFactory, theInMemoryResourceMatcher);
}
@Bean
IResourceChangeListenerCacheRefresher resourceChangeListenerCacheRefresher() {
return new ResourceChangeListenerCacheRefresherImpl();
}
@Bean
public ResourceChangeListenerRegistryInterceptor resourceChangeListenerRegistryInterceptor() {
return new ResourceChangeListenerRegistryInterceptor();
}
}

View File

@ -14,6 +14,7 @@ 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;
@ -23,6 +24,7 @@ import org.springframework.context.annotation.Import;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -43,9 +45,13 @@ public class TestCrDstu3Config {
}
@Bean
public EvaluationSettings evaluationSettings(TestCqlProperties theCqlProperties, Map<VersionedIdentifier, CompiledLibrary> theGlobalLibraryCache, Map<ModelIdentifier, Model> theGlobalModelCache) {
public EvaluationSettings evaluationSettings(TestCqlProperties theCqlProperties, Map<VersionedIdentifier,
CompiledLibrary> theGlobalLibraryCache, Map<ModelIdentifier, Model> theGlobalModelCache,
Map<String, List<Code>> theGlobalValueSetCache) {
var evaluationSettings = EvaluationSettings.getDefault();
var cqlEngineOptions = evaluationSettings.getEngineOptions();
var cqlOptions = evaluationSettings.getCqlOptions();
var cqlEngineOptions = cqlOptions.getCqlEngineOptions();
Set<CqlEngine.Options> options = EnumSet.noneOf(CqlEngine.Options.class);
if (theCqlProperties.isCqlRuntimeEnableExpressionCaching()) {
options.add(CqlEngine.Options.EnableExpressionCaching);
@ -54,18 +60,61 @@ public class TestCrDstu3Config {
options.add(CqlEngine.Options.EnableValidation);
}
cqlEngineOptions.setOptions(options);
var cqlOptions = evaluationSettings.getCqlOptions();
cqlOptions.setCqlEngineOptions(cqlEngineOptions);
var cqlCompilerOptions = new CqlCompilerOptions();
cqlCompilerOptions.setCompatibilityLevel("1.3");
if (theCqlProperties.isEnableDateRangeOptimization()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDateRangeOptimization);
}
if (theCqlProperties.isEnableAnnotations()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableAnnotations);
}
if (theCqlProperties.isEnableLocators()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableLocators);
}
if (theCqlProperties.isEnableResultsType()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableResultTypes);
}
cqlCompilerOptions.setVerifyOnly(theCqlProperties.isCqlCompilerVerifyOnly());
if (theCqlProperties.isEnableDetailedErrors()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDetailedErrors);
}
cqlCompilerOptions.setErrorLevel(theCqlProperties.getCqlCompilerErrorSeverityLevel());
if (theCqlProperties.isDisableListTraversal()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListTraversal);
}
if (theCqlProperties.isDisableListDemotion()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListDemotion);
}
if (theCqlProperties.isDisableListPromotion()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListPromotion);
}
if (theCqlProperties.isEnableIntervalDemotion()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalDemotion);
}
if (theCqlProperties.isEnableIntervalPromotion()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalPromotion);
}
if (theCqlProperties.isDisableMethodInvocation()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableMethodInvocation);
}
if (theCqlProperties.isRequireFromKeyword()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.RequireFromKeyword);
}
cqlCompilerOptions.setValidateUnits(theCqlProperties.isCqlCompilerValidateUnits());
if (theCqlProperties.isDisableDefaultModelInfoLoad()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableDefaultModelInfoLoad);
}
cqlCompilerOptions.setSignatureLevel(theCqlProperties.getCqlCompilerSignatureLevel());
cqlCompilerOptions.setCompatibilityLevel(theCqlProperties.getCqlCompilerCompatibilityLevel());
cqlCompilerOptions.setAnalyzeDataRequirements(theCqlProperties.isCqlCompilerAnalyzeDataRequirements());
cqlCompilerOptions.setCollapseDataRequirements(theCqlProperties.isCqlCompilerCollapseDataRequirements());
cqlOptions.setCqlCompilerOptions(cqlCompilerOptions);
evaluationSettings.setLibraryCache(theGlobalLibraryCache);
evaluationSettings.setModelCache(theGlobalModelCache);
evaluationSettings.setValueSetCache(theGlobalValueSetCache);
return evaluationSettings;
}
}

View File

@ -8,6 +8,9 @@ import ca.uhn.fhir.cr.config.r4.PackageOperationConfig;
import ca.uhn.fhir.cr.config.r4.PopulateOperationConfig;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerCache;
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerRegistryImpl;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
import ca.uhn.fhir.parser.IParser;
@ -35,7 +38,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -70,6 +75,7 @@ public abstract class BaseCrR4TestServer extends BaseJpaR4Test implements IResou
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
myStorageSettings.setIndexMissingFields(new JpaStorageSettings().getIndexMissingFields());
myEvaluationSettings.getLibraryCache().clear();
myEvaluationSettings.getValueSetCache().clear();
}
@Autowired
RestfulServer ourRestfulServer;

View File

@ -0,0 +1,176 @@
package ca.uhn.fhir.cr.r4;
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerCacheRefresherImpl;
import ca.uhn.fhir.jpa.cache.ResourceChangeListenerRegistryImpl;
import org.hl7.fhir.r4.model.DateType;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Library;
import org.hl7.fhir.r4.model.MeasureReport;
import org.hl7.fhir.r4.model.Parameters;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.opencds.cqf.fhir.cql.EvaluationSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ExtendWith(SpringExtension.class)
public class CrResourceListenerTests extends BaseCrR4TestServer {
@Autowired
EvaluationSettings myEvaluationSettings;
@Autowired
ResourceChangeListenerRegistryImpl myResourceChangeListenerRegistry;
@Autowired
ResourceChangeListenerCacheRefresherImpl myResourceChangeListenerCacheRefresher;
public MeasureReport runEvaluateMeasure(String periodStart, String periodEnd, String subject, String measureId, String reportType, String practitioner){
var parametersEval = new Parameters();
parametersEval.addParameter("periodStart", new DateType(periodStart));
parametersEval.addParameter("periodEnd", new DateType(periodEnd));
parametersEval.addParameter("practitioner", practitioner);
parametersEval.addParameter("reportType", reportType);
parametersEval.addParameter("subject", subject);
var report = ourClient.operation().onInstance("Measure/" + measureId)
.named("$evaluate-measure")
.withParameters(parametersEval)
.returnResourceType(MeasureReport.class)
.execute();
assertNotNull(report);
return report;
}
@Test
void testCodeCacheInvalidation() throws InterruptedException {
assertTrue(myResourceChangeListenerRegistry.getWatchedResourceNames().contains("ValueSet"));
loadBundle("ColorectalCancerScreeningsFHIR-bundle.json");
runEvaluateMeasure("2019-01-01", "2019-12-31", "Patient/numer-EXM130", "ColorectalCancerScreeningsFHIR", "Individual", null);
// This is a manual init
myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners();
//cached valueSets
assertEquals(11, myEvaluationSettings.getValueSetCache().size());
//remove valueset from server
var id = new IdType("ValueSet/2.16.840.1.113883.3.464.1003.101.12.1001");
ourClient.delete().resourceById(id).execute();
// This is a manual refresh
myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners();
//_ALL_ valuesets should be removed from cache
assertEquals(0, myEvaluationSettings.getValueSetCache().size());
}
@Test
void testElmCacheInvalidation() throws InterruptedException {
assertTrue(myResourceChangeListenerRegistry.getWatchedResourceNames().contains("Library"));
loadBundle("ColorectalCancerScreeningsFHIR-bundle.json");
// evaluate-measure adds library to repository cache
runEvaluateMeasure("2019-01-01", "2019-12-31", "Patient/numer-EXM130", "ColorectalCancerScreeningsFHIR", "Individual", null);
// This is a manual init
myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners();
//cached libraries
assertEquals(7, myEvaluationSettings.getLibraryCache().size());
//remove Library from server
var id = new IdType("Library/ColorectalCancerScreeningsFHIR");
ourClient.delete().resourceById(id).execute();
// This is a manual refresh
myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners();
//_ALL_ Libraries should be removed from cache
assertEquals(0, myEvaluationSettings.getLibraryCache().size());
}
@Test
void testAddNewVersionOfSameLibrary() throws InterruptedException {
assertTrue(myResourceChangeListenerRegistry.getWatchedResourceNames().contains("Library"));
// load measure bundle with measure library version
loadBundle("ColorectalCancerScreeningsFHIR-bundle.json");
// evaluate-measure adds library to repository cache
runEvaluateMeasure("2019-01-01", "2019-12-31", "Patient/numer-EXM130", "ColorectalCancerScreeningsFHIR", "Individual", null);
//cached libraries from bundle
assertEquals(7, myEvaluationSettings.getLibraryCache().size());
// manually refresh cache
myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners();
// add same version of measure Library to server with minor edits
loadBundle("multiversion/EXM130-0.0.001-bundle.json");
// manually refresh cache
myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners();
//cache should be invalidated for matching library name and version
assertEquals(6, myEvaluationSettings.getLibraryCache().size());
}
@Test
void testNewVersionLibraryAdd() throws InterruptedException {
assertTrue(myResourceChangeListenerRegistry.getWatchedResourceNames().contains("Library"));
// load measure bundle with measure library version
loadBundle("ColorectalCancerScreeningsFHIR-bundle.json");
// evaluate-measure adds library to repository cache
runEvaluateMeasure("2019-01-01", "2019-12-31", "Patient/numer-EXM130", "ColorectalCancerScreeningsFHIR", "Individual", null);
//cached libraries from bundle
assertEquals(7, myEvaluationSettings.getLibraryCache().size());
// manually refresh cache
myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners();
// add same version of measure Library to server with minor edits
loadBundle("multiversion/EXM130-0.0.002-bundle.json");
// manually refresh cache
myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners();
//cache should not be invalidated because name and version don't have a match in cache
assertEquals(7, myEvaluationSettings.getLibraryCache().size());
}
@Test
void testNewVersionValueSetAdd() throws InterruptedException {
assertTrue(myResourceChangeListenerRegistry.getWatchedResourceNames().contains("ValueSet"));
// load measure bundle with measure library version
loadBundle("ColorectalCancerScreeningsFHIR-bundle.json");
// evaluate-measure adds valueset to repository cache
runEvaluateMeasure("2019-01-01", "2019-12-31", "Patient/numer-EXM130", "ColorectalCancerScreeningsFHIR", "Individual", null);
//cached valueset from bundle
assertEquals(11, myEvaluationSettings.getValueSetCache().size());
// manually refresh cache
myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners();
// add new version of valueset to server
loadBundle("multiversion/valueset-version-bundle.json");
// manually refresh cache
myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners();
//cache should be invalidated for valueset url and removed
assertEquals(10, myEvaluationSettings.getValueSetCache().size());
}
}

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.cr.r4;
import ca.uhn.fhir.cr.r4.measure.MeasureOperationsProvider;
import org.hl7.fhir.r4.model.DateType;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.MeasureReport;
@ -9,7 +8,7 @@ import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Resource;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.Optional;
@ -20,8 +19,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
@ExtendWith(SpringExtension.class)
class R4MeasureOperationProviderIT extends BaseCrR4TestServer {
@Autowired
MeasureOperationsProvider myMeasureOperationsProvider;
public MeasureReport runEvaluateMeasure(String periodStart, String periodEnd, String subject, String measureId, String reportType, String practitioner){
@ -44,7 +41,7 @@ class R4MeasureOperationProviderIT extends BaseCrR4TestServer {
}
@Test
void testMeasureEvaluate_EXM130() {
void testMeasureEvaluate_EXM130() throws InterruptedException {
loadBundle("ColorectalCancerScreeningsFHIR-bundle.json");
runEvaluateMeasure("2019-01-01", "2019-12-31", "Patient/numer-EXM130", "ColorectalCancerScreeningsFHIR", "Individual", null);
}
@ -169,4 +166,5 @@ class R4MeasureOperationProviderIT extends BaseCrR4TestServer {
}
}

View File

@ -14,6 +14,7 @@ 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;
@ -25,6 +26,7 @@ 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.ExecutorService;
@ -63,10 +65,13 @@ public class TestCrR4Config {
return measureEvalOptions;
}
@Bean
public EvaluationSettings evaluationSettings(TestCqlProperties theCqlProperties, Map<VersionedIdentifier, CompiledLibrary> theGlobalLibraryCache, Map<ModelIdentifier, Model> theGlobalModelCache) {
public EvaluationSettings evaluationSettings(TestCqlProperties theCqlProperties, Map<VersionedIdentifier,
CompiledLibrary> theGlobalLibraryCache, Map<ModelIdentifier, Model> theGlobalModelCache,
Map<String, List<Code>> theGlobalValueSetCache) {
var evaluationSettings = EvaluationSettings.getDefault();
var cqlOptions = evaluationSettings.getCqlOptions();
var cqlEngineOptions = evaluationSettings.getEngineOptions();
var cqlEngineOptions = cqlOptions.getCqlEngineOptions();
Set<CqlEngine.Options> options = EnumSet.noneOf(CqlEngine.Options.class);
if (theCqlProperties.isCqlRuntimeEnableExpressionCaching()) {
options.add(CqlEngine.Options.EnableExpressionCaching);
@ -75,20 +80,61 @@ public class TestCrR4Config {
options.add(CqlEngine.Options.EnableValidation);
}
cqlEngineOptions.setOptions(options);
var cqlOptions = evaluationSettings.getCqlOptions();
cqlOptions.setCqlEngineOptions(cqlEngineOptions);
var cqlCompilerOptions = new CqlCompilerOptions();
cqlCompilerOptions.setCompatibilityLevel("1.5");
cqlOptions.setUseEmbeddedLibraries(true);
if (theCqlProperties.isEnableDateRangeOptimization()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDateRangeOptimization);
}
if (theCqlProperties.isEnableAnnotations()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableAnnotations);
}
if (theCqlProperties.isEnableLocators()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableLocators);
}
if (theCqlProperties.isEnableResultsType()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableResultTypes);
}
cqlCompilerOptions.setVerifyOnly(theCqlProperties.isCqlCompilerVerifyOnly());
if (theCqlProperties.isEnableDetailedErrors()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableDetailedErrors);
}
cqlCompilerOptions.setErrorLevel(theCqlProperties.getCqlCompilerErrorSeverityLevel());
if (theCqlProperties.isDisableListTraversal()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListTraversal);
}
if (theCqlProperties.isDisableListDemotion()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListDemotion);
}
if (theCqlProperties.isDisableListPromotion()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableListPromotion);
}
if (theCqlProperties.isEnableIntervalDemotion()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalDemotion);
}
if (theCqlProperties.isEnableIntervalPromotion()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.EnableIntervalPromotion);
}
if (theCqlProperties.isDisableMethodInvocation()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableMethodInvocation);
}
if (theCqlProperties.isRequireFromKeyword()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.RequireFromKeyword);
}
cqlCompilerOptions.setValidateUnits(theCqlProperties.isCqlCompilerValidateUnits());
if (theCqlProperties.isDisableDefaultModelInfoLoad()) {
cqlCompilerOptions.setOptions(CqlCompilerOptions.Options.DisableDefaultModelInfoLoad);
}
cqlCompilerOptions.setSignatureLevel(theCqlProperties.getCqlCompilerSignatureLevel());
cqlCompilerOptions.setCompatibilityLevel(theCqlProperties.getCqlCompilerCompatibilityLevel());
cqlCompilerOptions.setAnalyzeDataRequirements(theCqlProperties.isCqlCompilerAnalyzeDataRequirements());
cqlCompilerOptions.setCollapseDataRequirements(theCqlProperties.isCqlCompilerCollapseDataRequirements());
cqlOptions.setCqlCompilerOptions(cqlCompilerOptions);
evaluationSettings.setLibraryCache(theGlobalLibraryCache);
evaluationSettings.setModelCache(theGlobalModelCache);
evaluationSettings.setValueSetCache(theGlobalValueSetCache);
return evaluationSettings;
}

View File

@ -147712,7 +147712,7 @@
}
],
"library": [
"http://ecqi.healthit.gov/ecqms/Library/ColorectalCancerScreeningsFHIR"
"http://ecqi.healthit.gov/ecqms/Library/ColorectalCancerScreeningsFHIR|0.0.001"
],
"disclaimer": "The performance Measure is not a clinical guideline and does not establish a standard of medical care, and has not been tested for all potential applications. THE MEASURE AND SPECIFICATIONS ARE PROVIDED \"AS IS\" WITHOUT WARRANTY OF ANY KIND.\n \nDue to technical limitations, registered trademarks are indicated by (R) or [R] and unregistered trademarks are indicated by (TM) or [TM].",
"scoring": {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -9,7 +9,7 @@
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<packaging>pom</packaging>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<name>HAPI-FHIR</name>
<description>An open-source implementation of the FHIR specification in Java.</description>
@ -983,7 +983,7 @@
<ucum_version>1.0.8</ucum_version>
<!-- CQL Support -->
<clinical-reasoning.version>3.0.0-PRE7</clinical-reasoning.version>
<clinical-reasoning.version>3.0.0-PRE8</clinical-reasoning.version>
<!-- Site properties -->
<fontawesomeVersion>5.4.1</fontawesomeVersion>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version>
<version>6.9.10-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>