Bump HAPI to release 6.6.0 (#539)

* Start tracking 6.5

* Use JpaStorageSettings and StorageSettings

* Bump parent pom version + add deps for jaxb

* Bump HAPI

* Fix Subscription/Topic resource creation

* fix subscription topic beans

* Change to rel_6_6 hapi-fhir SNAPSHOT

* Fix emailSender config

* Split method calls by line.

* Merge pull request #524 from hapifhir/do-20230509-smoke-test-ci

Create smoke-tests.yml

* Bump core to release 6.6.0

---------

Co-authored-by: Michael Buckley <michaelabuckley@gmail.com>
Co-authored-by: Kevin Dougan SmileCDR <72025369+KevinDougan-SmileCDR@users.noreply.github.com>
Co-authored-by: Ken Stevens <ken@smilecdr.com>
Co-authored-by: Mark Iantorno <markiantorno@gmail.com>
This commit is contained in:
dotasek
2023-05-29 14:33:45 -04:00
committed by GitHub
parent eb65ec68cc
commit 53a958ac66
7 changed files with 137 additions and 91 deletions

14
pom.xml
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.4.4</version> <version>6.6.0</version>
</parent> </parent>
<artifactId>hapi-fhir-jpaserver-starter</artifactId> <artifactId>hapi-fhir-jpaserver-starter</artifactId>
@@ -62,7 +62,17 @@
<groupId>com.microsoft.sqlserver</groupId> <groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId> <artifactId>mssql-jdbc</artifactId>
</dependency> </dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-ri</artifactId>
<version>2.3.5</version>
<type>pom</type>
</dependency>
<!-- Needed for Email subscriptions --> <!-- Needed for Email subscriptions -->
<dependency> <dependency>
<groupId>org.simplejavamail</groupId> <groupId>org.simplejavamail</groupId>

View File

@@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.jpa.api.config.DaoConfig.ClientIdStrategyEnum; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings.ClientIdStrategyEnum;
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel; import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;

View File

@@ -1,12 +1,12 @@
package ca.uhn.fhir.jpa.starter.common; package ca.uhn.fhir.jpa.starter.common;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.binary.api.IBinaryStorageSvc; import ca.uhn.fhir.jpa.binary.api.IBinaryStorageSvc;
import ca.uhn.fhir.jpa.binstore.DatabaseBlobBinaryStorageSvcImpl; import ca.uhn.fhir.jpa.binstore.DatabaseBlobBinaryStorageSvcImpl;
import ca.uhn.fhir.jpa.config.HibernatePropertiesProvider; import ca.uhn.fhir.jpa.config.HibernatePropertiesProvider;
import ca.uhn.fhir.jpa.model.config.PartitionSettings; import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.config.PartitionSettings.CrossPartitionReferenceMode; import ca.uhn.fhir.jpa.model.config.PartitionSettings.CrossPartitionReferenceMode;
import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.model.entity.StorageSettings;
import ca.uhn.fhir.jpa.starter.AppProperties; import ca.uhn.fhir.jpa.starter.AppProperties;
import ca.uhn.fhir.jpa.starter.util.JpaHibernatePropertiesProvider; import ca.uhn.fhir.jpa.starter.util.JpaHibernatePropertiesProvider;
import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionDeliveryHandlerFactory; import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionDeliveryHandlerFactory;
@@ -17,7 +17,7 @@ import ca.uhn.fhir.rest.server.mail.MailConfig;
import ca.uhn.fhir.rest.server.mail.MailSvc; import ca.uhn.fhir.rest.server.mail.MailSvc;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import org.hl7.fhir.r4.model.Bundle.BundleType; import org.hl7.fhir.r4.model.Bundle.BundleType;
import org.hl7.fhir.dstu2.model.Subscription;
import org.springframework.boot.env.YamlPropertySourceLoader; import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -81,84 +81,85 @@ public class FhirServerConfigCommon {
* Configure FHIR properties around the the JPA server via this bean * Configure FHIR properties around the the JPA server via this bean
*/ */
@Bean @Bean
public DaoConfig daoConfig(AppProperties appProperties) { public JpaStorageSettings jpaStorageSettings(AppProperties appProperties) {
DaoConfig daoConfig = new DaoConfig(); JpaStorageSettings jpaStorageSettings = new JpaStorageSettings();
daoConfig.setIndexMissingFields(appProperties.getEnable_index_missing_fields() ? DaoConfig.IndexEnabledEnum.ENABLED : DaoConfig.IndexEnabledEnum.DISABLED); jpaStorageSettings.setIndexMissingFields(appProperties.getEnable_index_missing_fields() ? JpaStorageSettings.IndexEnabledEnum.ENABLED : JpaStorageSettings.IndexEnabledEnum.DISABLED);
daoConfig.setAutoCreatePlaceholderReferenceTargets(appProperties.getAuto_create_placeholder_reference_targets()); jpaStorageSettings.setAutoCreatePlaceholderReferenceTargets(appProperties.getAuto_create_placeholder_reference_targets());
daoConfig.setEnforceReferentialIntegrityOnWrite(appProperties.getEnforce_referential_integrity_on_write()); jpaStorageSettings.setEnforceReferentialIntegrityOnWrite(appProperties.getEnforce_referential_integrity_on_write());
daoConfig.setEnforceReferentialIntegrityOnDelete(appProperties.getEnforce_referential_integrity_on_delete()); jpaStorageSettings.setEnforceReferentialIntegrityOnDelete(appProperties.getEnforce_referential_integrity_on_delete());
daoConfig.setAllowContainsSearches(appProperties.getAllow_contains_searches()); jpaStorageSettings.setAllowContainsSearches(appProperties.getAllow_contains_searches());
daoConfig.setAllowMultipleDelete(appProperties.getAllow_multiple_delete()); jpaStorageSettings.setAllowMultipleDelete(appProperties.getAllow_multiple_delete());
daoConfig.setAllowExternalReferences(appProperties.getAllow_external_references()); jpaStorageSettings.setAllowExternalReferences(appProperties.getAllow_external_references());
daoConfig.setSchedulingDisabled(!appProperties.getDao_scheduling_enabled()); jpaStorageSettings.setSchedulingDisabled(!appProperties.getDao_scheduling_enabled());
daoConfig.setDeleteExpungeEnabled(appProperties.getDelete_expunge_enabled()); jpaStorageSettings.setDeleteExpungeEnabled(appProperties.getDelete_expunge_enabled());
daoConfig.setExpungeEnabled(appProperties.getExpunge_enabled()); jpaStorageSettings.setExpungeEnabled(appProperties.getExpunge_enabled());
if(appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null) if(appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null)
daoConfig.setEmailFromAddress(appProperties.getSubscription().getEmail().getFrom()); jpaStorageSettings.setEmailFromAddress(appProperties.getSubscription().getEmail().getFrom());
Integer maxFetchSize = appProperties.getMax_page_size(); Integer maxFetchSize = appProperties.getMax_page_size();
daoConfig.setFetchSizeDefaultMaximum(maxFetchSize); jpaStorageSettings.setFetchSizeDefaultMaximum(maxFetchSize);
ourLog.info("Server configured to have a maximum fetch size of " + (maxFetchSize == Integer.MAX_VALUE ? "'unlimited'" : maxFetchSize)); ourLog.info("Server configured to have a maximum fetch size of " + (maxFetchSize == Integer.MAX_VALUE ? "'unlimited'" : maxFetchSize));
Long reuseCachedSearchResultsMillis = appProperties.getReuse_cached_search_results_millis(); Long reuseCachedSearchResultsMillis = appProperties.getReuse_cached_search_results_millis();
daoConfig.setReuseCachedSearchResultsForMillis(reuseCachedSearchResultsMillis); jpaStorageSettings.setReuseCachedSearchResultsForMillis(reuseCachedSearchResultsMillis);
ourLog.info("Server configured to cache search results for {} milliseconds", reuseCachedSearchResultsMillis); ourLog.info("Server configured to cache search results for {} milliseconds", reuseCachedSearchResultsMillis);
Long retainCachedSearchesMinutes = appProperties.getRetain_cached_searches_mins(); Long retainCachedSearchesMinutes = appProperties.getRetain_cached_searches_mins();
daoConfig.setExpireSearchResultsAfterMillis(retainCachedSearchesMinutes * 60 * 1000); jpaStorageSettings.setExpireSearchResultsAfterMillis(retainCachedSearchesMinutes * 60 * 1000);
if(appProperties.getSubscription() != null) { if(appProperties.getSubscription() != null) {
// Subscriptions are enabled by channel type // Subscriptions are enabled by channel type
if (appProperties.getSubscription().getResthook_enabled()) { if (appProperties.getSubscription().getResthook_enabled()) {
ourLog.info("Enabling REST-hook subscriptions"); ourLog.info("Enabling REST-hook subscriptions");
daoConfig.addSupportedSubscriptionType(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.RESTHOOK); jpaStorageSettings.addSupportedSubscriptionType(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.RESTHOOK);
} }
if (appProperties.getSubscription().getEmail() != null) { if (appProperties.getSubscription().getEmail() != null) {
ourLog.info("Enabling email subscriptions"); ourLog.info("Enabling email subscriptions");
daoConfig.addSupportedSubscriptionType(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.EMAIL); jpaStorageSettings.addSupportedSubscriptionType(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.EMAIL);
} }
if (appProperties.getSubscription().getWebsocket_enabled()) { if (appProperties.getSubscription().getWebsocket_enabled()) {
ourLog.info("Enabling websocket subscriptions"); ourLog.info("Enabling websocket subscriptions");
daoConfig.addSupportedSubscriptionType(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.WEBSOCKET); jpaStorageSettings.addSupportedSubscriptionType(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.WEBSOCKET);
} }
} }
daoConfig.setFilterParameterEnabled(appProperties.getFilter_search_enabled()); jpaStorageSettings.setFilterParameterEnabled(appProperties.getFilter_search_enabled());
daoConfig.setAdvancedHSearchIndexing(appProperties.getAdvanced_lucene_indexing()); jpaStorageSettings.setAdvancedHSearchIndexing(appProperties.getAdvanced_lucene_indexing());
daoConfig.setTreatBaseUrlsAsLocal(new HashSet<>(appProperties.getLocal_base_urls())); jpaStorageSettings.setTreatBaseUrlsAsLocal(new HashSet<>(appProperties.getLocal_base_urls()));
if (appProperties.getLastn_enabled()) { if (appProperties.getLastn_enabled()) {
daoConfig.setLastNEnabled(true); jpaStorageSettings.setLastNEnabled(true);
} }
if(appProperties.getInline_resource_storage_below_size() != 0){ if(appProperties.getInline_resource_storage_below_size() != 0){
daoConfig.setInlineResourceTextBelowSize(appProperties.getInline_resource_storage_below_size()); jpaStorageSettings.setInlineResourceTextBelowSize(appProperties.getInline_resource_storage_below_size());
} }
daoConfig.setStoreResourceInHSearchIndex(appProperties.getStore_resource_in_lucene_index_enabled()); jpaStorageSettings.setStoreResourceInHSearchIndex(appProperties.getStore_resource_in_lucene_index_enabled());
daoConfig.getModelConfig().setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level()); jpaStorageSettings.setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level());
daoConfig.getModelConfig().setIndexOnContainedResources(appProperties.getEnable_index_contained_resource()); jpaStorageSettings.setIndexOnContainedResources(appProperties.getEnable_index_contained_resource());
if (appProperties.getAllowed_bundle_types() != null) { if (appProperties.getAllowed_bundle_types() != null) {
daoConfig.setBundleTypesAllowedForStorage(appProperties.getAllowed_bundle_types().stream().map(BundleType::toCode).collect(Collectors.toSet())); jpaStorageSettings.setBundleTypesAllowedForStorage(appProperties.getAllowed_bundle_types().stream().map(BundleType::toCode).collect(Collectors.toSet()));
} }
daoConfig.setDeferIndexingForCodesystemsOfSize(appProperties.getDefer_indexing_for_codesystems_of_size()); jpaStorageSettings.setDeferIndexingForCodesystemsOfSize(appProperties.getDefer_indexing_for_codesystems_of_size());
if (appProperties.getClient_id_strategy() == DaoConfig.ClientIdStrategyEnum.ANY) { if (appProperties.getClient_id_strategy() == JpaStorageSettings.ClientIdStrategyEnum.ANY) {
daoConfig.setResourceServerIdStrategy(DaoConfig.IdStrategyEnum.UUID); jpaStorageSettings.setResourceServerIdStrategy(JpaStorageSettings.IdStrategyEnum.UUID);
daoConfig.setResourceClientIdStrategy(appProperties.getClient_id_strategy()); jpaStorageSettings.setResourceClientIdStrategy(appProperties.getClient_id_strategy());
} }
//Parallel Batch GET execution settings //Parallel Batch GET execution settings
daoConfig.setBundleBatchPoolSize(appProperties.getBundle_batch_pool_size()); jpaStorageSettings.setBundleBatchPoolSize(appProperties.getBundle_batch_pool_size());
daoConfig.setBundleBatchMaxPoolSize(appProperties.getBundle_batch_pool_max_size()); jpaStorageSettings.setBundleBatchPoolSize(appProperties.getBundle_batch_pool_max_size());
return daoConfig; storageSettings(appProperties, jpaStorageSettings);
return jpaStorageSettings;
} }
@Bean @Bean
@@ -191,20 +192,19 @@ public class FhirServerConfigCommon {
return new JpaHibernatePropertiesProvider(myEntityManagerFactory); return new JpaHibernatePropertiesProvider(myEntityManagerFactory);
} }
@Bean
public ModelConfig modelConfig(AppProperties appProperties, DaoConfig daoConfig) { protected StorageSettings storageSettings(AppProperties appProperties, JpaStorageSettings jpaStorageSettings) {
ModelConfig modelConfig = daoConfig.getModelConfig(); jpaStorageSettings.setAllowContainsSearches(appProperties.getAllow_contains_searches());
modelConfig.setAllowContainsSearches(appProperties.getAllow_contains_searches()); jpaStorageSettings.setAllowExternalReferences(appProperties.getAllow_external_references());
modelConfig.setAllowExternalReferences(appProperties.getAllow_external_references()); jpaStorageSettings.setDefaultSearchParamsCanBeOverridden(appProperties.getAllow_override_default_search_params());
modelConfig.setDefaultSearchParamsCanBeOverridden(appProperties.getAllow_override_default_search_params());
if(appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null) if(appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null)
modelConfig.setEmailFromAddress(appProperties.getSubscription().getEmail().getFrom()); jpaStorageSettings.setEmailFromAddress(appProperties.getSubscription().getEmail().getFrom());
modelConfig.setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level()); jpaStorageSettings.setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level());
modelConfig.setIndexOnContainedResources(appProperties.getEnable_index_contained_resource()); jpaStorageSettings.setIndexOnContainedResources(appProperties.getEnable_index_contained_resource());
modelConfig.setIndexIdentifierOfType(appProperties.getEnable_index_of_type()); jpaStorageSettings.setIndexIdentifierOfType(appProperties.getEnable_index_of_type());
return modelConfig; return jpaStorageSettings;
} }
@Lazy @Lazy
@@ -220,7 +220,7 @@ public class FhirServerConfigCommon {
} }
@Bean @Bean
public IEmailSender emailSender(AppProperties appProperties, Optional<SubscriptionDeliveryHandlerFactory> subscriptionDeliveryHandlerFactory) { public IEmailSender emailSender(AppProperties appProperties) {
if (appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null) { if (appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null) {
MailConfig mailConfig = new MailConfig(); MailConfig mailConfig = new MailConfig();
@@ -234,8 +234,6 @@ public class FhirServerConfigCommon {
IMailSvc mailSvc = new MailSvc(mailConfig); IMailSvc mailSvc = new MailSvc(mailConfig);
IEmailSender emailSender = new EmailSenderImpl(mailSvc); IEmailSender emailSender = new EmailSenderImpl(mailSvc);
subscriptionDeliveryHandlerFactory.ifPresent(theSubscriptionDeliveryHandlerFactory -> theSubscriptionDeliveryHandlerFactory.setEmailSender(emailSender));
return emailSender; return emailSender;
} }

View File

@@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.starter.common;
import ca.uhn.fhir.jpa.config.r4b.JpaR4BConfig; import ca.uhn.fhir.jpa.config.r4b.JpaR4BConfig;
import ca.uhn.fhir.jpa.starter.annotations.OnR4BCondition; import ca.uhn.fhir.jpa.starter.annotations.OnR4BCondition;
import ca.uhn.fhir.jpa.topic.SubscriptionTopicConfig;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@@ -10,6 +11,7 @@ import org.springframework.context.annotation.Import;
@Conditional(OnR4BCondition.class) @Conditional(OnR4BCondition.class)
@Import({ @Import({
JpaR4BConfig.class, JpaR4BConfig.class,
SubscriptionTopicConfig.class,
StarterJpaConfig.class, StarterJpaConfig.class,
ElasticsearchConfig.class ElasticsearchConfig.class
}) })

View File

@@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.starter.common;
import ca.uhn.fhir.jpa.config.r5.JpaR5Config; import ca.uhn.fhir.jpa.config.r5.JpaR5Config;
import ca.uhn.fhir.jpa.starter.annotations.OnR5Condition; import ca.uhn.fhir.jpa.starter.annotations.OnR5Condition;
import ca.uhn.fhir.jpa.topic.SubscriptionTopicConfig;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@@ -11,6 +12,7 @@ import org.springframework.context.annotation.Import;
@Import({ @Import({
StarterJpaConfig.class, StarterJpaConfig.class,
JpaR5Config.class, JpaR5Config.class,
SubscriptionTopicConfig.class,
ElasticsearchConfig.class ElasticsearchConfig.class
}) })
public class FhirServerConfigR5 { public class FhirServerConfigR5 {

View File

@@ -11,7 +11,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.jpa.api.IDaoRegistry; import ca.uhn.fhir.jpa.api.IDaoRegistry;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.api.config.ThreadPoolFactoryConfig; import ca.uhn.fhir.jpa.api.config.ThreadPoolFactoryConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
@@ -241,7 +241,7 @@ public class StarterJpaConfig {
} }
@Bean @Bean
public RestfulServer restfulServer(IFhirSystemDao<?, ?> fhirSystemDao, AppProperties appProperties, DaoRegistry daoRegistry, Optional<MdmProviderLoader> mdmProviderProvider, IJpaSystemProvider jpaSystemProvider, ResourceProviderFactory resourceProviderFactory, DaoConfig daoConfig, ISearchParamRegistry searchParamRegistry, IValidationSupport theValidationSupport, DatabaseBackedPagingProvider databaseBackedPagingProvider, LoggingInterceptor loggingInterceptor, Optional<TerminologyUploaderProvider> terminologyUploaderProvider, Optional<SubscriptionTriggeringProvider> subscriptionTriggeringProvider, Optional<CorsInterceptor> corsInterceptor, IInterceptorBroadcaster interceptorBroadcaster, Optional<BinaryAccessProvider> binaryAccessProvider, BinaryStorageInterceptor binaryStorageInterceptor, IValidatorModule validatorModule, Optional<GraphQLProvider> graphQLProvider, BulkDataExportProvider bulkDataExportProvider, BulkDataImportProvider bulkDataImportProvider, ValueSetOperationProvider theValueSetOperationProvider, ReindexProvider reindexProvider, PartitionManagementProvider partitionManagementProvider, Optional<RepositoryValidatingInterceptor> repositoryValidatingInterceptor, IPackageInstallerSvc packageInstallerSvc, ThreadSafeResourceDeleterSvc theThreadSafeResourceDeleterSvc, ApplicationContext appContext, Optional<IpsOperationProvider> theIpsOperationProvider) { public RestfulServer restfulServer(IFhirSystemDao<?, ?> fhirSystemDao, AppProperties appProperties, DaoRegistry daoRegistry, Optional<MdmProviderLoader> mdmProviderProvider, IJpaSystemProvider jpaSystemProvider, ResourceProviderFactory resourceProviderFactory, JpaStorageSettings jpaStorageSettings, ISearchParamRegistry searchParamRegistry, IValidationSupport theValidationSupport, DatabaseBackedPagingProvider databaseBackedPagingProvider, LoggingInterceptor loggingInterceptor, Optional<TerminologyUploaderProvider> terminologyUploaderProvider, Optional<SubscriptionTriggeringProvider> subscriptionTriggeringProvider, Optional<CorsInterceptor> corsInterceptor, IInterceptorBroadcaster interceptorBroadcaster, Optional<BinaryAccessProvider> binaryAccessProvider, BinaryStorageInterceptor binaryStorageInterceptor, IValidatorModule validatorModule, Optional<GraphQLProvider> graphQLProvider, BulkDataExportProvider bulkDataExportProvider, BulkDataImportProvider bulkDataImportProvider, ValueSetOperationProvider theValueSetOperationProvider, ReindexProvider reindexProvider, PartitionManagementProvider partitionManagementProvider, Optional<RepositoryValidatingInterceptor> repositoryValidatingInterceptor, IPackageInstallerSvc packageInstallerSvc, ThreadSafeResourceDeleterSvc theThreadSafeResourceDeleterSvc, ApplicationContext appContext, Optional<IpsOperationProvider> theIpsOperationProvider) {
RestfulServer fhirServer = new RestfulServer(fhirSystemDao.getContext()); RestfulServer fhirServer = new RestfulServer(fhirSystemDao.getContext());
List<String> supportedResourceTypes = appProperties.getSupported_resource_types(); List<String> supportedResourceTypes = appProperties.getSupported_resource_types();
@@ -263,7 +263,7 @@ public class StarterJpaConfig {
fhirServer.registerProviders(resourceProviderFactory.createProviders()); fhirServer.registerProviders(resourceProviderFactory.createProviders());
fhirServer.registerProvider(jpaSystemProvider); fhirServer.registerProvider(jpaSystemProvider);
fhirServer.setServerConformanceProvider(calculateConformanceProvider(fhirSystemDao, fhirServer, daoConfig, searchParamRegistry, theValidationSupport)); fhirServer.setServerConformanceProvider(calculateConformanceProvider(fhirSystemDao, fhirServer, jpaStorageSettings, searchParamRegistry, theValidationSupport));
/* /*
* ETag Support * ETag Support
@@ -339,7 +339,7 @@ public class StarterJpaConfig {
corsInterceptor.ifPresent(fhirServer::registerInterceptor); corsInterceptor.ifPresent(fhirServer::registerInterceptor);
if (daoConfig.getSupportedSubscriptionTypes().size() > 0) { if (jpaStorageSettings.getSupportedSubscriptionTypes().size() > 0) {
// Subscription debug logging // Subscription debug logging
fhirServer.registerInterceptor(new SubscriptionDebugLogInterceptor()); fhirServer.registerInterceptor(new SubscriptionDebugLogInterceptor());
} }
@@ -458,30 +458,30 @@ public class StarterJpaConfig {
} }
} }
public static IServerConformanceProvider<?> calculateConformanceProvider(IFhirSystemDao fhirSystemDao, RestfulServer fhirServer, DaoConfig daoConfig, ISearchParamRegistry searchParamRegistry, IValidationSupport theValidationSupport) { public static IServerConformanceProvider<?> calculateConformanceProvider(IFhirSystemDao fhirSystemDao, RestfulServer fhirServer, JpaStorageSettings jpaStorageSettings, ISearchParamRegistry searchParamRegistry, IValidationSupport theValidationSupport) {
FhirVersionEnum fhirVersion = fhirSystemDao.getContext().getVersion().getVersion(); FhirVersionEnum fhirVersion = fhirSystemDao.getContext().getVersion().getVersion();
if (fhirVersion == FhirVersionEnum.DSTU2) { if (fhirVersion == FhirVersionEnum.DSTU2) {
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(fhirServer, fhirSystemDao, daoConfig); JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(fhirServer, fhirSystemDao, jpaStorageSettings);
confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server"); confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server");
return confProvider; return confProvider;
} else if (fhirVersion == FhirVersionEnum.DSTU3) { } else if (fhirVersion == FhirVersionEnum.DSTU3) {
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(fhirServer, fhirSystemDao, daoConfig, searchParamRegistry); JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(fhirServer, fhirSystemDao, jpaStorageSettings, searchParamRegistry);
confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server"); confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server");
return confProvider; return confProvider;
} else if (fhirVersion == FhirVersionEnum.R4) { } else if (fhirVersion == FhirVersionEnum.R4) {
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, daoConfig, searchParamRegistry, theValidationSupport); JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, jpaStorageSettings, searchParamRegistry, theValidationSupport);
confProvider.setImplementationDescription("HAPI FHIR R4 Server"); confProvider.setImplementationDescription("HAPI FHIR R4 Server");
return confProvider; return confProvider;
} else if (fhirVersion == FhirVersionEnum.R4B) { } else if (fhirVersion == FhirVersionEnum.R4B) {
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, daoConfig, searchParamRegistry, theValidationSupport); JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, jpaStorageSettings, searchParamRegistry, theValidationSupport);
confProvider.setImplementationDescription("HAPI FHIR R4B Server"); confProvider.setImplementationDescription("HAPI FHIR R4B Server");
return confProvider; return confProvider;
} else if (fhirVersion == FhirVersionEnum.R5) { } else if (fhirVersion == FhirVersionEnum.R5) {
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, daoConfig, searchParamRegistry, theValidationSupport); JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, jpaStorageSettings, searchParamRegistry, theValidationSupport);
confProvider.setImplementationDescription("HAPI FHIR R5 Server"); confProvider.setImplementationDescription("HAPI FHIR R5 Server");
return confProvider; return confProvider;
} else { } else {

View File

@@ -37,7 +37,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
"spring.datasource.url=jdbc:h2:mem:dbr5", "spring.datasource.url=jdbc:h2:mem:dbr5",
"hapi.fhir.fhir_version=r5", "hapi.fhir.fhir_version=r5",
"hapi.fhir.subscription.websocket_enabled=true", "hapi.fhir.subscription.websocket_enabled=true",
"hapi.fhir.subscription.websocket_enabled=true", "hapi.fhir.subscription.websocket_enabled=true"
}) })
public class ExampleServerR5IT { public class ExampleServerR5IT {
@@ -45,6 +45,9 @@ public class ExampleServerR5IT {
private IGenericClient ourClient; private IGenericClient ourClient;
private FhirContext ourCtx; private FhirContext ourCtx;
public static final String SUBSCRIPTION_TOPIC_TEST_URL = "http://example.com/topic/test";
@LocalServerPort @LocalServerPort
private int port; private int port;
@@ -64,32 +67,62 @@ public class ExampleServerR5IT {
@Test @Test
public void testWebsocketSubscription() throws Exception { public void testWebsocketSubscription() throws Exception {
String endpoint = "ws://localhost:" + port + "/websocket";
/* /*
* Create topic (will be contained in subscription) * Create topic
*/ */
SubscriptionTopic topic = new SubscriptionTopic(); SubscriptionTopic topic = new SubscriptionTopic();
topic.setId("#1");
topic.getResourceTriggerFirstRep().getQueryCriteria().setCurrent("Observation?status=final"); topic.setUrl(SUBSCRIPTION_TOPIC_TEST_URL);
topic.setStatus(Enumerations.PublicationStatus.ACTIVE);
SubscriptionTopic.SubscriptionTopicResourceTriggerComponent trigger = topic.addResourceTrigger();
trigger.setResource("Observation");
trigger.addSupportedInteraction(SubscriptionTopic.InteractionTrigger.CREATE);
trigger.addSupportedInteraction(SubscriptionTopic.InteractionTrigger.UPDATE);
ourClient.create().resource(topic).execute();
waitForSize(1, () -> ourClient
.search()
.forResource(SubscriptionTopic.class)
.where(Subscription.STATUS.exactly().code("active"))
.cacheControl(
new CacheControlDirective()
.setNoCache(true))
.returnBundle(Bundle.class)
.execute()
.getEntry()
.size());
/* /*
* Create subscription * Create subscription
*/ */
Subscription subscription = new Subscription(); Subscription subscription = new Subscription();
subscription.getContained().add(topic);
subscription.setTopic("#1"); subscription.setTopic(SUBSCRIPTION_TOPIC_TEST_URL);
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)"); subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
subscription.setStatus(Enumerations.SubscriptionStatusCodes.REQUESTED); subscription.setStatus(Enumerations.SubscriptionStatusCodes.REQUESTED);
subscription.getChannelType() subscription.getChannelType()
.setSystem("http://terminology.hl7.org/CodeSystem/subscription-channel-type") .setSystem("http://terminology.hl7.org/CodeSystem/subscription-channel-type")
.setCode("websocket"); .setCode("websocket");
subscription.setContentType("application/json"); subscription.setContentType("application/fhir+json");
subscription.setEndpoint(endpoint);
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute(); MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();
IIdType mySubscriptionId = methodOutcome.getId(); IIdType mySubscriptionId = methodOutcome.getId();
// Wait for the subscription to be activated // Wait for the subscription to be activated
waitForSize(1, () -> ourClient.search().forResource(Subscription.class).where(Subscription.STATUS.exactly().code("active")).cacheControl(new CacheControlDirective().setNoCache(true)).returnBundle(Bundle.class).execute().getEntry().size()); waitForSize(1, () -> ourClient
.search()
.forResource(Subscription.class)
.where(Subscription.STATUS.exactly().code("active"))
.cacheControl(
new CacheControlDirective()
.setNoCache(true))
.returnBundle(Bundle.class)
.execute()
.getEntry()
.size());
/* /*
* Attach websocket * Attach websocket
@@ -99,7 +132,8 @@ public class ExampleServerR5IT {
SocketImplementation mySocketImplementation = new SocketImplementation(mySubscriptionId.getIdPart(), EncodingEnum.JSON); SocketImplementation mySocketImplementation = new SocketImplementation(mySubscriptionId.getIdPart(), EncodingEnum.JSON);
myWebSocketClient.start(); myWebSocketClient.start();
URI echoUri = new URI("ws://localhost:" + port + "/websocket");
URI echoUri = new URI(endpoint);
ClientUpgradeRequest request = new ClientUpgradeRequest(); ClientUpgradeRequest request = new ClientUpgradeRequest();
ourLog.info("Connecting to : {}", echoUri); ourLog.info("Connecting to : {}", echoUri);
Future<Session> connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request); Future<Session> connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request);