add valueset cache and cache invalidation listeners

This commit is contained in:
Justin McKelvy
2023-10-11 15:16:17 -06:00
parent 3a0b42b265
commit 6d10c0bade
5 changed files with 136 additions and 68 deletions

View File

@@ -14,7 +14,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId> <artifactId>hapi-fhir</artifactId>
<version>6.9.9-SNAPSHOT</version> <version>6.9.10-SNAPSHOT</version>
</parent> </parent>
<artifactId>hapi-fhir-jpaserver-starter</artifactId> <artifactId>hapi-fhir-jpaserver-starter</artifactId>

View File

@@ -0,0 +1,85 @@
package ca.uhn.fhir.jpa.starter.cr;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.cr.common.CodeCacheResourceChangeListener;
import ca.uhn.fhir.cr.common.ElmCacheResourceChangeListener;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerCacheRefresher;
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
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.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.matcher.InMemoryResourceMatcher;
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.runtime.Code;
import org.opencds.cqf.fhir.cql.EvaluationSettings;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Configuration
public class BaseCrConfig {
@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 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

@@ -17,7 +17,6 @@ import ca.uhn.fhir.cr.r4.activitydefinition.ActivityDefinitionApplyProvider;
import ca.uhn.fhir.cr.r4.cqlexecution.CqlExecutionOperationProvider; import ca.uhn.fhir.cr.r4.cqlexecution.CqlExecutionOperationProvider;
import ca.uhn.fhir.cr.r4.measure.CareGapsOperationProvider; import ca.uhn.fhir.cr.r4.measure.CareGapsOperationProvider;
import ca.uhn.fhir.cr.r4.measure.MeasureOperationsProvider; 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.cr.r4.measure.SubmitDataProvider;
import ca.uhn.fhir.cr.r4.plandefinition.PlanDefinitionApplyProvider; import ca.uhn.fhir.cr.r4.plandefinition.PlanDefinitionApplyProvider;
import ca.uhn.fhir.cr.r4.plandefinition.PlanDefinitionPackageProvider; import ca.uhn.fhir.cr.r4.plandefinition.PlanDefinitionPackageProvider;
@@ -31,6 +30,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.CareGapsProperties;
import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; 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.R4CareGapsService;
import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureService;
import org.opencds.cqf.fhir.cr.measure.r4.R4SubmitDataService; import org.opencds.cqf.fhir.cr.measure.r4.R4SubmitDataService;
import org.opencds.cqf.fhir.cr.plandefinition.r4.PlanDefinitionProcessor; import org.opencds.cqf.fhir.cr.plandefinition.r4.PlanDefinitionProcessor;
import org.opencds.cqf.fhir.cr.questionnaire.r4.QuestionnaireProcessor; import org.opencds.cqf.fhir.cr.questionnaire.r4.QuestionnaireProcessor;
@@ -49,8 +49,8 @@ public class CrR4Config {
@Bean @Bean
IMeasureServiceFactory r4MeasureServiceFactory( IMeasureServiceFactory r4MeasureServiceFactory(
IRepositoryFactory theRepositoryFactory, MeasureEvaluationOptions theEvaluationOptions) { IRepositoryFactory theRepositoryFactory, MeasureEvaluationOptions theEvaluationOptions) {
return rd -> new MeasureService(theRepositoryFactory.create(rd), theEvaluationOptions); return rd -> new R4MeasureService(theRepositoryFactory.create(rd), theEvaluationOptions);
} }
@Bean @Bean
@@ -60,7 +60,7 @@ public class CrR4Config {
@Bean @Bean
ICqlExecutionServiceFactory r4CqlExecutionServiceFactory( ICqlExecutionServiceFactory r4CqlExecutionServiceFactory(
IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) {
return rd -> new R4CqlExecutionService(theRepositoryFactory.create(rd), theEvaluationSettings); return rd -> new R4CqlExecutionService(theRepositoryFactory.create(rd), theEvaluationSettings);
} }
@@ -71,16 +71,16 @@ public class CrR4Config {
@Bean @Bean
ICareGapsServiceFactory careGapsServiceFactory( ICareGapsServiceFactory careGapsServiceFactory(
IRepositoryFactory theRepositoryFactory, IRepositoryFactory theRepositoryFactory,
CareGapsProperties theCareGapsProperties, CareGapsProperties theCareGapsProperties,
MeasureEvaluationOptions theMeasureEvaluationOptions, MeasureEvaluationOptions theMeasureEvaluationOptions,
@Qualifier("cqlExecutor") Executor theExecutor) { @Qualifier("cqlExecutor") Executor theExecutor) {
return rd -> new R4CareGapsService( return rd -> new R4CareGapsService(
theCareGapsProperties, theCareGapsProperties,
theRepositoryFactory.create(rd), theRepositoryFactory.create(rd),
theMeasureEvaluationOptions, theMeasureEvaluationOptions,
theExecutor, theExecutor,
rd.getFhirServerBase()); rd.getFhirServerBase());
} }
@Bean @Bean
@@ -100,30 +100,30 @@ public class CrR4Config {
@Bean @Bean
IActivityDefinitionProcessorFactory r4ActivityDefinitionProcessorFactory( IActivityDefinitionProcessorFactory r4ActivityDefinitionProcessorFactory(
IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) {
return rd -> new ActivityDefinitionProcessor( return rd -> new ActivityDefinitionProcessor(
theRepositoryFactory.create(rd), theEvaluationSettings); theRepositoryFactory.create(rd), theEvaluationSettings);
} }
@Bean @Bean
IPlanDefinitionProcessorFactory r4PlanDefinitionProcessorFactory( IPlanDefinitionProcessorFactory r4PlanDefinitionProcessorFactory(
IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) {
return rd -> new PlanDefinitionProcessor( return rd -> new PlanDefinitionProcessor(
theRepositoryFactory.create(rd), theEvaluationSettings); theRepositoryFactory.create(rd), theEvaluationSettings);
} }
@Bean @Bean
IQuestionnaireProcessorFactory r4QuestionnaireProcessorFactory( IQuestionnaireProcessorFactory r4QuestionnaireProcessorFactory(
IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) {
return rd -> new QuestionnaireProcessor( return rd -> new QuestionnaireProcessor(
theRepositoryFactory.create(rd), theEvaluationSettings); theRepositoryFactory.create(rd), theEvaluationSettings);
} }
@Bean @Bean
IQuestionnaireResponseProcessorFactory r4QuestionnaireResponseProcessorFactory( IQuestionnaireResponseProcessorFactory r4QuestionnaireResponseProcessorFactory(
IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) {
return rd -> new QuestionnaireResponseProcessor( return rd -> new QuestionnaireResponseProcessor(
theRepositoryFactory.create(rd), theEvaluationSettings); theRepositoryFactory.create(rd), theEvaluationSettings);
} }
@Bean @Bean
@@ -138,7 +138,7 @@ public class CrR4Config {
@Bean @Bean
QuestionnaireResponseExtractProvider QuestionnaireResponseExtractProvider
r4QuestionnaireResponseExtractProvider() { r4QuestionnaireResponseExtractProvider() {
return new QuestionnaireResponseExtractProvider(); return new QuestionnaireResponseExtractProvider();
} }
@@ -159,24 +159,24 @@ public class CrR4Config {
@Bean @Bean
public ProviderLoader r4PdLoader( public ProviderLoader r4PdLoader(
ApplicationContext theApplicationContext, FhirContext theFhirContext, RestfulServer theRestfulServer) { ApplicationContext theApplicationContext, FhirContext theFhirContext, RestfulServer theRestfulServer) {
var selector = new ProviderSelector( var selector = new ProviderSelector(
theFhirContext, theFhirContext,
Map.of( Map.of(
FhirVersionEnum.R4, FhirVersionEnum.R4,
Arrays.asList( Arrays.asList(
MeasureOperationsProvider.class, MeasureOperationsProvider.class,
SubmitDataProvider.class, SubmitDataProvider.class,
CareGapsOperationProvider.class, CareGapsOperationProvider.class,
CqlExecutionOperationProvider.class, CqlExecutionOperationProvider.class,
ActivityDefinitionApplyProvider.class, ActivityDefinitionApplyProvider.class,
PlanDefinitionApplyProvider.class, PlanDefinitionApplyProvider.class,
QuestionnaireResponseExtractProvider.class, QuestionnaireResponseExtractProvider.class,
QuestionnairePackageProvider.class, QuestionnairePackageProvider.class,
PlanDefinitionPackageProvider.class, PlanDefinitionPackageProvider.class,
QuestionnairePopulateProvider.class))); QuestionnairePopulateProvider.class)));
return new ProviderLoader(theRestfulServer, theApplicationContext, selector); return new ProviderLoader(theRestfulServer, theApplicationContext, selector);
} }
} }

View File

@@ -15,6 +15,7 @@ import org.cqframework.cql.cql2elm.model.Model;
import org.hl7.cql.model.ModelIdentifier; import org.hl7.cql.model.ModelIdentifier;
import org.hl7.elm.r1.VersionedIdentifier; import org.hl7.elm.r1.VersionedIdentifier;
import org.opencds.cqf.cql.engine.execution.CqlEngine; 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.EvaluationSettings;
import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions;
import org.opencds.cqf.fhir.utility.ValidationProfile; import org.opencds.cqf.fhir.utility.ValidationProfile;
@@ -23,6 +24,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.*; import org.springframework.context.annotation.*;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -33,7 +35,7 @@ import java.util.concurrent.ConcurrentHashMap;
ApplyOperationConfig.class, ApplyOperationConfig.class,
ExtractOperationConfig.class, ExtractOperationConfig.class,
PackageOperationConfig.class, PackageOperationConfig.class,
PopulateOperationConfig.class}) PopulateOperationConfig.class, BaseCrConfig.class})
public class StarterCrDstu3Config { public class StarterCrDstu3Config {
private static final Logger ourLogger = LoggerFactory.getLogger(StarterCrDstu3Config.class); private static final Logger ourLogger = LoggerFactory.getLogger(StarterCrDstu3Config.class);
@@ -52,7 +54,8 @@ public class StarterCrDstu3Config {
public EvaluationSettings evaluationSettings( public EvaluationSettings evaluationSettings(
AppProperties theAppProperties, AppProperties theAppProperties,
Map<VersionedIdentifier, CompiledLibrary> theGlobalLibraryCache, Map<VersionedIdentifier, CompiledLibrary> theGlobalLibraryCache,
Map<ModelIdentifier, Model> theGlobalModelCache) { Map<ModelIdentifier, Model> theGlobalModelCache,
Map<String, List<Code>> theGlobalValueSetCache) {
var evaluationSettings = EvaluationSettings.getDefault(); var evaluationSettings = EvaluationSettings.getDefault();
var cqlOptions = evaluationSettings.getCqlOptions(); var cqlOptions = evaluationSettings.getCqlOptions();
@@ -120,19 +123,10 @@ public class StarterCrDstu3Config {
cqlOptions.setCqlCompilerOptions(cqlCompilerOptions); cqlOptions.setCqlCompilerOptions(cqlCompilerOptions);
evaluationSettings.setLibraryCache(theGlobalLibraryCache); evaluationSettings.setLibraryCache(theGlobalLibraryCache);
evaluationSettings.setModelCache(theGlobalModelCache); evaluationSettings.setModelCache(theGlobalModelCache);
evaluationSettings.setValueSetCache(theGlobalValueSetCache);
return evaluationSettings; return evaluationSettings;
} }
@Bean
public Map<VersionedIdentifier, CompiledLibrary> globalLibraryCache() {
return new ConcurrentHashMap<>();
}
@Bean
public Map<ModelIdentifier, Model> globalModelCache() {
return new ConcurrentHashMap<>();
}
@Bean @Bean
public PostInitProviderRegisterer postInitProviderRegisterer(RestfulServer theRestfulServer, public PostInitProviderRegisterer postInitProviderRegisterer(RestfulServer theRestfulServer,
ResourceProviderFactory theResourceProviderFactory) { ResourceProviderFactory theResourceProviderFactory) {

View File

@@ -1,13 +1,9 @@
package ca.uhn.fhir.jpa.starter.cr; package ca.uhn.fhir.jpa.starter.cr;
import ca.uhn.fhir.cr.repo.HapiFhirRepository;
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.RestfulServer;
import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
import ca.uhn.fhir.cr.common.CqlThreadFactory; import ca.uhn.fhir.cr.common.CqlThreadFactory;
import ca.uhn.fhir.cr.common.IRepositoryFactory;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.starter.AppProperties; import ca.uhn.fhir.jpa.starter.AppProperties;
import org.cqframework.cql.cql2elm.CqlCompilerOptions; import org.cqframework.cql.cql2elm.CqlCompilerOptions;
import org.cqframework.cql.cql2elm.model.CompiledLibrary; import org.cqframework.cql.cql2elm.model.CompiledLibrary;
@@ -15,6 +11,7 @@ import org.cqframework.cql.cql2elm.model.Model;
import org.hl7.cql.model.ModelIdentifier; import org.hl7.cql.model.ModelIdentifier;
import org.hl7.elm.r1.VersionedIdentifier; import org.hl7.elm.r1.VersionedIdentifier;
import org.opencds.cqf.cql.engine.execution.CqlEngine; 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.EvaluationSettings;
import org.opencds.cqf.fhir.cr.measure.CareGapsProperties; import org.opencds.cqf.fhir.cr.measure.CareGapsProperties;
import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions;
@@ -25,15 +22,15 @@ import org.springframework.context.annotation.*;
import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService; import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@Configuration @Configuration
@Conditional({ OnR4Condition.class, CrConfigCondition.class }) @Conditional({ OnR4Condition.class, CrConfigCondition.class })
@Import(CrR4Config.class) @Import({BaseCrConfig.class, CrR4Config.class})
public class StarterCrR4Config { public class StarterCrR4Config {
private static final Logger ourLogger = LoggerFactory.getLogger(StarterCrR4Config.class); private static final Logger ourLogger = LoggerFactory.getLogger(StarterCrR4Config.class);
@@ -72,7 +69,8 @@ public class StarterCrR4Config {
public EvaluationSettings evaluationSettings( public EvaluationSettings evaluationSettings(
AppProperties theAppProperties, AppProperties theAppProperties,
Map<VersionedIdentifier, CompiledLibrary> theGlobalLibraryCache, Map<VersionedIdentifier, CompiledLibrary> theGlobalLibraryCache,
Map<ModelIdentifier, Model> theGlobalModelCache) { Map<ModelIdentifier, Model> theGlobalModelCache,
Map<String, List<Code>> theGlobalValueSetCache) {
var evaluationSettings = EvaluationSettings.getDefault(); var evaluationSettings = EvaluationSettings.getDefault();
var cqlOptions = evaluationSettings.getCqlOptions(); var cqlOptions = evaluationSettings.getCqlOptions();
@@ -140,19 +138,10 @@ public class StarterCrR4Config {
cqlOptions.setCqlCompilerOptions(cqlCompilerOptions); cqlOptions.setCqlCompilerOptions(cqlCompilerOptions);
evaluationSettings.setLibraryCache(theGlobalLibraryCache); evaluationSettings.setLibraryCache(theGlobalLibraryCache);
evaluationSettings.setModelCache(theGlobalModelCache); evaluationSettings.setModelCache(theGlobalModelCache);
evaluationSettings.setValueSetCache(theGlobalValueSetCache);
return evaluationSettings; return evaluationSettings;
} }
@Bean
public Map<VersionedIdentifier, CompiledLibrary> globalLibraryCache() {
return new ConcurrentHashMap<>();
}
@Bean
public Map<ModelIdentifier, Model> globalModelCache() {
return new ConcurrentHashMap<>();
}
@Bean @Bean
public PostInitProviderRegisterer postInitProviderRegisterer(RestfulServer theRestfulServer, public PostInitProviderRegisterer postInitProviderRegisterer(RestfulServer theRestfulServer,
ResourceProviderFactory theResourceProviderFactory) { ResourceProviderFactory theResourceProviderFactory) {