merge master

This commit is contained in:
Justin McKelvy
2023-09-18 18:41:34 -06:00
38 changed files with 447 additions and 391 deletions

View File

@@ -1,32 +1,32 @@
package ca.uhn.fhir.jpa.starter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings.ClientIdStrategyEnum;
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
import ca.uhn.fhir.rest.api.EncodingEnum;
import org.cqframework.cql.cql2elm.CqlCompilerException;
import org.cqframework.cql.cql2elm.CqlTranslator;
import org.cqframework.cql.cql2elm.CqlTranslatorOptions;
import org.cqframework.cql.cql2elm.LibraryBuilder;
import org.hl7.fhir.r4.model.Bundle;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import com.google.common.collect.ImmutableList;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings.ClientIdStrategyEnum;
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
import ca.uhn.fhir.rest.api.EncodingEnum;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@ConfigurationProperties(prefix = "hapi.fhir")
@Configuration
@EnableConfigurationProperties
public class AppProperties {
private Boolean cr_enabled = false;
//cql settings
private Boolean cql_use_embedded_libraries = true;
private Boolean cql_runtime_debug_logging_enabled = false;
@@ -56,7 +56,6 @@ public class AppProperties {
// Care-gaps Settings
private String caregaps_reporter = "default";
private String caregaps_section_author = "default";
private Boolean cr_enabled = false;
private Boolean ips_enabled = false;
private Boolean openapi_enabled = false;
private Boolean mdm_enabled = false;
@@ -68,6 +67,7 @@ public class AppProperties {
private Boolean allow_multiple_delete = false;
private Boolean allow_override_default_search_params = true;
private Boolean auto_create_placeholder_reference_targets = false;
private final Set<String> auto_version_reference_at_paths = new HashSet<>();
private Boolean dao_scheduling_enabled = true;
private Boolean delete_expunge_enabled = false;
private Boolean enable_index_missing_fields = false;
@@ -98,17 +98,21 @@ public class AppProperties {
private List<String> supported_resource_types = new ArrayList<>();
private List<Bundle.BundleType> allowed_bundle_types = null;
private Boolean narrative_enabled = true;
private Validation validation = new Validation();
private Map<String, Tester> tester = new HashMap<>();
private Map<String, Tester> tester = null;
private Logger logger = new Logger();
private Subscription subscription = new Subscription();
private Cors cors = null;
private Partitioning partitioning = null;
private Boolean install_transitive_ig_dependencies = true;
private Boolean reload_existing_implementationguides = false;
private Map<String, ImplementationGuide> implementationGuides = null;
private Map<String, PackageInstallationSpec> implementationGuides = null;
private String staticLocation = null;
private String staticLocationPrefix = "/static";
private Boolean lastn_enabled = false;
private boolean store_resource_in_lucene_index_enabled = false;
private NormalizedQuantitySearchLevel normalized_quantity_search_level = NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED;
@@ -118,14 +122,24 @@ public class AppProperties {
private Integer bundle_batch_pool_size = 20;
private Integer bundle_batch_pool_max_size = 100;
private final List<String> local_base_urls = new ArrayList<>();
private final Set<String> local_base_urls = new HashSet<>();
private final List<String> custom_interceptor_classes = new ArrayList<>();
public String getStaticLocationPrefix() {
return staticLocationPrefix;
}
public void setStaticLocationPrefix(String staticLocationPrefix) {
this.staticLocationPrefix = staticLocationPrefix;
}
public List<String> getCustomInterceptorClasses() {
return custom_interceptor_classes;
}
public String getStaticLocation() {
return staticLocation;
}
@@ -134,6 +148,7 @@ public class AppProperties {
this.staticLocation = staticLocation;
}
public Boolean getOpenapi_enabled() {
return openapi_enabled;
}
@@ -166,11 +181,11 @@ public class AppProperties {
this.defer_indexing_for_codesystems_of_size = defer_indexing_for_codesystems_of_size;
}
public Map<String, ImplementationGuide> getImplementationGuides() {
public Map<String, PackageInstallationSpec> getImplementationGuides() {
return implementationGuides;
}
public void setImplementationGuides(Map<String, ImplementationGuide> implementationGuides) {
public void setImplementationGuides(Map<String, PackageInstallationSpec> implementationGuides) {
this.implementationGuides = implementationGuides;
}
@@ -182,6 +197,14 @@ public class AppProperties {
this.partitioning = partitioning;
}
public Boolean getCr_enabled() {
return cr_enabled;
}
public void setCr_enabled(Boolean cr_enabled) {
this.cr_enabled = cr_enabled;
}
public boolean isCqlUseEmbeddedLibraries() {
return cql_use_embedded_libraries;
}
@@ -382,14 +405,6 @@ public class AppProperties {
this.cql_compiler_translator_format = cqlTranslatorFormat;
}
public Boolean getCr_enabled() {
return cr_enabled;
}
public void setCr_enabled(Boolean cr_enabled) {
this.cr_enabled = cr_enabled;
}
public String getCareGapsReporter() {
return caregaps_reporter;
}
@@ -401,6 +416,7 @@ public class AppProperties {
public void setCareGapsReporter(String theCareGapsReporter) {
this.caregaps_reporter = theCareGapsReporter;
}
public Boolean getIps_enabled() {
return ips_enabled;
}
@@ -409,6 +425,7 @@ public class AppProperties {
this.ips_enabled = ips_enabled;
}
public Boolean getMdm_enabled() {
return mdm_enabled;
}
@@ -486,7 +503,7 @@ public class AppProperties {
}
public void setClient_id_strategy(
ClientIdStrategyEnum client_id_strategy) {
ClientIdStrategyEnum client_id_strategy) {
this.client_id_strategy = client_id_strategy;
}
@@ -535,7 +552,7 @@ public class AppProperties {
}
public void setAllow_override_default_search_params(
Boolean allow_override_default_search_params) {
Boolean allow_override_default_search_params) {
this.allow_override_default_search_params = allow_override_default_search_params;
}
@@ -544,10 +561,14 @@ public class AppProperties {
}
public void setAuto_create_placeholder_reference_targets(
Boolean auto_create_placeholder_reference_targets) {
Boolean auto_create_placeholder_reference_targets) {
this.auto_create_placeholder_reference_targets = auto_create_placeholder_reference_targets;
}
public Set<String> getAuto_version_reference_at_paths() {
return auto_version_reference_at_paths;
}
public Integer getDefault_page_size() {
return default_page_size;
}
@@ -601,7 +622,7 @@ public class AppProperties {
}
public void setEnforce_referential_integrity_on_delete(
Boolean enforce_referential_integrity_on_delete) {
Boolean enforce_referential_integrity_on_delete) {
this.enforce_referential_integrity_on_delete = enforce_referential_integrity_on_delete;
}
@@ -610,7 +631,7 @@ public class AppProperties {
}
public void setEnforce_referential_integrity_on_write(
Boolean enforce_referential_integrity_on_write) {
Boolean enforce_referential_integrity_on_write) {
this.enforce_referential_integrity_on_write = enforce_referential_integrity_on_write;
}
@@ -746,11 +767,13 @@ public class AppProperties {
this.tester = tester;
}
public Boolean getNarrative_enabled() {
public Boolean getNarrative_enabled()
{
return narrative_enabled;
}
public void setNarrative_enabled(Boolean narrative_enabled) {
public void setNarrative_enabled(Boolean narrative_enabled)
{
this.narrative_enabled = narrative_enabled;
}
@@ -810,13 +833,13 @@ public class AppProperties {
this.bundle_batch_pool_max_size = bundle_batch_pool_max_size;
}
public List<String> getLocal_base_urls() {
public Set<String> getLocal_base_urls() {
return local_base_urls;
}
public static class Cors {
private Boolean allow_Credentials = true;
private List<String> allowed_origin = ImmutableList.of("*");
private List<String> allowed_origin = List.of("*");
public List<String> getAllowed_origin() {
return allowed_origin;
@@ -834,6 +857,7 @@ public class AppProperties {
this.allow_Credentials = allow_Credentials;
}
}
public static class Logger {
@@ -876,6 +900,7 @@ public class AppProperties {
}
}
public static class Tester {
private String name;
@@ -916,35 +941,6 @@ public class AppProperties {
}
}
public static class ImplementationGuide {
private String url;
private String name;
private String version;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
public static class Validation {
@@ -980,7 +976,6 @@ public class AppProperties {
public void setPartitioning_include_in_search_hashes(Boolean partitioning_include_in_search_hashes) {
this.partitioning_include_in_search_hashes = partitioning_include_in_search_hashes;
}
public Boolean getAllow_references_across_partitions() {
return allow_references_across_partitions;
}
@@ -1020,6 +1015,7 @@ public class AppProperties {
this.email = email;
}
public static class Email {
public String getFrom() {
return from;
@@ -1112,4 +1108,4 @@ public class AppProperties {
public void setEnable_index_of_type(boolean enable_index_of_type) {
this.enable_index_of_type = enable_index_of_type;
}
}
}

View File

@@ -1,6 +1,5 @@
package ca.uhn.fhir.jpa.starter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
@@ -14,25 +13,37 @@ import java.net.URI;
@ConditionalOnProperty(prefix = "hapi.fhir", name = "staticLocation")
public class ExtraStaticFilesConfigurer implements WebMvcConfigurer {
public static final String ROOT_CONTEXT_PATH = "/static";
@Autowired
AppProperties appProperties;
private String staticLocation;
private String rootContextPath;
@Override
public ExtraStaticFilesConfigurer(AppProperties appProperties) {
rootContextPath = appProperties.getStaticLocationPrefix();
if(rootContextPath.endsWith("/"))
rootContextPath = rootContextPath.substring(0, rootContextPath.lastIndexOf('/'));
staticLocation = appProperties.getStaticLocation();
if(staticLocation.endsWith("/"))
staticLocation = staticLocation.substring(0, staticLocation.lastIndexOf('/'));
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry theRegistry) {
theRegistry.addResourceHandler(ROOT_CONTEXT_PATH + "/**").addResourceLocations(appProperties.getStaticLocation());
theRegistry.addResourceHandler(rootContextPath + "/**").addResourceLocations(staticLocation);
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
String path = URI.create(appProperties.getStaticLocation()).getPath();
String path = URI.create(staticLocation).getPath();
String lastSegment = path.substring(path.lastIndexOf('/') + 1);
registry.addViewController(ROOT_CONTEXT_PATH).setViewName("redirect:" + ROOT_CONTEXT_PATH + "/" + lastSegment + "/index.html");
registry.addViewController(rootContextPath).setViewName("redirect:" + rootContextPath + "/" + lastSegment + "/index.html");
registry.addViewController(ROOT_CONTEXT_PATH + "/*").setViewName("redirect:" + ROOT_CONTEXT_PATH + "/" + lastSegment + "/index.html");
registry.addViewController(rootContextPath + "/*").setViewName("redirect:" + rootContextPath + "/" + lastSegment + "/index.html");
registry.addViewController(ROOT_CONTEXT_PATH + "/" + lastSegment + "/").setViewName("redirect:" + ROOT_CONTEXT_PATH + "/" + lastSegment + "/index.html");
registry.addViewController(rootContextPath + "/" + lastSegment + "/").setViewName("redirect:" + rootContextPath + "/" + lastSegment + "/index.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}

View File

@@ -29,7 +29,6 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.HashSet;
import java.util.Optional;
import java.util.stream.Collectors;
/**
@@ -41,23 +40,16 @@ public class FhirServerConfigCommon {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirServerConfigCommon.class);
public FhirServerConfigCommon(AppProperties appProperties) {
ourLog.info("Server configured to " + (appProperties.getAllow_contains_searches() ? "allow" : "deny")
+ " contains searches");
ourLog.info("Server configured to " + (appProperties.getAllow_multiple_delete() ? "allow" : "deny")
+ " multiple deletes");
ourLog.info("Server configured to " + (appProperties.getAllow_external_references() ? "allow" : "deny")
+ " external references");
ourLog.info("Server configured to " + (appProperties.getDao_scheduling_enabled() ? "enable" : "disable")
+ " DAO scheduling");
ourLog.info("Server configured to " + (appProperties.getDelete_expunge_enabled() ? "enable" : "disable")
+ " delete expunges");
ourLog.info("Server configured to " + (appProperties.getExpunge_enabled() ? "enable" : "disable") + " expunges");
ourLog.info("Server configured to " + (appProperties.getAllow_override_default_search_params() ? "allow" : "deny")
+ " overriding default search params");
ourLog.info("Server configured to "
+ (appProperties.getAuto_create_placeholder_reference_targets() ? "allow" : "disable")
+ " auto-creating placeholder references");
public FhirServerConfigCommon(AppProperties appProperties) {
ourLog.info("Server configured to " + (appProperties.getAllow_contains_searches() ? "allow" : "deny") + " contains searches");
ourLog.info("Server configured to " + (appProperties.getAllow_multiple_delete() ? "allow" : "deny") + " multiple deletes");
ourLog.info("Server configured to " + (appProperties.getAllow_external_references() ? "allow" : "deny") + " external references");
ourLog.info("Server configured to " + (appProperties.getDao_scheduling_enabled() ? "enable" : "disable") + " DAO scheduling");
ourLog.info("Server configured to " + (appProperties.getDelete_expunge_enabled() ? "enable" : "disable") + " delete expunges");
ourLog.info("Server configured to " + (appProperties.getExpunge_enabled() ? "enable" : "disable") + " expunges");
ourLog.info("Server configured to " + (appProperties.getAllow_override_default_search_params() ? "allow" : "deny") + " overriding default search params");
ourLog.info("Server configured to " + (appProperties.getAuto_create_placeholder_reference_targets() ? "allow" : "disable") + " auto-creating placeholder references");
ourLog.info("Server configured to auto-version references at paths {}", appProperties.getAuto_version_reference_at_paths());
if (appProperties.getSubscription().getEmail() != null) {
AppProperties.Subscription.Email email = appProperties.getSubscription().getEmail();
@@ -94,23 +86,19 @@ public class FhirServerConfigCommon {
public JpaStorageSettings jpaStorageSettings(AppProperties appProperties) {
JpaStorageSettings jpaStorageSettings = new JpaStorageSettings();
jpaStorageSettings.setIndexMissingFields(
appProperties.getEnable_index_missing_fields() ? JpaStorageSettings.IndexEnabledEnum.ENABLED
: JpaStorageSettings.IndexEnabledEnum.DISABLED);
jpaStorageSettings
.setAutoCreatePlaceholderReferenceTargets(appProperties.getAuto_create_placeholder_reference_targets());
jpaStorageSettings
.setEnforceReferentialIntegrityOnWrite(appProperties.getEnforce_referential_integrity_on_write());
jpaStorageSettings
.setEnforceReferentialIntegrityOnDelete(appProperties.getEnforce_referential_integrity_on_delete());
jpaStorageSettings.setAllowContainsSearches(appProperties.getAllow_contains_searches());
jpaStorageSettings.setAllowMultipleDelete(appProperties.getAllow_multiple_delete());
jpaStorageSettings.setAllowExternalReferences(appProperties.getAllow_external_references());
jpaStorageSettings.setSchedulingDisabled(!appProperties.getDao_scheduling_enabled());
jpaStorageSettings.setDeleteExpungeEnabled(appProperties.getDelete_expunge_enabled());
jpaStorageSettings.setExpungeEnabled(appProperties.getExpunge_enabled());
if (appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null)
jpaStorageSettings.setEmailFromAddress(appProperties.getSubscription().getEmail().getFrom());
jpaStorageSettings.setIndexMissingFields(appProperties.getEnable_index_missing_fields() ? StorageSettings.IndexEnabledEnum.ENABLED : StorageSettings.IndexEnabledEnum.DISABLED);
jpaStorageSettings.setAutoCreatePlaceholderReferenceTargets(appProperties.getAuto_create_placeholder_reference_targets());
jpaStorageSettings.setAutoVersionReferenceAtPaths(appProperties.getAuto_version_reference_at_paths());
jpaStorageSettings.setEnforceReferentialIntegrityOnWrite(appProperties.getEnforce_referential_integrity_on_write());
jpaStorageSettings.setEnforceReferentialIntegrityOnDelete(appProperties.getEnforce_referential_integrity_on_delete());
jpaStorageSettings.setAllowContainsSearches(appProperties.getAllow_contains_searches());
jpaStorageSettings.setAllowMultipleDelete(appProperties.getAllow_multiple_delete());
jpaStorageSettings.setAllowExternalReferences(appProperties.getAllow_external_references());
jpaStorageSettings.setSchedulingDisabled(!appProperties.getDao_scheduling_enabled());
jpaStorageSettings.setDeleteExpungeEnabled(appProperties.getDelete_expunge_enabled());
jpaStorageSettings.setExpungeEnabled(appProperties.getExpunge_enabled());
if(appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null)
jpaStorageSettings.setEmailFromAddress(appProperties.getSubscription().getEmail().getFrom());
Integer maxFetchSize = appProperties.getMax_page_size();
jpaStorageSettings.setFetchSizeDefaultMaximum(maxFetchSize);
@@ -143,13 +131,13 @@ public class FhirServerConfigCommon {
}
}
jpaStorageSettings.setFilterParameterEnabled(appProperties.getFilter_search_enabled());
jpaStorageSettings.setAdvancedHSearchIndexing(appProperties.getAdvanced_lucene_indexing());
jpaStorageSettings.setTreatBaseUrlsAsLocal(new HashSet<>(appProperties.getLocal_base_urls()));
jpaStorageSettings.setFilterParameterEnabled(appProperties.getFilter_search_enabled());
jpaStorageSettings.setAdvancedHSearchIndexing(appProperties.getAdvanced_lucene_indexing());
jpaStorageSettings.setTreatBaseUrlsAsLocal(new HashSet<>(appProperties.getLocal_base_urls()));
if (appProperties.getLastn_enabled()) {
jpaStorageSettings.setLastNEnabled(true);
}
if (appProperties.getLastn_enabled()) {
jpaStorageSettings.setLastNEnabled(true);
}
if (appProperties.getInline_resource_storage_below_size() != 0) {
jpaStorageSettings.setInlineResourceTextBelowSize(appProperties.getInline_resource_storage_below_size());

View File

@@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.starter.AppProperties;
import ca.uhn.fhir.to.FhirTesterMvcConfig;
import ca.uhn.fhir.to.TesterConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -18,6 +19,7 @@ import org.springframework.context.annotation.Import;
*/
@Configuration
@Import(FhirTesterMvcConfig.class)
@Conditional(FhirTesterConfigCondition.class)
public class FhirTesterConfig {
/**
@@ -26,7 +28,7 @@ public class FhirTesterConfig {
* server, as well as one public server. If you are creating a project to
* deploy somewhere else, you might choose to only put your own server's
* address here.
*
* <p>
* Note the use of the ${serverBase} variable below. This will be replaced with
* the base URL as reported by the server itself. Often for a simple Tomcat
* (or other container) installation, this will end up being something

View File

@@ -0,0 +1,16 @@
package ca.uhn.fhir.jpa.starter.common;
import ca.uhn.fhir.jpa.starter.util.EnvironmentHelper;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class FhirTesterConfigCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
var properties = EnvironmentHelper.getPropertiesStartingWith((ConfigurableEnvironment) conditionContext.getEnvironment(), "hapi.fhir.tester");
return !properties.isEmpty();
}
}

View File

@@ -1,7 +1,6 @@
package ca.uhn.fhir.jpa.starter.common;
import ca.uhn.fhir.batch2.coordinator.JobDefinitionRegistry;
import ca.uhn.fhir.batch2.jobs.export.BulkDataExportProvider;
import ca.uhn.fhir.batch2.jobs.imprt.BulkDataImportProvider;
import ca.uhn.fhir.batch2.jobs.reindex.ReindexJobParameters;
import ca.uhn.fhir.batch2.jobs.reindex.ReindexProvider;
@@ -10,6 +9,7 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.jpa.api.IDaoRegistry;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
@@ -18,6 +18,7 @@ import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.binary.interceptor.BinaryStorageInterceptor;
import ca.uhn.fhir.jpa.binary.provider.BinaryAccessProvider;
import ca.uhn.fhir.batch2.jobs.export.BulkDataExportProvider;
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
import ca.uhn.fhir.jpa.config.util.ResourceCountCacheUtil;
import ca.uhn.fhir.jpa.config.util.ValidationSupportConfigUtil;
@@ -60,7 +61,6 @@ 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;
import com.google.common.collect.ImmutableList;
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -73,26 +73,23 @@ import org.springframework.http.HttpHeaders;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.web.cors.CorsConfiguration;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.*;
import static ca.uhn.fhir.context.FhirVersionEnum.DSTU3;
import static ca.uhn.fhir.context.FhirVersionEnum.R4;
import static ca.uhn.fhir.jpa.starter.common.validation.IRepositoryValidationInterceptorFactory.ENABLE_REPOSITORY_VALIDATING_INTERCEPTOR;
@Configuration
// allow users to configure custom packages to scan for additional beans
//allow users to configure custom packages to scan for additional beans
@ComponentScan(basePackages = { "${hapi.fhir.custom-bean-packages:}" })
@Import({ ThreadPoolFactoryConfig.class })
@Import(
ThreadPoolFactoryConfig.class
)
public class StarterJpaConfig {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(StarterJpaConfig.class);
public StarterJpaConfig() {
}
@Bean
public IFulltextSearchSvc fullTextSearchSvc() {
return new FulltextSearchSvcImpl();
@@ -109,12 +106,14 @@ public class StarterJpaConfig {
return ValidationSupportConfigUtil.newCachingValidationSupport(theJpaValidationSupportChain);
}
@Autowired
private ConfigurableEnvironment configurableEnvironment;
/**
* Customize the default/max page sizes for search results. You can set these
* however
* Customize the default/max page sizes for search results. You can set these however
* you want, although very large page sizes will require a lot of RAM.
*/
@Bean
@@ -125,6 +124,7 @@ public class StarterJpaConfig {
return pagingProvider;
}
@Bean
public IResourceSupportedSvc resourceSupportedSvc(IDaoRegistry theDaoRegistry) {
return new DaoRegistryResourceSupportedSvc(theDaoRegistry);
@@ -137,10 +137,8 @@ public class StarterJpaConfig {
@Primary
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource myDataSource,
ConfigurableListableBeanFactory myConfigurableListableBeanFactory, FhirContext theFhirContext) {
LocalContainerEntityManagerFactoryBean retVal = HapiEntityManagerFactoryUtil
.newEntityManagerFactory(myConfigurableListableBeanFactory, theFhirContext);
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource myDataSource, ConfigurableListableBeanFactory myConfigurableListableBeanFactory, FhirContext theFhirContext) {
LocalContainerEntityManagerFactoryBean retVal = HapiEntityManagerFactoryUtil.newEntityManagerFactory(myConfigurableListableBeanFactory, theFhirContext);
retVal.setPersistenceUnitName("HAPI_PU");
try {
@@ -148,8 +146,7 @@ public class StarterJpaConfig {
} catch (Exception e) {
throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
}
retVal.setJpaProperties(
EnvironmentHelper.getHibernateProperties(configurableEnvironment, myConfigurableListableBeanFactory));
retVal.setJpaProperties(EnvironmentHelper.getHibernateProperties(configurableEnvironment, myConfigurableListableBeanFactory));
return retVal;
}
@@ -166,10 +163,10 @@ public class StarterJpaConfig {
return new HSearchSortHelperImpl(mySearchParamRegistry);
}
@Bean
@ConditionalOnProperty(prefix = "hapi.fhir", name = ENABLE_REPOSITORY_VALIDATING_INTERCEPTOR, havingValue = "true")
public RepositoryValidatingInterceptor repositoryValidatingInterceptor(
IRepositoryValidationInterceptorFactory factory) {
public RepositoryValidatingInterceptor repositoryValidatingInterceptor(IRepositoryValidationInterceptorFactory factory) {
return factory.buildUsingStoredStructureDefinitions();
}
@@ -191,23 +188,20 @@ public class StarterJpaConfig {
@Bean("packageInstaller")
@Primary
@Conditional(OnImplementationGuidesPresent.class)
public IPackageInstallerSvc packageInstaller(AppProperties appProperties,
JobDefinition<ReindexJobParameters> reindexJobParametersJobDefinition,
JobDefinitionRegistry jobDefinitionRegistry, IPackageInstallerSvc packageInstallerSvc) {
public IPackageInstallerSvc packageInstaller(AppProperties appProperties, JobDefinition<ReindexJobParameters> reindexJobParametersJobDefinition, JobDefinitionRegistry jobDefinitionRegistry, IPackageInstallerSvc packageInstallerSvc)
{
jobDefinitionRegistry.addJobDefinitionIfNotRegistered(reindexJobParametersJobDefinition);
if (appProperties.getImplementationGuides() != null) {
Map<String, AppProperties.ImplementationGuide> guides = appProperties.getImplementationGuides();
for (Map.Entry<String, AppProperties.ImplementationGuide> guide : guides.entrySet()) {
PackageInstallationSpec packageInstallationSpec = new PackageInstallationSpec()
.setPackageUrl(guide.getValue().getUrl()).setName(guide.getValue().getName())
.setVersion(guide.getValue().getVersion())
.setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL);
packageInstallationSpec.setReloadExisting(appProperties.getReload_existing_implementationguides());
Map<String, PackageInstallationSpec> guides = appProperties.getImplementationGuides();
for (Map.Entry<String, PackageInstallationSpec> guidesEntry : guides.entrySet()) {
PackageInstallationSpec packageInstallationSpec = guidesEntry.getValue();
if (appProperties.getInstall_transitive_ig_dependencies()) {
packageInstallationSpec.setFetchDependencies(true);
packageInstallationSpec.setDependencyExcludes(
ImmutableList.of("hl7.fhir.r2.core", "hl7.fhir.r3.core", "hl7.fhir.r4.core", "hl7.fhir.r5.core"));
packageInstallationSpec.addDependencyExclude("hl7.fhir.r2.core")
.addDependencyExclude("hl7.fhir.r3.core")
.addDependencyExclude("hl7.fhir.r4.core")
.addDependencyExclude("hl7.fhir.r5.core");
}
packageInstallerSvc.install(packageInstallationSpec);
}
@@ -247,24 +241,7 @@ public class StarterJpaConfig {
}
@Bean
public RestfulServer restfulServer(IFhirSystemDao<?, ?> fhirSystemDao, AppProperties appProperties,
DaoRegistry daoRegistry,
Optional<MdmProviderLoader> mdmProviderProvider, IJpaSystemProvider jpaSystemProvider,
ResourceProviderFactory resourceProviderFactory, JpaStorageSettings jpaStorageSettings,
ISearchParamRegistry searchParamRegistry, IValidationSupport theValidationSupport,
DatabaseBackedPagingProvider databaseBackedPagingProvider, LoggingInterceptor loggingInterceptor,
Optional<TerminologyUploaderProvider> terminologyUploaderProvider,
Optional<SubscriptionTriggeringProvider> subscriptionTriggeringProvider,
Optional<CorsInterceptor> corsInterceptor, IInterceptorBroadcaster interceptorBroadcaster,
Optional<BinaryAccessProvider> binaryAccessProvider, BinaryStorageInterceptor binaryStorageInterceptor,
IValidatorModule validatorModule, Optional<GraphQLProvider> graphQLProvider,
BulkDataExportProvider bulkDataExportProvider, BulkDataImportProvider bulkDataImportProvider,
ValueSetOperationProvider theValueSetOperationProvider, ReindexProvider reindexProvider,
PartitionManagementProvider partitionManagementProvider,
Optional<RepositoryValidatingInterceptor> repositoryValidatingInterceptor,
IPackageInstallerSvc packageInstallerSvc, ThreadSafeResourceDeleterSvc theThreadSafeResourceDeleterSvc,
ApplicationContext appContext,
Optional<IpsOperationProvider> theIpsOperationProvider) {
public RestfulServer restfulServer(IFhirSystemDao<?, ?> fhirSystemDao, AppProperties appProperties, DaoRegistry daoRegistry, Optional<MdmProviderLoader> mdmProviderProvider, IJpaSystemProvider jpaSystemProvider, ResourceProviderFactory resourceProviderFactory, JpaStorageSettings jpaStorageSettings, ISearchParamRegistry searchParamRegistry, IValidationSupport theValidationSupport, DatabaseBackedPagingProvider databaseBackedPagingProvider, LoggingInterceptor loggingInterceptor, Optional<TerminologyUploaderProvider> terminologyUploaderProvider, Optional<SubscriptionTriggeringProvider> subscriptionTriggeringProvider, Optional<CorsInterceptor> corsInterceptor, IInterceptorBroadcaster interceptorBroadcaster, Optional<BinaryAccessProvider> binaryAccessProvider, BinaryStorageInterceptor binaryStorageInterceptor, IValidatorModule validatorModule, Optional<GraphQLProvider> graphQLProvider, BulkDataExportProvider bulkDataExportProvider, BulkDataImportProvider bulkDataImportProvider, ValueSetOperationProvider theValueSetOperationProvider, ReindexProvider reindexProvider, PartitionManagementProvider partitionManagementProvider, Optional<RepositoryValidatingInterceptor> repositoryValidatingInterceptor, IPackageInstallerSvc packageInstallerSvc, ThreadSafeResourceDeleterSvc theThreadSafeResourceDeleterSvc, ApplicationContext appContext, Optional<IpsOperationProvider> theIpsOperationProvider) {
RestfulServer fhirServer = new RestfulServer(fhirSystemDao.getContext());
List<String> supportedResourceTypes = appProperties.getSupported_resource_types();
@@ -282,21 +259,18 @@ public class StarterJpaConfig {
fhirSystemDao.getContext().setNarrativeGenerator(new NullNarrativeGenerator());
}
if (appProperties.getMdm_enabled()) {
mdmProviderProvider.get().loadProvider();
}
if (appProperties.getMdm_enabled()) mdmProviderProvider.get().loadProvider();
fhirServer.registerProviders(resourceProviderFactory.createProviders());
fhirServer.registerProvider(jpaSystemProvider);
fhirServer.setServerConformanceProvider(calculateConformanceProvider(fhirSystemDao, fhirServer,
jpaStorageSettings, searchParamRegistry, theValidationSupport));
fhirServer.setServerConformanceProvider(calculateConformanceProvider(fhirSystemDao, fhirServer, jpaStorageSettings, searchParamRegistry, theValidationSupport));
/*
* ETag Support
*/
if (!appProperties.getEtag_support_enabled())
fhirServer.setETagSupport(ETagSupportEnum.DISABLED);
if (!appProperties.getEtag_support_enabled()) fhirServer.setETagSupport(ETagSupportEnum.DISABLED);
/*
* Default to JSON and pretty printing
@@ -333,8 +307,7 @@ public class StarterJpaConfig {
/*
* 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
* 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();
@@ -342,24 +315,19 @@ public class StarterJpaConfig {
fhirServer.setServerAddressStrategy(new HardcodedServerAddressStrategy(serverAddress));
} else if (appProperties.getUse_apache_address_strategy()) {
boolean useHttps = appProperties.getUse_apache_address_strategy_https();
fhirServer.setServerAddressStrategy(
useHttps ? ApacheProxyAddressStrategy.forHttps() : ApacheProxyAddressStrategy.forHttp());
fhirServer.setServerAddressStrategy(useHttps ? ApacheProxyAddressStrategy.forHttps() : ApacheProxyAddressStrategy.forHttp());
} else {
fhirServer.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
* 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 (fhirSystemDao.getContext().getVersion().getVersion().isEqualOrNewerThan(DSTU3)) { // <-- ENABLED RIGHT NOW
if (fhirSystemDao.getContext().getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) { // <-- ENABLED RIGHT NOW
fhirServer.registerProvider(terminologyUploaderProvider.get());
}
@@ -377,8 +345,7 @@ public class StarterJpaConfig {
}
if (appProperties.getAllow_cascading_deletes()) {
CascadingDeleteInterceptor cascadingDeleteInterceptor = new CascadingDeleteInterceptor(
fhirSystemDao.getContext(), daoRegistry, interceptorBroadcaster, theThreadSafeResourceDeleterSvc);
CascadingDeleteInterceptor cascadingDeleteInterceptor = new CascadingDeleteInterceptor(fhirSystemDao.getContext(), daoRegistry, interceptorBroadcaster, theThreadSafeResourceDeleterSvc);
fhirServer.registerInterceptor(cascadingDeleteInterceptor);
}
@@ -407,7 +374,7 @@ public class StarterJpaConfig {
// GraphQL
if (appProperties.getGraphql_enabled()) {
if (fhirSystemDao.getContext().getVersion().getVersion().isEqualOrNewerThan(DSTU3)) {
if (fhirSystemDao.getContext().getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
fhirServer.registerProvider(graphQLProvider.get());
}
}
@@ -421,15 +388,16 @@ public class StarterJpaConfig {
fhirServer.registerProvider(bulkDataExportProvider);
}
// Bulk Import
//Bulk Import
if (appProperties.getBulk_import_enabled()) {
fhirServer.registerProvider(bulkDataImportProvider);
}
// valueSet Operations i.e $expand
fhirServer.registerProvider(theValueSetOperationProvider);
// reindex Provider $reindex
//reindex Provider $reindex
fhirServer.registerProvider(reindexProvider);
// Partitioning
@@ -443,7 +411,8 @@ public class StarterJpaConfig {
// register custom interceptors
registerCustomInterceptors(fhirServer, appContext, appProperties.getCustomInterceptorClasses());
// register the IPS Provider
//register the IPS Provider
if (!theIpsOperationProvider.isEmpty()) {
fhirServer.registerProvider(theIpsOperationProvider.get());
}
@@ -455,8 +424,7 @@ public class StarterJpaConfig {
* check the properties for custom interceptor classes and registers them.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private void registerCustomInterceptors(RestfulServer fhirServer, ApplicationContext theAppContext,
List<String> customInterceptorClasses) {
private void registerCustomInterceptors(RestfulServer fhirServer, ApplicationContext theAppContext, List<String> customInterceptorClasses) {
if (customInterceptorClasses == null) {
return;
@@ -490,37 +458,30 @@ public class StarterJpaConfig {
}
}
public static IServerConformanceProvider<?> calculateConformanceProvider(IFhirSystemDao fhirSystemDao,
RestfulServer fhirServer, JpaStorageSettings jpaStorageSettings, ISearchParamRegistry searchParamRegistry,
IValidationSupport theValidationSupport) {
public static IServerConformanceProvider<?> calculateConformanceProvider(IFhirSystemDao fhirSystemDao, RestfulServer fhirServer, JpaStorageSettings jpaStorageSettings, ISearchParamRegistry searchParamRegistry, IValidationSupport theValidationSupport) {
FhirVersionEnum fhirVersion = fhirSystemDao.getContext().getVersion().getVersion();
if (fhirVersion == FhirVersionEnum.DSTU2) {
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(fhirServer, fhirSystemDao,
jpaStorageSettings);
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(fhirServer, fhirSystemDao, jpaStorageSettings);
confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server");
return confProvider;
} else if (fhirVersion == DSTU3) {
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(fhirServer, fhirSystemDao,
jpaStorageSettings, searchParamRegistry);
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(fhirServer, fhirSystemDao, jpaStorageSettings, searchParamRegistry);
confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server");
return confProvider;
} else if (fhirVersion == R4) {
} else if (fhirVersion == FhirVersionEnum.R4) {
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao,
jpaStorageSettings, searchParamRegistry, theValidationSupport);
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, jpaStorageSettings, searchParamRegistry, theValidationSupport);
confProvider.setImplementationDescription("HAPI FHIR R4 Server");
return confProvider;
} else if (fhirVersion == FhirVersionEnum.R4B) {
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao,
jpaStorageSettings, searchParamRegistry, theValidationSupport);
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, jpaStorageSettings, searchParamRegistry, theValidationSupport);
confProvider.setImplementationDescription("HAPI FHIR R4B Server");
return confProvider;
} else if (fhirVersion == FhirVersionEnum.R5) {
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao,
jpaStorageSettings, searchParamRegistry, theValidationSupport);
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, jpaStorageSettings, searchParamRegistry, theValidationSupport);
confProvider.setImplementationDescription("HAPI FHIR R5 Server");
return confProvider;
} else {

View File

@@ -47,12 +47,12 @@ public class RepositoryValidationInterceptorFactoryDstu3 implements IRepositoryV
public RepositoryValidatingInterceptor buildUsingStoredStructureDefinitions() {
IBundleProvider results = structureDefinitionResourceProvider.search(new SearchParameterMap().add(StructureDefinition.SP_KIND, new TokenParam("resource")));
Map<String, List<StructureDefinition>> structureDefintions = results.getResources(0, results.size())
Map<String, List<StructureDefinition>> structureDefinitions = results.getResources(0, results.size())
.stream()
.map(StructureDefinition.class::cast)
.collect(Collectors.groupingBy(StructureDefinition::getType));
structureDefintions.forEach((key, value) -> {
structureDefinitions.forEach((key, value) -> {
String[] urls = value.stream().map(StructureDefinition::getUrl).toArray(String[]::new);
repositoryValidatingRuleBuilder.forResourcesOfType(key).requireAtLeastOneProfileOf(urls).and().requireValidationToDeclaredProfiles();
});

View File

@@ -1,14 +1,16 @@
package ca.uhn.fhir.jpa.starter.cr;
import ca.uhn.fhir.cr.config.r4.CrR4Config;
import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Import;
import ca.uhn.fhir.cr.common.CqlThreadFactory;
import ca.uhn.fhir.cr.config.ApplyOperationConfig;
import ca.uhn.fhir.cr.config.ExtractOperationConfig;
import ca.uhn.fhir.cr.config.PackageOperationConfig;
import ca.uhn.fhir.cr.config.PopulateOperationConfig;
import ca.uhn.fhir.cr.config.r4.CrR4Config;
import ca.uhn.fhir.jpa.starter.AppProperties;
import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition;
import org.cqframework.cql.cql2elm.CqlCompilerOptions;
import org.cqframework.cql.cql2elm.model.CompiledLibrary;
import org.cqframework.cql.cql2elm.model.Model;
@@ -29,7 +31,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
@Configuration
@Conditional({ OnR4Condition.class, CrConfigCondition.class })

View File

@@ -15,18 +15,18 @@ import ca.uhn.fhir.jpa.ips.generator.IpsGeneratorSvcImpl;
@Conditional(IpsConfigCondition.class)
public class StarterIpsConfig {
@Bean
IIpsGenerationStrategy IpsGenerationStrategy()
IIpsGenerationStrategy ipsGenerationStrategy()
{
return new DefaultIpsGenerationStrategy();
}
@Bean
public IpsOperationProvider IpsOperationProvider(IIpsGeneratorSvc theIpsGeneratorSvc){
public IpsOperationProvider ipsOperationProvider(IIpsGeneratorSvc theIpsGeneratorSvc){
return new IpsOperationProvider(theIpsGeneratorSvc);
}
@Bean
public IIpsGeneratorSvc IpsGeneratorSvcImpl(FhirContext theFhirContext, IIpsGenerationStrategy theGenerationStrategy, DaoRegistry theDaoRegistry)
public IIpsGeneratorSvc ipsGeneratorSvcImpl(FhirContext theFhirContext, IIpsGenerationStrategy theGenerationStrategy, DaoRegistry theDaoRegistry)
{
return new IpsGeneratorSvcImpl(theFhirContext, theGenerationStrategy, theDaoRegistry);
}

View File

@@ -6,7 +6,6 @@ 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 com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@@ -17,6 +16,7 @@ import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@Configuration
@Conditional(MdmConfigCondition.class)
@@ -27,7 +27,7 @@ public class MdmConfig {
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);
String json = IOUtils.toString(resource.getInputStream(), StandardCharsets.UTF_8);
return new MdmSettings(theMdmRuleValidator).setEnabled(appProperties.getMdm_enabled()).setScriptText(json);
}
}

View File

@@ -17,7 +17,6 @@ import org.hibernate.search.mapper.orm.cfg.HibernateOrmMapperSettings;
import org.hibernate.search.mapper.orm.schema.management.SchemaManagementStrategyName;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
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;

View File

@@ -68,7 +68,8 @@ hapi:
### 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
### enables the server to host content like HTML, css, etc. under the url pattern of /static/**
### enables the server to host content like HTML, css, etc. under the url pattern of eg. /static/**
# staticLocationPrefix: /static
### the deepest folder level will be used. E.g. - if you put file:/foo/bar/bazz as value then the files are resolved under /static/bazz/**
#staticLocation: file:/foo/bar/bazz
### enable to set the Server URL
@@ -77,14 +78,15 @@ hapi:
# install_transitive_ig_dependencies: true
### tells the server whether to attempt to load IG resources that are already present
# reload_existing_implementationGuides : false
# implementationguides:
#implementationguides:
### example from registry (packages.fhir.org)
# swiss:
# name: swiss.mednet.fhir
# version: 0.8.0
# swiss:
# name: swiss.mednet.fhir
# version: 0.8.0
# reloadExisting : false
# example not from registry
# ips_1_0_0:
# url: https://build.fhir.org/ig/HL7/fhir-ips/package.tgz
# packageUrl: https://build.fhir.org/ig/HL7/fhir-ips/package.tgz
# name: hl7.fhir.uv.ips
# version: 1.0.0
# supported_resource_types:
@@ -100,6 +102,8 @@ hapi:
# allow_multiple_delete: true
# allow_override_default_search_params: true
# auto_create_placeholder_reference_targets: false
### tells the server to automatically append the current version of the target resource to references at these paths
# auto_version_reference_at_paths: Device.patient, Device.location, Device.parent, DeviceMetric.parent, DeviceMetric.source, Observation.device, Observation.subject
# cr_enabled: true
# ips_enabled: false
# default_encoding: JSON

View File

@@ -15,7 +15,7 @@ import org.springframework.boot.test.context.SpringBootTest;
"hapi.fhir.subscription.websocket_enabled=false",
"spring.main.allow-bean-definition-overriding=true"
})
public class CustomBeanTest {
class CustomBeanTest {
@Autowired
some.custom.pkg1.CustomBean customBean1;

View File

@@ -22,7 +22,7 @@ import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
"hapi.fhir.fhir_version=r4"
})
public class CustomInterceptorTest {
class CustomInterceptorTest {
@LocalServerPort
private int port;

View File

@@ -3,16 +3,23 @@ package ca.uhn.fhir.jpa.starter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.search.lastn.ElasticsearchRestClientFactory;
import ca.uhn.fhir.jpa.search.lastn.ElasticsearchSvcImpl;
import ca.uhn.fhir.jpa.test.config.TestElasticsearchContainerHelper;
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 java.io.IOException;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import javax.annotation.PreDestroy;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.elasticsearch.common.settings.Settings;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.DateTimeType;
@@ -34,8 +41,11 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@ExtendWith(SpringExtension.class)
@Testcontainers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {Application.class, JpaStarterWebsocketDispatcherConfig.class}, properties =
{
"spring.datasource.url=jdbc:h2:mem:dbr4",
@@ -43,6 +53,7 @@ import org.testcontainers.elasticsearch.ElasticsearchContainer;
"hapi.fhir.lastn_enabled=true",
"hapi.fhir.store_resource_in_lucene_index_enabled=true",
"hapi.fhir.advanced_lucene_indexing=true",
"elasticsearch.enabled=true",
"hapi.fhir.cr_enabled=false",
// Because the port is set randomly, we will set the rest_url using the Initializer.
@@ -62,19 +73,31 @@ public class ElasticsearchLastNR4IT {
private IGenericClient ourClient;
private FhirContext ourCtx;
private static final String ELASTIC_VERSION = "7.16.3";
private static final String ELASTIC_IMAGE = "docker.elastic.co/elasticsearch/elasticsearch:" + ELASTIC_VERSION;
private static ElasticsearchContainer embeddedElastic;
@Container
public static ElasticsearchContainer embeddedElastic = TestElasticsearchContainerHelper.getEmbeddedElasticSearch();
@Autowired
private ElasticsearchSvcImpl myElasticsearchSvc;
@BeforeAll
public static void beforeClass() {
embeddedElastic = new ElasticsearchContainer(ELASTIC_IMAGE).withStartupTimeout(Duration.of(300, ChronoUnit.SECONDS));
embeddedElastic.start();
public static void beforeClass() throws IOException {
//Given
RestHighLevelClient elasticsearchHighLevelRestClient = ElasticsearchRestClientFactory.createElasticsearchHighLevelRestClient(
"http", embeddedElastic.getHost() + ":" + embeddedElastic.getMappedPort(9200), "", "");
/* As of 2023-08-10, HAPI FHIR sets SubscriptionConstants.MAX_SUBSCRIPTION_RESULTS to 50000
which is in excess of elastic's default max_result_window. If MAX_SUBSCRIPTION_RESULTS is changed
to a value <= 10000, the following will no longer be necessary. - dotasek
*/
PutIndexTemplateRequest putIndexTemplateRequest = new PutIndexTemplateRequest("hapi_fhir_template");
putIndexTemplateRequest.patterns(List.of("*"));
Settings settings = Settings.builder().put("index.max_result_window", 50000).build();
putIndexTemplateRequest.settings(settings);
elasticsearchHighLevelRestClient.indices().putTemplate(putIndexTemplateRequest, RequestOptions.DEFAULT);
}
@PreDestroy
public void stop() {
embeddedElastic.stop();
@@ -116,7 +139,7 @@ public class ElasticsearchLastNR4IT {
}
@BeforeEach
void beforeEach() {
void beforeEach() throws IOException {
ourCtx = FhirContext.forR4();
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
@@ -124,6 +147,7 @@ public class ElasticsearchLastNR4IT {
String ourServerBase = "http://localhost:" + port + "/fhir/";
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
ourClient.registerInterceptor(new LoggingInterceptor(true));
}
static class Initializer

View File

@@ -23,7 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
"spring.datasource.url=jdbc:h2:mem:dbr2",
"hapi.fhir.cr_enabled=false",
})
public class ExampleServerDstu2IT {
class ExampleServerDstu2IT {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
private IGenericClient ourClient;

View File

@@ -51,7 +51,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
})
public class ExampleServerDstu3IT implements IServerSupport {
class ExampleServerDstu3IT implements IServerSupport {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu3IT.class);
private IGenericClient ourClient;
@@ -73,8 +73,8 @@ public class ExampleServerDstu3IT implements IServerSupport {
ourClient.registerInterceptor(new LoggingInterceptor(true));
}
@Test
public void testCreateAndRead() {
@Test
void testCreateAndRead() {
String methodName = "testCreateResourceConditional";
@@ -157,7 +157,7 @@ public class ExampleServerDstu3IT implements IServerSupport {
}
@Test
public void testWebsocketSubscription() throws Exception {
void testWebsocketSubscription() throws Exception {
/*
* Create subscription
*/

View File

@@ -55,7 +55,7 @@ class ExampleServerR4BIT {
@Test
public void testBatchPutWithIdenticalTags() {
void testBatchPutWithIdenticalTags() {
String batchPuts = "{\n" +
"\t\"resourceType\": \"Bundle\",\n" +
"\t\"id\": \"patients\",\n" +

View File

@@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.jpa.searchparam.config.NicknameServiceConfig;
import ca.uhn.fhir.rest.api.CacheControlDirective;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
@@ -16,11 +17,9 @@ import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
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.web.server.LocalServerPort;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.io.IOException;
@@ -37,10 +36,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.opencds.cqf.fhir.utility.r4.Parameters.parameters;
import static org.opencds.cqf.fhir.utility.r4.Parameters.stringPart;
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = {Application.class, JpaStarterWebsocketDispatcherConfig.class},
properties = {
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {Application.class, JpaStarterWebsocketDispatcherConfig.class, NicknameServiceConfig.class}, properties = {
"spring.datasource.url=jdbc:h2:mem:dbr4",
"hapi.fhir.enable_repository_validating_interceptor=true",
"hapi.fhir.fhir_version=r4",
@@ -147,7 +143,7 @@ class ExampleServerR4IT implements IServerSupport{
return result.get(0);
}
@Test
public void testBatchPutWithIdenticalTags() {
void testBatchPutWithIdenticalTags() {
String batchPuts = "{\n" +
"\t\"resourceType\": \"Bundle\",\n" +
"\t\"id\": \"patients\",\n" +

View File

@@ -45,15 +45,15 @@ public class ExampleServerR5IT {
private IGenericClient ourClient;
private FhirContext ourCtx;
public static final String SUBSCRIPTION_TOPIC_TEST_URL = "http://example.com/topic/test";
public static final String SUBSCRIPTION_TOPIC_TEST_URL = "http://example.com/topic/test";
@LocalServerPort
@LocalServerPort
private int port;
@Test
public void testCreateAndRead() {
void testCreateAndRead() {
String methodName = "testCreateResourceConditional";
@@ -66,7 +66,7 @@ public class ExampleServerR5IT {
}
@Test
public void testWebsocketSubscription() throws Exception {
void testWebsocketSubscription() throws Exception {
String endpoint = "ws://localhost:" + port + "/websocket";
/*
* Create topic

View File

@@ -27,7 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
"hapi.fhir.partitioning.partitioning_include_in_search_hashes=false",
})
public class MultitenantServerR4IT {
class MultitenantServerR4IT {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
@@ -41,7 +41,7 @@ public class MultitenantServerR4IT {
@Test
public void testCreateAndReadInTenantA() {
void testCreateAndReadInTenantA() {
// Create tenant A
@@ -67,7 +67,7 @@ public class MultitenantServerR4IT {
}
@Test
public void testCreateAndReadInTenantB() {
void testCreateAndReadInTenantB() {
// Create tenant A

View File

@@ -18,7 +18,7 @@ public class SocketImplementation {
private final String myCriteria;
protected String myError;
protected boolean myGotBound;
private final List<String> myMessages = new ArrayList<String>();
private final List<String> myMessages = new ArrayList<>();
protected int myPingCount;
protected String mySubsId;
private Session session;

View File

@@ -64,9 +64,10 @@ hapi:
# swiss:
# name: swiss.mednet.fhir
# version: 0.8.0
# reloadExisting : false
# example not from registry
# ips_1_0_0:
# url: https://build.fhir.org/ig/HL7/fhir-ips/package.tgz
# packageUrl: https://build.fhir.org/ig/HL7/fhir-ips/package.tgz
# name: hl7.fhir.uv.ips
# version: 1.0.0
# supported_resource_types: