Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
130b6ba
Logic to do the basics
jkiddo Feb 21, 2025
926cc95
Added configurable folders
jkiddo Feb 22, 2025
2e294d8
Scoped additional resources to - pr. IG
jkiddo Feb 22, 2025
36202d8
Updated telemetry version
jkiddo Feb 23, 2025
4b509a8
Changed to set
jkiddo Feb 24, 2025
578ee8b
Merge branch 'hapi-master' into feat/extra-resource-loading-from-npm
jkiddo Feb 24, 2025
e6b4866
Changed PostConstruct to Component and introduced use of PartitionCon…
jkiddo Feb 24, 2025
8fafde9
Satisfying spotless
jkiddo Feb 24, 2025
dea6fc6
Reverted to default config
jkiddo Feb 27, 2025
224b2bd
Merge branch 'hapi-master' into feat/extra-resource-loading-from-npm
jkiddo Mar 1, 2025
bad73a5
Apply spotless
jkiddo Mar 1, 2025
99e76ae
Merge branch 'master' into feat/extra-resource-loading-from-npm
jkiddo Mar 2, 2025
5e81861
Merge branch 'hapifhir:master' into feat/extra-resource-loading-from-npm
jkiddo Mar 26, 2025
3206140
Merge branch 'hapi-master' into feat/extra-resource-loading-from-npm
jkiddo May 7, 2025
ba8b38e
Merge branch 'hapifhir:master' into feat/extra-resource-loading-from-npm
jkiddo May 25, 2025
b2e4d61
Use core-provided feature
jkiddo May 26, 2025
c9d2aaf
Update src/main/java/ca/uhn/fhir/jpa/starter/util/JpaHibernatePropert…
jkiddo May 26, 2025
3149a6a
Merge branch 'master' into feat/extra-resource-loading-from-npm
jkiddo Jun 5, 2025
0e75261
Reverting dialect change - fit for a potential other PR
jkiddo Jun 5, 2025
8f5c657
Merge branch 'master' into feat/extra-resource-loading-from-npm
jkiddo Aug 25, 2025
5766fee
no message
jkiddo Aug 25, 2025
66575b4
Formatting
jkiddo Aug 25, 2025
4a69b63
Update src/main/java/ca/uhn/fhir/jpa/starter/ig/ExtendedPackageInstal…
jkiddo Aug 25, 2025
10ef2b0
Bad AI ... bad bad AI ...
jkiddo Aug 25, 2025
d43edb1
Formatting
jkiddo Aug 25, 2025
38847e9
bump of feature revision flag
jkiddo Aug 25, 2025
5593452
Merge branch 'hapifhir:master' into feat/extra-resource-loading-from-npm
jkiddo Aug 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM docker.io/library/maven:3.9.9-eclipse-temurin-17 AS build-hapi
WORKDIR /tmp/hapi-fhir-jpaserver-starter

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

COPY pom.xml .
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>8.2.0</version>
<version>8.4.0</version>
</parent>

<artifactId>hapi-fhir-jpaserver-starter</artifactId>
Expand Down
19 changes: 15 additions & 4 deletions src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings.ClientIdStrategyEnum;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings.IdStrategyEnum;
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
import ca.uhn.fhir.jpa.starter.ig.ExtendedPackageInstallationSpec;
import ca.uhn.fhir.rest.api.EncodingEnum;
import org.hl7.fhir.r4.model.Bundle;
import org.springframework.boot.context.properties.ConfigurationProperties;
Expand Down Expand Up @@ -88,7 +88,9 @@ public class AppProperties {
private Partitioning partitioning = null;
private Boolean validate_resource_status_for_package_upload = true;
private Boolean install_transitive_ig_dependencies = true;
private Map<String, PackageInstallationSpec> implementationGuides = null;

private List<String> install_additional_resources_from_ig_folders = new ArrayList<>();
private Map<String, ExtendedPackageInstallationSpec> implementationGuides = null;
private String custom_content_path = null;
private String app_content_path = null;
private Boolean lastn_enabled = false;
Expand Down Expand Up @@ -157,11 +159,11 @@ public void setDefer_indexing_for_codesystems_of_size(Integer defer_indexing_for
this.defer_indexing_for_codesystems_of_size = defer_indexing_for_codesystems_of_size;
}

public Map<String, PackageInstallationSpec> getImplementationGuides() {
public Map<String, ExtendedPackageInstallationSpec> getImplementationGuides() {
return implementationGuides;
}

public void setImplementationGuides(Map<String, PackageInstallationSpec> implementationGuides) {
public void setImplementationGuides(Map<String, ExtendedPackageInstallationSpec> implementationGuides) {
this.implementationGuides = implementationGuides;
}

Expand Down Expand Up @@ -710,6 +712,15 @@ public void setResource_dbhistory_enabled(Boolean resource_dbhistory_enabled) {
this.resource_dbhistory_enabled = resource_dbhistory_enabled;
}

public List<String> getInstall_additional_resources_from_ig_folders() {
return install_additional_resources_from_ig_folders;
}

public void setInstall_additional_resources_from_ig_folders(
List<String> install_additional_resources_from_ig_folders) {
this.install_additional_resources_from_ig_folders = install_additional_resources_from_ig_folders;
}

public Boolean getPre_expand_value_sets() {
return this.pre_expand_value_sets;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,11 +325,6 @@ public PartitionSettings partitionSettings(AppProperties appProperties) {
return retVal;
}

@Bean
public PartitionModeConfigurer partitionModeConfigurer() {
return new PartitionModeConfigurer();
}

@Primary
@Bean
public HibernatePropertiesProvider jpaStarterDialectProvider(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ca.uhn.fhir.jpa.starter.common;

import ca.uhn.fhir.jpa.starter.AppProperties;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class OnPartitionModeEnabled implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
var appProperties = Binder.get(context.getEnvironment())
.bind("hapi.fhir", AppProperties.class)
.orElse(null);
if (appProperties == null) return false;
return appProperties.getPartitioning() != null;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package ca.uhn.fhir.jpa.starter.common;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.interceptor.PatientIdPartitionInterceptor;
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.partition.PartitionManagementProvider;
Expand All @@ -9,48 +8,36 @@
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor;
import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;

@Component
@Conditional({OnPartitionModeEnabled.class})
public class PartitionModeConfigurer {
private static final Logger ourLog = LoggerFactory.getLogger(PartitionModeConfigurer.class);

@Autowired
private AppProperties myAppProperties;

@Autowired
private FhirContext myFhirContext;

@Autowired
private ISearchParamExtractor mySearchParamExtractor;

@Autowired
private PartitionSettings myPartitionSettings;

@Autowired
private RestfulServer myRestfulServer;

@Autowired
private PartitionManagementProvider myPartitionManagementProvider;

@PostConstruct
public void start() {
if (myAppProperties.getPartitioning() != null) {
if (myAppProperties.getPartitioning().getPatient_id_partitioning_mode() == Boolean.TRUE) {
ourLog.info("Partitioning mode enabled in: Patient ID partitioning mode");
PatientIdPartitionInterceptor patientIdInterceptor =
new PatientIdPartitionInterceptor(myFhirContext, mySearchParamExtractor, myPartitionSettings);
myRestfulServer.registerInterceptor(patientIdInterceptor);
myPartitionSettings.setUnnamedPartitionMode(true);
} else if (myAppProperties.getPartitioning().getRequest_tenant_partitioning_mode() == Boolean.TRUE) {
ourLog.info("Partitioning mode enabled in: Request tenant partitioning mode");
myRestfulServer.registerInterceptor(new RequestTenantPartitionInterceptor());
myRestfulServer.setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
}

myRestfulServer.registerProviders(myPartitionManagementProvider);
public PartitionModeConfigurer(
AppProperties myAppProperties,
ISearchParamExtractor mySearchParamExtractor,
PartitionSettings myPartitionSettings,
RestfulServer myRestfulServer,
PartitionManagementProvider myPartitionManagementProvider) {

var partitioning = myAppProperties.getPartitioning();
if (partitioning.getPatient_id_partitioning_mode()) {
ourLog.info("Partitioning mode enabled in: Patient ID partitioning mode");
var patientIdInterceptor = new PatientIdPartitionInterceptor(
myRestfulServer.getFhirContext(), mySearchParamExtractor, myPartitionSettings);
myRestfulServer.registerInterceptor(patientIdInterceptor);
myPartitionSettings.setUnnamedPartitionMode(true);
} else if (partitioning.getRequest_tenant_partitioning_mode()) {
ourLog.info("Partitioning mode enabled in: Request tenant partitioning mode");
myRestfulServer.registerInterceptor(new RequestTenantPartitionInterceptor());
myRestfulServer.setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
}

myRestfulServer.registerProviders(myPartitionManagementProvider);
}
}
42 changes: 32 additions & 10 deletions src/main/java/ca/uhn/fhir/jpa/starter/common/StarterJpaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.IDaoRegistry;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.api.config.ThreadPoolFactoryConfig;
Expand All @@ -20,6 +21,7 @@
import ca.uhn.fhir.jpa.config.util.ResourceCountCacheUtil;
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.dao.TransactionProcessor;
import ca.uhn.fhir.jpa.dao.search.HSearchSortHelperImpl;
import ca.uhn.fhir.jpa.dao.search.IHSearchSortHelper;
import ca.uhn.fhir.jpa.delete.ThreadSafeResourceDeleterSvc;
Expand All @@ -29,8 +31,9 @@
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor;
import ca.uhn.fhir.jpa.ips.provider.IpsOperationProvider;
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
import ca.uhn.fhir.jpa.packages.AdditionalResourcesParser;
import ca.uhn.fhir.jpa.packages.IHapiPackageCacheManager;
import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc;
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
import ca.uhn.fhir.jpa.provider.DaoRegistryResourceSupportedSvc;
import ca.uhn.fhir.jpa.provider.DiffProvider;
import ca.uhn.fhir.jpa.provider.IJpaSystemProvider;
Expand All @@ -47,6 +50,7 @@
import ca.uhn.fhir.jpa.starter.annotations.OnCorsPresent;
import ca.uhn.fhir.jpa.starter.annotations.OnImplementationGuidesPresent;
import ca.uhn.fhir.jpa.starter.common.validation.IRepositoryValidationInterceptorFactory;
import ca.uhn.fhir.jpa.starter.ig.ExtendedPackageInstallationSpec;
import ca.uhn.fhir.jpa.starter.ig.IImplementationGuideOperationProvider;
import ca.uhn.fhir.jpa.starter.util.EnvironmentHelper;
import ca.uhn.fhir.jpa.subscription.util.SubscriptionDebugLogInterceptor;
Expand All @@ -55,6 +59,7 @@
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.narrative2.NullNarrativeGenerator;
import ca.uhn.fhir.rest.api.IResourceSupportedSvc;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.rest.openapi.OpenApiInterceptor;
import ca.uhn.fhir.rest.server.ApacheProxyAddressStrategy;
import ca.uhn.fhir.rest.server.ETagSupportEnum;
Expand All @@ -74,6 +79,7 @@
import ca.uhn.fhir.validation.ResultSeverityEnum;
import com.google.common.base.Strings;
import jakarta.persistence.EntityManagerFactory;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
Expand All @@ -93,11 +99,8 @@
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.web.cors.CorsConfiguration;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.io.IOException;
import java.util.*;
import javax.sql.DataSource;

import static ca.uhn.fhir.jpa.starter.common.validation.IRepositoryValidationInterceptorFactory.ENABLE_REPOSITORY_VALIDATING_INTERCEPTOR;
Expand Down Expand Up @@ -207,14 +210,18 @@ public LoggingInterceptor loggingInterceptor(AppProperties appProperties) {
public IPackageInstallerSvc packageInstaller(
AppProperties appProperties,
IPackageInstallerSvc packageInstallerSvc,
Batch2JobRegisterer batch2JobRegisterer) {
Batch2JobRegisterer batch2JobRegisterer,
FhirContext fhirContext,
TransactionProcessor transactionProcessor,
IHapiPackageCacheManager iHapiPackageCacheManager)
throws IOException {

batch2JobRegisterer.start();

if (appProperties.getImplementationGuides() != null) {
Map<String, PackageInstallationSpec> guides = appProperties.getImplementationGuides();
for (Map.Entry<String, PackageInstallationSpec> guidesEntry : guides.entrySet()) {
PackageInstallationSpec packageInstallationSpec = guidesEntry.getValue();
Map<String, ExtendedPackageInstallationSpec> guides = appProperties.getImplementationGuides();
for (Map.Entry<String, ExtendedPackageInstallationSpec> guidesEntry : guides.entrySet()) {
ExtendedPackageInstallationSpec packageInstallationSpec = guidesEntry.getValue();
if (appProperties.getInstall_transitive_ig_dependencies()) {

packageInstallationSpec
Expand All @@ -223,7 +230,22 @@ public IPackageInstallerSvc packageInstaller(
.addDependencyExclude("hl7.fhir.r4.core")
.addDependencyExclude("hl7.fhir.r5.core");
}

packageInstallerSvc.install(packageInstallationSpec);

Set<String> extraResources = packageInstallationSpec.getAdditionalResourceFolders();
packageInstallationSpec.setPackageContents(iHapiPackageCacheManager
.loadPackageContents(packageInstallationSpec.getName(), packageInstallationSpec.getVersion())
.getBytes());

if (extraResources != null && !extraResources.isEmpty()) {
IBaseBundle transaction = AdditionalResourcesParser.bundleAdditionalResources(
extraResources, packageInstallationSpec, fhirContext);
transactionProcessor.transaction(
new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.defaultPartition()),
transaction,
false);
}
}
}
return packageInstallerSvc;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ca.uhn.fhir.jpa.starter.ig;

import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;

import java.util.Set;

public class ExtendedPackageInstallationSpec extends PackageInstallationSpec {

public Set<String> getAdditionalResourceFolders() {
return additionalResourceFolders;
}

public void setAdditionalResourceFolders(Set<String> additionalResourceFolders) {
this.additionalResourceFolders = additionalResourceFolders;
}

@Schema(
description =
"Specifies folder names containing additional resources to load. These folders will be scanned for resources to include during installation.")
@JsonProperty("additionalResourceFolders")
private Set<String> additionalResourceFolders;
}
12 changes: 8 additions & 4 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,14 @@ hapi:
# reloadExisting: false
# installMode: STORE_AND_INSTALL
# example not from registry
# ips_1_0_0:
# packageUrl: https://build.fhir.org/ig/HL7/fhir-ips/package.tgz
# name: hl7.fhir.uv.ips
# version: 1.0.0
# ips_1_0_0:
# packageUrl: https://costateixeira.github.io/smart-ips-pilgrimage-fulltest/package.tgz
# name: smart.who.int.ips-pilgrimage-test
# version: 0.1.0
# installMode: STORE_AND_INSTALL
# additionalResourceFolders:
# - example
# - example2
# supported_resource_types:
# - Patient
# - Observation
Expand Down
Loading