From 4f8d34cbb45baf2317018c2d6d07620a18823612 Mon Sep 17 00:00:00 2001 From: Ken Stevens Date: Mon, 27 Apr 2020 12:49:15 -0400 Subject: [PATCH 1/6] updated to match 5.0.0 --- pom.xml | 16 ++++++--- .../fhir/jpa/starter/ApplicationContext.java | 3 +- .../ca/uhn/fhir/jpa/starter/EmpiConfig.java | 27 +++++++++++++++ .../jpa/starter/FhirServerConfigCommon.java | 14 ++++---- .../uhn/fhir/jpa/starter/HapiProperties.java | 5 +++ .../fhir/jpa/starter/JpaRestfulServer.java | 33 +++++++++++-------- src/main/resources/empi-rules.json | 32 ++++++++++++++++++ 7 files changed, 105 insertions(+), 25 deletions(-) create mode 100644 src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java create mode 100644 src/main/resources/empi-rules.json diff --git a/pom.xml b/pom.xml index 3ad764d..7cc8094 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 + + ca.uhn.hapi.fhir + hapi-fhir-jpaserver-empi + ${project.version} + ca.uhn.hapi.fhir @@ -276,7 +282,7 @@ org.eclipse.jetty jetty-maven-plugin - ${jetty_version} + ${jetty_version} /hapi-fhir-jpaserver diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/ApplicationContext.java b/src/main/java/ca/uhn/fhir/jpa/starter/ApplicationContext.java index 24b4f79..3770e1a 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/ApplicationContext.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/ApplicationContext.java @@ -1,6 +1,7 @@ package ca.uhn.fhir.jpa.starter; import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.jpa.subscription.match.config.WebsocketDispatcherConfig; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; public class ApplicationContext extends AnnotationConfigWebApplicationContext { @@ -20,7 +21,7 @@ public class ApplicationContext extends AnnotationConfigWebApplicationContext { } if (HapiProperties.getSubscriptionWebsocketEnabled()) { - register(ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig.class); + register(WebsocketDispatcherConfig.class); } } diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java b/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java new file mode 100644 index 0000000..3617036 --- /dev/null +++ b/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java @@ -0,0 +1,27 @@ +package ca.uhn.fhir.jpa.starter; + +import ca.uhn.fhir.empi.api.IEmpiSettings; +import ca.uhn.fhir.empi.rules.config.EmpiSettingsImpl; +import ca.uhn.fhir.jpa.empi.config.EmpiConsumerConfig; +import ca.uhn.fhir.jpa.empi.config.EmpiSubmitterConfig; +import com.google.common.base.Charsets; +import org.apache.commons.io.IOUtils; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; + +import java.io.IOException; + +@Configuration +@Import({EmpiSubmitterConfig.class, EmpiConsumerConfig.class}) +public class EmpiConfig { + @Bean + IEmpiSettings empiProperties() throws IOException { + DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); + Resource resource = resourceLoader.getResource("empi-rules.json"); + String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8); + return new EmpiSettingsImpl().setEnabled(HapiProperties.getEmpiEnabled()).setScriptText(json); + } +} diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java index 70bfb4d..5647d03 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java @@ -1,17 +1,18 @@ package ca.uhn.fhir.jpa.starter; +import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.binstore.DatabaseBlobBinaryStorageSvcImpl; import ca.uhn.fhir.jpa.binstore.IBinaryStorageSvc; -import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.model.entity.ModelConfig; -import ca.uhn.fhir.jpa.subscription.module.channel.SubscriptionDeliveryHandlerFactory; -import ca.uhn.fhir.jpa.subscription.module.subscriber.email.IEmailSender; -import ca.uhn.fhir.jpa.subscription.module.subscriber.email.JavaMailEmailSender; +import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionDeliveryHandlerFactory; +import ca.uhn.fhir.jpa.subscription.match.deliver.email.IEmailSender; +import ca.uhn.fhir.jpa.subscription.match.deliver.email.JavaMailEmailSender; import org.apache.commons.dbcp2.BasicDataSource; import org.hl7.fhir.dstu2.model.Subscription; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.thymeleaf.util.Validate; @@ -23,7 +24,8 @@ import java.sql.Driver; * This is the primary configuration file for the example server */ @Configuration -@EnableTransactionManagement() +@EnableTransactionManagement +@Import(EmpiConfig.class) public class FhirServerConfigCommon { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirServerConfigCommon.class); @@ -191,7 +193,7 @@ public class FhirServerConfigCommon { retVal.setSmtpServerPort(this.emailPort); retVal.setSmtpServerUsername(this.emailUsername); retVal.setSmtpServerPassword(this.emailPassword); - // TODO KHS add these when HAPI 4.2.0 is released + // FIXME KHS add these once this has merged in hapi // retVal.setAuth(this.emailAuth); // retVal.setStartTlsEnable(this.emailStartTlsEnable); // retVal.setStartTlsRequired(this.emailStartTlsRequired); diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java b/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java index 5be55f4..a159758 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java @@ -57,6 +57,7 @@ public class HapiProperties { static final String SUBSCRIPTION_EMAIL_ENABLED = "subscription.email.enabled"; static final String SUBSCRIPTION_RESTHOOK_ENABLED = "subscription.resthook.enabled"; static final String SUBSCRIPTION_WEBSOCKET_ENABLED = "subscription.websocket.enabled"; + static final String EMPI_ENABLED = "empi.enabled"; static final String ALLOWED_BUNDLE_TYPES = "allowed_bundle_types"; static final String TEST_PORT = "test.port"; static final String TESTER_CONFIG_REFUSE_TO_FETCH_THIRD_PARTY_URLS = "tester.config.refuse_to_fetch_third_party_urls"; @@ -373,6 +374,10 @@ public class HapiProperties { return HapiProperties.getBooleanProperty(SUBSCRIPTION_WEBSOCKET_ENABLED, false); } + public static Boolean getEmpiEnabled() { + return HapiProperties.getBooleanProperty(EMPI_ENABLED, false); + } + public static Boolean getAllowContainsSearches() { return HapiProperties.getBooleanProperty(ALLOW_CONTAINS_SEARCHES, true); } diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java index f5a47f6..e32148e 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java @@ -4,11 +4,11 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorService; +import ca.uhn.fhir.jpa.api.config.DaoConfig; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor; import ca.uhn.fhir.jpa.bulk.BulkDataExportProvider; -import ca.uhn.fhir.jpa.dao.DaoConfig; -import ca.uhn.fhir.jpa.dao.DaoRegistry; -import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; import ca.uhn.fhir.jpa.provider.GraphQLProvider; import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2; @@ -22,9 +22,9 @@ import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4; import ca.uhn.fhir.jpa.provider.r5.JpaConformanceProviderR5; import ca.uhn.fhir.jpa.provider.r5.JpaSystemProviderR5; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; -import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader; -import ca.uhn.fhir.jpa.subscription.module.interceptor.SubscriptionDebugLogInterceptor; -import ca.uhn.fhir.jpa.util.ResourceProviderFactory; +import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; +import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionSubmitInterceptorLoader; +import ca.uhn.fhir.jpa.subscription.util.SubscriptionDebugLogInterceptor; import ca.uhn.fhir.model.dstu2.composite.MetaDt; import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy; @@ -34,6 +34,7 @@ import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor; import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor; import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor; +import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhir.validation.ResultSeverityEnum; import java.util.HashSet; @@ -123,21 +124,21 @@ public class JpaRestfulServer extends RestfulServer { IFhirSystemDao systemDao = appCtx .getBean("mySystemDaoDstu3", IFhirSystemDao.class); JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, - appCtx.getBean(DaoConfig.class)); + appCtx.getBean(DaoConfig.class), appCtx.getBean(ISearchParamRegistry.class)); confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server"); setServerConformanceProvider(confProvider); } else if (fhirVersion == FhirVersionEnum.R4) { IFhirSystemDao systemDao = appCtx .getBean("mySystemDaoR4", IFhirSystemDao.class); JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, systemDao, - appCtx.getBean(DaoConfig.class)); + appCtx.getBean(DaoConfig.class), appCtx.getBean(ISearchParamRegistry.class)); confProvider.setImplementationDescription("HAPI FHIR R4 Server"); setServerConformanceProvider(confProvider); } else if (fhirVersion == FhirVersionEnum.R5) { IFhirSystemDao systemDao = appCtx .getBean("mySystemDaoR5", IFhirSystemDao.class); JpaConformanceProviderR5 confProvider = new JpaConformanceProviderR5(this, systemDao, - appCtx.getBean(DaoConfig.class)); + appCtx.getBean(DaoConfig.class), appCtx.getBean(ISearchParamRegistry.class)); confProvider.setImplementationDescription("HAPI FHIR R5 Server"); setServerConformanceProvider(confProvider); } else { @@ -259,9 +260,10 @@ public class JpaRestfulServer extends RestfulServer { HapiProperties.getSubscriptionRestHookEnabled()) { // Loads subscription interceptors (SubscriptionActivatingInterceptor, SubscriptionMatcherInterceptor) // with activation of scheduled subscription - SubscriptionInterceptorLoader subscriptionInterceptorLoader = appCtx - .getBean(SubscriptionInterceptorLoader.class); - subscriptionInterceptorLoader.registerInterceptors(); + + SubscriptionSubmitInterceptorLoader subscriptionInterceptorLoader = appCtx + .getBean(SubscriptionSubmitInterceptorLoader.class); + subscriptionInterceptorLoader.start(); // Subscription debug logging IInterceptorService interceptorService = appCtx.getBean(IInterceptorService.class); @@ -272,7 +274,7 @@ public class JpaRestfulServer extends RestfulServer { DaoRegistry daoRegistry = appCtx.getBean(DaoRegistry.class); IInterceptorBroadcaster interceptorBroadcaster = appCtx.getBean(IInterceptorBroadcaster.class); if (HapiProperties.getAllowCascadingDeletes()) { - CascadingDeleteInterceptor cascadingDeleteInterceptor = new CascadingDeleteInterceptor( + CascadingDeleteInterceptor cascadingDeleteInterceptor = new CascadingDeleteInterceptor(getFhirContext(), daoRegistry, interceptorBroadcaster); getInterceptorService().registerInterceptor(cascadingDeleteInterceptor); } @@ -345,6 +347,11 @@ public class JpaRestfulServer extends RestfulServer { registerProvider(appCtx.getBean(BulkDataExportProvider.class)); } + + if (HapiProperties.getEmpiEnabled()) { + // FIXME KHS } + + } } diff --git a/src/main/resources/empi-rules.json b/src/main/resources/empi-rules.json new file mode 100644 index 0000000..c305c1c --- /dev/null +++ b/src/main/resources/empi-rules.json @@ -0,0 +1,32 @@ +{ + "resourceSearchParams" : [ { + "resourceType" : "Patient", + "searchParam" : "birthdate" + }, { + "resourceType" : "All", + "searchParam" : "identifier" + } ], + "filterSearchParams" : [ { + "resourceType" : "All", + "searchParam" : "active", + "fixedValue" : "true" + } ], + "matchFields" : [ { + "name" : "given-name", + "resourceType" : "All", + "resourcePath" : "name.given", + "metric" : "COSINE", + "matchThreshold" : 0.8 + }, { + "name" : "last-name", + "resourceType" : "All", + "resourcePath" : "name.family", + "metric" : "JARO_WINKLER", + "matchThreshold" : 0.8 + }], + "weightMap" : { + "given-name" : "POSSIBLE_MATCH", + "given-name,last-name" : "MATCH" + }, + "eidSystem": "http://company.io/fhir/NamingSystem/custom-eid-system" +} From 1e8e64d26594321e88880558665b7632407ac296 Mon Sep 17 00:00:00 2001 From: Ken Stevens Date: Mon, 27 Apr 2020 13:21:01 -0400 Subject: [PATCH 2/6] confirmed empi works --- .../fhir/jpa/starter/FhirServerConfigCommon.java | 15 ++++++++++++++- .../ca/uhn/fhir/jpa/starter/JpaRestfulServer.java | 4 ++++ src/main/resources/hapi.properties | 5 +++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java index 5647d03..c36c668 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java @@ -3,10 +3,14 @@ package ca.uhn.fhir.jpa.starter; import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.binstore.DatabaseBlobBinaryStorageSvcImpl; import ca.uhn.fhir.jpa.binstore.IBinaryStorageSvc; +import ca.uhn.fhir.jpa.model.config.PartitionSettings; import ca.uhn.fhir.jpa.model.entity.ModelConfig; +import ca.uhn.fhir.jpa.subscription.channel.config.SubscriptionChannelConfig; import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionDeliveryHandlerFactory; +import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig; import ca.uhn.fhir.jpa.subscription.match.deliver.email.IEmailSender; import ca.uhn.fhir.jpa.subscription.match.deliver.email.JavaMailEmailSender; +import ca.uhn.fhir.jpa.subscription.submit.config.SubscriptionSubmitterConfig; import org.apache.commons.dbcp2.BasicDataSource; import org.hl7.fhir.dstu2.model.Subscription; import org.springframework.beans.factory.annotation.Autowired; @@ -25,7 +29,11 @@ import java.sql.Driver; */ @Configuration @EnableTransactionManagement -@Import(EmpiConfig.class) +@Import({EmpiConfig.class, + SubscriptionSubmitterConfig.class, + SubscriptionProcessorConfig.class, + SubscriptionChannelConfig.class +}) public class FhirServerConfigCommon { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirServerConfigCommon.class); @@ -208,4 +216,9 @@ public class FhirServerConfigCommon { return null; } + + @Bean + public PartitionSettings partitionSettings() { + return new PartitionSettings(); + } } diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java index e32148e..62fc7be 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java @@ -288,6 +288,8 @@ public class JpaRestfulServer extends RestfulServer { // Validation IValidatorModule validatorModule; + // FIXME KHS + /* switch (fhirVersion) { case DSTU2: validatorModule = appCtx.getBean("myInstanceValidatorDstu2", IValidatorModule.class); @@ -308,6 +310,8 @@ public class JpaRestfulServer extends RestfulServer { validatorModule = null; break; } + */ + validatorModule = appCtx.getBean(IValidatorModule.class); if (validatorModule != null) { if (HapiProperties.getValidateRequestsEnabled()) { RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor(); diff --git a/src/main/resources/hapi.properties b/src/main/resources/hapi.properties index 991bd28..5abe2b1 100644 --- a/src/main/resources/hapi.properties +++ b/src/main/resources/hapi.properties @@ -147,3 +147,8 @@ email.password= # Enable Websocket Subscription Channel subscription.websocket.enabled=false + +######## +# EMPI +######## +empi.enabled=false From f598dd8e1f00348b527fadc80ab2756baa98143a Mon Sep 17 00:00:00 2001 From: Ken Stevens Date: Mon, 27 Apr 2020 14:28:45 -0400 Subject: [PATCH 3/6] README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 877e579..035d0bf 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,10 @@ The server may be configured with subscription support by enabling properties in - `subscription.websocket.enabled` - Enables websocket subscriptions. With this enabled, your server will accept incoming websocket connections on the following URL (this example uses the default context path and port, you may need to tweak depending on your deployment environment): [ws://localhost:8080/hapi-fhir-jpaserver/websocket](ws://localhost:8080/hapi-fhir-jpaserver/websocket) +## Enabling EMPI + +Set `empi.enabled=true` in the [hapi.properties](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/hapi.properties) file to enable EMPI on this server. The EMPI matching rules are configured in [empi-rules.json](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/empi-rules.json). The rules in this example file should be replaced with actual matching rules appropriate to your data. + ## Using Elasticsearch By default, the server will use embedded lucene indexes for terminology and fulltext indexing purposes. You can switch this to using lucene by editing the properties in [hapi.properties](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/hapi.properties) From 0c9b9f7f77c3477a1488ee3494de869323e8626b Mon Sep 17 00:00:00 2001 From: Ken Stevens Date: Wed, 27 May 2020 17:04:39 -0400 Subject: [PATCH 4/6] just need to merge the email TLS --- pom.xml | 9 +- .../ca/uhn/fhir/jpa/starter/EmpiConfig.java | 4 +- .../jpa/starter/FhirServerConfigCommon.java | 9 +- .../uhn/fhir/jpa/starter/HapiProperties.java | 16 ++ .../fhir/jpa/starter/JpaRestfulServer.java | 95 ++++---- src/main/resources/empi-rules.json | 17 +- src/main/resources/hapi.properties | 7 +- src/main/resources/logback.xml | 19 ++ .../fhir/jpa/starter/ExampleServerR4IT.java | 41 +++- .../fhir/jpa/starter/ExampleServerR5IT.java | 212 +++++++++--------- 10 files changed, 248 insertions(+), 181 deletions(-) diff --git a/pom.xml b/pom.xml index 7cc8094..8b61b9b 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.0.0-SNAPSHOT + 5.1.0-SNAPSHOT hapi-fhir-jpaserver-starter @@ -255,7 +255,12 @@ test - + + org.awaitility + awaitility + 4.0.0-rc1 + test + war diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java b/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java index 3617036..c34f3e1 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java @@ -1,7 +1,7 @@ package ca.uhn.fhir.jpa.starter; import ca.uhn.fhir.empi.api.IEmpiSettings; -import ca.uhn.fhir.empi.rules.config.EmpiSettingsImpl; +import ca.uhn.fhir.empi.rules.config.EmpiSettings; import ca.uhn.fhir.jpa.empi.config.EmpiConsumerConfig; import ca.uhn.fhir.jpa.empi.config.EmpiSubmitterConfig; import com.google.common.base.Charsets; @@ -22,6 +22,6 @@ public class EmpiConfig { DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); Resource resource = resourceLoader.getResource("empi-rules.json"); String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8); - return new EmpiSettingsImpl().setEnabled(HapiProperties.getEmpiEnabled()).setScriptText(json); + return new EmpiSettings().setEnabled(HapiProperties.getEmpiEnabled()).setScriptText(json); } } diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java index c36c668..df39a4c 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java @@ -201,11 +201,10 @@ public class FhirServerConfigCommon { retVal.setSmtpServerPort(this.emailPort); retVal.setSmtpServerUsername(this.emailUsername); retVal.setSmtpServerPassword(this.emailPassword); - // FIXME KHS add these once this has merged in hapi -// retVal.setAuth(this.emailAuth); -// retVal.setStartTlsEnable(this.emailStartTlsEnable); -// retVal.setStartTlsRequired(this.emailStartTlsRequired); -// retVal.setQuitWait(this.emailQuitWait); + retVal.setAuth(this.emailAuth); + retVal.setStartTlsEnable(this.emailStartTlsEnable); + retVal.setStartTlsRequired(this.emailStartTlsRequired); + retVal.setQuitWait(this.emailQuitWait); Validate.notNull(mySubscriptionDeliveryHandlerFactory, "No subscription delivery handler"); mySubscriptionDeliveryHandlerFactory.setEmailSender(retVal); diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java b/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java index a159758..c0fe97c 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java @@ -58,6 +58,10 @@ public class HapiProperties { static final String SUBSCRIPTION_RESTHOOK_ENABLED = "subscription.resthook.enabled"; static final String SUBSCRIPTION_WEBSOCKET_ENABLED = "subscription.websocket.enabled"; static final String EMPI_ENABLED = "empi.enabled"; + static final String PARTITIONING_ENABLED = "partitioning.enabled"; + static final String PARTITIONING_CROSS_PARTITION_REFERENCE_MODE = "partitioning.cross_partition_reference_mode"; + private static final String PARTITIONING_INCLUDE_PARTITION_IN_SEARCH_HASHES = "partitioning.partitioning_include_in_search_hashes"; + static final String ALLOWED_BUNDLE_TYPES = "allowed_bundle_types"; static final String TEST_PORT = "test.port"; static final String TESTER_CONFIG_REFUSE_TO_FETCH_THIRD_PARTY_URLS = "tester.config.refuse_to_fetch_third_party_urls"; @@ -378,6 +382,18 @@ public class HapiProperties { return HapiProperties.getBooleanProperty(EMPI_ENABLED, false); } + public static Boolean getPartitioningEnabled() { + return HapiProperties.getBooleanProperty(PARTITIONING_ENABLED, false); + } + + public static String getPartitioningCrossPartitionReferenceMode() { + return HapiProperties.getProperty(PARTITIONING_CROSS_PARTITION_REFERENCE_MODE, "NOT_ALLOWED"); + } + + public static Boolean getIncludePartitionInSearchHashes() { + return HapiProperties.getBooleanProperty(PARTITIONING_INCLUDE_PARTITION_IN_SEARCH_HASHES, true); + } + public static Boolean getAllowContainsSearches() { return HapiProperties.getBooleanProperty(ALLOW_CONTAINS_SEARCHES, true); } diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java index 62fc7be..9cd2e07 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java @@ -2,6 +2,9 @@ package ca.uhn.fhir.jpa.starter; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.empi.provider.EmpiProviderDstu3; +import ca.uhn.fhir.empi.provider.EmpiProviderR4; +import ca.uhn.fhir.empi.rules.config.EmpiSettings; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorService; import ca.uhn.fhir.jpa.api.config.DaoConfig; @@ -10,6 +13,8 @@ import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor; import ca.uhn.fhir.jpa.bulk.BulkDataExportProvider; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; +import ca.uhn.fhir.jpa.model.config.PartitionSettings; +import ca.uhn.fhir.jpa.partition.PartitionManagementProvider; import ca.uhn.fhir.jpa.provider.GraphQLProvider; import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2; import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2; @@ -37,11 +42,9 @@ import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor; import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhir.validation.ResultSeverityEnum; -import java.util.HashSet; -import java.util.TreeSet; import org.hl7.fhir.dstu3.model.Bundle; -import org.hl7.fhir.r4.model.Bundle.BundleType; import org.hl7.fhir.dstu3.model.Meta; +import org.hl7.fhir.r4.model.Bundle.BundleType; import org.springframework.context.ApplicationContext; import org.springframework.http.HttpHeaders; import org.springframework.web.cors.CorsConfiguration; @@ -49,7 +52,9 @@ import org.springframework.web.cors.CorsConfiguration; import javax.servlet.ServletException; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.Set; +import java.util.TreeSet; public class JpaRestfulServer extends RestfulServer { @@ -65,12 +70,12 @@ public class JpaRestfulServer extends RestfulServer { * specified in the properties file. */ ApplicationContext appCtx = (ApplicationContext) getServletContext() - .getAttribute("org.springframework.web.context.WebApplicationContext.ROOT"); + .getAttribute("org.springframework.web.context.WebApplicationContext.ROOT"); // Customize supported resource types Set supportedResourceTypes = HapiProperties.getSupportedResourceTypes(); if (!supportedResourceTypes.isEmpty() && !supportedResourceTypes.contains("SearchParameter")) { - supportedResourceTypes.add("SearchParameter"); + supportedResourceTypes.add("SearchParameter"); } if (!supportedResourceTypes.isEmpty()) { @@ -115,30 +120,30 @@ public class JpaRestfulServer extends RestfulServer { */ if (fhirVersion == FhirVersionEnum.DSTU2) { IFhirSystemDao systemDao = appCtx - .getBean("mySystemDaoDstu2", IFhirSystemDao.class); + .getBean("mySystemDaoDstu2", IFhirSystemDao.class); JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao, - appCtx.getBean(DaoConfig.class)); + appCtx.getBean(DaoConfig.class)); confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server"); setServerConformanceProvider(confProvider); } else if (fhirVersion == FhirVersionEnum.DSTU3) { IFhirSystemDao systemDao = appCtx - .getBean("mySystemDaoDstu3", IFhirSystemDao.class); + .getBean("mySystemDaoDstu3", IFhirSystemDao.class); JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, - appCtx.getBean(DaoConfig.class), appCtx.getBean(ISearchParamRegistry.class)); + appCtx.getBean(DaoConfig.class), appCtx.getBean(ISearchParamRegistry.class)); confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server"); setServerConformanceProvider(confProvider); } else if (fhirVersion == FhirVersionEnum.R4) { IFhirSystemDao systemDao = appCtx - .getBean("mySystemDaoR4", IFhirSystemDao.class); + .getBean("mySystemDaoR4", IFhirSystemDao.class); JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, systemDao, - appCtx.getBean(DaoConfig.class), appCtx.getBean(ISearchParamRegistry.class)); + appCtx.getBean(DaoConfig.class), appCtx.getBean(ISearchParamRegistry.class)); confProvider.setImplementationDescription("HAPI FHIR R4 Server"); setServerConformanceProvider(confProvider); } else if (fhirVersion == FhirVersionEnum.R5) { IFhirSystemDao systemDao = appCtx - .getBean("mySystemDaoR5", IFhirSystemDao.class); + .getBean("mySystemDaoR5", IFhirSystemDao.class); JpaConformanceProviderR5 confProvider = new JpaConformanceProviderR5(this, systemDao, - appCtx.getBean(DaoConfig.class), appCtx.getBean(ISearchParamRegistry.class)); + appCtx.getBean(DaoConfig.class), appCtx.getBean(ISearchParamRegistry.class)); confProvider.setImplementationDescription("HAPI FHIR R5 Server"); setServerConformanceProvider(confProvider); } else { @@ -219,7 +224,7 @@ public class JpaRestfulServer extends RestfulServer { // manual triggering of a subscription delivery, enable this provider if (false) { // <-- DISABLED RIGHT NOW SubscriptionTriggeringProvider retriggeringProvider = appCtx - .getBean(SubscriptionTriggeringProvider.class); + .getBean(SubscriptionTriggeringProvider.class); registerProvider(retriggeringProvider); } @@ -245,7 +250,7 @@ public class JpaRestfulServer extends RestfulServer { config.addExposedHeader("Location"); config.addExposedHeader("Content-Location"); config.setAllowedMethods( - Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD")); + Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD")); config.setAllowCredentials(HapiProperties.getCorsAllowedCredentials()); // Create the interceptor and register it @@ -256,13 +261,13 @@ public class JpaRestfulServer extends RestfulServer { // If subscriptions are enabled, we want to register the interceptor that // will activate them and match results against them if (HapiProperties.getSubscriptionWebsocketEnabled() || - HapiProperties.getSubscriptionEmailEnabled() || - HapiProperties.getSubscriptionRestHookEnabled()) { + HapiProperties.getSubscriptionEmailEnabled() || + HapiProperties.getSubscriptionRestHookEnabled()) { // Loads subscription interceptors (SubscriptionActivatingInterceptor, SubscriptionMatcherInterceptor) // with activation of scheduled subscription SubscriptionSubmitInterceptorLoader subscriptionInterceptorLoader = appCtx - .getBean(SubscriptionSubmitInterceptorLoader.class); + .getBean(SubscriptionSubmitInterceptorLoader.class); subscriptionInterceptorLoader.start(); // Subscription debug logging @@ -275,43 +280,19 @@ public class JpaRestfulServer extends RestfulServer { IInterceptorBroadcaster interceptorBroadcaster = appCtx.getBean(IInterceptorBroadcaster.class); if (HapiProperties.getAllowCascadingDeletes()) { CascadingDeleteInterceptor cascadingDeleteInterceptor = new CascadingDeleteInterceptor(getFhirContext(), - daoRegistry, interceptorBroadcaster); + daoRegistry, interceptorBroadcaster); getInterceptorService().registerInterceptor(cascadingDeleteInterceptor); } // Binary Storage if (HapiProperties.isBinaryStorageEnabled()) { BinaryStorageInterceptor binaryStorageInterceptor = appCtx - .getBean(BinaryStorageInterceptor.class); + .getBean(BinaryStorageInterceptor.class); getInterceptorService().registerInterceptor(binaryStorageInterceptor); } // Validation - IValidatorModule validatorModule; - // FIXME KHS - /* - switch (fhirVersion) { - case DSTU2: - validatorModule = appCtx.getBean("myInstanceValidatorDstu2", IValidatorModule.class); - break; - case DSTU3: - validatorModule = appCtx.getBean("myInstanceValidatorDstu3", IValidatorModule.class); - break; - case R4: - validatorModule = appCtx.getBean("myInstanceValidatorR4", IValidatorModule.class); - break; - case R5: - validatorModule = appCtx.getBean("myInstanceValidatorR5", IValidatorModule.class); - break; - // These versions are not supported by HAPI FHIR JPA - case DSTU2_HL7ORG: - case DSTU2_1: - default: - validatorModule = null; - break; - } - */ - validatorModule = appCtx.getBean(IValidatorModule.class); + IValidatorModule validatorModule = appCtx.getBean(IValidatorModule.class); if (validatorModule != null) { if (HapiProperties.getValidateRequestsEnabled()) { RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor(); @@ -343,19 +324,21 @@ public class JpaRestfulServer extends RestfulServer { }); DaoConfig config = appCtx.getBean(DaoConfig.class); config.setBundleTypesAllowedForStorage( - Collections.unmodifiableSet(new TreeSet<>(allowedBundleTypes))); - } - - // Bulk Export - if (HapiProperties.getBulkExportEnabled()) { - registerProvider(appCtx.getBean(BulkDataExportProvider.class)); - } - - - if (HapiProperties.getEmpiEnabled()) { - // FIXME KHS + Collections.unmodifiableSet(new TreeSet<>(allowedBundleTypes))); } + // Bulk Export + if (HapiProperties.getBulkExportEnabled()) { + registerProvider(appCtx.getBean(BulkDataExportProvider.class)); + } + if (HapiProperties.getPartitioningEnabled()) { + PartitionSettings partitionSettings = appCtx.getBean(PartitionSettings.class); + partitionSettings.setPartitioningEnabled(true); + PartitionSettings.CrossPartitionReferenceMode mode = PartitionSettings.CrossPartitionReferenceMode.valueOf(HapiProperties.getPartitioningCrossPartitionReferenceMode()); + partitionSettings.setAllowReferencesAcrossPartitions(mode); + partitionSettings.setIncludePartitionInSearchHashes(HapiProperties.getIncludePartitionInSearchHashes()); + registerProvider(appCtx.getBean(PartitionManagementProvider.class)); + } } } diff --git a/src/main/resources/empi-rules.json b/src/main/resources/empi-rules.json index c305c1c..78e77b6 100644 --- a/src/main/resources/empi-rules.json +++ b/src/main/resources/empi-rules.json @@ -1,30 +1,33 @@ { - "resourceSearchParams" : [ { + "candidateSearchParams" : [ { "resourceType" : "Patient", "searchParam" : "birthdate" }, { - "resourceType" : "All", + "resourceType" : "*", "searchParam" : "identifier" + },{ + "resourceType" : "Patient", + "searchParam" : "general-practitioner" } ], - "filterSearchParams" : [ { - "resourceType" : "All", + "candidateFilterSearchParams" : [ { + "resourceType" : "*", "searchParam" : "active", "fixedValue" : "true" } ], "matchFields" : [ { "name" : "given-name", - "resourceType" : "All", + "resourceType" : "*", "resourcePath" : "name.given", "metric" : "COSINE", "matchThreshold" : 0.8 }, { "name" : "last-name", - "resourceType" : "All", + "resourceType" : "*", "resourcePath" : "name.family", "metric" : "JARO_WINKLER", "matchThreshold" : 0.8 }], - "weightMap" : { + "matchResultMap" : { "given-name" : "POSSIBLE_MATCH", "given-name,last-name" : "MATCH" }, diff --git a/src/main/resources/hapi.properties b/src/main/resources/hapi.properties index 5abe2b1..4c0a4c4 100644 --- a/src/main/resources/hapi.properties +++ b/src/main/resources/hapi.properties @@ -148,7 +148,10 @@ email.password= # Enable Websocket Subscription Channel subscription.websocket.enabled=false -######## # EMPI -######## empi.enabled=false + +# Partitioning +partitioning.enabled=false +partitioning.cross_partition_reference_mode=NOT_ALLOWED +partitioning.partitioning_include_in_search_hashes=true diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index ffec8d3..9364495 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -9,6 +9,25 @@ + + DEBUG + ${smile.basedir}/log/empi-troubleshooting.log + + ${smile.basedir}/log/empi-troubleshooting.log.%i.gz + 1 + 9 + + + 5MB + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n${log.stackfilter.pattern} + + + + + + diff --git a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4IT.java b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4IT.java index 1eedafd..b5d3bbb 100644 --- a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4IT.java +++ b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4IT.java @@ -8,6 +8,7 @@ import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.test.utilities.JettyUtil; +import ca.uhn.fhir.util.BundleUtil; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.websocket.api.Session; @@ -17,6 +18,8 @@ import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Person; +import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Subscription; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -24,11 +27,16 @@ import org.junit.Test; import java.net.URI; import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; +import java.util.Optional; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import static ca.uhn.fhir.util.TestUtil.waitForSize; +import static org.awaitility.Awaitility.await; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class ExampleServerR4IT { @@ -43,6 +51,7 @@ public class ExampleServerR4IT { HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr4"); HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "R4"); HapiProperties.setProperty(HapiProperties.SUBSCRIPTION_WEBSOCKET_ENABLED, "true"); + HapiProperties.setProperty(HapiProperties.EMPI_ENABLED, "true"); ourCtx = FhirContext.forR4(); } @@ -57,9 +66,31 @@ public class ExampleServerR4IT { Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute(); assertEquals(methodName, pt2.getName().get(0).getFamily()); + + + // Test EMPI + + // Wait until the EMPI message has been processed + await().until(() -> getPeople().size() > 0); + List persons = getPeople(); + + // Verify a Person was created that links to our Patient + Optional personLinkToCreatedPatient = persons.stream() + .map(Person::getLink) + .flatMap(Collection::stream) + .map(Person.PersonLinkComponent::getTarget) + .map(Reference::getReference) + .filter(pid -> id.toUnqualifiedVersionless().getValue().equals(pid)) + .findAny(); + assertTrue(personLinkToCreatedPatient.isPresent()); } - @Test + private List getPeople() { + Bundle bundle = ourClient.search().forResource(Person.class).cacheControl(new CacheControlDirective().setNoCache(true)).returnBundle(Bundle.class).execute(); + return BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Person.class); + } + + @Test public void testWebsocketSubscription() throws Exception { /* * Create subscription @@ -78,7 +109,7 @@ public class ExampleServerR4IT { IIdType mySubscriptionId = methodOutcome.getId(); // 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()); + await().until(() -> activeSubscriptionCount() == 3); /* * Attach websocket @@ -117,7 +148,11 @@ public class ExampleServerR4IT { ourClient.delete().resourceById(mySubscriptionId).execute(); } - @AfterClass + private int activeSubscriptionCount() { + return ourClient.search().forResource(Subscription.class).where(Subscription.STATUS.exactly().code("active")).cacheControl(new CacheControlDirective().setNoCache(true)).returnBundle(Bundle.class).execute().getEntry().size(); + } + + @AfterClass public static void afterClass() throws Exception { ourServer.stop(); } diff --git a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR5IT.java b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR5IT.java index 80f7a20..d72b8a9 100644 --- a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR5IT.java +++ b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR5IT.java @@ -14,7 +14,13 @@ import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; import org.eclipse.jetty.websocket.client.WebSocketClient; import org.hl7.fhir.instance.model.api.IIdType; -import org.hl7.fhir.r5.model.*; +import org.hl7.fhir.r5.model.Bundle; +import org.hl7.fhir.r5.model.Coding; +import org.hl7.fhir.r5.model.Enumerations; +import org.hl7.fhir.r5.model.Observation; +import org.hl7.fhir.r5.model.Patient; +import org.hl7.fhir.r5.model.Subscription; +import org.hl7.fhir.r5.model.SubscriptionTopic; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -29,135 +35,133 @@ import static org.junit.Assert.assertEquals; public class ExampleServerR5IT { - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerR5IT.class); - private static IGenericClient ourClient; - private static FhirContext ourCtx; - private static int ourPort; - private static Server ourServer; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerR5IT.class); + private static IGenericClient ourClient; + private static FhirContext ourCtx; + private static int ourPort; + private static Server ourServer; - static { - HapiProperties.forceReload(); - HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr5"); - HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "R5"); - HapiProperties.setProperty(HapiProperties.SUBSCRIPTION_WEBSOCKET_ENABLED, "true"); - ourCtx = FhirContext.forR5(); - } + static { + HapiProperties.forceReload(); + HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr5"); + HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "R5"); + HapiProperties.setProperty(HapiProperties.SUBSCRIPTION_WEBSOCKET_ENABLED, "true"); + ourCtx = FhirContext.forR5(); + } - @Test - public void testCreateAndRead() { - ourLog.info("Base URL is: " + HapiProperties.getServerAddress()); - String methodName = "testCreateResourceConditional"; + @Test + public void testCreateAndRead() { + ourLog.info("Base URL is: " + HapiProperties.getServerAddress()); + String methodName = "testCreateResourceConditional"; - Patient pt = new Patient(); - pt.addName().setFamily(methodName); - IIdType id = ourClient.create().resource(pt).execute().getId(); + Patient pt = new Patient(); + pt.addName().setFamily(methodName); + IIdType id = ourClient.create().resource(pt).execute().getId(); - Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute(); - assertEquals(methodName, pt2.getName().get(0).getFamily()); - } + Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute(); + assertEquals(methodName, pt2.getName().get(0).getFamily()); + } - @Test - public void testWebsocketSubscription() throws Exception { + @Test + public void testWebsocketSubscription() throws Exception { - /* - * Create topic - */ - Topic topic = new Topic(); - topic.getResourceTrigger().getQueryCriteria().setCurrent("Observation?status=final"); + /* + * Create topic + */ + SubscriptionTopic topic = new SubscriptionTopic(); + topic.getResourceTrigger().getQueryCriteria().setCurrent("Observation?status=final"); - /* - * Create subscription - */ - Subscription subscription = new Subscription(); - subscription.getTopic().setResource(topic); - subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)"); - subscription.setStatus(Subscription.SubscriptionStatus.REQUESTED); + /* + * Create subscription + */ + Subscription subscription = new Subscription(); + subscription.getTopic().setResource(topic); + subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)"); + subscription.setStatus(Enumerations.SubscriptionState.REQUESTED); - Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent(); - channel.getType().addCoding() - .setSystem("http://terminology.hl7.org/CodeSystem/subscription-channel-type") - .setCode("websocket"); - channel.getPayload().setContentType("application/json"); - subscription.setChannel(channel); + subscription.setContentType("application/json"); + Coding channelType = new Coding().setSystem("http://terminology.hl7.org/CodeSystem/subscription-channel-type") + .setCode("websocket");; + subscription.setChannelType(channelType); - MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute(); - IIdType mySubscriptionId = methodOutcome.getId(); + MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute(); + IIdType mySubscriptionId = methodOutcome.getId(); - // 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()); + // 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()); - /* - * Attach websocket - */ + /* + * Attach websocket + */ - WebSocketClient myWebSocketClient = new WebSocketClient(); - SocketImplementation mySocketImplementation = new SocketImplementation(mySubscriptionId.getIdPart(), EncodingEnum.JSON); + WebSocketClient myWebSocketClient = new WebSocketClient(); + SocketImplementation mySocketImplementation = new SocketImplementation(mySubscriptionId.getIdPart(), EncodingEnum.JSON); - myWebSocketClient.start(); - URI echoUri = new URI("ws://localhost:" + ourPort + "/hapi-fhir-jpaserver/websocket"); - ClientUpgradeRequest request = new ClientUpgradeRequest(); - ourLog.info("Connecting to : {}", echoUri); - Future connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request); - Session session = connection.get(2, TimeUnit.SECONDS); + myWebSocketClient.start(); + URI echoUri = new URI("ws://localhost:" + ourPort + "/hapi-fhir-jpaserver/websocket"); + ClientUpgradeRequest request = new ClientUpgradeRequest(); + ourLog.info("Connecting to : {}", echoUri); + Future connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request); + Session session = connection.get(2, TimeUnit.SECONDS); - ourLog.info("Connected to WS: {}", session.isOpen()); + ourLog.info("Connected to WS: {}", session.isOpen()); - /* - * Create a matching resource - */ - Observation obs = new Observation(); - obs.setStatus(Enumerations.ObservationStatus.FINAL); - ourClient.create().resource(obs).execute(); + /* + * Create a matching resource + */ + Observation obs = new Observation(); + obs.setStatus(Enumerations.ObservationStatus.FINAL); + ourClient.create().resource(obs).execute(); - // Give some time for the subscription to deliver - Thread.sleep(2000); + // Give some time for the subscription to deliver + Thread.sleep(2000); - /* - * Ensure that we receive a ping on the websocket - */ - waitForSize(1, () -> mySocketImplementation.myPingCount); + /* + * Ensure that we receive a ping on the websocket + */ + waitForSize(1, () -> mySocketImplementation.myPingCount); - /* - * Clean up - */ - ourClient.delete().resourceById(mySubscriptionId).execute(); - } + /* + * Clean up + */ + ourClient.delete().resourceById(mySubscriptionId).execute(); + } - @AfterClass - public static void afterClass() throws Exception { - ourServer.stop(); - } + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } - @BeforeClass - public static void beforeClass() throws Exception { - String path = Paths.get("").toAbsolutePath().toString(); + @BeforeClass + public static void beforeClass() throws Exception { + String path = Paths.get("").toAbsolutePath().toString(); - ourLog.info("Project base path is: {}", path); + ourLog.info("Project base path is: {}", path); - ourServer = new Server(0); + ourServer = new Server(0); - WebAppContext webAppContext = new WebAppContext(); - webAppContext.setContextPath("/hapi-fhir-jpaserver"); - webAppContext.setDisplayName("HAPI FHIR"); - webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml"); - webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-starter"); - webAppContext.setParentLoaderPriority(true); + WebAppContext webAppContext = new WebAppContext(); + webAppContext.setContextPath("/hapi-fhir-jpaserver"); + webAppContext.setDisplayName("HAPI FHIR"); + webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml"); + webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-starter"); + webAppContext.setParentLoaderPriority(true); - ourServer.setHandler(webAppContext); - ourServer.start(); + ourServer.setHandler(webAppContext); + ourServer.start(); - ourPort = JettyUtil.getPortForStartedServer(ourServer); + ourPort = JettyUtil.getPortForStartedServer(ourServer); - ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); - ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); - String ourServerBase = "http://localhost:" + ourPort + "/hapi-fhir-jpaserver/fhir/"; + ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); + ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); + String ourServerBase = "http://localhost:" + ourPort + "/hapi-fhir-jpaserver/fhir/"; - ourClient = ourCtx.newRestfulGenericClient(ourServerBase); - ourClient.registerInterceptor(new LoggingInterceptor(true)); - } + ourClient = ourCtx.newRestfulGenericClient(ourServerBase); + ourClient.registerInterceptor(new LoggingInterceptor(true)); + } - public static void main(String[] theArgs) throws Exception { - ourPort = 8080; - beforeClass(); - } + public static void main(String[] theArgs) throws Exception { + ourPort = 8080; + beforeClass(); + } } From e9fa2f2b8a0d8f62cb5166299114fdbe52ea3c16 Mon Sep 17 00:00:00 2001 From: Ken Stevens Date: Wed, 27 May 2020 17:54:07 -0400 Subject: [PATCH 5/6] pre-review cleanup --- .travis.yml | 2 +- pom.xml | 5 +- .../fhir/jpa/starter/ApplicationContext.java | 55 +++++++++++++------ .../ca/uhn/fhir/jpa/starter/EmpiConfig.java | 6 +- .../jpa/starter/FhirServerConfigCommon.java | 28 ++++------ .../uhn/fhir/jpa/starter/HapiProperties.java | 4 ++ .../fhir/jpa/starter/JpaRestfulServer.java | 52 +++++++----------- src/main/resources/hapi.properties | 2 + .../fhir/jpa/starter/ExampleServerR4IT.java | 1 - .../fhir/jpa/starter/ExampleServerR5IT.java | 8 +-- 10 files changed, 80 insertions(+), 83 deletions(-) diff --git a/.travis.yml b/.travis.yml index 54d387b..c0c0974 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ before_script: - sudo chown -R travis:travis "$HOME/.m2/repository"; script: - - mvn -U install + - mvn -B install diff --git a/pom.xml b/pom.xml index 8b61b9b..3618cb5 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,5 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0