Add repository validating interceptor, and update for EMPI->MDM rename
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
[*.java]
|
[*.java]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
indent_style = space
|
indent_style = tab
|
||||||
indent_size = 2
|
indent_size = 3
|
||||||
|
|
||||||
|
|||||||
@@ -316,9 +316,9 @@ The server may be configured with subscription support by enabling properties in
|
|||||||
|
|
||||||
- `hapi.fhir.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/websocket](ws://localhost:8080/websocket)
|
- `hapi.fhir.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/websocket](ws://localhost:8080/websocket)
|
||||||
|
|
||||||
## Enabling EMPI
|
## Enabling MDM (EMPI)
|
||||||
|
|
||||||
Set `hapi.fhir.empi_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) 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.
|
Set `hapi.fhir.mdm_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable MDM on this server. The MDM matching rules are configured in [mdm-rules.json](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/mdm-rules.json). The rules in this example file should be replaced with actual matching rules appropriate to your data. Note that MDM relies on subscriptions, so for MDM to work, subscriptions must be enabled.
|
||||||
|
|
||||||
## Using Elasticsearch
|
## Using Elasticsearch
|
||||||
|
|
||||||
|
|||||||
6
pom.xml
6
pom.xml
@@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>8</java.version>
|
<java.version>8</java.version>
|
||||||
<spring_boot_version>2.3.4.RELEASE</spring_boot_version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<prerequisites>
|
<prerequisites>
|
||||||
@@ -100,10 +99,10 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- This dependency includes the JPA EMPI Server -->
|
<!-- This dependency includes the JPA MDM Server -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-jpaserver-empi</artifactId>
|
<artifactId>hapi-fhir-jpaserver-mdm</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
|
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
|
||||||
@@ -358,7 +357,6 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<version>3.0.0-M5</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
package ca.uhn.fhir.jpa.empi;
|
|
||||||
|
|
||||||
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.config.EmpiConsumerConfig;
|
|
||||||
import ca.uhn.fhir.jpa.empi.config.EmpiSubmitterConfig;
|
|
||||||
import ca.uhn.fhir.jpa.starter.AppProperties;
|
|
||||||
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.Conditional;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Move this to package "ca.uhn.fhir.jpa.starter" in HAPI FHIR 5.2.0+. The lousy component scan
|
|
||||||
* in 5.1.0 picks this up even if EMPI is disabled currently.
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@Conditional(EmpiConfigCondition.class)
|
|
||||||
@Import({EmpiConsumerConfig.class, EmpiSubmitterConfig.class})
|
|
||||||
public class EmpiConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
EmpiRuleValidator empiRuleValidator(FhirContext theFhirContext, ISearchParamRetriever theSearchParamRetriever) {
|
|
||||||
return new EmpiRuleValidator(theFhirContext, theSearchParamRetriever);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
IEmpiSettings empiSettings(@Autowired EmpiRuleValidator theEmpiRuleValidator, AppProperties appProperties) 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(appProperties.getEmpi_enabled()).setScriptText(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
45
src/main/java/ca/uhn/fhir/jpa/mdm/MdmConfig.java
Normal file
45
src/main/java/ca/uhn/fhir/jpa/mdm/MdmConfig.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package ca.uhn.fhir.jpa.mdm;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.mdm.config.MdmConsumerConfig;
|
||||||
|
import ca.uhn.fhir.jpa.mdm.config.MdmSubmitterConfig;
|
||||||
|
import ca.uhn.fhir.jpa.starter.AppProperties;
|
||||||
|
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||||
|
import ca.uhn.fhir.mdm.rules.config.MdmRuleValidator;
|
||||||
|
import ca.uhn.fhir.mdm.rules.config.MdmSettings;
|
||||||
|
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.Conditional;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Move this to package "ca.uhn.fhir.jpa.starter" in HAPI FHIR 5.2.0+. The lousy component scan
|
||||||
|
* in 5.1.0 picks this up even if MDM is disabled currently.
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Conditional(MdmConfigCondition.class)
|
||||||
|
@Import({MdmConsumerConfig.class, MdmSubmitterConfig.class})
|
||||||
|
public class MdmConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
MdmRuleValidator mdmRuleValidator(FhirContext theFhirContext, ISearchParamRetriever theSearchParamRetriever) {
|
||||||
|
return new MdmRuleValidator(theFhirContext, theSearchParamRetriever);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
IMdmSettings mdmSettings(@Autowired MdmRuleValidator theMdmRuleValidator, AppProperties appProperties) throws IOException {
|
||||||
|
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||||
|
Resource resource = resourceLoader.getResource("mdm-rules.json");
|
||||||
|
String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8);
|
||||||
|
return new MdmSettings(theMdmRuleValidator).setEnabled(appProperties.getMdm_enabled()).setScriptText(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package ca.uhn.fhir.jpa.empi;
|
package ca.uhn.fhir.jpa.mdm;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Condition;
|
import org.springframework.context.annotation.Condition;
|
||||||
import org.springframework.context.annotation.ConditionContext;
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
|
||||||
public class EmpiConfigCondition implements Condition {
|
public class MdmConfigCondition implements Condition {
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
|
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
|
||||||
String property = conditionContext.getEnvironment().getProperty("hapi.fhir.empi_enabled");
|
String property = conditionContext.getEnvironment().getProperty("hapi.fhir.mdm_enabled");
|
||||||
return Boolean.parseBoolean(property);
|
return Boolean.parseBoolean(property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
@EnableConfigurationProperties
|
@EnableConfigurationProperties
|
||||||
public class AppProperties {
|
public class AppProperties {
|
||||||
|
|
||||||
private Boolean empi_enabled = false;
|
private Boolean mdm_enabled = false;
|
||||||
private Boolean allow_cascading_deletes = false;
|
private Boolean allow_cascading_deletes = false;
|
||||||
private Boolean allow_contains_searches = true;
|
private Boolean allow_contains_searches = true;
|
||||||
private Boolean allow_external_references = false;
|
private Boolean allow_external_references = false;
|
||||||
@@ -32,6 +32,7 @@ public class AppProperties {
|
|||||||
private Boolean allow_placeholder_references = true;
|
private Boolean allow_placeholder_references = true;
|
||||||
private Boolean auto_create_placeholder_reference_targets = true;
|
private Boolean auto_create_placeholder_reference_targets = true;
|
||||||
private Boolean enable_index_missing_fields = false;
|
private Boolean enable_index_missing_fields = false;
|
||||||
|
private Boolean enable_repository_validating_interceptor = false;
|
||||||
private Boolean enforce_referential_integrity_on_delete = true;
|
private Boolean enforce_referential_integrity_on_delete = true;
|
||||||
private Boolean enforce_referential_integrity_on_write = true;
|
private Boolean enforce_referential_integrity_on_write = true;
|
||||||
private Boolean etag_support_enabled = true;
|
private Boolean etag_support_enabled = true;
|
||||||
@@ -90,12 +91,12 @@ public class AppProperties {
|
|||||||
this.partitioning = partitioning;
|
this.partitioning = partitioning;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getEmpi_enabled() {
|
public Boolean getMdm_enabled() {
|
||||||
return empi_enabled;
|
return mdm_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEmpi_enabled(Boolean empi_enabled) {
|
public void setMdm_enabled(Boolean mdm_enabled) {
|
||||||
this.empi_enabled = empi_enabled;
|
this.mdm_enabled = mdm_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -246,6 +247,14 @@ public class AppProperties {
|
|||||||
this.enable_index_missing_fields = enable_index_missing_fields;
|
this.enable_index_missing_fields = enable_index_missing_fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getEnable_repository_validating_interceptor() {
|
||||||
|
return enable_repository_validating_interceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnable_repository_validating_interceptor(Boolean theEnable_repository_validating_interceptor) {
|
||||||
|
enable_repository_validating_interceptor = theEnable_repository_validating_interceptor;
|
||||||
|
}
|
||||||
|
|
||||||
public Boolean getEnforce_referential_integrity_on_delete() {
|
public Boolean getEnforce_referential_integrity_on_delete() {
|
||||||
return enforce_referential_integrity_on_delete;
|
return enforce_referential_integrity_on_delete;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package ca.uhn.fhir.jpa.starter;
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.empi.EmpiConfig;
|
import ca.uhn.fhir.jpa.mdm.MdmConfig;
|
||||||
import ca.uhn.fhir.jpa.starter.annotations.OnEitherVersion;
|
import ca.uhn.fhir.jpa.starter.annotations.OnEitherVersion;
|
||||||
import ca.uhn.fhir.jpa.subscription.channel.config.SubscriptionChannelConfig;
|
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.SubscriptionProcessorConfig;
|
||||||
@@ -24,7 +24,7 @@ import org.springframework.web.servlet.DispatcherServlet;
|
|||||||
@ServletComponentScan(basePackageClasses = {
|
@ServletComponentScan(basePackageClasses = {
|
||||||
JpaRestfulServer.class})
|
JpaRestfulServer.class})
|
||||||
@SpringBootApplication(exclude = {ElasticsearchRestClientAutoConfiguration.class})
|
@SpringBootApplication(exclude = {ElasticsearchRestClientAutoConfiguration.class})
|
||||||
@Import({SubscriptionSubmitterConfig.class, SubscriptionProcessorConfig.class, SubscriptionChannelConfig.class, WebsocketDispatcherConfig.class, EmpiConfig.class})
|
@Import({SubscriptionSubmitterConfig.class, SubscriptionProcessorConfig.class, SubscriptionChannelConfig.class, WebsocketDispatcherConfig.class, MdmConfig.class})
|
||||||
public class Application extends SpringBootServletInitializer {
|
public class Application extends SpringBootServletInitializer {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
|||||||
import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
|
import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
|
||||||
import ca.uhn.fhir.jpa.bulk.provider.BulkDataExportProvider;
|
import ca.uhn.fhir.jpa.bulk.provider.BulkDataExportProvider;
|
||||||
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor;
|
||||||
import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc;
|
import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc;
|
||||||
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
|
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
|
||||||
import ca.uhn.fhir.jpa.partition.PartitionManagementProvider;
|
import ca.uhn.fhir.jpa.partition.PartitionManagementProvider;
|
||||||
@@ -362,6 +363,12 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
|||||||
daoConfig.setLastNEnabled(true);
|
daoConfig.setLastNEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repository Validating Interceptor
|
||||||
|
if (Boolean.TRUE.equals(appProperties.getEnable_repository_validating_interceptor())) {
|
||||||
|
RepositoryValidationInterceptorFactory repositoryValidationInterceptorFactory = myApplicationContext.getBean(RepositoryValidationInterceptorFactory.class);
|
||||||
|
RepositoryValidatingInterceptor interceptor = repositoryValidationInterceptorFactory.build();
|
||||||
|
interceptorService.registerInterceptor(interceptor);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,6 +132,13 @@ public class FhirServerConfigCommon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Lazy
|
||||||
|
public RepositoryValidationInterceptorFactory repositoryValidationInterceptorFactory() {
|
||||||
|
return new RepositoryValidationInterceptorFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Primary
|
@Primary
|
||||||
@Bean
|
@Bean
|
||||||
public HibernateDialectProvider jpaStarterDialectProvider(LocalContainerEntityManagerFactoryBean myEntityManagerFactory) {
|
public HibernateDialectProvider jpaStarterDialectProvider(LocalContainerEntityManagerFactoryBean myEntityManagerFactory) {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package ca.uhn.fhir.jpa.starter;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.IRepositoryValidatingRule;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor;
|
||||||
|
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingRuleBuilder;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be customized to enable the {@link ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor}
|
||||||
|
* on this server.
|
||||||
|
*
|
||||||
|
* The <code>enable_repository_validating_interceptor</code> property must be enabled in <code>application.yaml</code>
|
||||||
|
* in order to use this class.
|
||||||
|
*/
|
||||||
|
public class RepositoryValidationInterceptorFactory {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationContext myApplicationContext;
|
||||||
|
@Autowired
|
||||||
|
private FhirContext myFhirContext;
|
||||||
|
|
||||||
|
public RepositoryValidatingInterceptor build() {
|
||||||
|
RepositoryValidatingRuleBuilder ruleBuilder = myApplicationContext.getBean(RepositoryValidatingRuleBuilder.class);
|
||||||
|
|
||||||
|
// Customize the ruleBuilder here to have the rules you want! We will give a simple example
|
||||||
|
// of enabling validation for all Patient resources
|
||||||
|
ruleBuilder.forResourcesOfType("Patient").requireValidationToDeclaredProfiles();
|
||||||
|
|
||||||
|
// Do not customize below this line
|
||||||
|
List<IRepositoryValidatingRule> rules = ruleBuilder.build();
|
||||||
|
return new RepositoryValidatingInterceptor(myFhirContext, rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -57,6 +57,7 @@ hapi:
|
|||||||
# default_encoding: JSON
|
# default_encoding: JSON
|
||||||
# default_pretty_print: true
|
# default_pretty_print: true
|
||||||
# default_page_size: 20
|
# default_page_size: 20
|
||||||
|
# enable_repository_validating_interceptor: false
|
||||||
# enable_index_missing_fields: false
|
# enable_index_missing_fields: false
|
||||||
# enforce_referential_integrity_on_delete: false
|
# enforce_referential_integrity_on_delete: false
|
||||||
# enforce_referential_integrity_on_write: false
|
# enforce_referential_integrity_on_write: false
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "1",
|
"version": "1",
|
||||||
|
"mdmTypes": ["Patient", "Practitioner"],
|
||||||
"candidateSearchParams": [
|
"candidateSearchParams": [
|
||||||
{
|
{
|
||||||
"resourceType": "Patient",
|
"resourceType": "Patient",
|
||||||
@@ -12,8 +12,12 @@ import org.eclipse.jetty.websocket.api.Session;
|
|||||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
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.Subscription;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Order;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
@@ -21,26 +25,27 @@ import org.springframework.boot.web.server.LocalServerPort;
|
|||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static ca.uhn.fhir.util.TestUtil.waitForSize;
|
import static ca.uhn.fhir.util.TestUtil.waitForSize;
|
||||||
|
import static java.util.Comparator.comparing;
|
||||||
import static org.awaitility.Awaitility.await;
|
import static org.awaitility.Awaitility.await;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
@ExtendWith(SpringExtension.class)
|
@ExtendWith(SpringExtension.class)
|
||||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
|
||||||
{
|
{
|
||||||
"spring.batch.job.enabled=false",
|
"spring.batch.job.enabled=false",
|
||||||
"spring.datasource.url=jdbc:h2:mem:dbr4",
|
"spring.datasource.url=jdbc:h2:mem:dbr4",
|
||||||
|
"hapi.fhir.enable_repository_validating_interceptor=true",
|
||||||
"hapi.fhir.fhir_version=r4",
|
"hapi.fhir.fhir_version=r4",
|
||||||
"hapi.fhir.subscription.websocket_enabled=true",
|
"hapi.fhir.subscription.websocket_enabled=true",
|
||||||
"hapi.fhir.empi_enabled=true",
|
"hapi.fhir.mdm_enabled=true",
|
||||||
//Override is currently required when using Empi as the construction of the Empi beans are ambiguous as they are constructed multiple places. This is evident when running in a spring boot environment
|
//Override is currently required when using MDM as the construction of the MDM beans are ambiguous as they are constructed multiple places. This is evident when running in a spring boot environment
|
||||||
"spring.main.allow-bean-definition-overriding=true"
|
"spring.main.allow-bean-definition-overriding=true"
|
||||||
})
|
})
|
||||||
public class ExampleServerR4IT {
|
public class ExampleServerR4IT {
|
||||||
@@ -54,6 +59,7 @@ public class ExampleServerR4IT {
|
|||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Order(0)
|
||||||
void testCreateAndRead() {
|
void testCreateAndRead() {
|
||||||
|
|
||||||
String methodName = "testCreateResourceConditional";
|
String methodName = "testCreateResourceConditional";
|
||||||
@@ -68,29 +74,26 @@ public class ExampleServerR4IT {
|
|||||||
Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute();
|
Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute();
|
||||||
assertEquals(methodName, pt2.getName().get(0).getFamily());
|
assertEquals(methodName, pt2.getName().get(0).getFamily());
|
||||||
|
|
||||||
// Test EMPI
|
// Test MDM
|
||||||
|
|
||||||
// Wait until the EMPI message has been processed
|
// Wait until the MDM message has been processed
|
||||||
await().until(() -> getPeople().size() > 0);
|
await().until(() -> getPatients().size(), equalTo(2));
|
||||||
List<Person> persons = getPeople();
|
List<Patient> persons = getPatients();
|
||||||
|
Patient goldenRecord = persons.get(0);
|
||||||
|
|
||||||
// Verify a Person was created that links to our Patient
|
// Verify that a golden record Patient was created
|
||||||
Optional<String> personLinkToCreatedPatient = persons.stream()
|
assertNotNull(goldenRecord.getMeta().getTag("http://hapifhir.io/fhir/NamingSystem/mdm-record-status", "GOLDEN_RECORD"));
|
||||||
.map(Person::getLink)
|
|
||||||
.flatMap(Collection::stream)
|
|
||||||
.map(Person.PersonLinkComponent::getTarget)
|
|
||||||
.map(Reference::getReference)
|
|
||||||
.filter(pid -> id.toUnqualifiedVersionless().getValue().equals(pid))
|
|
||||||
.findAny();
|
|
||||||
assertTrue(personLinkToCreatedPatient.isPresent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Person> getPeople() {
|
private List<Patient> getPatients() {
|
||||||
Bundle bundle = ourClient.search().forResource(Person.class).cacheControl(new CacheControlDirective().setNoCache(true)).returnBundle(Bundle.class).execute();
|
Bundle bundle = ourClient.search().forResource(Patient.class).cacheControl(new CacheControlDirective().setNoCache(true)).returnBundle(Bundle.class).execute();
|
||||||
return BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Person.class);
|
List<Patient> retVal = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class);
|
||||||
|
retVal.sort(comparing(o -> ((Patient) o).getMeta().getLastUpdated()).reversed());
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Order(1)
|
||||||
public void testWebsocketSubscription() throws Exception {
|
public void testWebsocketSubscription() throws Exception {
|
||||||
/*
|
/*
|
||||||
* Create subscription
|
* Create subscription
|
||||||
|
|||||||
Reference in New Issue
Block a user