Skip to content

Feat/extra resource loading from npm #784

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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.3.7-SNAPSHOT</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 @@ -4,7 +4,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 @@ -83,7 +83,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 @@ -148,11 +150,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 @@ -685,6 +687,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 @@ -291,11 +291,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 =
"If resources are being installed individually, this is list provides the resource types to install. By default, all conformance resources will be installed.")
@JsonProperty("additionalResourceFolders")
private Set<String> additionalResourceFolders;
}
25 changes: 16 additions & 9 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,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 Expand Up @@ -236,11 +240,14 @@ hapi:
- https://unitsofmeasure.org/*
- http://loinc.org/*
- https://loinc.org/*
# partitioning:
# allow_references_across_partitions: false
# partitioning_include_in_search_hashes: false
# conditional_create_duplicate_identifiers_enabled: false
# request_tenant_partitioning_mode: true
#partitioning:
# allow_references_across_partitions: true
# partitioning_include_in_search_hashes: true
# conditional_create_duplicate_identifiers_enabled: true
# patient-id-partitioning-mode: true
# request-tenant-partitioning-mode: true
# database-partition-mode-enabled: true
# default-partition-id: 0
cors:
allow_Credentials: true
# These are allowed_origin patterns, see: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/cors/CorsConfiguration.html#setAllowedOriginPatterns-java.util.List-
Expand Down
Loading