From 8aa322caf13efaeabc55f168b9c0581201daa4c4 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Fri, 29 May 2020 10:26:09 -0400 Subject: [PATCH 01/10] Start Release branch for 5.1.0 --- README.md | 4 + pom.xml | 20 +- .../fhir/jpa/starter/ApplicationContext.java | 12 +- .../ca/uhn/fhir/jpa/starter/EmpiConfig.java | 23 ++ .../jpa/starter/FhirServerConfigCommon.java | 12 +- .../uhn/fhir/jpa/starter/HapiProperties.java | 21 ++ .../fhir/jpa/starter/JpaRestfulServer.java | 13 +- src/main/resources/empi-rules.json | 35 ++++ src/main/resources/hapi.properties | 8 + src/main/resources/logback.xml | 19 ++ .../fhir/jpa/starter/ExampleServerR4IT.java | 40 +++- .../fhir/jpa/starter/ExampleServerR5IT.java | 196 +++++++++--------- 12 files changed, 286 insertions(+), 117 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/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) diff --git a/pom.xml b/pom.xml index 61f82de..4559f25 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,4 @@ - 4.0.0 @@ -11,7 +11,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.0.0 + 5.1.0-SNAPSHOT hapi-fhir-jpaserver-starter @@ -84,7 +84,12 @@ - + + + ca.uhn.hapi.fhir + hapi-fhir-jpaserver-empi + ${project.version} + ca.uhn.hapi.fhir @@ -249,7 +254,12 @@ test - + + org.awaitility + awaitility + 4.0.0-rc1 + test + war @@ -276,7 +286,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 c177603..c4d2919 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,8 @@ package ca.uhn.fhir.jpa.starter; import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.jpa.empi.config.EmpiConsumerConfig; +import ca.uhn.fhir.jpa.empi.config.EmpiSubmitterConfig; import ca.uhn.fhir.jpa.subscription.channel.config.SubscriptionChannelConfig; import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig; import ca.uhn.fhir.jpa.subscription.match.config.WebsocketDispatcherConfig; @@ -28,13 +30,19 @@ public class ApplicationContext extends AnnotationConfigWebApplicationContext { } if (HapiProperties.getSubscriptionEmailEnabled() - || HapiProperties.getSubscriptionRestHookEnabled() - || HapiProperties.getSubscriptionWebsocketEnabled()) { + || HapiProperties.getSubscriptionRestHookEnabled() + || HapiProperties.getSubscriptionWebsocketEnabled()) { register(SubscriptionSubmitterConfig.class); register(SubscriptionProcessorConfig.class); register(SubscriptionChannelConfig.class); } + if (HapiProperties.getEmpiEnabled()) { + register(EmpiSubmitterConfig.class); + register(EmpiConsumerConfig.class); + register(EmpiConfig.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..b1d83f1 --- /dev/null +++ b/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java @@ -0,0 +1,23 @@ +package ca.uhn.fhir.jpa.starter; + +import ca.uhn.fhir.empi.api.IEmpiSettings; +import ca.uhn.fhir.empi.rules.config.EmpiSettings; +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.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; + +import java.io.IOException; + +@Configuration +public class EmpiConfig { + @Bean + IEmpiSettings empiSettings() throws IOException { + DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); + Resource resource = resourceLoader.getResource("empi-rules.json"); + String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8); + 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 74e10d3..5460c58 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java @@ -10,7 +10,6 @@ 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.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -25,7 +24,7 @@ import java.sql.Driver; * This is the primary configuration file for the example server */ @Configuration -@EnableTransactionManagement() +@EnableTransactionManagement public class FhirServerConfigCommon { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirServerConfigCommon.class); @@ -198,11 +197,10 @@ 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 -// 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); SubscriptionDeliveryHandlerFactory subscriptionDeliveryHandlerFactory = myAppCtx.getBean(SubscriptionDeliveryHandlerFactory.class); Validate.notNull(subscriptionDeliveryHandlerFactory, "No subscription delivery handler"); 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 7f7e741..c8b3cbd 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,11 @@ 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 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"; @@ -373,6 +378,22 @@ public class HapiProperties { return HapiProperties.getBooleanProperty(SUBSCRIPTION_WEBSOCKET_ENABLED, false); } + public static Boolean getEmpiEnabled() { + 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 d967a70..fe321f3 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java @@ -7,10 +7,11 @@ 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.api.rp.ResourceProviderFactory; 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; @@ -35,6 +36,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 org.hl7.fhir.dstu3.model.Bundle; @@ -318,6 +320,13 @@ public class JpaRestfulServer extends RestfulServer { 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 new file mode 100644 index 0000000..78e77b6 --- /dev/null +++ b/src/main/resources/empi-rules.json @@ -0,0 +1,35 @@ +{ + "candidateSearchParams" : [ { + "resourceType" : "Patient", + "searchParam" : "birthdate" + }, { + "resourceType" : "*", + "searchParam" : "identifier" + },{ + "resourceType" : "Patient", + "searchParam" : "general-practitioner" + } ], + "candidateFilterSearchParams" : [ { + "resourceType" : "*", + "searchParam" : "active", + "fixedValue" : "true" + } ], + "matchFields" : [ { + "name" : "given-name", + "resourceType" : "*", + "resourcePath" : "name.given", + "metric" : "COSINE", + "matchThreshold" : 0.8 + }, { + "name" : "last-name", + "resourceType" : "*", + "resourcePath" : "name.family", + "metric" : "JARO_WINKLER", + "matchThreshold" : 0.8 + }], + "matchResultMap" : { + "given-name" : "POSSIBLE_MATCH", + "given-name,last-name" : "MATCH" + }, + "eidSystem": "http://company.io/fhir/NamingSystem/custom-eid-system" +} diff --git a/src/main/resources/hapi.properties b/src/main/resources/hapi.properties index 44736f5..0d287bd 100644 --- a/src/main/resources/hapi.properties +++ b/src/main/resources/hapi.properties @@ -149,3 +149,11 @@ 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..22b5656 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,30 @@ 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 +108,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 +147,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 3c02375..62ac1a3 100644 --- a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR5IT.java +++ b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR5IT.java @@ -34,132 +34,132 @@ 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 - */ - SubscriptionTopic topic = new SubscriptionTopic(); - 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(Enumerations.SubscriptionState.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.getChannelType() .setSystem("http://terminology.hl7.org/CodeSystem/subscription-channel-type") .setCode("websocket"); - subscription.setContentType("application/json"); + subscription.setContentType("application/json"); - 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 d1def4a621d56efab28e7bd1d541e3ce683dedfe Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Mon, 15 Jun 2020 18:22:14 -0400 Subject: [PATCH 02/10] Get test passing --- .../java/ca/uhn/fhir/jpa/starter/EmpiConfig.java | 4 +++- .../ca/uhn/fhir/jpa/starter/HapiProperties.java | 11 +++++------ .../ca/uhn/fhir/jpa/starter/JpaRestfulServer.java | 14 ++++++++------ .../fhir/jpa/starter/MultitenantServerR4IT.java | 7 +++---- 4 files changed, 19 insertions(+), 17 deletions(-) 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 b1d83f1..462aba8 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java @@ -13,11 +13,13 @@ import java.io.IOException; @Configuration public class EmpiConfig { + @Bean IEmpiSettings empiSettings() throws IOException { DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); Resource resource = resourceLoader.getResource("empi-rules.json"); String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8); - return new EmpiSettings().setEnabled(HapiProperties.getEmpiEnabled()).setScriptText(json); + return null; // new EmpiSettings().setEnabled(HapiProperties.getEmpiEnabled()).setScriptText(json); } + } 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 7c62f13..ab66ef2 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java @@ -60,8 +60,6 @@ public class HapiProperties { 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"; @@ -79,7 +77,7 @@ public class HapiProperties { static final String EXPIRE_SEARCH_RESULTS_AFTER_MINS = "retain_cached_searches_mins"; static final String MAX_BINARY_SIZE = "max_binary_size"; static final String PARTITIONING_MULTITENANCY_ENABLED = "partitioning.multitenancy.enabled"; - + private static final String PARTITIONING_INCLUDE_PARTITION_IN_SEARCH_HASHES = "partitioning.partitioning_include_in_search_hashes"; private static Properties ourProperties; public static boolean isElasticSearchEnabled() { @@ -388,6 +386,10 @@ public class HapiProperties { return HapiProperties.getBooleanProperty(PARTITIONING_ENABLED, false); } + public static boolean getPartitioningMultitenancyEnabled() { + return HapiProperties.getBooleanProperty(PARTITIONING_MULTITENANCY_ENABLED, false); + } + public static String getPartitioningCrossPartitionReferenceMode() { return HapiProperties.getProperty(PARTITIONING_CROSS_PARTITION_REFERENCE_MODE, "NOT_ALLOWED"); } @@ -513,8 +515,5 @@ public class HapiProperties { return HapiProperties.getBooleanProperty("fhirpath_interceptor.enabled", false); } - public static boolean getPartitioningMultitenancyEnabled() { - return HapiProperties.getBooleanProperty(PARTITIONING_MULTITENANCY_ENABLED, false); - } } 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 b599d6b..1a21ae9 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java @@ -36,8 +36,8 @@ 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.rest.server.interceptor.partition.RequestTenantPartitionInterceptor; +import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy; import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhir.validation.ResultSeverityEnum; @@ -330,11 +330,13 @@ public class JpaRestfulServer extends RestfulServer { partitionSettings.setIncludePartitionInSearchHashes(HapiProperties.getIncludePartitionInSearchHashes()); registerProvider(appCtx.getBean(PartitionManagementProvider.class)); -if (HapiProperties.getPartitioningMultitenancyEnabled()) { - registerInterceptor(new RequestTenantPartitionInterceptor()); - setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy()); - registerProviders(appCtx.getBean(PartitionManagementProvider.class)); + if (HapiProperties.getPartitioningMultitenancyEnabled()) { + registerInterceptor(new RequestTenantPartitionInterceptor()); + setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy()); + } + } } -} + +} \ No newline at end of file diff --git a/src/test/java/ca/uhn/fhir/jpa/starter/MultitenantServerR4IT.java b/src/test/java/ca/uhn/fhir/jpa/starter/MultitenantServerR4IT.java index 23fb19a..7e32013 100644 --- a/src/test/java/ca/uhn/fhir/jpa/starter/MultitenantServerR4IT.java +++ b/src/test/java/ca/uhn/fhir/jpa/starter/MultitenantServerR4IT.java @@ -1,16 +1,15 @@ package ca.uhn.fhir.jpa.starter; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.model.util.ProviderConstants; import ca.uhn.fhir.rest.api.CacheControlDirective; 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.rest.client.interceptor.UrlTenantSelectionInterceptor; +import ca.uhn.fhir.rest.server.provider.ProviderConstants; import ca.uhn.fhir.test.utilities.JettyUtil; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.webapp.WebAppContext; -import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.IntegerType; @@ -39,6 +38,7 @@ public class MultitenantServerR4IT { HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr4-mt"); HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "R4"); HapiProperties.setProperty(HapiProperties.SUBSCRIPTION_WEBSOCKET_ENABLED, "true"); + HapiProperties.setProperty(HapiProperties.PARTITIONING_ENABLED, "true"); HapiProperties.setProperty(HapiProperties.PARTITIONING_MULTITENANCY_ENABLED, "true"); ourCtx = FhirContext.forR4(); } @@ -70,7 +70,6 @@ public class MultitenantServerR4IT { } @Test - @Ignore public void testCreateAndReadInTenantB() { ourLog.info("Base URL is: " + HapiProperties.getServerAddress()); @@ -80,7 +79,7 @@ public class MultitenantServerR4IT { .operation() .onServer() .named(ProviderConstants.PARTITION_MANAGEMENT_CREATE_PARTITION) - .withParameter(Parameters.class, ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID, new IntegerType(1)) + .withParameter(Parameters.class, ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID, new IntegerType(2)) .andParameter(ProviderConstants.PARTITION_MANAGEMENT_PARTITION_NAME, new CodeType("TENANT-B")) .execute(); From 7282db245ea4420bc03f1b6b158f3a5fdf785062 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Tue, 16 Jun 2020 08:53:10 -0400 Subject: [PATCH 03/10] Add repo --- pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pom.xml b/pom.xml index 4559f25..ee7e997 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,16 @@ 3.5.0 + + + oss-snapshots + + true + + https://oss.sonatype.org/content/repositories/snapshots/ + + + org.eclipse.jetty.websocket From 21a4754ebdcc6080738e3eb0b1062c20d6b32bad Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Thu, 2 Jul 2020 11:24:03 -0400 Subject: [PATCH 04/10] Resolve some compile errors --- pom.xml | 28 +++++++++---------- .../jpa/starter/FhirServerConfigDstu2.java | 6 ++-- .../jpa/starter/FhirServerConfigDstu3.java | 8 ++++-- .../fhir/jpa/starter/FhirServerConfigR4.java | 6 ++-- .../fhir/jpa/starter/FhirServerConfigR5.java | 6 ++-- .../fhir/jpa/starter/JpaRestfulServer.java | 4 +-- 6 files changed, 33 insertions(+), 25 deletions(-) diff --git a/pom.xml b/pom.xml index ee7e997..1bc2f27 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,10 @@ 3.5.0 + war + + HAPI FHIR JPA Server - Starter Project + oss-snapshots @@ -270,22 +274,17 @@ 4.0.0-rc1 test + + + + junit + junit + 4.12 + test + + - war - - HAPI FHIR JPA Server - Starter Project - - - - oss-snapshots - - false - - https://oss.sonatype.org/content/repositories/snapshots/ - - - @@ -441,6 +440,7 @@ .*\.txt$ .*\.html$ + config/favicon.ico diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu2.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu2.java index dc91099..d80e70f 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu2.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu2.java @@ -6,6 +6,7 @@ import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -47,8 +48,9 @@ public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 { return retVal; } - @Bean() - public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + @Bean + @Primary + public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) { JpaTransactionManager retVal = new JpaTransactionManager(); retVal.setEntityManagerFactory(entityManagerFactory); return retVal; diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu3.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu3.java index 3344952..2a93154 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu3.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu3.java @@ -6,6 +6,7 @@ import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -32,7 +33,7 @@ public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 { } @Override - @Bean() + @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory(); retVal.setPersistenceUnitName("HAPI_PU"); @@ -47,8 +48,9 @@ public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 { return retVal; } - @Bean() - public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + @Bean + @Primary + public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) { JpaTransactionManager retVal = new JpaTransactionManager(); retVal.setEntityManagerFactory(entityManagerFactory); return retVal; diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java index 77a798e..5f3f8a9 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java @@ -6,6 +6,7 @@ import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -47,8 +48,9 @@ public class FhirServerConfigR4 extends BaseJavaConfigR4 { return retVal; } - @Bean() - public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + @Bean + @Primary + public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) { JpaTransactionManager retVal = new JpaTransactionManager(); retVal.setEntityManagerFactory(entityManagerFactory); return retVal; diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR5.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR5.java index 6d9e45b..d6cf537 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR5.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR5.java @@ -6,6 +6,7 @@ import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -47,8 +48,9 @@ public class FhirServerConfigR5 extends BaseJavaConfigR5 { return retVal; } - @Bean() - public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + @Bean + @Primary + public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) { JpaTransactionManager retVal = new JpaTransactionManager(); retVal.setEntityManagerFactory(entityManagerFactory); return retVal; 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 1a21ae9..275b62f 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java @@ -8,7 +8,7 @@ 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.bulk.provider.BulkDataExportProvider; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; import ca.uhn.fhir.jpa.model.config.PartitionSettings; import ca.uhn.fhir.jpa.partition.PartitionManagementProvider; @@ -312,7 +312,7 @@ public class JpaRestfulServer extends RestfulServer { BundleType type = BundleType.valueOf(o); allowedBundleTypes.add(type.toCode()); }); - DaoConfig config = (DaoConfig) daoConfig; + DaoConfig config = daoConfig; config.setBundleTypesAllowedForStorage( Collections.unmodifiableSet(new TreeSet<>(allowedBundleTypes))); } From 745d82a608b6da4038bdbe33a7dba0fcb39ff0d8 Mon Sep 17 00:00:00 2001 From: Tadgh Date: Thu, 9 Jul 2020 09:46:23 -0700 Subject: [PATCH 05/10] Fix EMPI rules json --- src/main/resources/empi-rules.json | 77 +++++++++++++++++------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/src/main/resources/empi-rules.json b/src/main/resources/empi-rules.json index 78e77b6..ad549d8 100644 --- a/src/main/resources/empi-rules.json +++ b/src/main/resources/empi-rules.json @@ -1,35 +1,46 @@ { - "candidateSearchParams" : [ { - "resourceType" : "Patient", - "searchParam" : "birthdate" - }, { - "resourceType" : "*", - "searchParam" : "identifier" - },{ - "resourceType" : "Patient", - "searchParam" : "general-practitioner" - } ], - "candidateFilterSearchParams" : [ { - "resourceType" : "*", - "searchParam" : "active", - "fixedValue" : "true" - } ], - "matchFields" : [ { - "name" : "given-name", - "resourceType" : "*", - "resourcePath" : "name.given", - "metric" : "COSINE", - "matchThreshold" : 0.8 - }, { - "name" : "last-name", - "resourceType" : "*", - "resourcePath" : "name.family", - "metric" : "JARO_WINKLER", - "matchThreshold" : 0.8 - }], - "matchResultMap" : { - "given-name" : "POSSIBLE_MATCH", - "given-name,last-name" : "MATCH" - }, - "eidSystem": "http://company.io/fhir/NamingSystem/custom-eid-system" + "candidateSearchParams": [ + { + "resourceType": "Patient", + "searchParams": ["birthdate"] + }, + { + "resourceType": "*", + "searchParams": ["identifier"] + }, + { + "resourceType": "Patient", + "searchParams": ["general-practitioner"] + } + ], + "candidateFilterSearchParams": [ + { + "resourceType": "*", + "searchParam": "active", + "fixedValue": "true" + } + ], + "matchFields": [ + { + "name": "cosine-given-name", + "resourceType": "*", + "resourcePath": "name.given", + "metric": "COSINE", + "matchThreshold": 0.8, + "exact": true + }, + { + "name": "jaro-last-name", + "resourceType": "*", + "resourcePath": "name.family", + "metric": "JARO_WINKLER", + "matchThreshold": 0.8, + "exact": true + } + ], + "matchResultMap": { + "cosine-given-name" : "POSSIBLE_MATCH", + "cosine-given-name,jaro-last-name" : "MATCH" + }, + "eidSystem": "http://company.io/fhir/NamingSystem/custom-eid-system" } From 5d0b26bbf33a4bd7ddfc2e2aaefd8b3896e42722 Mon Sep 17 00:00:00 2001 From: Tadgh Date: Thu, 9 Jul 2020 10:00:00 -0700 Subject: [PATCH 06/10] Have EmpiSettings actually return an EmpiSettings bean --- src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) 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 462aba8..3a8fe78 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java @@ -1,9 +1,15 @@ package ca.uhn.fhir.jpa.starter; +import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.empi.api.IEmpiSettings; +import ca.uhn.fhir.empi.rules.config.EmpiRuleValidator; import ca.uhn.fhir.empi.rules.config.EmpiSettings; +import ca.uhn.fhir.jpa.empi.svc.EmpiSearchParamSvc; +import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer; +import ca.uhn.fhir.rest.server.util.ISearchParamRetriever; import com.google.common.base.Charsets; import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.DefaultResourceLoader; @@ -15,11 +21,11 @@ import java.io.IOException; public class EmpiConfig { @Bean - IEmpiSettings empiSettings() throws IOException { + public IEmpiSettings empiSettings(EmpiRuleValidator theEmpiRuleValidator) throws IOException { DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); Resource resource = resourceLoader.getResource("empi-rules.json"); String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8); - return null; // new EmpiSettings().setEnabled(HapiProperties.getEmpiEnabled()).setScriptText(json); + return new EmpiSettings(theEmpiRuleValidator).setEnabled(HapiProperties.getEmpiEnabled()).setScriptText(json); } } From 53315a54d02b93664820dfeee5e03622a45f7ba5 Mon Sep 17 00:00:00 2001 From: Tadgh Date: Thu, 9 Jul 2020 10:01:09 -0700 Subject: [PATCH 07/10] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 035d0bf..8ebf6cd 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ The server may be configured with subscription support by enabling properties in ## 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. +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. Note that EMPI relies on subscriptions, so for EMPI to work, subscriptions must be enabled. ## Using Elasticsearch From d263b5e14c782690b636c6a03ff20839497365fd Mon Sep 17 00:00:00 2001 From: Tadgh Date: Thu, 9 Jul 2020 10:13:25 -0700 Subject: [PATCH 08/10] Remove dead space --- src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 3a8fe78..107aa97 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/EmpiConfig.java @@ -21,11 +21,11 @@ import java.io.IOException; public class EmpiConfig { @Bean - public IEmpiSettings empiSettings(EmpiRuleValidator theEmpiRuleValidator) throws IOException { + IEmpiSettings empiSettings(EmpiRuleValidator theEmpiRuleValidator) throws IOException { DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); Resource resource = resourceLoader.getResource("empi-rules.json"); String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8); - return new EmpiSettings(theEmpiRuleValidator).setEnabled(HapiProperties.getEmpiEnabled()).setScriptText(json); + return new EmpiSettings(theEmpiRuleValidator).setEnabled(HapiProperties.getEmpiEnabled()).setScriptText(json); } } From 423a3959d1c46fe9a2d44b268fb3db0a192d6ec1 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Thu, 13 Aug 2020 15:52:47 -0400 Subject: [PATCH 09/10] Prepare for release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1bc2f27..2d6db5d 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.1.0-SNAPSHOT + 5.1.0 hapi-fhir-jpaserver-starter From dafdf5b437a7e06b1e4b174d1c3bd82b9c092b86 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Thu, 13 Aug 2020 16:13:00 -0400 Subject: [PATCH 10/10] Merge master --- .../uhn/fhir/jpa/starter/BaseJpaRestfulServer.java | 4 ++-- .../ca/uhn/fhir/jpa/starter/HapiProperties.java | 14 +++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java b/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java index 9eafd27..5b482c8 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java @@ -7,9 +7,8 @@ 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.api.rp.ResourceProviderFactory; import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor; -import ca.uhn.fhir.jpa.bulk.BulkDataExportProvider; +import ca.uhn.fhir.jpa.bulk.provider.BulkDataExportProvider; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; import ca.uhn.fhir.jpa.partition.PartitionManagementProvider; import ca.uhn.fhir.jpa.provider.GraphQLProvider; @@ -37,6 +36,7 @@ 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.interceptor.partition.RequestTenantPartitionInterceptor; +import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy; import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhir.validation.ResultSeverityEnum; 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 5cd67ea..20628e5 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/HapiProperties.java @@ -7,6 +7,7 @@ import ca.uhn.fhir.jpa.search.elastic.ElasticsearchHibernatePropertiesBuilder; import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.server.ETagSupportEnum; import com.google.common.annotations.VisibleForTesting; +import org.apache.commons.lang3.StringUtils; import org.hibernate.search.elasticsearch.cfg.ElasticsearchIndexStatus; import org.hibernate.search.elasticsearch.cfg.IndexSchemaManagementStrategy; import org.jetbrains.annotations.NotNull; @@ -342,10 +343,6 @@ public class HapiProperties { return HapiProperties.getBooleanProperty("expunge_enabled", true); } - public static Integer getTestPort() { - return HapiProperties.getIntegerProperty(TEST_PORT, 0); - } - public static Boolean getTesterConfigRefustToFetchThirdPartyUrls() { return HapiProperties.getBooleanProperty(TESTER_CONFIG_REFUSE_TO_FETCH_THIRD_PARTY_URLS, false); } @@ -366,8 +363,8 @@ public class HapiProperties { public static Set getSupportedResourceTypes() { String[] types = defaultString(getProperty("supported_resource_types")).split(","); return Arrays.stream(types) - .map(t -> trim(t)) - .filter(t -> isNotBlank(t)) + .map(StringUtils::trim) + .filter(StringUtils::isNotBlank) .collect(Collectors.toSet()); } @@ -403,9 +400,6 @@ public class HapiProperties { return HapiProperties.getBooleanProperty(PARTITIONING_ENABLED, false); } - public static boolean getPartitioningMultitenancyEnabled() { - return HapiProperties.getBooleanProperty(PARTITIONING_MULTITENANCY_ENABLED, false); - } public static String getPartitioningCrossPartitionReferenceMode() { return HapiProperties.getProperty(PARTITIONING_CROSS_PARTITION_REFERENCE_MODE, "NOT_ALLOWED"); @@ -535,5 +529,7 @@ public class HapiProperties { public static boolean getPartitioningMultitenancyEnabled() { return HapiProperties.getBooleanProperty(PARTITIONING_MULTITENANCY_ENABLED, false); } + + }