Added support for hybrid remote terminology

This commit is contained in:
Jens Kristian Villadsen
2025-03-19 13:46:51 +01:00
parent 5dacdd1795
commit 9cf166e765
4 changed files with 87 additions and 1 deletions

View File

@@ -106,6 +106,8 @@ public class AppProperties {
private Integer pre_expand_value_sets_max_count = 1000; private Integer pre_expand_value_sets_max_count = 1000;
private Integer maximum_expansion_size = 1000; private Integer maximum_expansion_size = 1000;
private Map<String, RemoteSystem> remote_terminology_service = null;
public List<String> getCustomInterceptorClasses() { public List<String> getCustomInterceptorClasses() {
return custom_interceptor_classes; return custom_interceptor_classes;
} }
@@ -723,6 +725,14 @@ public class AppProperties {
this.maximum_expansion_size = maximum_expansion_size; this.maximum_expansion_size = maximum_expansion_size;
} }
public Map<String, RemoteSystem> getRemoteTerminologyServicesMap() {
return remote_terminology_service;
}
public void setRemote_terminology_service(Map<String, RemoteSystem> remote_terminology_service) {
this.remote_terminology_service = remote_terminology_service;
}
public static class Cors { public static class Cors {
private Boolean allow_Credentials = true; private Boolean allow_Credentials = true;
private List<String> allowed_origin = List.of("*"); private List<String> allowed_origin = List.of("*");
@@ -918,6 +928,26 @@ public class AppProperties {
request_tenant_partitioning_mode = theRequest_tenant_partitioning_mode; request_tenant_partitioning_mode = theRequest_tenant_partitioning_mode;
} }
} }
public static class RemoteSystem{
private String system;
private String url;
public String getSystem() {
return system;
}
public void setSystem(String system) {
this.system = system;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
public static class Subscription { public static class Subscription {

View File

@@ -1,9 +1,18 @@
package ca.uhn.fhir.jpa.starter.common; package ca.uhn.fhir.jpa.starter.common;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.ConceptValidationOptions;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.jpa.config.r4.JpaR4Config; import ca.uhn.fhir.jpa.config.r4.JpaR4Config;
import ca.uhn.fhir.jpa.starter.AppProperties;
import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition; import ca.uhn.fhir.jpa.starter.annotations.OnR4Condition;
import ca.uhn.fhir.jpa.starter.common.validation.OnRemoteTerminologyPresent;
import ca.uhn.fhir.jpa.starter.cr.StarterCrR4Config; import ca.uhn.fhir.jpa.starter.cr.StarterCrR4Config;
import ca.uhn.fhir.jpa.starter.ips.StarterIpsConfig; import ca.uhn.fhir.jpa.starter.ips.StarterIpsConfig;
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@@ -17,4 +26,24 @@ import org.springframework.context.annotation.Import;
ElasticsearchConfig.class, ElasticsearchConfig.class,
StarterIpsConfig.class StarterIpsConfig.class
}) })
public class FhirServerConfigR4 {} public class FhirServerConfigR4 {
@Bean(name = "myHybridRemoteValidationSupportChain")
@Conditional({OnR4Condition.class, OnRemoteTerminologyPresent.class})
public IValidationSupport addRemoteValidation(ValidationSupportChain theValidationSupport, FhirContext theFhirContext, AppProperties theAppProperties)
{
theAppProperties.getRemoteTerminologyServicesMap().forEach((key, remoteSystem) -> {
theValidationSupport.addValidationSupport(0 , new RemoteTerminologyServiceValidationSupport(theFhirContext, remoteSystem.getUrl()){
@Override
public CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) {
if (remoteSystem.getSystem().equalsIgnoreCase(theCodeSystem)) {
return super.validateCode(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSetUrl);
}
return null;
}
});
});
return theValidationSupport;
}
}

View File

@@ -0,0 +1,20 @@
package ca.uhn.fhir.jpa.starter.common.validation;
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 OnRemoteTerminologyPresent implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
AppProperties config = Binder.get(conditionContext.getEnvironment())
.bind("hapi.fhir", AppProperties.class)
.orElse(null);
if (config == null) return false;
if (config.getRemoteTerminologyServicesMap() == null) return false;
return !config.getRemoteTerminologyServicesMap().isEmpty();
}
}

View File

@@ -289,6 +289,13 @@ hapi:
# max_page_size: 200 # max_page_size: 200
# retain_cached_searches_mins: 60 # retain_cached_searches_mins: 60
# reuse_cached_search_results_millis: 60000 # reuse_cached_search_results_millis: 60000
remote_terminology_service:
snomed:
system: 'http://snomed.info/sct'
url: 'https://tx.fhir.org/r4/'
loinc:
system: 'http://loinc.org'
url: 'https://fhir.loinc.org/'
tester: tester:
home: home:
name: Local Tester name: Local Tester