Skip to content

Commit 509d5ff

Browse files
committed
Add support for Database Partition Mode
1 parent b3761a4 commit 509d5ff

File tree

8 files changed

+248
-29
lines changed

8 files changed

+248
-29
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<parent>
1515
<groupId>ca.uhn.hapi.fhir</groupId>
1616
<artifactId>hapi-fhir</artifactId>
17-
<version>7.7.16-SNAPSHOT</version>
17+
<version>7.7.18-SNAPSHOT</version>
1818
</parent>
1919

2020
<artifactId>hapi-fhir-jpaserver-starter</artifactId>

src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,11 @@ public void setCr_enabled(Boolean cr_enabled) {
175175
this.cr_enabled = cr_enabled;
176176
}
177177

178-
public Boolean getIps_enabled() {
178+
public Boolean getIps_enabled() {
179179
return ips_enabled;
180180
}
181181

182-
public void setIps_enabled(Boolean ips_enabled) {
182+
public void setIps_enabled(Boolean ips_enabled) {
183183
this.ips_enabled = ips_enabled;
184184
}
185185

@@ -810,8 +810,36 @@ public static class Partitioning {
810810
private Boolean partitioning_include_in_search_hashes = false;
811811
private Boolean allow_references_across_partitions = false;
812812
private Boolean conditional_create_duplicate_identifiers_enabled = false;
813+
private Boolean database_partition_mode_enabled = false;
814+
private Boolean patient_id_partitioning_mode = false;
815+
private Integer default_partition_id = 0;
816+
private boolean request_tenant_partitioning_mode;
813817

814-
public Boolean getPartitioning_include_in_search_hashes() {
818+
public Integer getDefault_partition_id() {
819+
return default_partition_id;
820+
}
821+
822+
public void setDefault_partition_id(Integer theDefault_partition_id) {
823+
default_partition_id = theDefault_partition_id;
824+
}
825+
826+
public Boolean getDatabase_partition_mode_enabled() {
827+
return database_partition_mode_enabled;
828+
}
829+
830+
public void setDatabase_partition_mode_enabled(Boolean theDatabase_partition_mode_enabled) {
831+
database_partition_mode_enabled = theDatabase_partition_mode_enabled;
832+
}
833+
834+
public Boolean getPatient_id_partitioning_mode() {
835+
return patient_id_partitioning_mode;
836+
}
837+
838+
public void setPatient_id_partitioning_mode(Boolean thePatient_id_partitioning_mode) {
839+
patient_id_partitioning_mode = thePatient_id_partitioning_mode;
840+
}
841+
842+
public Boolean getPartitioning_include_in_search_hashes() {
815843
return partitioning_include_in_search_hashes;
816844
}
817845

@@ -833,6 +861,10 @@ public Boolean getConditional_create_duplicate_identifiers_enabled() {
833861
public void setConditional_create_duplicate_identifiers_enabled(Boolean conditional_create_duplicate_identifiers_enabled) {
834862
this.conditional_create_duplicate_identifiers_enabled = conditional_create_duplicate_identifiers_enabled;
835863
}
864+
865+
public boolean getRequest_tenant_partitioning_mode() {
866+
return request_tenant_partitioning_mode;
867+
}
836868
}
837869

838870
public static class Subscription {

src/main/java/ca/uhn/fhir/jpa/starter/cdshooks/ModuleConfigurationPrefetchSvc.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import ca.uhn.fhir.context.FhirContext;
44
import ca.uhn.fhir.i18n.Msg;
5+
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
56
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
67
import ca.uhn.fhir.rest.client.api.IGenericClient;
78
import ca.uhn.fhir.rest.client.interceptor.BearerTokenAuthInterceptor;
@@ -53,8 +54,9 @@ public class ModuleConfigurationPrefetchSvc extends CdsPrefetchSvc {
5354
public ModuleConfigurationPrefetchSvc(CdsResolutionStrategySvc theCdsResolutionStrategySvc,
5455
CdsPrefetchDaoSvc theResourcePrefetchDao,
5556
CdsPrefetchFhirClientSvc theResourcePrefetchFhirClient,
56-
ICdsHooksDaoAuthorizationSvc theCdsHooksDaoAuthorizationSvc) {
57-
super(theCdsResolutionStrategySvc, theResourcePrefetchDao, theResourcePrefetchFhirClient, theCdsHooksDaoAuthorizationSvc);
57+
ICdsHooksDaoAuthorizationSvc theCdsHooksDaoAuthorizationSvc,
58+
IInterceptorBroadcaster theInterceptorBroadcaster) {
59+
super(theCdsResolutionStrategySvc, theResourcePrefetchDao, theResourcePrefetchFhirClient, theCdsHooksDaoAuthorizationSvc, theInterceptorBroadcaster);
5860
myResourcePrefetchFhirClient = theResourcePrefetchFhirClient;
5961
fhirContext = theResourcePrefetchDao.getFhirContext();
6062
}

src/main/java/ca/uhn/fhir/jpa/starter/common/FhirServerConfigCommon.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package ca.uhn.fhir.jpa.starter.common;
22

3+
import ca.uhn.fhir.context.FhirContext;
4+
import ca.uhn.fhir.interceptor.api.IInterceptorService;
35
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
46
import ca.uhn.fhir.jpa.binary.api.IBinaryStorageSvc;
57
import ca.uhn.fhir.jpa.binstore.DatabaseBinaryContentStorageSvcImpl;
68
import ca.uhn.fhir.jpa.config.HibernatePropertiesProvider;
9+
import ca.uhn.fhir.jpa.interceptor.PatientIdPartitionInterceptor;
710
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
811
import ca.uhn.fhir.jpa.model.config.PartitionSettings.CrossPartitionReferenceMode;
912
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
1013
import ca.uhn.fhir.jpa.model.entity.StorageSettings;
14+
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
1115
import ca.uhn.fhir.jpa.starter.AppProperties;
1216
import ca.uhn.fhir.jpa.starter.util.JpaHibernatePropertiesProvider;
1317
import ca.uhn.fhir.jpa.subscription.match.deliver.email.EmailSenderImpl;
@@ -27,6 +31,8 @@
2731
import java.util.HashSet;
2832
import java.util.stream.Collectors;
2933

34+
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
35+
3036
/**
3137
* This is the primary configuration file for the example server
3238
*/
@@ -171,7 +177,7 @@ public JpaStorageSettings jpaStorageSettings(AppProperties appProperties) {
171177

172178

173179
jpaStorageSettings.setFilterParameterEnabled(appProperties.getFilter_search_enabled());
174-
jpaStorageSettings.setAdvancedHSearchIndexing(appProperties.getAdvanced_lucene_indexing());
180+
jpaStorageSettings.setHibernateSearchIndexSearchParams(appProperties.getAdvanced_lucene_indexing());
175181
jpaStorageSettings.setTreatBaseUrlsAsLocal(new HashSet<>(appProperties.getLocal_base_urls()));
176182
jpaStorageSettings.setTreatReferencesAsLogical(new HashSet<>(appProperties.getLogical_urls()));
177183

@@ -233,13 +239,21 @@ public YamlPropertySourceLoader yamlPropertySourceLoader() {
233239
return new YamlPropertySourceLoader();
234240
}
235241

242+
236243
@Bean
237244
public PartitionSettings partitionSettings(AppProperties appProperties) {
238245
PartitionSettings retVal = new PartitionSettings();
239246

240247
// Partitioning
241248
if (appProperties.getPartitioning() != null) {
242249
retVal.setPartitioningEnabled(true);
250+
boolean databasePartitionModeEnabled = defaultIfNull(appProperties.getPartitioning().getDatabase_partition_mode_enabled(), Boolean.FALSE);
251+
Integer defaultPartitionId = appProperties.getPartitioning().getDefault_partition_id();
252+
if (databasePartitionModeEnabled) {
253+
retVal.setDatabasePartitionMode(true);
254+
defaultPartitionId = defaultIfNull(defaultPartitionId, 0);
255+
}
256+
retVal.setDefaultPartitionId(defaultPartitionId);
243257
retVal.setIncludePartitionInSearchHashes(
244258
appProperties.getPartitioning().getPartitioning_include_in_search_hashes());
245259
if (appProperties.getPartitioning().getAllow_references_across_partitions()) {
@@ -251,9 +265,16 @@ public PartitionSettings partitionSettings(AppProperties appProperties) {
251265
appProperties.getPartitioning().getConditional_create_duplicate_identifiers_enabled());
252266
}
253267

268+
254269
return retVal;
255270
}
256271

272+
@Bean
273+
public PartitionModeConfigurer partitionModeConfigurer() {
274+
return new PartitionModeConfigurer();
275+
}
276+
277+
257278
@Primary
258279
@Bean
259280
public HibernatePropertiesProvider jpaStarterDialectProvider(
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package ca.uhn.fhir.jpa.starter.common;
2+
3+
import ca.uhn.fhir.context.FhirContext;
4+
import ca.uhn.fhir.interceptor.api.IInterceptorService;
5+
import ca.uhn.fhir.jpa.interceptor.PatientIdPartitionInterceptor;
6+
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
7+
import ca.uhn.fhir.jpa.partition.PartitionManagementProvider;
8+
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
9+
import ca.uhn.fhir.jpa.starter.AppProperties;
10+
import ca.uhn.fhir.rest.server.RestfulServer;
11+
import ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor;
12+
import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy;
13+
import jakarta.annotation.PostConstruct;
14+
import org.slf4j.Logger;
15+
import org.slf4j.LoggerFactory;
16+
import org.springframework.beans.factory.annotation.Autowired;
17+
18+
public class PartitionModeConfigurer {
19+
private static final Logger ourLog = LoggerFactory.getLogger(PartitionModeConfigurer.class);
20+
21+
@Autowired
22+
private AppProperties myAppProperties;
23+
@Autowired
24+
private FhirContext myFhirContext;
25+
@Autowired
26+
private ISearchParamExtractor mySearchParamExtractor;
27+
@Autowired
28+
private PartitionSettings myPartitionSettings;
29+
@Autowired
30+
private RestfulServer myRestfulServer;
31+
@Autowired
32+
private PartitionManagementProvider myPartitionManagementProvider;
33+
34+
35+
@PostConstruct
36+
public void start() {
37+
if (myAppProperties.getPartitioning() != null) {
38+
if (myAppProperties.getPartitioning().getPatient_id_partitioning_mode() == Boolean.TRUE) {
39+
ourLog.info("Partitioning mode enabled in: Patient ID partitioning mode");
40+
PatientIdPartitionInterceptor patientIdInterceptor = new PatientIdPartitionInterceptor(myFhirContext, mySearchParamExtractor, myPartitionSettings);
41+
myRestfulServer.registerInterceptor(patientIdInterceptor);
42+
myPartitionSettings.setUnnamedPartitionMode(true);
43+
} else if (myAppProperties.getPartitioning().getRequest_tenant_partitioning_mode() == Boolean.TRUE) {
44+
ourLog.info("Partitioning mode enabled in: Request tenant partitioning mode");
45+
myRestfulServer.registerInterceptor(new RequestTenantPartitionInterceptor());
46+
myRestfulServer.setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
47+
}
48+
49+
myRestfulServer.registerProviders(myPartitionManagementProvider);
50+
}
51+
}
52+
53+
}

src/main/java/ca/uhn/fhir/jpa/starter/common/StarterJpaConfig.java

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package ca.uhn.fhir.jpa.starter.common;
22

33
import ca.uhn.fhir.batch2.config.Batch2JobRegisterer;
4-
import ca.uhn.fhir.batch2.coordinator.JobDefinitionRegistry;
54
import ca.uhn.fhir.batch2.jobs.export.BulkDataExportProvider;
65
import ca.uhn.fhir.batch2.jobs.imprt.BulkDataImportProvider;
7-
import ca.uhn.fhir.batch2.jobs.reindex.ReindexJobParameters;
86
import ca.uhn.fhir.batch2.jobs.reindex.ReindexProvider;
9-
import ca.uhn.fhir.batch2.model.JobDefinition;
107
import ca.uhn.fhir.context.ConfigurationException;
118
import ca.uhn.fhir.context.FhirContext;
129
import ca.uhn.fhir.context.FhirVersionEnum;
@@ -21,7 +18,6 @@
2118
import ca.uhn.fhir.jpa.binary.provider.BinaryAccessProvider;
2219
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
2320
import ca.uhn.fhir.jpa.config.util.ResourceCountCacheUtil;
24-
2521
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
2622
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
2723
import ca.uhn.fhir.jpa.dao.search.HSearchSortHelperImpl;
@@ -35,9 +31,14 @@
3531
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
3632
import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc;
3733
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
38-
import ca.uhn.fhir.jpa.partition.PartitionManagementProvider;
34+
import ca.uhn.fhir.jpa.provider.DaoRegistryResourceSupportedSvc;
35+
import ca.uhn.fhir.jpa.provider.IJpaSystemProvider;
36+
import ca.uhn.fhir.jpa.provider.JpaCapabilityStatementProvider;
37+
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
38+
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
39+
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
40+
import ca.uhn.fhir.jpa.provider.ValueSetOperationProvider;
3941
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
40-
import ca.uhn.fhir.jpa.provider.*;
4142
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
4243
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
4344
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
@@ -49,39 +50,54 @@
4950
import ca.uhn.fhir.jpa.starter.util.EnvironmentHelper;
5051
import ca.uhn.fhir.jpa.subscription.util.SubscriptionDebugLogInterceptor;
5152
import ca.uhn.fhir.jpa.util.ResourceCountCache;
52-
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChain;
5353
import ca.uhn.fhir.mdm.provider.MdmProviderLoader;
5454
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
5555
import ca.uhn.fhir.narrative2.NullNarrativeGenerator;
5656
import ca.uhn.fhir.rest.api.IResourceSupportedSvc;
5757
import ca.uhn.fhir.rest.openapi.OpenApiInterceptor;
58-
import ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor;
59-
import ca.uhn.fhir.rest.server.*;
60-
import ca.uhn.fhir.rest.server.interceptor.*;
58+
import ca.uhn.fhir.rest.server.ApacheProxyAddressStrategy;
59+
import ca.uhn.fhir.rest.server.ETagSupportEnum;
60+
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
61+
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
62+
import ca.uhn.fhir.rest.server.IncomingRequestAddressStrategy;
63+
import ca.uhn.fhir.rest.server.RestfulServer;
64+
import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
65+
import ca.uhn.fhir.rest.server.interceptor.FhirPathFilterInterceptor;
66+
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
67+
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
68+
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
69+
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
6170
import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
62-
import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy;
6371
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
6472
import ca.uhn.fhir.validation.IValidatorModule;
6573
import ca.uhn.fhir.validation.ResultSeverityEnum;
6674
import com.google.common.base.Strings;
6775
import jakarta.persistence.EntityManagerFactory;
68-
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
6976
import org.slf4j.Logger;
7077
import org.slf4j.LoggerFactory;
7178
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
7279
import org.springframework.beans.factory.annotation.Autowired;
7380
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
7481
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7582
import org.springframework.context.ApplicationContext;
76-
import org.springframework.context.annotation.*;
83+
import org.springframework.context.annotation.Bean;
84+
import org.springframework.context.annotation.ComponentScan;
85+
import org.springframework.context.annotation.Conditional;
86+
import org.springframework.context.annotation.Configuration;
87+
import org.springframework.context.annotation.Import;
88+
import org.springframework.context.annotation.Primary;
7789
import org.springframework.core.env.ConfigurableEnvironment;
7890
import org.springframework.http.HttpHeaders;
7991
import org.springframework.orm.jpa.JpaTransactionManager;
8092
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
8193
import org.springframework.web.cors.CorsConfiguration;
8294

83-
import java.util.*;
8495
import javax.sql.DataSource;
96+
import java.util.Arrays;
97+
import java.util.Collections;
98+
import java.util.List;
99+
import java.util.Map;
100+
import java.util.Optional;
85101

86102
import static ca.uhn.fhir.jpa.starter.common.validation.IRepositoryValidationInterceptorFactory.ENABLE_REPOSITORY_VALIDATING_INTERCEPTOR;
87103

@@ -267,7 +283,6 @@ public RestfulServer restfulServer(
267283
BulkDataImportProvider bulkDataImportProvider,
268284
ValueSetOperationProvider theValueSetOperationProvider,
269285
ReindexProvider reindexProvider,
270-
PartitionManagementProvider partitionManagementProvider,
271286
Optional<RepositoryValidatingInterceptor> repositoryValidatingInterceptor,
272287
IPackageInstallerSvc packageInstallerSvc,
273288
ThreadSafeResourceDeleterSvc theThreadSafeResourceDeleterSvc,
@@ -438,12 +453,7 @@ public RestfulServer restfulServer(
438453
// reindex Provider $reindex
439454
fhirServer.registerProvider(reindexProvider);
440455

441-
// Partitioning
442-
if (appProperties.getPartitioning() != null) {
443-
fhirServer.registerInterceptor(new RequestTenantPartitionInterceptor());
444-
fhirServer.setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
445-
fhirServer.registerProviders(partitionManagementProvider);
446-
}
456+
// Validation
447457
repositoryValidatingInterceptor.ifPresent(fhirServer::registerInterceptor);
448458

449459
// register custom interceptors

0 commit comments

Comments
 (0)