From 6d10c0badecb4d45cd4e3dbcadd4c17dc43081f4 Mon Sep 17 00:00:00 2001 From: Justin McKelvy <60718638+Capt-Mac@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:16:17 -0600 Subject: [PATCH] add valueset cache and cache invalidation listeners --- pom.xml | 2 +- .../uhn/fhir/jpa/starter/cr/BaseCrConfig.java | 85 +++++++++++++++++++ .../uhn/fhir/jpa/starter/cr/CrR4Config.java | 76 ++++++++--------- .../jpa/starter/cr/StarterCrDstu3Config.java | 18 ++-- .../jpa/starter/cr/StarterCrR4Config.java | 23 ++--- 5 files changed, 136 insertions(+), 68 deletions(-) create mode 100644 src/main/java/ca/uhn/fhir/jpa/starter/cr/BaseCrConfig.java diff --git a/pom.xml b/pom.xml index 02913fa..b477e48 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.9.9-SNAPSHOT + 6.9.10-SNAPSHOT hapi-fhir-jpaserver-starter diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cr/BaseCrConfig.java b/src/main/java/ca/uhn/fhir/jpa/starter/cr/BaseCrConfig.java new file mode 100644 index 0000000..1e08b33 --- /dev/null +++ b/src/main/java/ca/uhn/fhir/jpa/starter/cr/BaseCrConfig.java @@ -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 globalLibraryCache() { + return new ConcurrentHashMap<>(); + } + + @Bean + public Map globalModelCache() { + return new ConcurrentHashMap<>(); + } + + @Bean + public Map> 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(); + } +} diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cr/CrR4Config.java b/src/main/java/ca/uhn/fhir/jpa/starter/cr/CrR4Config.java index 4713bdb..07cc7cc 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/cr/CrR4Config.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/cr/CrR4Config.java @@ -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.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.cr.r4.plandefinition.PlanDefinitionApplyProvider; 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.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.opencds.cqf.fhir.cr.plandefinition.r4.PlanDefinitionProcessor; import org.opencds.cqf.fhir.cr.questionnaire.r4.QuestionnaireProcessor; @@ -49,8 +49,8 @@ public class CrR4Config { @Bean IMeasureServiceFactory r4MeasureServiceFactory( - IRepositoryFactory theRepositoryFactory, MeasureEvaluationOptions theEvaluationOptions) { - return rd -> new MeasureService(theRepositoryFactory.create(rd), theEvaluationOptions); + IRepositoryFactory theRepositoryFactory, MeasureEvaluationOptions theEvaluationOptions) { + return rd -> new R4MeasureService(theRepositoryFactory.create(rd), theEvaluationOptions); } @Bean @@ -60,7 +60,7 @@ public class CrR4Config { @Bean ICqlExecutionServiceFactory r4CqlExecutionServiceFactory( - IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { + IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { return rd -> new R4CqlExecutionService(theRepositoryFactory.create(rd), theEvaluationSettings); } @@ -71,16 +71,16 @@ public class CrR4Config { @Bean ICareGapsServiceFactory careGapsServiceFactory( - IRepositoryFactory theRepositoryFactory, - CareGapsProperties theCareGapsProperties, - MeasureEvaluationOptions theMeasureEvaluationOptions, - @Qualifier("cqlExecutor") Executor theExecutor) { + IRepositoryFactory theRepositoryFactory, + CareGapsProperties theCareGapsProperties, + MeasureEvaluationOptions theMeasureEvaluationOptions, + @Qualifier("cqlExecutor") Executor theExecutor) { return rd -> new R4CareGapsService( - theCareGapsProperties, - theRepositoryFactory.create(rd), - theMeasureEvaluationOptions, - theExecutor, - rd.getFhirServerBase()); + theCareGapsProperties, + theRepositoryFactory.create(rd), + theMeasureEvaluationOptions, + theExecutor, + rd.getFhirServerBase()); } @Bean @@ -100,30 +100,30 @@ public class CrR4Config { @Bean IActivityDefinitionProcessorFactory r4ActivityDefinitionProcessorFactory( - IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { + IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { return rd -> new ActivityDefinitionProcessor( - theRepositoryFactory.create(rd), theEvaluationSettings); + theRepositoryFactory.create(rd), theEvaluationSettings); } @Bean IPlanDefinitionProcessorFactory r4PlanDefinitionProcessorFactory( - IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { + IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { return rd -> new PlanDefinitionProcessor( - theRepositoryFactory.create(rd), theEvaluationSettings); + theRepositoryFactory.create(rd), theEvaluationSettings); } @Bean IQuestionnaireProcessorFactory r4QuestionnaireProcessorFactory( - IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { + IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { return rd -> new QuestionnaireProcessor( - theRepositoryFactory.create(rd), theEvaluationSettings); + theRepositoryFactory.create(rd), theEvaluationSettings); } @Bean IQuestionnaireResponseProcessorFactory r4QuestionnaireResponseProcessorFactory( - IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { + IRepositoryFactory theRepositoryFactory, EvaluationSettings theEvaluationSettings) { return rd -> new QuestionnaireResponseProcessor( - theRepositoryFactory.create(rd), theEvaluationSettings); + theRepositoryFactory.create(rd), theEvaluationSettings); } @Bean @@ -138,7 +138,7 @@ public class CrR4Config { @Bean QuestionnaireResponseExtractProvider - r4QuestionnaireResponseExtractProvider() { + r4QuestionnaireResponseExtractProvider() { return new QuestionnaireResponseExtractProvider(); } @@ -159,24 +159,24 @@ public class CrR4Config { @Bean public ProviderLoader r4PdLoader( - ApplicationContext theApplicationContext, FhirContext theFhirContext, RestfulServer theRestfulServer) { + ApplicationContext theApplicationContext, FhirContext theFhirContext, RestfulServer theRestfulServer) { var selector = new ProviderSelector( - theFhirContext, - Map.of( - FhirVersionEnum.R4, - Arrays.asList( - MeasureOperationsProvider.class, - SubmitDataProvider.class, - CareGapsOperationProvider.class, - CqlExecutionOperationProvider.class, - ActivityDefinitionApplyProvider.class, - PlanDefinitionApplyProvider.class, - QuestionnaireResponseExtractProvider.class, - QuestionnairePackageProvider.class, - PlanDefinitionPackageProvider.class, - QuestionnairePopulateProvider.class))); + theFhirContext, + Map.of( + FhirVersionEnum.R4, + Arrays.asList( + MeasureOperationsProvider.class, + SubmitDataProvider.class, + CareGapsOperationProvider.class, + CqlExecutionOperationProvider.class, + ActivityDefinitionApplyProvider.class, + PlanDefinitionApplyProvider.class, + QuestionnaireResponseExtractProvider.class, + QuestionnairePackageProvider.class, + PlanDefinitionPackageProvider.class, + QuestionnairePopulateProvider.class))); return new ProviderLoader(theRestfulServer, theApplicationContext, selector); } -} +} \ No newline at end of file diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrDstu3Config.java b/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrDstu3Config.java index 6afcbc3..58c731f 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrDstu3Config.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrDstu3Config.java @@ -15,6 +15,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.MeasureEvaluationOptions; import org.opencds.cqf.fhir.utility.ValidationProfile; @@ -23,6 +24,7 @@ import org.slf4j.LoggerFactory; 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; @@ -33,7 +35,7 @@ import java.util.concurrent.ConcurrentHashMap; ApplyOperationConfig.class, ExtractOperationConfig.class, PackageOperationConfig.class, - PopulateOperationConfig.class}) + PopulateOperationConfig.class, BaseCrConfig.class}) public class StarterCrDstu3Config { private static final Logger ourLogger = LoggerFactory.getLogger(StarterCrDstu3Config.class); @@ -52,7 +54,8 @@ public class StarterCrDstu3Config { public EvaluationSettings evaluationSettings( AppProperties theAppProperties, Map theGlobalLibraryCache, - Map theGlobalModelCache) { + Map theGlobalModelCache, + Map> theGlobalValueSetCache) { var evaluationSettings = EvaluationSettings.getDefault(); var cqlOptions = evaluationSettings.getCqlOptions(); @@ -120,19 +123,10 @@ public class StarterCrDstu3Config { cqlOptions.setCqlCompilerOptions(cqlCompilerOptions); evaluationSettings.setLibraryCache(theGlobalLibraryCache); evaluationSettings.setModelCache(theGlobalModelCache); + evaluationSettings.setValueSetCache(theGlobalValueSetCache); return evaluationSettings; } - @Bean - public Map globalLibraryCache() { - return new ConcurrentHashMap<>(); - } - - @Bean - public Map globalModelCache() { - return new ConcurrentHashMap<>(); - } - @Bean public PostInitProviderRegisterer postInitProviderRegisterer(RestfulServer theRestfulServer, ResourceProviderFactory theResourceProviderFactory) { diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrR4Config.java b/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrR4Config.java index 09e37b7..46e4abe 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrR4Config.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/cr/StarterCrR4Config.java @@ -1,13 +1,9 @@ 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.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; 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 org.cqframework.cql.cql2elm.CqlCompilerOptions; 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.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,15 +22,15 @@ import org.springframework.context.annotation.*; 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 @Conditional({ OnR4Condition.class, CrConfigCondition.class }) -@Import(CrR4Config.class) +@Import({BaseCrConfig.class, CrR4Config.class}) public class StarterCrR4Config { private static final Logger ourLogger = LoggerFactory.getLogger(StarterCrR4Config.class); @@ -72,7 +69,8 @@ public class StarterCrR4Config { public EvaluationSettings evaluationSettings( AppProperties theAppProperties, Map theGlobalLibraryCache, - Map theGlobalModelCache) { + Map theGlobalModelCache, + Map> theGlobalValueSetCache) { var evaluationSettings = EvaluationSettings.getDefault(); var cqlOptions = evaluationSettings.getCqlOptions(); @@ -140,19 +138,10 @@ public class StarterCrR4Config { cqlOptions.setCqlCompilerOptions(cqlCompilerOptions); evaluationSettings.setLibraryCache(theGlobalLibraryCache); evaluationSettings.setModelCache(theGlobalModelCache); + evaluationSettings.setValueSetCache(theGlobalValueSetCache); return evaluationSettings; } - @Bean - public Map globalLibraryCache() { - return new ConcurrentHashMap<>(); - } - - @Bean - public Map globalModelCache() { - return new ConcurrentHashMap<>(); - } - @Bean public PostInitProviderRegisterer postInitProviderRegisterer(RestfulServer theRestfulServer, ResourceProviderFactory theResourceProviderFactory) {