diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 0000000..74c342f
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,24 @@
+# This workflow will build a Java project with Maven
+# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
+
+name: Java CI with Maven
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Build with Maven
+ run: mvn -B package --file pom.xml
diff --git a/README.md b/README.md
index 7ee6092..09c080d 100644
--- a/README.md
+++ b/README.md
@@ -42,15 +42,23 @@ docker run -p 8080:8080 -e hapi.fhir.default_encoding=xml hapiproject/hapi:lates
HAPI looks in the environment variables for properties in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file for defaults.
-### Configuration via overridden application.yaml file
+### Configuration via overridden application.yaml file and using Docker
You can customize HAPI by telling HAPI to look for the configuration file in a different location, eg.:
+```
+docker run -p 8090:8080 -v $(pwd)/yourLocalFolder:/configs -e "--spring.config.location=file:///configs/another.application.yaml" hapiproject/hapi:latest
+```
+Here, the configuration file (*another.application.yaml*) is placed locally in the folder *yourLocalFolder*.
+
+
+
```
docker run -p 8090:8080 -e "--spring.config.location=classpath:/another.application.yaml" hapiproject/hapi:latest
```
+Here, the configuration file (*another.application.yaml*) is part of the compiled set of resources.
-### Example docker-compose.yml
+### Example using docker-compose.yml for docker-compose
```
version: '3.7'
@@ -314,6 +322,10 @@ elasticsearch.required_index_status=YELLOW
elasticsearch.schema_management_strategy=CREATE
```
+## Enabling LastN
+
+Set `hapi.fhir.lastn_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable the $lastn operation on this server. Note that the $lastn operation relies on Elasticsearch, so for $lastn to work, indexing must be enabled using Elasticsearch.
+
## Example of a Dockerfile based on distroless images (for lower footprint and improved security)
```code
diff --git a/pom.xml b/pom.xml
index e17c0cc..ecf437a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,7 +14,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 5.1.0
+ 5.2.0
hapi-fhir-jpaserver-starter
@@ -177,37 +177,30 @@
org.webjars
Eonasdan-bootstrap-datetimepicker
- 4.17.43
org.webjars
font-awesome
- 5.8.2
org.webjars.bower
awesome-bootstrap-checkbox
- 1.0.1
org.webjars
jstimezonedetect
- 1.0.6
org.webjars
select2
- 4.0.3
org.webjars.bower
jquery
- 3.3.1
org.webjars.bower
moment
- 2.15.1
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java b/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java
index 2835656..30df010 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java
@@ -7,8 +7,10 @@ import ca.uhn.fhir.rest.api.EncodingEnum;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import org.hl7.fhir.r4.model.Bundle;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -52,14 +54,17 @@ public class AppProperties {
private ClientIdStrategyEnum client_id_strategy = ClientIdStrategyEnum.ALPHANUMERIC;
private List supported_resource_types = new ArrayList<>();
private List allowed_bundle_types = null;
+ private Boolean narrative_enabled = true;
private Validation validation = new Validation();
- private List tester = ImmutableList.of(new Tester());
+ private Map tester = ImmutableMap.of("home", new Tester());
private Logger logger = new Logger();
private Subscription subscription = new Subscription();
private Cors cors = null;
private Partitioning partitioning = null;
- private List implementationGuides = null;
+ private Map implementationGuides = null;
+
+ private Boolean lastn_enabled = false;
public Integer getDefer_indexing_for_codesystems_of_size() {
return defer_indexing_for_codesystems_of_size;
@@ -69,11 +74,11 @@ public class AppProperties {
this.defer_indexing_for_codesystems_of_size = defer_indexing_for_codesystems_of_size;
}
- public List getImplementationGuides() {
+ public Map getImplementationGuides() {
return implementationGuides;
}
- public void setImplementationGuides(List implementationGuides) {
+ public void setImplementationGuides(Map implementationGuides) {
this.implementationGuides = implementationGuides;
}
@@ -363,14 +368,32 @@ public class AppProperties {
this.reuse_cached_search_results_millis = reuse_cached_search_results_millis;
}
- public List getTester() {
+ public Map getTester() {
return tester;
}
- public void setTester(List tester) {
+ public void setTester(Map tester) {
this.tester = tester;
}
+ public Boolean getNarrative_enabled()
+ {
+ return narrative_enabled;
+ }
+
+ public void setNarrative_enabled(Boolean narrative_enabled)
+ {
+ this.narrative_enabled = narrative_enabled;
+ }
+
+ public Boolean getLastn_enabled() {
+ return lastn_enabled;
+ }
+
+ public void setLastn_enabled(Boolean lastn_enabled) {
+ this.lastn_enabled = lastn_enabled;
+ }
+
public static class Cors {
private Boolean allow_Credentials = true;
private List allowed_origin = ImmutableList.of("*");
@@ -437,7 +460,6 @@ public class AppProperties {
public static class Tester {
- private String id = "home";
private String name = "Local Tester";
private String server_address = "http://localhost:8080/fhir";
private Boolean refuse_to_fetch_third_party_urls = true;
@@ -451,14 +473,6 @@ public class AppProperties {
this.fhir_version = fhir_version;
}
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
public String getName() {
return name;
}
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/Application.java b/src/main/java/ca/uhn/fhir/jpa/starter/Application.java
index fab5481..272feb6 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/Application.java
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/Application.java
@@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.jpa.empi.EmpiConfig;
+import ca.uhn.fhir.jpa.starter.annotations.OnEitherVersion;
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;
@@ -15,6 +16,7 @@ import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Import;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
@@ -44,6 +46,7 @@ public class Application extends SpringBootServletInitializer {
AutowireCapableBeanFactory beanFactory;
@Bean
+ @Conditional(OnEitherVersion.class)
public ServletRegistrationBean hapiServletRegistration() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
JpaRestfulServer jpaRestfulServer = new JpaRestfulServer();
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 2f7c044..dfbe8c8 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java
@@ -13,11 +13,7 @@ import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc;
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
import ca.uhn.fhir.jpa.partition.PartitionManagementProvider;
-import ca.uhn.fhir.jpa.provider.GraphQLProvider;
-import ca.uhn.fhir.jpa.provider.IJpaSystemProvider;
-import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
-import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
-import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
+import ca.uhn.fhir.jpa.provider.*;
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4;
import ca.uhn.fhir.jpa.provider.r5.JpaConformanceProviderR5;
@@ -25,6 +21,8 @@ import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.jpa.subscription.util.SubscriptionDebugLogInterceptor;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
+import ca.uhn.fhir.narrative.INarrativeGenerator;
+import ca.uhn.fhir.narrative2.NullNarrativeGenerator;
import ca.uhn.fhir.rest.server.ETagSupportEnum;
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
import ca.uhn.fhir.rest.server.RestfulServer;
@@ -42,10 +40,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.web.cors.CorsConfiguration;
import javax.servlet.ServletException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
import java.util.stream.Collectors;
public class BaseJpaRestfulServer extends RestfulServer {
@@ -181,7 +176,11 @@ public class BaseJpaRestfulServer extends RestfulServer {
* This server tries to dynamically generate narratives
*/
FhirContext ctx = getFhirContext();
- ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
+ INarrativeGenerator theNarrativeGenerator =
+ appProperties.getNarrative_enabled() ?
+ new DefaultThymeleafNarrativeGenerator() :
+ new NullNarrativeGenerator();
+ ctx.setNarrativeGenerator(theNarrativeGenerator);
/*
* Default to JSON and pretty printing
@@ -349,15 +348,21 @@ public class BaseJpaRestfulServer extends RestfulServer {
}
if (appProperties.getImplementationGuides() != null) {
- List guides = appProperties.getImplementationGuides();
- for (AppProperties.ImplementationGuide guide : guides) {
+ Map guides = appProperties.getImplementationGuides();
+ for (Map.Entry guide : guides.entrySet()) {
packageInstallerSvc.install(new PackageInstallationSpec()
- .setPackageUrl(guide.getUrl())
- .setName(guide.getName())
- .setVersion(guide.getVersion())
+ .setPackageUrl(guide.getValue().getUrl())
+ .setName(guide.getValue().getName())
+ .setVersion(guide.getValue().getVersion())
.setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL));
}
}
+
+ if (appProperties.getLastn_enabled()) {
+ daoConfig.setLastNEnabled(true);
+ }
+
+
}
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java b/src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java
index 4dbc122..6dd8311 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java
@@ -1,5 +1,8 @@
package ca.uhn.fhir.jpa.starter;
+import ca.uhn.fhir.jpa.search.elastic.ElasticsearchHibernatePropertiesBuilder;
+import org.hibernate.search.elasticsearch.cfg.ElasticsearchIndexStatus;
+import org.hibernate.search.elasticsearch.cfg.IndexSchemaManagementStrategy;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
@@ -35,9 +38,66 @@ public class EnvironmentHelper {
properties.put(values[0], values[1]);
});
}
+
+ if (environment.getProperty("elasticsearch.enabled", Boolean.class) != null
+ && environment.getProperty("elasticsearch.enabled", Boolean.class) == true ){
+ ElasticsearchHibernatePropertiesBuilder builder = new ElasticsearchHibernatePropertiesBuilder();
+ ElasticsearchIndexStatus requiredIndexStatus = environment.getProperty("elasticsearch.required_index_status", ElasticsearchIndexStatus.class);
+ if (requiredIndexStatus == null) {
+ builder.setRequiredIndexStatus(ElasticsearchIndexStatus.YELLOW);
+ } else {
+ builder.setRequiredIndexStatus(requiredIndexStatus);
+ }
+
+ builder.setRestUrl(getElasticsearchServerUrl(environment));
+ builder.setUsername(getElasticsearchServerUsername(environment));
+ builder.setPassword(getElasticsearchServerPassword(environment));
+ IndexSchemaManagementStrategy indexSchemaManagementStrategy = environment.getProperty("elasticsearch.schema_management_strategy", IndexSchemaManagementStrategy.class);
+ if (indexSchemaManagementStrategy == null) {
+ builder.setIndexSchemaManagementStrategy(IndexSchemaManagementStrategy.CREATE);
+ } else {
+ builder.setIndexSchemaManagementStrategy(indexSchemaManagementStrategy);
+ }
+ // pretty_print_json_log: false
+ Boolean refreshAfterWrite = environment.getProperty("elasticsearch.debug.refresh_after_write", Boolean.class);
+ if (refreshAfterWrite == null) {
+ builder.setDebugRefreshAfterWrite(false);
+ } else {
+ builder.setDebugRefreshAfterWrite(refreshAfterWrite);
+ }
+ // pretty_print_json_log: false
+ Boolean prettyPrintJsonLog = environment.getProperty("elasticsearch.debug.pretty_print_json_log", Boolean.class);
+ if (prettyPrintJsonLog == null) {
+ builder.setDebugPrettyPrintJsonLog(false);
+ } else {
+ builder.setDebugPrettyPrintJsonLog(prettyPrintJsonLog);
+ }
+ builder.apply(properties);
+ }
+
return properties;
}
+ public static String getElasticsearchServerUrl(ConfigurableEnvironment environment) {
+ return environment.getProperty("elasticsearch.rest_url", String.class);
+ }
+
+ public static String getElasticsearchServerUsername(ConfigurableEnvironment environment) {
+ return environment.getProperty("elasticsearch.username");
+ }
+
+ public static String getElasticsearchServerPassword(ConfigurableEnvironment environment) {
+ return environment.getProperty("elasticsearch.password");
+ }
+
+ public static Boolean isElasticsearchEnabled(ConfigurableEnvironment environment) {
+ if (environment.getProperty("elasticsearch.enabled", Boolean.class) != null) {
+ return environment.getProperty("elasticsearch.enabled", Boolean.class);
+ } else {
+ return false;
+ }
+ }
+
public static Map getPropertiesStartingWith(ConfigurableEnvironment aEnv,
String aKeyPrefix) {
Map result = new HashMap<>();
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 cfe9bde..4b7d721 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java
@@ -3,6 +3,7 @@ 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.config.HibernateDialectProvider;
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionDeliveryHandlerFactory;
@@ -10,9 +11,12 @@ import ca.uhn.fhir.jpa.subscription.match.deliver.email.IEmailSender;
import ca.uhn.fhir.jpa.subscription.match.deliver.email.JavaMailEmailSender;
import com.google.common.base.Strings;
import org.hl7.fhir.dstu2.model.Subscription;
+import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
+import org.springframework.context.annotation.Primary;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.Optional;
@@ -110,6 +114,11 @@ public class FhirServerConfigCommon {
return retVal;
}
+ @Bean
+ public YamlPropertySourceLoader yamlPropertySourceLoader() {
+ return new YamlPropertySourceLoader();
+ }
+
@Bean
public PartitionSettings partitionSettings(AppProperties appProperties) {
PartitionSettings retVal = new PartitionSettings();
@@ -123,6 +132,12 @@ public class FhirServerConfigCommon {
}
+ @Primary
+ @Bean
+ public HibernateDialectProvider jpaStarterDialectProvider(LocalContainerEntityManagerFactoryBean myEntityManagerFactory) {
+ return new JpaHibernateDialectProvider(myEntityManagerFactory);
+ }
+
@Bean
public ModelConfig modelConfig(AppProperties appProperties) {
ModelConfig modelConfig = new ModelConfig();
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 8efc81f..5674d2a 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu2.java
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu2.java
@@ -3,24 +3,21 @@ package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
+import ca.uhn.fhir.jpa.starter.annotations.OnDSTU2Condition;
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.Primary;
-import org.springframework.context.annotation.Profile;
import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
@Configuration
-@Profile("dstu2")
+@Conditional(OnDSTU2Condition.class)
public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
@Autowired
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 ace88af..07406b2 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu3.java
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu3.java
@@ -3,11 +3,10 @@ package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
+import ca.uhn.fhir.jpa.search.lastn.ElasticsearchSvcImpl;
+import ca.uhn.fhir.jpa.starter.annotations.OnDSTU3Condition;
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.context.annotation.Profile;
+import org.springframework.context.annotation.*;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@@ -16,7 +15,7 @@ import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
@Configuration
-@Profile("dstu3")
+@Conditional(OnDSTU3Condition.class)
public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 {
@Autowired
@@ -65,4 +64,18 @@ public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 {
return retVal;
}
+ @Bean()
+ public ElasticsearchSvcImpl elasticsearchSvc() {
+ if (EnvironmentHelper.isElasticsearchEnabled(configurableEnvironment)) {
+ String elasticsearchUrl = EnvironmentHelper.getElasticsearchServerUrl(configurableEnvironment);
+ String elasticsearchHost = elasticsearchUrl.substring(elasticsearchUrl.indexOf("://")+3, elasticsearchUrl.lastIndexOf(":"));
+ String elasticsearchUsername = EnvironmentHelper.getElasticsearchServerUsername(configurableEnvironment);
+ String elasticsearchPassword = EnvironmentHelper.getElasticsearchServerPassword(configurableEnvironment);
+ int elasticsearchPort = Integer.parseInt(elasticsearchUrl.substring(elasticsearchUrl.lastIndexOf(":")+1));
+ return new ElasticsearchSvcImpl(elasticsearchHost, elasticsearchPort, elasticsearchUsername, elasticsearchPassword);
+ } else {
+ return null;
+ }
+ }
+
}
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 8d8e699..e415fea 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java
@@ -3,23 +3,22 @@ package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.jpa.config.BaseJavaConfigR4;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
+import ca.uhn.fhir.jpa.search.lastn.ElasticsearchSvcImpl;
+import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition;
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.Primary;
-import org.springframework.context.annotation.Profile;
import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
-import java.util.Arrays;
-import java.util.Properties;
@Configuration
-@Profile("r4")
+@Conditional(OnR4Condition.class)
public class FhirServerConfigR4 extends BaseJavaConfigR4 {
@Autowired
@@ -68,4 +67,18 @@ public class FhirServerConfigR4 extends BaseJavaConfigR4 {
return retVal;
}
+ @Bean()
+ public ElasticsearchSvcImpl elasticsearchSvc() {
+ if (EnvironmentHelper.isElasticsearchEnabled(configurableEnvironment)) {
+ String elasticsearchUrl = EnvironmentHelper.getElasticsearchServerUrl(configurableEnvironment);
+ String elasticsearchHost = elasticsearchUrl.substring(elasticsearchUrl.indexOf("://")+3, elasticsearchUrl.lastIndexOf(":"));
+ String elasticsearchUsername = EnvironmentHelper.getElasticsearchServerUsername(configurableEnvironment);
+ String elasticsearchPassword = EnvironmentHelper.getElasticsearchServerPassword(configurableEnvironment);
+ int elasticsearchPort = Integer.parseInt(elasticsearchUrl.substring(elasticsearchUrl.lastIndexOf(":")+1));
+ return new ElasticsearchSvcImpl(elasticsearchHost, elasticsearchPort, elasticsearchUsername, elasticsearchPassword);
+ } else {
+ return null;
+ }
+ }
+
}
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 5a5145b..6e5bd98 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR5.java
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR5.java
@@ -3,11 +3,13 @@ package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.jpa.config.BaseJavaConfigR5;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
+import ca.uhn.fhir.jpa.search.lastn.ElasticsearchSvcImpl;
+import ca.uhn.fhir.jpa.starter.annotations.OnR5Condition;
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.Primary;
-import org.springframework.context.annotation.Profile;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@@ -16,7 +18,7 @@ import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
@Configuration
-@Profile("r5")
+@Conditional(OnR5Condition.class)
public class FhirServerConfigR5 extends BaseJavaConfigR5 {
@Autowired
@@ -65,4 +67,19 @@ public class FhirServerConfigR5 extends BaseJavaConfigR5 {
return retVal;
}
+ @Bean()
+ public ElasticsearchSvcImpl elasticsearchSvc() {
+ if (EnvironmentHelper.isElasticsearchEnabled(configurableEnvironment)) {
+ String elasticsearchUrl = EnvironmentHelper.getElasticsearchServerUrl(configurableEnvironment);
+ String elasticsearchHost = elasticsearchUrl.substring(elasticsearchUrl.indexOf("://")+3, elasticsearchUrl.lastIndexOf(":"));
+ String elasticsearchUsername = EnvironmentHelper.getElasticsearchServerUsername(configurableEnvironment);
+ String elasticsearchPassword = EnvironmentHelper.getElasticsearchServerPassword(configurableEnvironment);
+ int elasticsearchPort = Integer.parseInt(elasticsearchUrl.substring(elasticsearchUrl.lastIndexOf(":")+1));
+ return new ElasticsearchSvcImpl(elasticsearchHost, elasticsearchPort, elasticsearchUsername, elasticsearchPassword);
+ } else {
+ return null;
+ }
+ }
+
+
}
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirTesterConfig.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirTesterConfig.java
index 45a7808..7adf8bf 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirTesterConfig.java
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirTesterConfig.java
@@ -36,15 +36,15 @@ public class FhirTesterConfig {
@Bean
public TesterConfig testerConfig(AppProperties appProperties) {
TesterConfig retVal = new TesterConfig();
- appProperties.getTester().stream().forEach(t -> {
+ appProperties.getTester().entrySet().stream().forEach(t -> {
retVal
.addServer()
- .withId(t.getId())
- .withFhirVersion(t.getFhir_version())
- .withBaseUrl(t.getServer_address())
- .withName(t.getName());
+ .withId(t.getKey())
+ .withFhirVersion(t.getValue().getFhir_version())
+ .withBaseUrl(t.getValue().getServer_address())
+ .withName(t.getValue().getName());
retVal.setRefuseToFetchThirdPartyUrls(
- t.getRefuse_to_fetch_third_party_urls());
+ t.getValue().getRefuse_to_fetch_third_party_urls());
});
return retVal;
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/JpaHibernateDialectProvider.java b/src/main/java/ca/uhn/fhir/jpa/starter/JpaHibernateDialectProvider.java
new file mode 100644
index 0000000..49d31ee
--- /dev/null
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/JpaHibernateDialectProvider.java
@@ -0,0 +1,31 @@
+package ca.uhn.fhir.jpa.starter;
+
+import ca.uhn.fhir.context.ConfigurationException;
+import ca.uhn.fhir.jpa.config.HibernateDialectProvider;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.jdbc.dialect.internal.StandardDialectResolver;
+import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+
+import javax.sql.DataSource;
+import java.sql.SQLException;
+
+public class JpaHibernateDialectProvider extends HibernateDialectProvider {
+
+ private final Dialect dialect;
+
+ public JpaHibernateDialectProvider(LocalContainerEntityManagerFactoryBean myEntityManagerFactory) {
+ DataSource connection = myEntityManagerFactory.getDataSource();
+ try {
+ dialect = new StandardDialectResolver()
+ .resolveDialect(new DatabaseMetaDataDialectResolutionInfoAdapter(connection.getConnection().getMetaData()));
+ } catch (SQLException sqlException) {
+ throw new ConfigurationException(sqlException.getMessage(), sqlException);
+ }
+ }
+
+ @Override
+ public Dialect getDialect() {
+ return dialect;
+ }
+}
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnDSTU2Condition.java b/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnDSTU2Condition.java
new file mode 100644
index 0000000..2c2419c
--- /dev/null
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnDSTU2Condition.java
@@ -0,0 +1,19 @@
+package ca.uhn.fhir.jpa.starter.annotations;
+
+import ca.uhn.fhir.context.FhirVersionEnum;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+public class OnDSTU2Condition implements Condition {
+ @Override
+ public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
+ FhirVersionEnum version = FhirVersionEnum.forVersionString(conditionContext.
+ getEnvironment()
+ .getProperty("hapi.fhir.fhir_version")
+ .toUpperCase());
+
+ return version == FhirVersionEnum.DSTU2;
+
+ }
+}
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnDSTU3Condition.java b/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnDSTU3Condition.java
new file mode 100644
index 0000000..1196245
--- /dev/null
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnDSTU3Condition.java
@@ -0,0 +1,19 @@
+package ca.uhn.fhir.jpa.starter.annotations;
+
+import ca.uhn.fhir.context.FhirVersionEnum;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+public class OnDSTU3Condition implements Condition {
+ @Override
+ public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
+ FhirVersionEnum version = FhirVersionEnum.forVersionString(conditionContext.
+ getEnvironment()
+ .getProperty("hapi.fhir.fhir_version")
+ .toUpperCase());
+
+ return version == FhirVersionEnum.DSTU3;
+
+ }
+}
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnEitherVersion.java b/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnEitherVersion.java
new file mode 100644
index 0000000..abf564f
--- /dev/null
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnEitherVersion.java
@@ -0,0 +1,35 @@
+package ca.uhn.fhir.jpa.starter.annotations;
+
+import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
+import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
+import org.springframework.context.annotation.Conditional;
+
+public class OnEitherVersion extends AnyNestedCondition {
+
+ OnEitherVersion() {
+ super(ConfigurationPhase.REGISTER_BEAN);
+ }
+
+ @Override
+ protected ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes) {
+ ConditionOutcome result = super.getFinalMatchOutcome(memberOutcomes);
+ return result;
+ }
+
+ @Conditional(OnDSTU2Condition.class)
+ static class OnDSTU2 {
+ }
+
+ @Conditional(OnDSTU3Condition.class)
+ static class OnDSTU3 {
+ }
+
+ @Conditional(OnR4Condition.class)
+ static class OnR4 {
+ }
+
+ @Conditional(OnR5Condition.class)
+ static class OnR5 {
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnR4Condition.java b/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnR4Condition.java
new file mode 100644
index 0000000..e362aea
--- /dev/null
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnR4Condition.java
@@ -0,0 +1,19 @@
+package ca.uhn.fhir.jpa.starter.annotations;
+
+import ca.uhn.fhir.context.FhirVersionEnum;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+public class OnR4Condition implements Condition {
+ @Override
+ public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
+ FhirVersionEnum version = FhirVersionEnum.forVersionString(conditionContext.
+ getEnvironment()
+ .getProperty("hapi.fhir.fhir_version")
+ .toUpperCase());
+
+ return version == FhirVersionEnum.R4;
+
+ }
+}
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnR5Condition.java b/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnR5Condition.java
new file mode 100644
index 0000000..1ecca66
--- /dev/null
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/annotations/OnR5Condition.java
@@ -0,0 +1,19 @@
+package ca.uhn.fhir.jpa.starter.annotations;
+
+import ca.uhn.fhir.context.FhirVersionEnum;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+public class OnR5Condition implements Condition {
+ @Override
+ public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
+ FhirVersionEnum version = FhirVersionEnum.forVersionString(conditionContext.
+ getEnvironment()
+ .getProperty("hapi.fhir.fhir_version")
+ .toUpperCase());
+
+ return version == FhirVersionEnum.R5;
+
+ }
+}
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
index b7ec776..d081516 100644
--- a/src/main/resources/application.yaml
+++ b/src/main/resources/application.yaml
@@ -1,28 +1,26 @@
spring:
datasource:
url: 'jdbc:h2:file:./target/database/h2'
+ #url: jdbc:h2:mem:test_mem
username: sa
password: null
driverClassName: org.h2.Driver
max-active: 15
- profiles:
- ### This is the FHIR version. Choose between, dstu2, dstu3, r4 or r5
- active: r4
- jpa:
- properties:
- hibernate.dialect: org.hibernate.dialect.H2Dialect
- hibernate.search.model_mapping: ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory
- hibernate.format_sql: false
- hibernate.show_sql: false
- hibernate.hbm2ddl.auto: update
- hibernate.jdbc.batch_size: 20
- hibernate.cache.use_query_cache: false
- hibernate.cache.use_second_level_cache: false
- hibernate.cache.use_structured_entries: false
- hibernate.cache.use_minimal_puts: false
- hibernate.search.default.directory_provider: filesystem
- hibernate.search.default.indexBase: target/lucenefiles
- hibernate.search.lucene_version: LUCENE_CURRENT
+# jpa:
+# properties:
+# hibernate.dialect: org.hibernate.dialect.h2dialect
+# hibernate.search.model_mapping: ca.uhn.fhir.jpa.search.lucenesearchmappingfactory
+# hibernate.format_sql: false
+# hibernate.show_sql: false
+# hibernate.hbm2ddl.auto: update
+# hibernate.jdbc.batch_size: 20
+# hibernate.cache.use_query_cache: false
+# hibernate.cache.use_second_level_cache: false
+# hibernate.cache.use_structured_entries: false
+# hibernate.cache.use_minimal_puts: false
+# hibernate.search.default.directory_provider: filesystem
+# hibernate.search.default.indexbase: target/lucenefiles
+# hibernate.search.lucene_version: lucene_current
batch:
job:
@@ -30,15 +28,21 @@ spring:
hapi:
fhir:
- defer_indexing_for_codesystems_of_size: 101
-# implementationguides:
-# -
-# url: https://build.fhir.org/ig/hl7dk/dk-medcom/branches/corrections/package.tgz
-# name: dk.fhir.ig.medcom-core
-# version: 0.8.0
-# -
-# name: hl7.fhir.uv.ips
-# version: 0.3.0
+ ### enable to set the Server URL
+# server_address: http://hapi.fhir.org/baseR4
+ ### This is the FHIR version. Choose between, DSTU2, DSTU3, R4 or R5
+ fhir_version: R4
+# defer_indexing_for_codesystems_of_size: 101
+ #implementationguides:
+ #example from registry (packages.fhir.org)
+ #swiss:
+ #name: swiss.mednet.fhir
+ #version: 0.8.0
+ #example not from registry
+ #ips_1_0_0:
+ #url: https://build.fhir.org/ig/HL7/fhir-ips/package.tgz
+ #name: hl7.fhir.uv.ips
+ #version: 1.0.0
#supported_resource_types:
# - Patient
@@ -62,6 +66,7 @@ hapi:
# fhirpath_interceptor_enabled: false
# filter_search_enabled: true
# graphql_enabled: true
+# narrative_enabled: true
#partitioning:
# cross_partition_reference_mode: true
# multitenancy_enabled: true
@@ -87,14 +92,14 @@ hapi:
# retain_cached_searches_mins: 60
# reuse_cached_search_results_millis: 60000
tester:
- -
- id: home
+
+ home:
name: Local Tester
server_address: 'http://localhost:8080/fhir'
refuse_to_fetch_third_party_urls: false
fhir_version: R4
- -
- id: global
+
+ global:
name: Global Tester
server_address: "http://hapi.fhir.org/baseR4"
refuse_to_fetch_third_party_urls: false
@@ -118,6 +123,7 @@ hapi:
# startTlsEnable:
# startTlsRequired:
# quitWait:
+# lastn_enabled: true
#
diff --git a/src/main/resources/empi-rules.json b/src/main/resources/empi-rules.json
index 9f2706a..cb1d710 100644
--- a/src/main/resources/empi-rules.json
+++ b/src/main/resources/empi-rules.json
@@ -26,17 +26,17 @@
"name": "cosine-given-name",
"resourceType": "*",
"resourcePath": "name.given",
- "metric": "COSINE",
- "matchThreshold": 0.8,
- "exact": true
+ "matcher": {
+ "algorithm": "COLOGNE"
+ }
},
{
"name": "jaro-last-name",
"resourceType": "*",
"resourcePath": "name.family",
- "metric": "JARO_WINKLER",
- "matchThreshold": 0.8,
- "exact": true
+ "matcher": {
+ "algorithm": "SOUNDEX"
+ }
}
],
"matchResultMap": {
diff --git a/src/test/java/ca/uhn/fhir/jpa/starter/ElasticsearchLastNR4IT.java b/src/test/java/ca/uhn/fhir/jpa/starter/ElasticsearchLastNR4IT.java
new file mode 100644
index 0000000..c3fb7f7
--- /dev/null
+++ b/src/test/java/ca/uhn/fhir/jpa/starter/ElasticsearchLastNR4IT.java
@@ -0,0 +1,144 @@
+package ca.uhn.fhir.jpa.starter;
+
+import ca.uhn.fhir.context.ConfigurationException;
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jpa.search.lastn.ElasticsearchSvcImpl;
+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 org.hl7.fhir.instance.model.api.IIdType;
+import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.DateTimeType;
+import org.hl7.fhir.r4.model.IntegerType;
+import org.hl7.fhir.r4.model.Observation;
+import org.hl7.fhir.r4.model.Parameters;
+import org.hl7.fhir.r4.model.Patient;
+import org.hl7.fhir.r4.model.StringType;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.util.TestPropertyValues;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import pl.allegro.tech.embeddedelasticsearch.EmbeddedElastic;
+import pl.allegro.tech.embeddedelasticsearch.PopularProperties;
+
+import javax.annotation.PreDestroy;
+import java.io.IOException;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
+ {
+ "spring.batch.job.enabled=false",
+ "spring.datasource.url=jdbc:h2:mem:dbr4",
+ "hapi.fhir.fhir_version=r4",
+ "hapi.fhir.lastn_enabled=true",
+ "elasticsearch.enabled=true",
+ // Because the port is set randomly, we will set the rest_url using the Initializer.
+ // "elasticsearch.rest_url='http://localhost:9200'",
+ "elasticsearch.username=SomeUsername",
+ "elasticsearch.password=SomePassword"
+ })
+@ContextConfiguration(initializers = ElasticsearchLastNR4IT.Initializer.class)
+public class ElasticsearchLastNR4IT {
+
+ private IGenericClient ourClient;
+ private FhirContext ourCtx;
+
+ private static final String ELASTIC_VERSION = "6.5.4";
+ private static EmbeddedElastic embeddedElastic;
+
+ @Autowired
+ private ElasticsearchSvcImpl myElasticsearchSvc;
+
+ @BeforeAll
+ public static void beforeClass() {
+
+ embeddedElastic = null;
+ try {
+ embeddedElastic = EmbeddedElastic.builder()
+ .withElasticVersion(ELASTIC_VERSION)
+ .withSetting(PopularProperties.TRANSPORT_TCP_PORT, 0)
+ .withSetting(PopularProperties.HTTP_PORT, 0)
+ .withSetting(PopularProperties.CLUSTER_NAME, UUID.randomUUID())
+ .withStartTimeout(60, TimeUnit.SECONDS)
+ .build()
+ .start();
+ } catch (IOException | InterruptedException e) {
+ throw new ConfigurationException(e);
+ }
+ }
+
+ @PreDestroy
+ public void stop() {
+ embeddedElastic.stop();
+ }
+
+ @LocalServerPort
+ private int port;
+
+ @Test
+ void testLastN() throws IOException {
+
+ Patient pt = new Patient();
+ pt.addName().setFamily("Lastn").addGiven("Arthur");
+ IIdType id = ourClient.create().resource(pt).execute().getId().toUnqualifiedVersionless();
+
+ Observation obs = new Observation();
+ obs.getSubject().setReferenceElement(id);
+ String observationCode = "testobservationcode";
+ String codeSystem = "http://testobservationcodesystem";
+ obs.getCode().addCoding().setCode(observationCode).setSystem(codeSystem);
+ obs.setValue(new StringType(observationCode));
+ Date effectiveDtm = new GregorianCalendar().getTime();
+ obs.setEffective(new DateTimeType(effectiveDtm));
+ obs.getCategoryFirstRep().addCoding().setCode("testcategorycode").setSystem("http://testcategorycodesystem");
+ IIdType obsId = ourClient.create().resource(obs).execute().getId().toUnqualifiedVersionless();
+
+ myElasticsearchSvc.refreshIndex(ElasticsearchSvcImpl.OBSERVATION_INDEX);
+
+ Parameters output = ourClient.operation().onType(Observation.class).named("lastn")
+ .withParameter(Parameters.class, "max", new IntegerType(1))
+ .andParameter("subject", new StringType("Patient/" + id.getIdPart()))
+ .execute();
+ Bundle b = (Bundle) output.getParameter().get(0).getResource();
+ assertEquals(1, b.getTotal());
+ assertEquals(obsId, b.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless());
+ }
+
+ @BeforeEach
+ void beforeEach() {
+
+ ourCtx = FhirContext.forR4();
+ ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
+ ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
+ String ourServerBase = "http://localhost:" + port + "/fhir/";
+ ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
+ ourClient.registerInterceptor(new LoggingInterceptor(true));
+ }
+
+ static class Initializer
+ implements ApplicationContextInitializer {
+
+ @Override
+ public void initialize(
+ ConfigurableApplicationContext configurableApplicationContext) {
+ // Since the port is dynamically generated, replace the URL with one that has the correct port
+ TestPropertyValues.of("elasticsearch.rest_url=http://localhost:" + embeddedElastic.getHttpPort())
+ .applyTo(configurableApplicationContext.getEnvironment());
+ }
+
+ }
+}
diff --git a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerDstu2IT.java b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerDstu2IT.java
index b99ea65..3aa1556 100644
--- a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerDstu2IT.java
+++ b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerDstu2IT.java
@@ -19,7 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
{
"spring.batch.job.enabled=false",
- "spring.profiles.active=dstu2",
+ "hapi.fhir.fhir_version=dstu2",
"spring.datasource.url=jdbc:h2:mem:dbr2"
})
public class ExampleServerDstu2IT {
diff --git a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerDstu3IT.java b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerDstu3IT.java
index ca1cbf1..f190697 100644
--- a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerDstu3IT.java
+++ b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerDstu3IT.java
@@ -33,8 +33,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
{
"spring.batch.job.enabled=false",
- "spring.profiles.active=dstu3",
"spring.datasource.url=jdbc:h2:mem:dbr3",
+ "hapi.fhir.fhir_version=dstu3",
"hapi.fhir.subscription.websocket_enabled=true",
"hapi.fhir.allow_external_references=true",
"hapi.fhir.allow_placeholder_references=true",
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 6fc36b3..8a011be 100644
--- a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4IT.java
+++ b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4IT.java
@@ -36,8 +36,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
{
"spring.batch.job.enabled=false",
- "spring.profiles.active=r4",
"spring.datasource.url=jdbc:h2:mem:dbr4",
+ "hapi.fhir.fhir_version=r4",
"hapi.fhir.subscription.websocket_enabled=true",
"hapi.fhir.empi_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
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 3a52ec7..9ac9997 100644
--- a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR5IT.java
+++ b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR5IT.java
@@ -35,8 +35,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
{
"spring.batch.job.enabled=false",
- "spring.profiles.active=r5",
"spring.datasource.url=jdbc:h2:mem:dbr5",
+ "hapi.fhir.fhir_version=r5",
"hapi.fhir.subscription.websocket_enabled=true"
})
public class ExampleServerR5IT {
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 66fb4df..f13a11a 100644
--- a/src/test/java/ca/uhn/fhir/jpa/starter/MultitenantServerR4IT.java
+++ b/src/test/java/ca/uhn/fhir/jpa/starter/MultitenantServerR4IT.java
@@ -21,8 +21,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
{
"spring.batch.job.enabled=false",
- "spring.profiles.active=r4",
"spring.datasource.url=jdbc:h2:mem:dbr4-mt",
+ "hapi.fhir.fhir_version=r4",
"hapi.fhir.subscription.websocket_enabled=true",
"hapi.fhir.partitioning.partitioning_include_in_search_hashes=false"