more work on multiple terminology servers

This commit is contained in:
Grahame Grieve 2024-01-12 09:16:16 +11:00
parent e2ba911f4e
commit 362e7e2600
13 changed files with 80 additions and 16 deletions

View File

@ -1,6 +1,6 @@
## Validator Changes ## Validator Changes
* no changes * Fix issues with multiple terminology servers (should be live soon)
## Other code changes ## Other code changes

View File

@ -231,7 +231,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
private Object lock = new Object(); // used as a lock for the data that follows private Object lock = new Object(); // used as a lock for the data that follows
protected String version; // although the internal resources are all R5, the version of FHIR they describe may not be protected String version; // although the internal resources are all R5, the version of FHIR they describe may not be
protected TerminologyClientManager terminologyClientManager = new TerminologyClientManager(new TerminologyClientR5Factory()); protected TerminologyClientManager terminologyClientManager = new TerminologyClientManager(null);
private boolean minimalMemory = false; private boolean minimalMemory = false;
private Map<String, Map<String, ResourceProxy>> allResourcesById = new HashMap<String, Map<String, ResourceProxy>>(); private Map<String, Map<String, ResourceProxy>> allResourcesById = new HashMap<String, Map<String, ResourceProxy>>();
@ -850,6 +850,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
} }
Set<String> systems = findRelevantSystems(vs); Set<String> systems = findRelevantSystems(vs);
TerminologyClientContext tc = terminologyClientManager.chooseServer(systems, true); TerminologyClientContext tc = terminologyClientManager.chooseServer(systems, true);
if (tc == null) {
res = new ValueSetExpansionOutcome("No server available", TerminologyServiceErrorClass.INTERNAL_ERROR, true);
}
Parameters p = constructParameters(tc, vs, hierarchical); Parameters p = constructParameters(tc, vs, hierarchical);
for (ConceptSetComponent incl : vs.getCompose().getInclude()) { for (ConceptSetComponent incl : vs.getCompose().getInclude()) {
codeSystemsUsed.add(incl.getSystem()); codeSystemsUsed.add(incl.getSystem());
@ -1885,8 +1888,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
return expParameters; return expParameters;
} }
public void setExpansionProfile(Parameters expParameters) { public void setExpansionParameters(Parameters expParameters) {
this.expParameters = expParameters; this.expParameters = expParameters;
this.terminologyClientManager.setExpansionParameters(expParameters);
} }
@Override @Override

View File

@ -284,7 +284,7 @@ public interface IWorkerContext {
* *
* Note that the Validation Options override these when they are specified on validateCode * Note that the Validation Options override these when they are specified on validateCode
*/ */
public void setExpansionProfile(Parameters expParameters); public void setExpansionParameters(Parameters expParameters);
// these are the terminology services used internally by the tools // these are the terminology services used internally by the tools
/** /**

View File

@ -535,7 +535,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
version = "5.0.0"; version = "5.0.0";
} }
} }
if (loader != null) { if (loader != null && terminologyClientManager.getFactory() == null) {
terminologyClientManager.setFactory(loader.txFactory()); terminologyClientManager.setFactory(loader.txFactory());
} }
return t; return t;

View File

@ -1512,7 +1512,14 @@ public String toString() {
} }
return s; return s;
} }
public boolean hasValuePrimitive() {
return hasValue() && getValue() instanceof PrimitiveType<?>;
}
// end addition // end addition
} }
/** /**

View File

@ -2,7 +2,9 @@ package org.hl7.fhir.r5.terminologies.client;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -11,6 +13,8 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.hl7.fhir.exceptions.TerminologyServiceException; import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r5.model.TerminologyCapabilities; import org.hl7.fhir.r5.model.TerminologyCapabilities;
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache; import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache;
import org.hl7.fhir.utilities.ToolingClientLogger; import org.hl7.fhir.utilities.ToolingClientLogger;
@ -37,10 +41,12 @@ public class TerminologyClientManager {
private Map<String, TerminologyClientContext> serverMap = new HashMap<>(); // clients by server address private Map<String, TerminologyClientContext> serverMap = new HashMap<>(); // clients by server address
private Map<String, String> resMap = new HashMap<>(); // client resolution list private Map<String, String> resMap = new HashMap<>(); // client resolution list
private List<String> internalErrors = new ArrayList<>(); private List<String> internalErrors = new ArrayList<>();
protected Parameters expParameters;
private TerminologyCache cache; private TerminologyCache cache;
private File cacheFile; private File cacheFile;
private String usage;
private String monitorServiceURL; private String monitorServiceURL;
@ -65,7 +71,6 @@ public class TerminologyClientManager {
this.isTxCaching = isTxCaching; this.isTxCaching = isTxCaching;
} }
public void copy(TerminologyClientManager other) { public void copy(TerminologyClientManager other) {
cacheId = other.cacheId; cacheId = other.cacheId;
isTxCaching = other.isTxCaching; isTxCaching = other.isTxCaching;
@ -74,6 +79,7 @@ public class TerminologyClientManager {
resMap.putAll(other.resMap); resMap.putAll(other.resMap);
monitorServiceURL = other.monitorServiceURL; monitorServiceURL = other.monitorServiceURL;
factory = other.factory; factory = other.factory;
usage = other.usage;
} }
public boolean usingCache() { public boolean usingCache() {
@ -105,6 +111,13 @@ public class TerminologyClientManager {
String server = resMap.get(s); String server = resMap.get(s);
if (server == null) { if (server == null) {
server = decideWhichServer(s); server = decideWhichServer(s);
// testing support
if (server != null && server.contains("://tx.fhir.org")) {
try {
server = server.replace("tx.fhir.org", new URL(getMasterClient().getAddress()).getHost());
} catch (MalformedURLException e) {
}
}
resMap.put(s, server); resMap.put(s, server);
save(); save();
} }
@ -123,7 +136,27 @@ public class TerminologyClientManager {
} }
private String decideWhichServer(String url) { private String decideWhichServer(String url) {
if (expParameters != null) {
if (!url.contains("|")) {
// the client hasn''t specified an explicit version, but the expansion parameters might
for (ParametersParameterComponent p : expParameters.getParameter()) {
if (Utilities.existsInList(p.getName(), "system-version", "force-system-version") && p.hasValuePrimitive() && p.getValue().primitiveValue().startsWith(url+"|")) {
url = p.getValue().primitiveValue();
}
}
} else {
// the expansion parameters might override the version
for (ParametersParameterComponent p : expParameters.getParameter()) {
if (Utilities.existsInList(p.getName(), "force-system-version") && p.hasValueCanonicalType() && p.getValue().primitiveValue().startsWith(url+"|")) {
url = p.getValue().primitiveValue();
}
}
}
}
String request = Utilities.pathURL(monitorServiceURL, "resolve?fhirVersion="+factory.getVersion()+"&url="+url); String request = Utilities.pathURL(monitorServiceURL, "resolve?fhirVersion="+factory.getVersion()+"&url="+url);
if (usage != null) {
request = request + "&usage="+usage;
}
try { try {
JsonObject json = JsonParser.parseObjectFromUrl(request); JsonObject json = JsonParser.parseObjectFromUrl(request);
for (JsonObject item : json.getJsonObjects("authoritative")) { for (JsonObject item : json.getJsonObjects("authoritative")) {
@ -209,6 +242,7 @@ public class TerminologyClientManager {
public void setFactory(ITerminologyClientFactory factory) { public void setFactory(ITerminologyClientFactory factory) {
this.factory = factory; this.factory = factory;
System.out.println("tcc factory version = "+factory.getVersion());
} }
public void setCache(TerminologyCache cache) { public void setCache(TerminologyCache cache) {
@ -263,5 +297,21 @@ public class TerminologyClientManager {
} }
public Parameters getExpansionParameters() {
return expParameters;
}
public void setExpansionParameters(Parameters expParameters) {
this.expParameters = expParameters;
}
public String getUsage() {
return usage;
}
public void setUsage(String usage) {
this.usage = usage;
}
} }

View File

@ -86,7 +86,7 @@ public class TestingUtilities extends BaseTestingUtilities {
fcontext = getWorkerContext(pcm.loadPackage(VersionUtilities.packageForVersion(version), version)); fcontext = getWorkerContext(pcm.loadPackage(VersionUtilities.packageForVersion(version), version));
} }
fcontext.setUcumService(new UcumEssenceService(TestingUtilities.loadTestResourceStream("ucum", "ucum-essence.xml"))); fcontext.setUcumService(new UcumEssenceService(TestingUtilities.loadTestResourceStream("ucum", "ucum-essence.xml")));
fcontext.setExpansionProfile(new Parameters()); fcontext.setExpansionParameters(new Parameters());
if (!fcontext.hasPackage("hl7.terminology.r5", null)) { if (!fcontext.hasPackage("hl7.terminology.r5", null)) {
NpmPackage utg = pcm.loadPackage("hl7.terminology.r5"); NpmPackage utg = pcm.loadPackage("hl7.terminology.r5");
System.out.println("Loading THO: "+utg.name()+"#"+utg.version()); System.out.println("Loading THO: "+utg.name()+"#"+utg.version());

View File

@ -1,6 +1,8 @@
package org.hl7.fhir.r5.context; package org.hl7.fhir.r5.context;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import org.hl7.fhir.r5.terminologies.client.TerminologyClientR5.TerminologyClientR5Factory;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat;
@ -432,7 +434,7 @@ public class SimpleWorkerContextTests {
Mockito.doReturn(terminologyCapabilities).when(terminologyCache).getTerminologyCapabilities(); Mockito.doReturn(terminologyCapabilities).when(terminologyCache).getTerminologyCapabilities();
Mockito.doReturn(capabilitiesStatement).when(terminologyCache).getCapabilityStatement(); Mockito.doReturn(capabilitiesStatement).when(terminologyCache).getCapabilityStatement();
String actual = context.connectToTSServer(null, terminologyClient, null); String actual = context.connectToTSServer(new TerminologyClientR5Factory(), terminologyClient, null);
assertEquals("dummyVersion", actual); assertEquals("dummyVersion", actual);
@ -454,7 +456,7 @@ public class SimpleWorkerContextTests {
Mockito.doReturn(terminologyCapabilities).when(terminologyClient).getTerminologyCapabilities(); Mockito.doReturn(terminologyCapabilities).when(terminologyClient).getTerminologyCapabilities();
Mockito.doReturn(capabilitiesStatement).when(terminologyClient).getCapabilitiesStatementQuick(); Mockito.doReturn(capabilitiesStatement).when(terminologyClient).getCapabilitiesStatementQuick();
String actual = context.connectToTSServer(null, terminologyClient, null); String actual = context.connectToTSServer(new TerminologyClientR5Factory(), terminologyClient, null);
assertEquals("dummyVersion", actual); assertEquals("dummyVersion", actual);

View File

@ -477,7 +477,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
context.setCanNoTS(true); context.setCanNoTS(true);
context.setCacheId(UUID.randomUUID().toString()); context.setCacheId(UUID.randomUUID().toString());
context.setAllowLoadingDuplicates(true); // because of Forge context.setAllowLoadingDuplicates(true); // because of Forge
context.setExpansionProfile(makeExpProfile()); context.setExpansionParameters(makeExpProfile());
if (tt != null) { if (tt != null) {
context.setClock(tt); context.setClock(tt);
} }
@ -841,6 +841,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
public InstanceValidator getValidator(FhirFormat format) throws FHIRException, IOException { public InstanceValidator getValidator(FhirFormat format) throws FHIRException, IOException {
InstanceValidator validator = new InstanceValidator(context, null, null); InstanceValidator validator = new InstanceValidator(context, null, null);
context.getTxClientManager().setUsage("validation");
validator.setHintAboutNonMustSupport(hintAboutNonMustSupport); validator.setHintAboutNonMustSupport(hintAboutNonMustSupport);
validator.setAnyExtensionsAllowed(anyExtensionsAllowed); validator.setAnyExtensionsAllowed(anyExtensionsAllowed);
validator.getExtensionDomains().clear(); validator.getExtensionDomains().clear();

View File

@ -196,7 +196,7 @@ public class R4R5MapTester implements IValidatorResourceFetcher {
validator.setDebug(false); validator.setDebug(false);
validator.setForPublication(true); validator.setForPublication(true);
validator.setNoTerminologyChecks(true); validator.setNoTerminologyChecks(true);
context.setExpansionProfile(new Parameters()); context.setExpansionParameters(new Parameters());
log("Load R4 Examples"); log("Load R4 Examples");
NpmPackage r4Examples = pcm.loadPackage("hl7.fhir.r4.examples"); NpmPackage r4Examples = pcm.loadPackage("hl7.fhir.r4.examples");

View File

@ -90,7 +90,7 @@ public class UtilitiesXTests {
pcm = new FilesystemPackageCacheManager.Builder().build(); pcm = new FilesystemPackageCacheManager.Builder().build();
IWorkerContext fcontext = TestingUtilities.getWorkerContext(pcm.loadPackage(VersionUtilities.packageForVersion(version), version), loaderForVersion(version)); IWorkerContext fcontext = TestingUtilities.getWorkerContext(pcm.loadPackage(VersionUtilities.packageForVersion(version), version), loaderForVersion(version));
fcontext.setUcumService(new UcumEssenceService(UtilitiesXTests.loadTestResourceStream("ucum", "ucum-essence.xml"))); fcontext.setUcumService(new UcumEssenceService(UtilitiesXTests.loadTestResourceStream("ucum", "ucum-essence.xml")));
fcontext.setExpansionProfile(new Parameters()); fcontext.setExpansionParameters(new Parameters());
fcontexts.put(version, fcontext); fcontexts.put(version, fcontext);
} catch (Exception e) { } catch (Exception e) {
throw new Error(e); throw new Error(e);

View File

@ -140,9 +140,9 @@ public class TerminologyServiceTests {
fo.delete(); fo.delete();
} }
if (setup.test.has("profile")) { if (setup.test.has("profile")) {
engine.getContext().setExpansionProfile((org.hl7.fhir.r5.model.Parameters) loadResource(setup.test.asString("profile"))); engine.getContext().setExpansionParameters((org.hl7.fhir.r5.model.Parameters) loadResource(setup.test.asString("profile")));
} else { } else {
engine.getContext().setExpansionProfile((org.hl7.fhir.r5.model.Parameters) loadResource("parameters-default.json")); engine.getContext().setExpansionParameters((org.hl7.fhir.r5.model.Parameters) loadResource("parameters-default.json"));
} }
if (setup.test.asString("operation").equals("expand")) { if (setup.test.asString("operation").equals("expand")) {
expand(engine, req, resp, setup.test.asString("Content-Language"), fp, ext); expand(engine, req, resp, setup.test.asString("Content-Language"), fp, ext);

View File

@ -20,7 +20,7 @@
<properties> <properties>
<guava_version>32.0.1-jre</guava_version> <guava_version>32.0.1-jre</guava_version>
<hapi_fhir_version>6.4.1</hapi_fhir_version> <hapi_fhir_version>6.4.1</hapi_fhir_version>
<validator_test_case_version>1.4.21</validator_test_case_version> <validator_test_case_version>1.4.22-SNAPSHOT</validator_test_case_version>
<jackson_version>2.16.0</jackson_version> <jackson_version>2.16.0</jackson_version>
<junit_jupiter_version>5.9.2</junit_jupiter_version> <junit_jupiter_version>5.9.2</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version> <junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>