From c142e6bdfa0d2699859dfda1c41cce9cc0400501 Mon Sep 17 00:00:00 2001 From: xluandc Date: Mon, 8 Mar 2021 09:45:40 -0500 Subject: [PATCH 01/10] - Added configuration parameters for search coordinator thread pool sizes - Added database connection pool size configuration parameter (spring.datasource.hikari.maximum-pool-size) - Fixed a bug in parsing elastic rest_url for all FHIR versions except for R4, which was correct. --- pom.xml | 2 +- .../uhn/fhir/jpa/starter/AppProperties.java | 21 ++++++++++++++++++ .../jpa/starter/FhirServerConfigDstu2.java | 14 ++++++++++++ .../jpa/starter/FhirServerConfigDstu3.java | 22 ++++++++++++++++++- .../fhir/jpa/starter/FhirServerConfigR4.java | 14 ++++++++++++ .../fhir/jpa/starter/FhirServerConfigR5.java | 21 +++++++++++++++++- src/main/resources/application.yaml | 9 ++++++++ 7 files changed, 100 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 10ee51c..3d3fe06 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.3.0 + 5.4.0-PRE1-SNAPSHOT hapi-fhir-jpaserver-starter 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 729b873..4d5edd1 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java @@ -67,6 +67,10 @@ public class AppProperties { private Boolean lastn_enabled = false; private NormalizedQuantitySearchLevel normalized_quantity_search_level = NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED; + private Integer search_coord_core_pool_size = 20; + private Integer search_coord_max_pool_size = 100; + private Integer search_coord_queue_capacity = 200; + public Integer getDefer_indexing_for_codesystems_of_size() { return defer_indexing_for_codesystems_of_size; } @@ -422,6 +426,23 @@ public class AppProperties { this.normalized_quantity_search_level = normalized_quantity_search_level; } + public Integer getSearch_coord_core_pool_size() { return search_coord_core_pool_size; } + + public void setSearch_coord_core_pool_size(Integer search_coord_core_pool_size) { + this.search_coord_core_pool_size = search_coord_core_pool_size; + } + + public Integer getSearch_coord_max_pool_size() { return search_coord_max_pool_size; } + + public void setSearch_coord_max_pool_size(Integer search_coord_max_pool_size) { + this.search_coord_max_pool_size = search_coord_max_pool_size; + } + + public Integer getSearch_coord_queue_capacity() { return search_coord_queue_capacity; } + + public void setSearch_coord_queue_capacity(Integer search_coord_queue_capacity) { + this.search_coord_queue_capacity = search_coord_queue_capacity; + } public static class Cors { private Boolean allow_Credentials = true; 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 5674d2a..6e26d41 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu2.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu2.java @@ -13,6 +13,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import javax.annotation.PostConstruct; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; @@ -31,6 +32,19 @@ public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 { @Autowired AppProperties appProperties; + @PostConstruct + public void initSettings() { + if(appProperties.getSearch_coord_core_pool_size() != null) { + setSearchCoordCorePoolSize(appProperties.getSearch_coord_core_pool_size()); + } + if(appProperties.getSearch_coord_max_pool_size() != null) { + setSearchCoordMaxPoolSize(appProperties.getSearch_coord_max_pool_size()); + } + if(appProperties.getSearch_coord_queue_capacity() != null) { + setSearchCoordQueueCapacity(appProperties.getSearch_coord_queue_capacity()); + } + } + @Override public DatabaseBackedPagingProvider databaseBackedPagingProvider() { DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider(); 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 07406b2..a10ecb4 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu3.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigDstu3.java @@ -11,6 +11,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import javax.annotation.PostConstruct; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; @@ -29,6 +30,20 @@ public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 { @Autowired AppProperties appProperties; + @PostConstruct + public void initSettings() { + if(appProperties.getSearch_coord_core_pool_size() != null) { + setSearchCoordCorePoolSize(appProperties.getSearch_coord_core_pool_size()); + } + if(appProperties.getSearch_coord_max_pool_size() != null) { + setSearchCoordMaxPoolSize(appProperties.getSearch_coord_max_pool_size()); + } + if(appProperties.getSearch_coord_queue_capacity() != null) { + setSearchCoordQueueCapacity(appProperties.getSearch_coord_queue_capacity()); + } + } + + @Override public DatabaseBackedPagingProvider databaseBackedPagingProvider() { DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider(); @@ -68,7 +83,12 @@ public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 { public ElasticsearchSvcImpl elasticsearchSvc() { if (EnvironmentHelper.isElasticsearchEnabled(configurableEnvironment)) { String elasticsearchUrl = EnvironmentHelper.getElasticsearchServerUrl(configurableEnvironment); - String elasticsearchHost = elasticsearchUrl.substring(elasticsearchUrl.indexOf("://")+3, elasticsearchUrl.lastIndexOf(":")); + String elasticsearchHost; + if (elasticsearchUrl.startsWith("http")) { + elasticsearchHost = elasticsearchUrl.substring(elasticsearchUrl.indexOf("://") + 3, elasticsearchUrl.lastIndexOf(":")); + } else { + elasticsearchHost = elasticsearchUrl.substring(0, elasticsearchUrl.indexOf(":")); + } String elasticsearchUsername = EnvironmentHelper.getElasticsearchServerUsername(configurableEnvironment); String elasticsearchPassword = EnvironmentHelper.getElasticsearchServerPassword(configurableEnvironment); int elasticsearchPort = Integer.parseInt(elasticsearchUrl.substring(elasticsearchUrl.lastIndexOf(":")+1)); 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 31c0dcc..a53b057 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java @@ -12,6 +12,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import javax.annotation.PostConstruct; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; @@ -31,6 +32,19 @@ public class FhirServerConfigR4 extends BaseJavaConfigR4 { @Autowired AppProperties appProperties; + @PostConstruct + public void initSettings() { + if(appProperties.getSearch_coord_core_pool_size() != null) { + setSearchCoordCorePoolSize(appProperties.getSearch_coord_core_pool_size()); + } + if(appProperties.getSearch_coord_max_pool_size() != null) { + setSearchCoordMaxPoolSize(appProperties.getSearch_coord_max_pool_size()); + } + if(appProperties.getSearch_coord_queue_capacity() != null) { + setSearchCoordQueueCapacity(appProperties.getSearch_coord_queue_capacity()); + } + } + @Override public DatabaseBackedPagingProvider databaseBackedPagingProvider() { DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider(); 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 6e5bd98..2c6d72e 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR5.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR5.java @@ -14,6 +14,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import javax.annotation.PostConstruct; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; @@ -32,6 +33,19 @@ public class FhirServerConfigR5 extends BaseJavaConfigR5 { @Autowired AppProperties appProperties; + @PostConstruct + public void initSettings() { + if(appProperties.getSearch_coord_core_pool_size() != null) { + setSearchCoordCorePoolSize(appProperties.getSearch_coord_core_pool_size()); + } + if(appProperties.getSearch_coord_max_pool_size() != null) { + setSearchCoordMaxPoolSize(appProperties.getSearch_coord_max_pool_size()); + } + if(appProperties.getSearch_coord_queue_capacity() != null) { + setSearchCoordQueueCapacity(appProperties.getSearch_coord_queue_capacity()); + } + } + @Override public DatabaseBackedPagingProvider databaseBackedPagingProvider() { DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider(); @@ -71,7 +85,12 @@ public class FhirServerConfigR5 extends BaseJavaConfigR5 { public ElasticsearchSvcImpl elasticsearchSvc() { if (EnvironmentHelper.isElasticsearchEnabled(configurableEnvironment)) { String elasticsearchUrl = EnvironmentHelper.getElasticsearchServerUrl(configurableEnvironment); - String elasticsearchHost = elasticsearchUrl.substring(elasticsearchUrl.indexOf("://")+3, elasticsearchUrl.lastIndexOf(":")); + String elasticsearchHost; + if (elasticsearchUrl.startsWith("http")) { + elasticsearchHost = elasticsearchUrl.substring(elasticsearchUrl.indexOf("://") + 3, elasticsearchUrl.lastIndexOf(":")); + } else { + elasticsearchHost = elasticsearchUrl.substring(0, elasticsearchUrl.indexOf(":")); + } String elasticsearchUsername = EnvironmentHelper.getElasticsearchServerUsername(configurableEnvironment); String elasticsearchPassword = EnvironmentHelper.getElasticsearchServerPassword(configurableEnvironment); int elasticsearchPort = Integer.parseInt(elasticsearchUrl.substring(elasticsearchUrl.lastIndexOf(":")+1)); diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index a4d8734..3416404 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -6,6 +6,10 @@ spring: password: null driverClassName: org.h2.Driver max-active: 15 + + # database connection pool size + hikari: + maximum-pool-size: 10 jpa: properties: hibernate.format_sql: false @@ -83,6 +87,11 @@ hapi: # allowed_origin: # - '*' + # Search coordinator thread pool sizes + search-coord-core-pool-size: 20 + search-coord-max-pool-size: 100 + search-coord-queue-capacity: 200 + # logger: # error_format: 'ERROR - ${requestVerb} ${requestUrl}' # format: >- From da326875dd5691883d96878cdb8eb74cf9139075 Mon Sep 17 00:00:00 2001 From: Frank Tao Date: Sat, 13 Mar 2021 21:49:50 -0500 Subject: [PATCH 02/10] Prepare for R5.4 --- pom.xml | 2 +- .../fhir/jpa/starter/EnvironmentHelper.java | 256 +++++++++--------- .../jpa/starter/ElasticsearchLastNR4IT.java | 2 +- 3 files changed, 124 insertions(+), 136 deletions(-) diff --git a/pom.xml b/pom.xml index 5d8d98a..218d077 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.3.0 + 5.4.0-PRE1-SNAPSHOT hapi-fhir-jpaserver-starter 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 082e3b4..3df2c53 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java @@ -1,182 +1,170 @@ package ca.uhn.fhir.jpa.starter; -import ca.uhn.fhir.jpa.config.HapiFhirLocalContainerEntityManagerFactoryBean; import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer; import ca.uhn.fhir.jpa.search.elastic.ElasticsearchHibernatePropertiesBuilder; -import org.apache.lucene.util.Version; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.search.backend.elasticsearch.cfg.ElasticsearchBackendSettings; +import org.apache.commons.lang3.StringUtils; +import org.elasticsearch.action.admin.indices.stats.IndexStats; import org.hibernate.search.backend.elasticsearch.index.IndexStatus; import org.hibernate.search.backend.lucene.cfg.LuceneBackendSettings; import org.hibernate.search.backend.lucene.cfg.LuceneIndexSettings; -import org.hibernate.search.backend.lucene.lowlevel.directory.impl.LocalFileSystemDirectoryProvider; import org.hibernate.search.engine.cfg.BackendSettings; import org.hibernate.search.mapper.orm.automaticindexing.session.AutomaticIndexingSynchronizationStrategyNames; import org.hibernate.search.mapper.orm.cfg.HibernateOrmMapperSettings; import org.hibernate.search.mapper.orm.schema.management.SchemaManagementStrategyName; -import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy; -import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.PropertySource; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; public class EnvironmentHelper { - public static Properties getHibernateProperties(ConfigurableEnvironment environment) { - Properties properties = new Properties(); - Map jpaProps = getPropertiesStartingWith(environment, "spring.jpa.properties"); - for (Map.Entry entry : jpaProps.entrySet()) { - String strippedKey = entry.getKey().replace("spring.jpa.properties.", ""); - properties.put(strippedKey, entry.getValue().toString()); - } + public static Properties getHibernateProperties(ConfigurableEnvironment environment) { + Properties properties = new Properties(); - //Spring Boot Autoconfiguration defaults - properties.putIfAbsent(AvailableSettings.SCANNER, "org.hibernate.boot.archive.scan.internal.DisabledScanner"); - properties.putIfAbsent(AvailableSettings.IMPLICIT_NAMING_STRATEGY, SpringImplicitNamingStrategy.class.getName()); - properties.putIfAbsent(AvailableSettings.PHYSICAL_NAMING_STRATEGY, SpringPhysicalNamingStrategy.class.getName()); - //TODO The bean factory should be added as parameter but that requires that it can be injected from the entityManagerFactory bean from xBaseConfig - //properties.putIfAbsent(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory)); + Map jpaProps = getPropertiesStartingWith(environment, "spring.jpa.properties"); + properties.putIfAbsent("hibernate.format_sql", "false"); + properties.putIfAbsent("hibernate.show_sql", "false"); + properties.putIfAbsent("hibernate.hbm2ddl.auto", "update"); + properties.putIfAbsent("hibernate.jdbc.batch_size", "20"); + properties.putIfAbsent("hibernate.cache.use_query_cache", "false"); + properties.putIfAbsent("hibernate.cache.use_second_level_cache", "false"); + properties.putIfAbsent("hibernate.cache.use_structured_entries", "false"); + properties.putIfAbsent("hibernate.cache.use_minimal_puts", "false"); - //hapi-fhir-jpaserver-base "sensible defaults" - Map hapiJpaPropertyMap = new HapiFhirLocalContainerEntityManagerFactoryBean().getJpaPropertyMap(); - hapiJpaPropertyMap.forEach(properties::putIfAbsent); + if (jpaProps.getOrDefault("spring.jpa.properties.hibernate.search.enabled", "false").toString() == "true") { + properties.putIfAbsent(HibernateOrmMapperSettings.ENABLED, true); + properties.putIfAbsent(BackendSettings.backendKey(LuceneIndexSettings.DIRECTORY_TYPE), "local-filesystem"); + properties.putIfAbsent(BackendSettings.backendKey(LuceneIndexSettings.DIRECTORY_ROOT), "target/lucenefiles"); + properties.putIfAbsent(BackendSettings.backendKey(BackendSettings.TYPE), "lucene"); + properties.putIfAbsent(BackendSettings.backendKey(LuceneBackendSettings.ANALYSIS_CONFIGURER), HapiLuceneAnalysisConfigurer.class.getName()); + properties.putIfAbsent(BackendSettings.backendKey(LuceneBackendSettings.LUCENE_VERSION), "LUCENE_CURRENT"); + } else { + properties.putIfAbsent(HibernateOrmMapperSettings.ENABLED, false); + } - //hapi-fhir-jpaserver-starter defaults - properties.putIfAbsent(AvailableSettings.FORMAT_SQL, false); - properties.putIfAbsent(AvailableSettings.SHOW_SQL, false); - properties.putIfAbsent(AvailableSettings.HBM2DDL_AUTO, "update"); - properties.putIfAbsent(AvailableSettings.STATEMENT_BATCH_SIZE, 20); - properties.putIfAbsent(AvailableSettings.USE_QUERY_CACHE, false); - properties.putIfAbsent(AvailableSettings.USE_SECOND_LEVEL_CACHE, false); - properties.putIfAbsent(AvailableSettings.USE_STRUCTURED_CACHE, false); - properties.putIfAbsent(AvailableSettings.USE_MINIMAL_PUTS, false); + for (Map.Entry entry : jpaProps.entrySet()) { + String strippedKey = entry.getKey().replace("spring.jpa.properties.", ""); + properties.put(strippedKey, entry.getValue().toString()); + } - //Hibernate Search defaults - properties.putIfAbsent(HibernateOrmMapperSettings.ENABLED, true); - if (Boolean.parseBoolean(String.valueOf(properties.get(HibernateOrmMapperSettings.ENABLED)))) { - properties.putIfAbsent(BackendSettings.backendKey(BackendSettings.TYPE), LuceneBackendSettings.TYPE_NAME); - if (properties.get(BackendSettings.backendKey(BackendSettings.TYPE)).equals(LuceneBackendSettings.TYPE_NAME)) { - properties.putIfAbsent(BackendSettings.backendKey(LuceneIndexSettings.DIRECTORY_TYPE), LocalFileSystemDirectoryProvider.NAME); - properties.putIfAbsent(BackendSettings.backendKey(LuceneIndexSettings.DIRECTORY_ROOT), "target/lucenefiles"); - properties.putIfAbsent(BackendSettings.backendKey(LuceneBackendSettings.ANALYSIS_CONFIGURER), HapiLuceneAnalysisConfigurer.class.getName()); - properties.putIfAbsent(BackendSettings.backendKey(LuceneBackendSettings.LUCENE_VERSION), Version.LATEST); + if (environment.getProperty("elasticsearch.enabled", Boolean.class) != null + && environment.getProperty("elasticsearch.enabled", Boolean.class) == true) { + ElasticsearchHibernatePropertiesBuilder builder = new ElasticsearchHibernatePropertiesBuilder(); + IndexStatus requiredIndexStatus = environment.getProperty("elasticsearch.required_index_status", IndexStatus.class); + if (requiredIndexStatus == null) { + builder.setRequiredIndexStatus(IndexStatus.YELLOW); + } else { + builder.setRequiredIndexStatus(requiredIndexStatus); + } - } else if (properties.get(BackendSettings.backendKey(BackendSettings.TYPE)).equals(ElasticsearchBackendSettings.TYPE_NAME)) { - ElasticsearchHibernatePropertiesBuilder builder = new ElasticsearchHibernatePropertiesBuilder(); - IndexStatus requiredIndexStatus = environment.getProperty("elasticsearch.required_index_status", IndexStatus.class); - builder.setRequiredIndexStatus(requireNonNullElse(requiredIndexStatus, IndexStatus.YELLOW)); - builder.setRestUrl(getElasticsearchServerUrl(environment)); - builder.setUsername(getElasticsearchServerUsername(environment)); - builder.setPassword(getElasticsearchServerPassword(environment)); - builder.setProtocol(getElasticsearchServerProtocol(environment)); - SchemaManagementStrategyName indexSchemaManagementStrategy = environment.getProperty("elasticsearch.schema_management_strategy", SchemaManagementStrategyName.class); - builder.setIndexSchemaManagementStrategy(requireNonNullElse(indexSchemaManagementStrategy, SchemaManagementStrategyName.CREATE)); - Boolean refreshAfterWrite = environment.getProperty("elasticsearch.debug.refresh_after_write", Boolean.class); - if (refreshAfterWrite == null || !refreshAfterWrite) { - builder.setDebugIndexSyncStrategy(AutomaticIndexingSynchronizationStrategyNames.ASYNC); - } else { - builder.setDebugIndexSyncStrategy(AutomaticIndexingSynchronizationStrategyNames.READ_SYNC); - } - builder.setDebugPrettyPrintJsonLog(requireNonNullElse(environment.getProperty("elasticsearch.debug.pretty_print_json_log", Boolean.class), false)); - builder.apply(properties); + builder.setRestUrl(getElasticsearchServerUrl(environment)); + builder.setUsername(getElasticsearchServerUsername(environment)); + builder.setPassword(getElasticsearchServerPassword(environment)); + builder.setProtocol(getElasticsearchServerProtocol(environment)); + SchemaManagementStrategyName indexSchemaManagementStrategy = environment.getProperty("elasticsearch.schema_management_strategy", SchemaManagementStrategyName.class); + if (indexSchemaManagementStrategy == null) { + builder.setIndexSchemaManagementStrategy(SchemaManagementStrategyName.CREATE); + } else { + builder.setIndexSchemaManagementStrategy(indexSchemaManagementStrategy); + } + // pretty_print_json_log: false + Boolean refreshAfterWrite = environment.getProperty("elasticsearch.debug.refresh_after_write", Boolean.class); + if (refreshAfterWrite == null || refreshAfterWrite == false) { + builder.setDebugIndexSyncStrategy(AutomaticIndexingSynchronizationStrategyNames.ASYNC); + } else { + builder.setDebugIndexSyncStrategy(AutomaticIndexingSynchronizationStrategyNames.READ_SYNC); + } + // 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; + } - } else { - throw new UnsupportedOperationException("Unsupported Hibernate Search backend: " + properties.get(BackendSettings.backendKey(BackendSettings.TYPE))); - } - } - - return properties; - } - - //TODO Removed when we're up on Java 11 - private static T requireNonNullElse(T obj, T defaultObj) { - return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj"); - } - - //TODO Removed when we're up on Java 11 - private static T requireNonNull(T obj, String message) { - if (obj == null) - throw new NullPointerException(message); - return obj; - } - - public static String getElasticsearchServerUrl(ConfigurableEnvironment environment) { - return environment.getProperty("elasticsearch.rest_url", String.class); - } + public static String getElasticsearchServerUrl(ConfigurableEnvironment environment) { + return environment.getProperty("elasticsearch.rest_url", String.class); + } public static String getElasticsearchServerProtocol(ConfigurableEnvironment environment) { return environment.getProperty("elasticsearch.protocol", String.class, "http"); } public static String getElasticsearchServerUsername(ConfigurableEnvironment environment) { - return environment.getProperty("elasticsearch.username"); - } + return environment.getProperty("elasticsearch.username"); + } - public static String getElasticsearchServerPassword(ConfigurableEnvironment environment) { - return environment.getProperty("elasticsearch.password"); - } + 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 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<>(); + public static Map getPropertiesStartingWith(ConfigurableEnvironment aEnv, + String aKeyPrefix) { + Map result = new HashMap<>(); - Map map = getAllProperties(aEnv); + Map map = getAllProperties(aEnv); - for (Map.Entry entry : map.entrySet()) { - String key = entry.getKey(); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); - if (key.startsWith(aKeyPrefix)) { - result.put(key, entry.getValue()); - } - } + if (key.startsWith(aKeyPrefix)) { + result.put(key, entry.getValue()); + } + } - return result; - } + return result; + } - public static Map getAllProperties(ConfigurableEnvironment aEnv) { - Map result = new HashMap<>(); - aEnv.getPropertySources().forEach(ps -> addAll(result, getAllProperties(ps))); - return result; - } + public static Map getAllProperties(ConfigurableEnvironment aEnv) { + Map result = new HashMap<>(); + aEnv.getPropertySources().forEach(ps -> addAll(result, getAllProperties(ps))); + return result; + } - public static Map getAllProperties(PropertySource aPropSource) { - Map result = new HashMap<>(); + public static Map getAllProperties(PropertySource aPropSource) { + Map result = new HashMap<>(); - if (aPropSource instanceof CompositePropertySource) { - CompositePropertySource cps = (CompositePropertySource) aPropSource; - cps.getPropertySources().forEach(ps -> addAll(result, getAllProperties(ps))); - return result; - } + if (aPropSource instanceof CompositePropertySource) { + CompositePropertySource cps = (CompositePropertySource) aPropSource; + cps.getPropertySources().forEach(ps -> addAll(result, getAllProperties(ps))); + return result; + } - if (aPropSource instanceof EnumerablePropertySource) { - EnumerablePropertySource ps = (EnumerablePropertySource) aPropSource; - Arrays.asList(ps.getPropertyNames()).forEach(key -> result.put(key, ps.getProperty(key))); - return result; - } + if (aPropSource instanceof EnumerablePropertySource) { + EnumerablePropertySource ps = (EnumerablePropertySource) aPropSource; + Arrays.asList(ps.getPropertyNames()).forEach(key -> result.put(key, ps.getProperty(key))); + return result; + } - return result; + return result; - } + } - private static void addAll(Map aBase, Map aToBeAdded) { - for (Map.Entry entry : aToBeAdded.entrySet()) { - if (aBase.containsKey(entry.getKey())) { - continue; - } + private static void addAll(Map aBase, Map aToBeAdded) { + for (Map.Entry entry : aToBeAdded.entrySet()) { + if (aBase.containsKey(entry.getKey())) { + continue; + } - aBase.put(entry.getKey(), entry.getValue()); - } - } + aBase.put(entry.getKey(), entry.getValue()); + } + } } diff --git a/src/test/java/ca/uhn/fhir/jpa/starter/ElasticsearchLastNR4IT.java b/src/test/java/ca/uhn/fhir/jpa/starter/ElasticsearchLastNR4IT.java index 902abbe..2dcf32d 100644 --- a/src/test/java/ca/uhn/fhir/jpa/starter/ElasticsearchLastNR4IT.java +++ b/src/test/java/ca/uhn/fhir/jpa/starter/ElasticsearchLastNR4IT.java @@ -60,7 +60,7 @@ public class ElasticsearchLastNR4IT { private IGenericClient ourClient; private FhirContext ourCtx; - private static final String ELASTIC_VERSION = "7.10.1"; + private static final String ELASTIC_VERSION = "7.10.2"; private static final String ELASTIC_IMAGE = "docker.elastic.co/elasticsearch/elasticsearch:" + ELASTIC_VERSION; private static ElasticsearchContainer embeddedElastic; From 8585a121c44e43a7c73656ca257397b4c7d79163 Mon Sep 17 00:00:00 2001 From: Frank Tao Date: Thu, 18 Mar 2021 21:01:13 -0400 Subject: [PATCH 03/10] Added enable_index_contained_resource --- src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java | 9 +++++++++ .../ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java | 2 ++ .../ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java | 6 ++++++ src/main/resources/application.yaml | 1 + 4 files changed, 18 insertions(+) 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 3955156..e361776 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java @@ -31,6 +31,7 @@ public class AppProperties { private Boolean allow_placeholder_references = true; private Boolean auto_create_placeholder_reference_targets = false; private Boolean enable_index_missing_fields = false; + private Boolean enable_index_contained_resource = false; private Boolean enable_repository_validating_interceptor = false; private Boolean enforce_referential_integrity_on_delete = true; private Boolean enforce_referential_integrity_on_write = true; @@ -273,6 +274,14 @@ public class AppProperties { this.enable_index_missing_fields = enable_index_missing_fields; } + public Boolean getEnable_index_contained_resource() { + return enable_index_contained_resource; + } + + public void setEnable_index_contained_resource(Boolean enable_index_contained_resource) { + this.enable_index_contained_resource = enable_index_contained_resource; + } + public Boolean getEnable_repository_validating_interceptor() { return enable_repository_validating_interceptor; } 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 8154714..95708e7 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java @@ -384,5 +384,7 @@ public class BaseJpaRestfulServer extends RestfulServer { } daoConfig.getModelConfig().setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level()); + + daoConfig.getModelConfig().setIndexOnContainedResources(appProperties.getEnable_index_contained_resource()); } } 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 e73ce18..55eae25 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java @@ -61,6 +61,10 @@ public class FhirServerConfigCommon { if (appProperties.getSubscription().getEmail() != null) { ourLog.info("Email subscriptions enabled"); } + + if (appProperties.getEnable_index_contained_resource() == Boolean.TRUE) { + ourLog.info("Indexed on contained resource enabled"); + } } /** @@ -163,6 +167,8 @@ public class FhirServerConfigCommon { } modelConfig.setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level()); + + modelConfig.setIndexOnContainedResources(appProperties.getEnable_index_contained_resource()); return modelConfig; } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 6d685bd..b348225 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -70,6 +70,7 @@ hapi: # default_page_size: 20 # enable_repository_validating_interceptor: false # enable_index_missing_fields: false +# enable_index_contained_resource: false # enforce_referential_integrity_on_delete: false # enforce_referential_integrity_on_write: false # etag_support_enabled: true From e452468a931faf901f734816d228e26d38f49a58 Mon Sep 17 00:00:00 2001 From: Frank Tao Date: Mon, 22 Mar 2021 20:04:49 -0400 Subject: [PATCH 04/10] Bump up the version to 5.4.0-PRE2-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 218d077..20b3fc7 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT hapi-fhir-jpaserver-starter From 415f2461e8228c8ad4ff2c11fdbab7d8291b3df4 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Wed, 19 May 2021 08:45:03 -0400 Subject: [PATCH 05/10] Compile fixes --- pom.xml | 3 +- .../java/ca/uhn/fhir/jpa/mdm/MdmConfig.java | 24 +- .../jpa/starter/BaseJpaRestfulServer.java | 689 +++++++++--------- .../fhir/jpa/starter/ExampleServerR5IT.java | 8 +- 4 files changed, 360 insertions(+), 364 deletions(-) diff --git a/pom.xml b/pom.xml index 20b3fc7..03ed67c 100644 --- a/pom.xml +++ b/pom.xml @@ -14,8 +14,7 @@ ca.uhn.hapi.fhir hapi-fhir - - 5.4.0-PRE2-SNAPSHOT + 5.4.0 hapi-fhir-jpaserver-starter diff --git a/src/main/java/ca/uhn/fhir/jpa/mdm/MdmConfig.java b/src/main/java/ca/uhn/fhir/jpa/mdm/MdmConfig.java index b14c7c4..be17571 100644 --- a/src/main/java/ca/uhn/fhir/jpa/mdm/MdmConfig.java +++ b/src/main/java/ca/uhn/fhir/jpa/mdm/MdmConfig.java @@ -7,7 +7,7 @@ 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 ca.uhn.fhir.rest.server.util.ISearchParamRegistry; import com.google.common.base.Charsets; import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -29,17 +29,17 @@ import java.io.IOException; @Import({MdmConsumerConfig.class, MdmSubmitterConfig.class}) public class MdmConfig { - @Bean - MdmRuleValidator mdmRuleValidator(FhirContext theFhirContext, ISearchParamRetriever theSearchParamRetriever) { - return new MdmRuleValidator(theFhirContext, theSearchParamRetriever); - } + @Bean + MdmRuleValidator mdmRuleValidator(FhirContext theFhirContext, ISearchParamRegistry theSearchParamRegistry) { + return new MdmRuleValidator(theFhirContext, theSearchParamRegistry); + } - @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); - } + @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); + } } 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 95708e7..8573130 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java @@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.starter; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.cql.common.provider.CqlProviderLoader; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorService; @@ -9,31 +10,38 @@ 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.provider.BulkDataExportProvider; +import ca.uhn.fhir.jpa.bulk.export.provider.BulkDataExportProvider; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc; -import ca.uhn.fhir.jpa.packages.PackageInstallOutcomeJson; import ca.uhn.fhir.jpa.packages.PackageInstallationSpec; import ca.uhn.fhir.jpa.partition.PartitionManagementProvider; -import ca.uhn.fhir.jpa.provider.*; +import ca.uhn.fhir.jpa.provider.GraphQLProvider; +import ca.uhn.fhir.jpa.provider.IJpaSystemProvider; +import ca.uhn.fhir.jpa.provider.JpaCapabilityStatementProvider; +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.dstu3.JpaConformanceProviderDstu3; -import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4; -import ca.uhn.fhir.jpa.provider.r5.JpaConformanceProviderR5; 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.ApacheProxyAddressStrategy; import ca.uhn.fhir.rest.server.ETagSupportEnum; import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy; -import ca.uhn.fhir.rest.server.ApacheProxyAddressStrategy; import ca.uhn.fhir.rest.server.IncomingRequestAddressStrategy; import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.interceptor.*; +import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor; +import ca.uhn.fhir.rest.server.interceptor.FhirPathFilterInterceptor; +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.interceptor.partition.RequestTenantPartitionInterceptor; import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy; +import ca.uhn.fhir.rest.server.util.ISearchParamRegistry; import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhir.validation.ResultSeverityEnum; import com.google.common.base.Strings; @@ -44,347 +52,334 @@ import org.springframework.http.HttpHeaders; import org.springframework.web.cors.CorsConfiguration; import javax.servlet.ServletException; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; public class BaseJpaRestfulServer extends RestfulServer { - @Autowired - DaoRegistry daoRegistry; - - @Autowired - DaoConfig daoConfig; - - @Autowired - ISearchParamRegistry searchParamRegistry; - - @Autowired - IFhirSystemDao fhirSystemDao; - - @Autowired - ResourceProviderFactory resourceProviders; - - @Autowired - IJpaSystemProvider jpaSystemProvider; - - @Autowired - IInterceptorBroadcaster interceptorBroadcaster; - - @Autowired - DatabaseBackedPagingProvider databaseBackedPagingProvider; - - @Autowired - IInterceptorService interceptorService; - - @Autowired - IValidatorModule validatorModule; - - @Autowired - Optional graphQLProvider; - - @Autowired - BulkDataExportProvider bulkDataExportProvider; - - @Autowired - PartitionManagementProvider partitionManagementProvider; - - @Autowired - BinaryStorageInterceptor binaryStorageInterceptor; - - @Autowired - IPackageInstallerSvc packageInstallerSvc; - - @Autowired - AppProperties appProperties; - - @Autowired - ApplicationContext myApplicationContext; - - @Autowired(required = false) - IRepositoryValidationInterceptorFactory factory; - - // These are set only if the features are enabled - private CqlProviderLoader cqlProviderLoader; - - public BaseJpaRestfulServer() { - } - - private static final long serialVersionUID = 1L; - - @SuppressWarnings("unchecked") - @Override - protected void initialize() throws ServletException { - super.initialize(); - - /* - * Create a FhirContext object that uses the version of FHIR - * specified in the properties file. - */ - // Customize supported resource types - List supportedResourceTypes = appProperties.getSupported_resource_types(); - - if (!supportedResourceTypes.isEmpty() && !supportedResourceTypes.contains("SearchParameter")) { - supportedResourceTypes.add("SearchParameter"); - daoRegistry.setSupportedResourceTypes(supportedResourceTypes); - } - - setFhirContext(fhirSystemDao.getContext()); - - registerProviders(resourceProviders.createProviders()); - registerProvider(jpaSystemProvider); - - /* - * The conformance provider exports the supported resources, search parameters, etc for - * this server. The JPA version adds resourceProviders counts to the exported statement, so it - * is a nice addition. - * - * You can also create your own subclass of the conformance provider if you need to - * provide further customization of your server's CapabilityStatement - */ - - FhirVersionEnum fhirVersion = fhirSystemDao.getContext().getVersion().getVersion(); - if (fhirVersion == FhirVersionEnum.DSTU2) { - - JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, fhirSystemDao, - daoConfig); - confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server"); - setServerConformanceProvider(confProvider); - } else { - if (fhirVersion == FhirVersionEnum.DSTU3) { - - JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, fhirSystemDao, - daoConfig, searchParamRegistry); - confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server"); - setServerConformanceProvider(confProvider); - } else if (fhirVersion == FhirVersionEnum.R4) { - - JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, fhirSystemDao, - daoConfig, searchParamRegistry); - confProvider.setImplementationDescription("HAPI FHIR R4 Server"); - setServerConformanceProvider(confProvider); - } else if (fhirVersion == FhirVersionEnum.R5) { - - JpaConformanceProviderR5 confProvider = new JpaConformanceProviderR5(this, fhirSystemDao, - daoConfig, searchParamRegistry); - confProvider.setImplementationDescription("HAPI FHIR R5 Server"); - setServerConformanceProvider(confProvider); - } else { - throw new IllegalStateException(); - } - } - - /* - * ETag Support - */ - - if (appProperties.getEtag_support_enabled() == false) - setETagSupport(ETagSupportEnum.DISABLED); - - - /* - * This server tries to dynamically generate narratives - */ - FhirContext ctx = getFhirContext(); - INarrativeGenerator theNarrativeGenerator = - appProperties.getNarrative_enabled() ? - new DefaultThymeleafNarrativeGenerator() : - new NullNarrativeGenerator(); - ctx.setNarrativeGenerator(theNarrativeGenerator); - - /* - * Default to JSON and pretty printing - */ - setDefaultPrettyPrint(appProperties.getDefault_pretty_print()); - - /* - * Default encoding - */ - setDefaultResponseEncoding(appProperties.getDefault_encoding()); - - /* - * This configures the server to page search results to and from - * the database, instead of only paging them to memory. This may mean - * a performance hit when performing searches that return lots of results, - * but makes the server much more scalable. - */ - - setPagingProvider(databaseBackedPagingProvider); - - /* - * This interceptor formats the output using nice colourful - * HTML output when the request is detected to come from a - * browser. - */ - ResponseHighlighterInterceptor responseHighlighterInterceptor = new ResponseHighlighterInterceptor(); - this.registerInterceptor(responseHighlighterInterceptor); - - if (appProperties.getFhirpath_interceptor_enabled()) { - registerInterceptor(new FhirPathFilterInterceptor()); - } - - /* - * Add some logging for each request - */ - LoggingInterceptor loggingInterceptor = new LoggingInterceptor(); - loggingInterceptor.setLoggerName(appProperties.getLogger().getName()); - loggingInterceptor.setMessageFormat(appProperties.getLogger().getFormat()); - loggingInterceptor.setErrorMessageFormat(appProperties.getLogger().getError_format()); - loggingInterceptor.setLogExceptions(appProperties.getLogger().getLog_exceptions()); - this.registerInterceptor(loggingInterceptor); - - /* - * If you are hosting this server at a specific DNS name, the server will try to - * figure out the FHIR base URL based on what the web container tells it, but - * this doesn't always work. If you are setting links in your search bundles that - * just refer to "localhost", you might want to use a server address strategy: - */ - String serverAddress = appProperties.getServer_address(); - if (!Strings.isNullOrEmpty(serverAddress)) { - setServerAddressStrategy(new HardcodedServerAddressStrategy(serverAddress)); - } else if (appProperties.getUse_apache_address_strategy()) { - boolean useHttps = appProperties.getUse_apache_address_strategy_https(); - setServerAddressStrategy(useHttps ? ApacheProxyAddressStrategy.forHttps() : - ApacheProxyAddressStrategy.forHttp()); - } else { - setServerAddressStrategy(new IncomingRequestAddressStrategy()); - } - - /* - * If you are using DSTU3+, you may want to add a terminology uploader, which allows - * uploading of external terminologies such as Snomed CT. Note that this uploader - * does not have any security attached (any anonymous user may use it by default) - * so it is a potential security vulnerability. Consider using an AuthorizationInterceptor - * with this feature. - */ - if (ctx.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) { // <-- ENABLED RIGHT NOW - registerProvider(myApplicationContext.getBean(TerminologyUploaderProvider.class)); - } - - // If you want to enable the $trigger-subscription operation to allow - // manual triggering of a subscription delivery, enable this provider - if (true) { // <-- ENABLED RIGHT NOW - registerProvider(myApplicationContext.getBean(SubscriptionTriggeringProvider.class)); - } - - // Define your CORS configuration. This is an example - // showing a typical setup. You should customize this - // to your specific needs - if (appProperties.getCors() != null) { - CorsConfiguration config = new CorsConfiguration(); - config.addAllowedHeader(HttpHeaders.ORIGIN); - config.addAllowedHeader(HttpHeaders.ACCEPT); - config.addAllowedHeader(HttpHeaders.CONTENT_TYPE); - config.addAllowedHeader(HttpHeaders.AUTHORIZATION); - config.addAllowedHeader(HttpHeaders.CACHE_CONTROL); - config.addAllowedHeader("x-fhir-starter"); - config.addAllowedHeader("X-Requested-With"); - config.addAllowedHeader("Prefer"); - List allAllowedCORSOrigins = appProperties.getCors().getAllowed_origin(); - allAllowedCORSOrigins.forEach(config::addAllowedOrigin); - - - config.addExposedHeader("Location"); - config.addExposedHeader("Content-Location"); - config.setAllowedMethods( - Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD")); - config.setAllowCredentials(appProperties.getCors().getAllow_Credentials()); - - // Create the interceptor and register it - CorsInterceptor interceptor = new CorsInterceptor(config); - registerInterceptor(interceptor); - } - - // If subscriptions are enabled, we want to register the interceptor that - // will activate them and match results against them - if (appProperties.getSubscription() != null) { - // Subscription debug logging - interceptorService.registerInterceptor(new SubscriptionDebugLogInterceptor()); - } - - // Cascading deletes - - - if (appProperties.getAllow_cascading_deletes()) { - CascadingDeleteInterceptor cascadingDeleteInterceptor = new CascadingDeleteInterceptor(ctx, - daoRegistry, interceptorBroadcaster); - getInterceptorService().registerInterceptor(cascadingDeleteInterceptor); - } - - // Binary Storage - if (appProperties.getBinary_storage_enabled()) { - getInterceptorService().registerInterceptor(binaryStorageInterceptor); - } - - // Validation - - if (validatorModule != null) { - if (appProperties.getValidation().getRequests_enabled()) { - RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor(); - interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); - interceptor.setValidatorModules(Collections.singletonList(validatorModule)); - registerInterceptor(interceptor); - } - if (appProperties.getValidation().getResponses_enabled()) { - ResponseValidatingInterceptor interceptor = new ResponseValidatingInterceptor(); - interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); - interceptor.setValidatorModules(Collections.singletonList(validatorModule)); - registerInterceptor(interceptor); - } - } - - // GraphQL - if (appProperties.getGraphql_enabled()) { - if (fhirVersion.isEqualOrNewerThan(FhirVersionEnum.DSTU3)) { - registerProvider(graphQLProvider.get()); - } - } - - if (appProperties.getAllowed_bundle_types() != null) { - daoConfig.setBundleTypesAllowedForStorage(appProperties.getAllowed_bundle_types().stream().map(BundleType::toCode).collect(Collectors.toSet())); - } - - daoConfig.setDeferIndexingForCodesystemsOfSize(appProperties.getDefer_indexing_for_codesystems_of_size()); - - // Bulk Export - if (appProperties.getBulk_export_enabled()) { - registerProvider(bulkDataExportProvider); - } - - // Partitioning - if (appProperties.getPartitioning() != null) { - registerInterceptor(new RequestTenantPartitionInterceptor()); - setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy()); - registerProviders(partitionManagementProvider); - } - - if (appProperties.getClient_id_strategy() == DaoConfig.ClientIdStrategyEnum.ANY) { - daoConfig.setResourceServerIdStrategy(DaoConfig.IdStrategyEnum.UUID); - daoConfig.setResourceClientIdStrategy(appProperties.getClient_id_strategy()); - } - - if (appProperties.getImplementationGuides() != null) { - Map guides = appProperties.getImplementationGuides(); - for (Map.Entry guide : guides.entrySet()) { - packageInstallerSvc.install(new PackageInstallationSpec() - .setPackageUrl(guide.getValue().getUrl()) - .setName(guide.getValue().getName()) - .setVersion(guide.getValue().getVersion()) - .setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL)); - - } - } - - if(factory != null) { - interceptorService.registerInterceptor(factory.buildUsingStoredStructureDefinitions()); - } - - - if (appProperties.getLastn_enabled()) { - daoConfig.setLastNEnabled(true); - } - - daoConfig.getModelConfig().setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level()); - - daoConfig.getModelConfig().setIndexOnContainedResources(appProperties.getEnable_index_contained_resource()); - } + private static final long serialVersionUID = 1L; + @Autowired + DaoRegistry daoRegistry; + @Autowired + DaoConfig daoConfig; + @Autowired + ISearchParamRegistry searchParamRegistry; + @Autowired + IFhirSystemDao fhirSystemDao; + @Autowired + ResourceProviderFactory resourceProviders; + @Autowired + IJpaSystemProvider jpaSystemProvider; + @Autowired + IInterceptorBroadcaster interceptorBroadcaster; + @Autowired + DatabaseBackedPagingProvider databaseBackedPagingProvider; + @Autowired + IInterceptorService interceptorService; + @Autowired + IValidatorModule validatorModule; + @Autowired + Optional graphQLProvider; + @Autowired + BulkDataExportProvider bulkDataExportProvider; + @Autowired + PartitionManagementProvider partitionManagementProvider; + @Autowired + BinaryStorageInterceptor binaryStorageInterceptor; + @Autowired + IPackageInstallerSvc packageInstallerSvc; + @Autowired + AppProperties appProperties; + @Autowired + ApplicationContext myApplicationContext; + @Autowired(required = false) + IRepositoryValidationInterceptorFactory factory; + // These are set only if the features are enabled + private CqlProviderLoader cqlProviderLoader; + @Autowired + private IValidationSupport myValidationSupport; + + public BaseJpaRestfulServer() { + } + + @SuppressWarnings("unchecked") + @Override + protected void initialize() throws ServletException { + super.initialize(); + + /* + * Create a FhirContext object that uses the version of FHIR + * specified in the properties file. + */ + // Customize supported resource types + List supportedResourceTypes = appProperties.getSupported_resource_types(); + + if (!supportedResourceTypes.isEmpty() && !supportedResourceTypes.contains("SearchParameter")) { + supportedResourceTypes.add("SearchParameter"); + daoRegistry.setSupportedResourceTypes(supportedResourceTypes); + } + + setFhirContext(fhirSystemDao.getContext()); + + registerProviders(resourceProviders.createProviders()); + registerProvider(jpaSystemProvider); + + /* + * The conformance provider exports the supported resources, search parameters, etc for + * this server. The JPA version adds resourceProviders counts to the exported statement, so it + * is a nice addition. + * + * You can also create your own subclass of the conformance provider if you need to + * provide further customization of your server's CapabilityStatement + */ + + FhirVersionEnum fhirVersion = fhirSystemDao.getContext().getVersion().getVersion(); + if (fhirVersion == FhirVersionEnum.DSTU2) { + + JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, fhirSystemDao, + daoConfig); + confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server"); + setServerConformanceProvider(confProvider); + } else { + if (fhirVersion == FhirVersionEnum.DSTU3) { + + JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, fhirSystemDao, + daoConfig, searchParamRegistry); + confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server"); + setServerConformanceProvider(confProvider); + } else if (fhirVersion == FhirVersionEnum.R4) { + + JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(this, fhirSystemDao, + daoConfig, searchParamRegistry, myValidationSupport); + confProvider.setImplementationDescription("HAPI FHIR R4 Server"); + setServerConformanceProvider(confProvider); + } else if (fhirVersion == FhirVersionEnum.R5) { + + JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(this, fhirSystemDao, + daoConfig, searchParamRegistry, myValidationSupport); + confProvider.setImplementationDescription("HAPI FHIR R5 Server"); + setServerConformanceProvider(confProvider); + } else { + throw new IllegalStateException(); + } + } + + /* + * ETag Support + */ + + if (appProperties.getEtag_support_enabled() == false) + setETagSupport(ETagSupportEnum.DISABLED); + + + /* + * This server tries to dynamically generate narratives + */ + FhirContext ctx = getFhirContext(); + INarrativeGenerator theNarrativeGenerator = + appProperties.getNarrative_enabled() ? + new DefaultThymeleafNarrativeGenerator() : + new NullNarrativeGenerator(); + ctx.setNarrativeGenerator(theNarrativeGenerator); + + /* + * Default to JSON and pretty printing + */ + setDefaultPrettyPrint(appProperties.getDefault_pretty_print()); + + /* + * Default encoding + */ + setDefaultResponseEncoding(appProperties.getDefault_encoding()); + + /* + * This configures the server to page search results to and from + * the database, instead of only paging them to memory. This may mean + * a performance hit when performing searches that return lots of results, + * but makes the server much more scalable. + */ + + setPagingProvider(databaseBackedPagingProvider); + + /* + * This interceptor formats the output using nice colourful + * HTML output when the request is detected to come from a + * browser. + */ + ResponseHighlighterInterceptor responseHighlighterInterceptor = new ResponseHighlighterInterceptor(); + this.registerInterceptor(responseHighlighterInterceptor); + + if (appProperties.getFhirpath_interceptor_enabled()) { + registerInterceptor(new FhirPathFilterInterceptor()); + } + + /* + * Add some logging for each request + */ + LoggingInterceptor loggingInterceptor = new LoggingInterceptor(); + loggingInterceptor.setLoggerName(appProperties.getLogger().getName()); + loggingInterceptor.setMessageFormat(appProperties.getLogger().getFormat()); + loggingInterceptor.setErrorMessageFormat(appProperties.getLogger().getError_format()); + loggingInterceptor.setLogExceptions(appProperties.getLogger().getLog_exceptions()); + this.registerInterceptor(loggingInterceptor); + + /* + * If you are hosting this server at a specific DNS name, the server will try to + * figure out the FHIR base URL based on what the web container tells it, but + * this doesn't always work. If you are setting links in your search bundles that + * just refer to "localhost", you might want to use a server address strategy: + */ + String serverAddress = appProperties.getServer_address(); + if (!Strings.isNullOrEmpty(serverAddress)) { + setServerAddressStrategy(new HardcodedServerAddressStrategy(serverAddress)); + } else if (appProperties.getUse_apache_address_strategy()) { + boolean useHttps = appProperties.getUse_apache_address_strategy_https(); + setServerAddressStrategy(useHttps ? ApacheProxyAddressStrategy.forHttps() : + ApacheProxyAddressStrategy.forHttp()); + } else { + setServerAddressStrategy(new IncomingRequestAddressStrategy()); + } + + /* + * If you are using DSTU3+, you may want to add a terminology uploader, which allows + * uploading of external terminologies such as Snomed CT. Note that this uploader + * does not have any security attached (any anonymous user may use it by default) + * so it is a potential security vulnerability. Consider using an AuthorizationInterceptor + * with this feature. + */ + if (ctx.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) { // <-- ENABLED RIGHT NOW + registerProvider(myApplicationContext.getBean(TerminologyUploaderProvider.class)); + } + + // If you want to enable the $trigger-subscription operation to allow + // manual triggering of a subscription delivery, enable this provider + if (true) { // <-- ENABLED RIGHT NOW + registerProvider(myApplicationContext.getBean(SubscriptionTriggeringProvider.class)); + } + + // Define your CORS configuration. This is an example + // showing a typical setup. You should customize this + // to your specific needs + if (appProperties.getCors() != null) { + CorsConfiguration config = new CorsConfiguration(); + config.addAllowedHeader(HttpHeaders.ORIGIN); + config.addAllowedHeader(HttpHeaders.ACCEPT); + config.addAllowedHeader(HttpHeaders.CONTENT_TYPE); + config.addAllowedHeader(HttpHeaders.AUTHORIZATION); + config.addAllowedHeader(HttpHeaders.CACHE_CONTROL); + config.addAllowedHeader("x-fhir-starter"); + config.addAllowedHeader("X-Requested-With"); + config.addAllowedHeader("Prefer"); + List allAllowedCORSOrigins = appProperties.getCors().getAllowed_origin(); + allAllowedCORSOrigins.forEach(config::addAllowedOrigin); + + + config.addExposedHeader("Location"); + config.addExposedHeader("Content-Location"); + config.setAllowedMethods( + Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD")); + config.setAllowCredentials(appProperties.getCors().getAllow_Credentials()); + + // Create the interceptor and register it + CorsInterceptor interceptor = new CorsInterceptor(config); + registerInterceptor(interceptor); + } + + // If subscriptions are enabled, we want to register the interceptor that + // will activate them and match results against them + if (appProperties.getSubscription() != null) { + // Subscription debug logging + interceptorService.registerInterceptor(new SubscriptionDebugLogInterceptor()); + } + + // Cascading deletes + + + if (appProperties.getAllow_cascading_deletes()) { + CascadingDeleteInterceptor cascadingDeleteInterceptor = new CascadingDeleteInterceptor(ctx, + daoRegistry, interceptorBroadcaster); + getInterceptorService().registerInterceptor(cascadingDeleteInterceptor); + } + + // Binary Storage + if (appProperties.getBinary_storage_enabled()) { + getInterceptorService().registerInterceptor(binaryStorageInterceptor); + } + + // Validation + + if (validatorModule != null) { + if (appProperties.getValidation().getRequests_enabled()) { + RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor(); + interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); + interceptor.setValidatorModules(Collections.singletonList(validatorModule)); + registerInterceptor(interceptor); + } + if (appProperties.getValidation().getResponses_enabled()) { + ResponseValidatingInterceptor interceptor = new ResponseValidatingInterceptor(); + interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); + interceptor.setValidatorModules(Collections.singletonList(validatorModule)); + registerInterceptor(interceptor); + } + } + + // GraphQL + if (appProperties.getGraphql_enabled()) { + if (fhirVersion.isEqualOrNewerThan(FhirVersionEnum.DSTU3)) { + registerProvider(graphQLProvider.get()); + } + } + + if (appProperties.getAllowed_bundle_types() != null) { + daoConfig.setBundleTypesAllowedForStorage(appProperties.getAllowed_bundle_types().stream().map(BundleType::toCode).collect(Collectors.toSet())); + } + + daoConfig.setDeferIndexingForCodesystemsOfSize(appProperties.getDefer_indexing_for_codesystems_of_size()); + + // Bulk Export + if (appProperties.getBulk_export_enabled()) { + registerProvider(bulkDataExportProvider); + } + + // Partitioning + if (appProperties.getPartitioning() != null) { + registerInterceptor(new RequestTenantPartitionInterceptor()); + setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy()); + registerProviders(partitionManagementProvider); + } + + if (appProperties.getClient_id_strategy() == DaoConfig.ClientIdStrategyEnum.ANY) { + daoConfig.setResourceServerIdStrategy(DaoConfig.IdStrategyEnum.UUID); + daoConfig.setResourceClientIdStrategy(appProperties.getClient_id_strategy()); + } + + if (appProperties.getImplementationGuides() != null) { + Map guides = appProperties.getImplementationGuides(); + for (Map.Entry guide : guides.entrySet()) { + packageInstallerSvc.install(new PackageInstallationSpec() + .setPackageUrl(guide.getValue().getUrl()) + .setName(guide.getValue().getName()) + .setVersion(guide.getValue().getVersion()) + .setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL)); + + } + } + + if (factory != null) { + interceptorService.registerInterceptor(factory.buildUsingStoredStructureDefinitions()); + } + + + if (appProperties.getLastn_enabled()) { + daoConfig.setLastNEnabled(true); + } + + daoConfig.getModelConfig().setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level()); + + daoConfig.getModelConfig().setIndexOnContainedResources(appProperties.getEnable_index_contained_resource()); + } } 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 52ffb6f..56b7316 100644 --- a/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR5IT.java +++ b/src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR5IT.java @@ -67,16 +67,18 @@ public class ExampleServerR5IT { public void testWebsocketSubscription() throws Exception { /* - * Create topic + * Create topic (will be contained in subscription) */ SubscriptionTopic topic = new SubscriptionTopic(); - topic.getResourceTrigger().getQueryCriteria().setCurrent("Observation?status=final"); + topic.setId("#1"); + topic.getResourceTriggerFirstRep().getQueryCriteria().setCurrent("Observation?status=final"); /* * Create subscription */ Subscription subscription = new Subscription(); - subscription.getTopic().setResource(topic); + subscription.getContained().add(topic); + subscription.setTopic("#1"); subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)"); subscription.setStatus(Enumerations.SubscriptionState.REQUESTED); subscription.getChannelType() From fe54a8dfc93e28b458981c4209f7128ec330fa48 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Wed, 19 May 2021 08:51:26 -0400 Subject: [PATCH 06/10] Fix compile error --- src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java | 2 -- 1 file changed, 2 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 fd85aee..8ba131f 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java @@ -106,8 +106,6 @@ public class BaseJpaRestfulServer extends RestfulServer { public BaseJpaRestfulServer() { } - private static final long serialVersionUID = 1L; - @SuppressWarnings("unchecked") @Override protected void initialize() throws ServletException { From b14d575ddb25c2a1da764f2ad9376e760886dc95 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Wed, 19 May 2021 09:03:31 -0400 Subject: [PATCH 07/10] Fix compile errors --- src/main/resources/application.yaml | 170 ++++++++++++++-------------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index e47f360..5a0e0e9 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -10,20 +10,20 @@ spring: properties: hibernate.format_sql: false hibernate.show_sql: false -# hibernate.dialect: org.hibernate.dialect.h2dialect -# 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 -### These settings will enable fulltext search with lucene -# hibernate.search.enabled: true -# hibernate.search.backend.type: lucene -# hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer -# hibernate.search.backend.directory.type: local-filesystem -# hibernate.search.backend.directory.root: target/lucenefiles -# hibernate.search.backend.lucene_version: lucene_current + # hibernate.dialect: org.hibernate.dialect.h2dialect + # 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 + ### These settings will enable fulltext search with lucene + # hibernate.search.enabled: true + # hibernate.search.backend.type: lucene + # hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer + # hibernate.search.backend.directory.type: local-filesystem + # hibernate.search.backend.directory.root: target/lucenefiles + # hibernate.search.backend.lucene_version: lucene_current batch: job: enabled: false @@ -31,83 +31,83 @@ hapi: fhir: ### This is the FHIR version. Choose between, DSTU2, DSTU3, R4 or R5 fhir_version: R4 -### enable to use the ApacheProxyAddressStrategy which uses X-Forwarded-* headers -### to determine the FHIR server address -# use_apache_address_strategy: false -### forces the use of the https:// protocol for the returned server address. -### alternatively, it may be set using the X-Forwarded-Proto header. -# use_apache_address_strategy_https: false -### enable to set the Server URL -# server_address: http://hapi.fhir.org/baseR4 -# 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 -# - Observation -# allow_cascading_deletes: true -# allow_contains_searches: true -# allow_external_references: true -# allow_multiple_delete: true -# allow_override_default_search_params: true -# allow_placeholder_references: true -# auto_create_placeholder_reference_targets: false -# cql_enabled: true -# default_encoding: JSON -# default_pretty_print: true -# default_page_size: 20 -# enable_repository_validating_interceptor: false -# enable_index_missing_fields: false -# enforce_referential_integrity_on_delete: false -# enforce_referential_integrity_on_write: false -# etag_support_enabled: true -# expunge_enabled: true -# daoconfig_client_id_strategy: null -# client_id_strategy: ALPHANUMERIC -# fhirpath_interceptor_enabled: false -# filter_search_enabled: true -# graphql_enabled: true -# narrative_enabled: true -# partitioning: -# allow_references_across_partitions: false -# partitioning_include_in_search_hashes: false + ### enable to use the ApacheProxyAddressStrategy which uses X-Forwarded-* headers + ### to determine the FHIR server address + # use_apache_address_strategy: false + ### forces the use of the https:// protocol for the returned server address. + ### alternatively, it may be set using the X-Forwarded-Proto header. + # use_apache_address_strategy_https: false + ### enable to set the Server URL + # server_address: http://hapi.fhir.org/baseR4 + # 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 + # - Observation + # allow_cascading_deletes: true + # allow_contains_searches: true + # allow_external_references: true + # allow_multiple_delete: true + # allow_override_default_search_params: true + # allow_placeholder_references: true + # auto_create_placeholder_reference_targets: false + # cql_enabled: true + # default_encoding: JSON + # default_pretty_print: true + # default_page_size: 20 + # enable_repository_validating_interceptor: false + # enable_index_missing_fields: false + # enforce_referential_integrity_on_delete: false + # enforce_referential_integrity_on_write: false + # etag_support_enabled: true + # expunge_enabled: true + # daoconfig_client_id_strategy: null + # client_id_strategy: ALPHANUMERIC + # fhirpath_interceptor_enabled: false + # filter_search_enabled: true + # graphql_enabled: true + # narrative_enabled: true + # partitioning: + # allow_references_across_partitions: false + # partitioning_include_in_search_hashes: false cors: allow_Credentials: true # These are allowed_origin patterns, see: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/cors/CorsConfiguration.html#setAllowedOriginPatterns-java.util.List- allowed_origin: - '*' -# logger: -# error_format: 'ERROR - ${requestVerb} ${requestUrl}' -# format: >- -# Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] -# Operation[${operationType} ${operationName} ${idOrResourceName}] -# UA[${requestHeader.user-agent}] Params[${requestParameters}] -# ResponseEncoding[${responseEncodingNoDefault}] -# log_exceptions: true -# name: fhirtest.access -# max_binary_size: 104857600 -# max_page_size: 200 -# retain_cached_searches_mins: 60 -# reuse_cached_search_results_millis: 60000 + # logger: + # error_format: 'ERROR - ${requestVerb} ${requestUrl}' + # format: >- + # Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] + # Operation[${operationType} ${operationName} ${idOrResourceName}] + # UA[${requestHeader.user-agent}] Params[${requestParameters}] + # ResponseEncoding[${responseEncodingNoDefault}] + # log_exceptions: true + # name: fhirtest.access + # max_binary_size: 104857600 + # max_page_size: 200 + # retain_cached_searches_mins: 60 + # reuse_cached_search_results_millis: 60000 tester: - home: - name: Local Tester - server_address: 'http://localhost:8080/fhir' - refuse_to_fetch_third_party_urls: false - fhir_version: R4 - global: - name: Global Tester - server_address: "http://hapi.fhir.org/baseR4" - refuse_to_fetch_third_party_urls: false - fhir_version: R4 + home: + name: Local Tester + server_address: 'http://localhost:8080/fhir' + refuse_to_fetch_third_party_urls: false + fhir_version: R4 + global: + name: Global Tester + server_address: "http://hapi.fhir.org/baseR4" + refuse_to_fetch_third_party_urls: false + fhir_version: R4 # validation: # requests_enabled: true # responses_enabled: true From ffed39d1bdf479b151da24f5e649878739068bbd Mon Sep 17 00:00:00 2001 From: chgl Date: Thu, 20 May 2021 13:52:56 +0200 Subject: [PATCH 08/10] Fixed indentation error in application.yaml --- src/main/resources/application.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index c2f6ba2..ea9bfa3 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -84,11 +84,11 @@ hapi: # partitioning: # allow_references_across_partitions: false # partitioning_include_in_search_hashes: false - cors: - allow_Credentials: true - # These are allowed_origin patterns, see: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/cors/CorsConfiguration.html#setAllowedOriginPatterns-java.util.List- - allowed_origin: - - '*' + cors: + allow_Credentials: true + # These are allowed_origin patterns, see: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/cors/CorsConfiguration.html#setAllowedOriginPatterns-java.util.List- + allowed_origin: + - '*' # Search coordinator thread pool sizes search-coord-core-pool-size: 20 From 787a1b8d0f872e08c6e21c3aa139cc547564db5a Mon Sep 17 00:00:00 2001 From: ppalacin Date: Fri, 21 May 2021 15:31:32 +0200 Subject: [PATCH 09/10] Add snakeyaml to dependencies --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 03ed67c..4471c2f 100644 --- a/pom.xml +++ b/pom.xml @@ -147,6 +147,13 @@ thymeleaf + + + org.yaml + snakeyaml + 1.28 + + From 35482602766040433951b64929f0fa60fbeb5a50 Mon Sep 17 00:00:00 2001 From: Sidharth Ramesh Date: Sun, 23 May 2021 21:41:45 +0530 Subject: [PATCH 10/10] Corrected subscription environment variables According to the default application.yaml, it's `hapi.fhir.subscription.resthook_enabled` (with the underscore). I've tested this with the latest docker container and it works. Setting `hapi.fhir.subscription.resthook.enabled=true` does not enable subscriptions. I spent a lot of time breaking my head over this simple variable name. Hopefully, this will help someone. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fecb5e8..5572ac6 100644 --- a/README.md +++ b/README.md @@ -317,11 +317,11 @@ It is important to use MySQL5Dialect when using MySQL version 5+. The server may be configured with subscription support by enabling properties in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file: -- `hapi.fhir.subscription.resthook.enabled` - Enables REST Hook subscriptions, where the server will make an outgoing connection to a remote REST server +- `hapi.fhir.subscription.resthook_enabled` - Enables REST Hook subscriptions, where the server will make an outgoing connection to a remote REST server - `hapi.fhir.subscription.email.*` - Enables email subscriptions. Note that you must also provide the connection details for a usable SMTP server. -- `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 CQL