Skip to content

Commit 8621c0d

Browse files
jkiddoCopilot
andauthored
Feat/extra resource loading from npm (#784)
* Logic to do the basics * Added configurable folders * Scoped additional resources to - pr. IG * Updated telemetry version * Changed to set * Changed PostConstruct to Component and introduced use of PartitionCondition Added try-load of HAPI optimized dialect * Satisfying spotless * Reverted to default config * Apply spotless * Use core-provided feature Addling the binary content as its needed for example resource inspection * Update src/main/java/ca/uhn/fhir/jpa/starter/util/JpaHibernatePropertiesProvider.java Co-authored-by: Copilot <[email protected]> * Reverting dialect change - fit for a potential other PR * no message * Formatting * Update src/main/java/ca/uhn/fhir/jpa/starter/ig/ExtendedPackageInstallationSpec.java Co-authored-by: Copilot <[email protected]> * Bad AI ... bad bad AI ... * Formatting * bump of feature revision flag --------- Co-authored-by: Copilot <[email protected]>
1 parent 0114510 commit 8621c0d

File tree

8 files changed

+122
-61
lines changed

8 files changed

+122
-61
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
FROM docker.io/library/maven:3.9.9-eclipse-temurin-17 AS build-hapi
22
WORKDIR /tmp/hapi-fhir-jpaserver-starter
33

4-
ARG OPENTELEMETRY_JAVA_AGENT_VERSION=1.33.3
4+
ARG OPENTELEMETRY_JAVA_AGENT_VERSION=2.13.1
55
RUN curl -LSsO https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v${OPENTELEMETRY_JAVA_AGENT_VERSION}/opentelemetry-javaagent.jar
66

77
COPY pom.xml .

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings.ClientIdStrategyEnum;
66
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings.IdStrategyEnum;
77
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
8-
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
8+
import ca.uhn.fhir.jpa.starter.ig.ExtendedPackageInstallationSpec;
99
import ca.uhn.fhir.rest.api.EncodingEnum;
1010
import org.hl7.fhir.r4.model.Bundle;
1111
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -88,7 +88,9 @@ public class AppProperties {
8888
private Partitioning partitioning = null;
8989
private Boolean validate_resource_status_for_package_upload = true;
9090
private Boolean install_transitive_ig_dependencies = true;
91-
private Map<String, PackageInstallationSpec> implementationGuides = null;
91+
92+
private List<String> install_additional_resources_from_ig_folders = new ArrayList<>();
93+
private Map<String, ExtendedPackageInstallationSpec> implementationGuides = null;
9294
private String custom_content_path = null;
9395
private String app_content_path = null;
9496
private Boolean lastn_enabled = false;
@@ -157,11 +159,11 @@ public void setDefer_indexing_for_codesystems_of_size(Integer defer_indexing_for
157159
this.defer_indexing_for_codesystems_of_size = defer_indexing_for_codesystems_of_size;
158160
}
159161

160-
public Map<String, PackageInstallationSpec> getImplementationGuides() {
162+
public Map<String, ExtendedPackageInstallationSpec> getImplementationGuides() {
161163
return implementationGuides;
162164
}
163165

164-
public void setImplementationGuides(Map<String, PackageInstallationSpec> implementationGuides) {
166+
public void setImplementationGuides(Map<String, ExtendedPackageInstallationSpec> implementationGuides) {
165167
this.implementationGuides = implementationGuides;
166168
}
167169

@@ -710,6 +712,15 @@ public void setResource_dbhistory_enabled(Boolean resource_dbhistory_enabled) {
710712
this.resource_dbhistory_enabled = resource_dbhistory_enabled;
711713
}
712714

715+
public List<String> getInstall_additional_resources_from_ig_folders() {
716+
return install_additional_resources_from_ig_folders;
717+
}
718+
719+
public void setInstall_additional_resources_from_ig_folders(
720+
List<String> install_additional_resources_from_ig_folders) {
721+
this.install_additional_resources_from_ig_folders = install_additional_resources_from_ig_folders;
722+
}
723+
713724
public Boolean getPre_expand_value_sets() {
714725
return this.pre_expand_value_sets;
715726
}

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,6 @@ public PartitionSettings partitionSettings(AppProperties appProperties) {
325325
return retVal;
326326
}
327327

328-
@Bean
329-
public PartitionModeConfigurer partitionModeConfigurer() {
330-
return new PartitionModeConfigurer();
331-
}
332-
333328
@Primary
334329
@Bean
335330
public HibernatePropertiesProvider jpaStarterDialectProvider(
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package ca.uhn.fhir.jpa.starter.common;
2+
3+
import ca.uhn.fhir.jpa.starter.AppProperties;
4+
import org.springframework.boot.context.properties.bind.Binder;
5+
import org.springframework.context.annotation.Condition;
6+
import org.springframework.context.annotation.ConditionContext;
7+
import org.springframework.core.type.AnnotatedTypeMetadata;
8+
9+
public class OnPartitionModeEnabled implements Condition {
10+
@Override
11+
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
12+
var appProperties = Binder.get(context.getEnvironment())
13+
.bind("hapi.fhir", AppProperties.class)
14+
.orElse(null);
15+
if (appProperties == null) return false;
16+
return appProperties.getPartitioning() != null;
17+
}
18+
}
Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package ca.uhn.fhir.jpa.starter.common;
22

3-
import ca.uhn.fhir.context.FhirContext;
43
import ca.uhn.fhir.jpa.interceptor.PatientIdPartitionInterceptor;
54
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
65
import ca.uhn.fhir.jpa.partition.PartitionManagementProvider;
@@ -9,48 +8,36 @@
98
import ca.uhn.fhir.rest.server.RestfulServer;
109
import ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor;
1110
import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy;
12-
import jakarta.annotation.PostConstruct;
1311
import org.slf4j.Logger;
1412
import org.slf4j.LoggerFactory;
15-
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.context.annotation.Conditional;
14+
import org.springframework.stereotype.Component;
1615

16+
@Component
17+
@Conditional({OnPartitionModeEnabled.class})
1718
public class PartitionModeConfigurer {
1819
private static final Logger ourLog = LoggerFactory.getLogger(PartitionModeConfigurer.class);
1920

20-
@Autowired
21-
private AppProperties myAppProperties;
22-
23-
@Autowired
24-
private FhirContext myFhirContext;
25-
26-
@Autowired
27-
private ISearchParamExtractor mySearchParamExtractor;
28-
29-
@Autowired
30-
private PartitionSettings myPartitionSettings;
31-
32-
@Autowired
33-
private RestfulServer myRestfulServer;
34-
35-
@Autowired
36-
private PartitionManagementProvider myPartitionManagementProvider;
37-
38-
@PostConstruct
39-
public void start() {
40-
if (myAppProperties.getPartitioning() != null) {
41-
if (myAppProperties.getPartitioning().getPatient_id_partitioning_mode() == Boolean.TRUE) {
42-
ourLog.info("Partitioning mode enabled in: Patient ID partitioning mode");
43-
PatientIdPartitionInterceptor patientIdInterceptor =
44-
new PatientIdPartitionInterceptor(myFhirContext, mySearchParamExtractor, myPartitionSettings);
45-
myRestfulServer.registerInterceptor(patientIdInterceptor);
46-
myPartitionSettings.setUnnamedPartitionMode(true);
47-
} else if (myAppProperties.getPartitioning().getRequest_tenant_partitioning_mode() == Boolean.TRUE) {
48-
ourLog.info("Partitioning mode enabled in: Request tenant partitioning mode");
49-
myRestfulServer.registerInterceptor(new RequestTenantPartitionInterceptor());
50-
myRestfulServer.setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
51-
}
52-
53-
myRestfulServer.registerProviders(myPartitionManagementProvider);
21+
public PartitionModeConfigurer(
22+
AppProperties myAppProperties,
23+
ISearchParamExtractor mySearchParamExtractor,
24+
PartitionSettings myPartitionSettings,
25+
RestfulServer myRestfulServer,
26+
PartitionManagementProvider myPartitionManagementProvider) {
27+
28+
var partitioning = myAppProperties.getPartitioning();
29+
if (partitioning.getPatient_id_partitioning_mode()) {
30+
ourLog.info("Partitioning mode enabled in: Patient ID partitioning mode");
31+
var patientIdInterceptor = new PatientIdPartitionInterceptor(
32+
myRestfulServer.getFhirContext(), mySearchParamExtractor, myPartitionSettings);
33+
myRestfulServer.registerInterceptor(patientIdInterceptor);
34+
myPartitionSettings.setUnnamedPartitionMode(true);
35+
} else if (partitioning.getRequest_tenant_partitioning_mode()) {
36+
ourLog.info("Partitioning mode enabled in: Request tenant partitioning mode");
37+
myRestfulServer.registerInterceptor(new RequestTenantPartitionInterceptor());
38+
myRestfulServer.setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
5439
}
40+
41+
myRestfulServer.registerProviders(myPartitionManagementProvider);
5542
}
5643
}

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

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import ca.uhn.fhir.context.FhirVersionEnum;
1010
import ca.uhn.fhir.context.support.IValidationSupport;
1111
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
12+
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
1213
import ca.uhn.fhir.jpa.api.IDaoRegistry;
1314
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
1415
import ca.uhn.fhir.jpa.api.config.ThreadPoolFactoryConfig;
@@ -20,6 +21,7 @@
2021
import ca.uhn.fhir.jpa.config.util.ResourceCountCacheUtil;
2122
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
2223
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
24+
import ca.uhn.fhir.jpa.dao.TransactionProcessor;
2325
import ca.uhn.fhir.jpa.dao.search.HSearchSortHelperImpl;
2426
import ca.uhn.fhir.jpa.dao.search.IHSearchSortHelper;
2527
import ca.uhn.fhir.jpa.delete.ThreadSafeResourceDeleterSvc;
@@ -29,8 +31,9 @@
2931
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor;
3032
import ca.uhn.fhir.jpa.ips.provider.IpsOperationProvider;
3133
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
34+
import ca.uhn.fhir.jpa.packages.AdditionalResourcesParser;
35+
import ca.uhn.fhir.jpa.packages.IHapiPackageCacheManager;
3236
import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc;
33-
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
3437
import ca.uhn.fhir.jpa.provider.DaoRegistryResourceSupportedSvc;
3538
import ca.uhn.fhir.jpa.provider.DiffProvider;
3639
import ca.uhn.fhir.jpa.provider.IJpaSystemProvider;
@@ -47,6 +50,7 @@
4750
import ca.uhn.fhir.jpa.starter.annotations.OnCorsPresent;
4851
import ca.uhn.fhir.jpa.starter.annotations.OnImplementationGuidesPresent;
4952
import ca.uhn.fhir.jpa.starter.common.validation.IRepositoryValidationInterceptorFactory;
53+
import ca.uhn.fhir.jpa.starter.ig.ExtendedPackageInstallationSpec;
5054
import ca.uhn.fhir.jpa.starter.ig.IImplementationGuideOperationProvider;
5155
import ca.uhn.fhir.jpa.starter.util.EnvironmentHelper;
5256
import ca.uhn.fhir.jpa.subscription.util.SubscriptionDebugLogInterceptor;
@@ -55,6 +59,7 @@
5559
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
5660
import ca.uhn.fhir.narrative2.NullNarrativeGenerator;
5761
import ca.uhn.fhir.rest.api.IResourceSupportedSvc;
62+
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
5863
import ca.uhn.fhir.rest.openapi.OpenApiInterceptor;
5964
import ca.uhn.fhir.rest.server.ApacheProxyAddressStrategy;
6065
import ca.uhn.fhir.rest.server.ETagSupportEnum;
@@ -74,6 +79,7 @@
7479
import ca.uhn.fhir.validation.ResultSeverityEnum;
7580
import com.google.common.base.Strings;
7681
import jakarta.persistence.EntityManagerFactory;
82+
import org.hl7.fhir.instance.model.api.IBaseBundle;
7783
import org.slf4j.Logger;
7884
import org.slf4j.LoggerFactory;
7985
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -93,11 +99,8 @@
9399
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
94100
import org.springframework.web.cors.CorsConfiguration;
95101

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;
102+
import java.io.IOException;
103+
import java.util.*;
101104
import javax.sql.DataSource;
102105

103106
import static ca.uhn.fhir.jpa.starter.common.validation.IRepositoryValidationInterceptorFactory.ENABLE_REPOSITORY_VALIDATING_INTERCEPTOR;
@@ -207,14 +210,18 @@ public LoggingInterceptor loggingInterceptor(AppProperties appProperties) {
207210
public IPackageInstallerSvc packageInstaller(
208211
AppProperties appProperties,
209212
IPackageInstallerSvc packageInstallerSvc,
210-
Batch2JobRegisterer batch2JobRegisterer) {
213+
Batch2JobRegisterer batch2JobRegisterer,
214+
FhirContext fhirContext,
215+
TransactionProcessor transactionProcessor,
216+
IHapiPackageCacheManager iHapiPackageCacheManager)
217+
throws IOException {
211218

212219
batch2JobRegisterer.start();
213220

214221
if (appProperties.getImplementationGuides() != null) {
215-
Map<String, PackageInstallationSpec> guides = appProperties.getImplementationGuides();
216-
for (Map.Entry<String, PackageInstallationSpec> guidesEntry : guides.entrySet()) {
217-
PackageInstallationSpec packageInstallationSpec = guidesEntry.getValue();
222+
Map<String, ExtendedPackageInstallationSpec> guides = appProperties.getImplementationGuides();
223+
for (Map.Entry<String, ExtendedPackageInstallationSpec> guidesEntry : guides.entrySet()) {
224+
ExtendedPackageInstallationSpec packageInstallationSpec = guidesEntry.getValue();
218225
if (appProperties.getInstall_transitive_ig_dependencies()) {
219226

220227
packageInstallationSpec
@@ -223,7 +230,22 @@ public IPackageInstallerSvc packageInstaller(
223230
.addDependencyExclude("hl7.fhir.r4.core")
224231
.addDependencyExclude("hl7.fhir.r5.core");
225232
}
233+
226234
packageInstallerSvc.install(packageInstallationSpec);
235+
236+
Set<String> extraResources = packageInstallationSpec.getAdditionalResourceFolders();
237+
packageInstallationSpec.setPackageContents(iHapiPackageCacheManager
238+
.loadPackageContents(packageInstallationSpec.getName(), packageInstallationSpec.getVersion())
239+
.getBytes());
240+
241+
if (extraResources != null && !extraResources.isEmpty()) {
242+
IBaseBundle transaction = AdditionalResourcesParser.bundleAdditionalResources(
243+
extraResources, packageInstallationSpec, fhirContext);
244+
transactionProcessor.transaction(
245+
new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.defaultPartition()),
246+
transaction,
247+
false);
248+
}
227249
}
228250
}
229251
return packageInstallerSvc;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package ca.uhn.fhir.jpa.starter.ig;
2+
3+
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import io.swagger.v3.oas.annotations.media.Schema;
6+
7+
import java.util.Set;
8+
9+
public class ExtendedPackageInstallationSpec extends PackageInstallationSpec {
10+
11+
public Set<String> getAdditionalResourceFolders() {
12+
return additionalResourceFolders;
13+
}
14+
15+
public void setAdditionalResourceFolders(Set<String> additionalResourceFolders) {
16+
this.additionalResourceFolders = additionalResourceFolders;
17+
}
18+
19+
@Schema(
20+
description =
21+
"Specifies folder names containing additional resources to load. These folders will be scanned for resources to include during installation.")
22+
@JsonProperty("additionalResourceFolders")
23+
private Set<String> additionalResourceFolders;
24+
}

src/main/resources/application.yaml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,14 @@ hapi:
171171
# reloadExisting: false
172172
# installMode: STORE_AND_INSTALL
173173
# example not from registry
174-
# ips_1_0_0:
175-
# packageUrl: https://build.fhir.org/ig/HL7/fhir-ips/package.tgz
176-
# name: hl7.fhir.uv.ips
177-
# version: 1.0.0
174+
# ips_1_0_0:
175+
# packageUrl: https://costateixeira.github.io/smart-ips-pilgrimage-fulltest/package.tgz
176+
# name: smart.who.int.ips-pilgrimage-test
177+
# version: 0.1.0
178+
# installMode: STORE_AND_INSTALL
179+
# additionalResourceFolders:
180+
# - example
181+
# - example2
178182
# supported_resource_types:
179183
# - Patient
180184
# - Observation

0 commit comments

Comments
 (0)