Fix issues with tracking supplement usage and getting supplement version matching correct

This commit is contained in:
Grahame Grieve 2024-12-19 13:15:15 +11:00
parent fd2bd896bf
commit 442ef9de3f

@ -59,6 +59,7 @@ import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
import org.hl7.fhir.r5.context.ILoggingService.LogCategory;
import org.hl7.fhir.r5.context.IWorkerContext.ITerminologyOperationDetails;
import org.hl7.fhir.r5.model.ActorDefinition;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.Bundle;
@ -849,7 +850,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
@Override
public ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean hierarchical, boolean noInactive) throws TerminologyServiceException {
public ValueSetExpansionOutcome expandVS(ITerminologyOperationDetails opCtxt, ConceptSetComponent inc, boolean hierarchical, boolean noInactive) throws TerminologyServiceException {
ValueSet vs = new ValueSet();
vs.setStatus(PublicationStatus.ACTIVE);
vs.setCompose(new ValueSetComposeComponent());
@ -866,7 +867,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
if (tc == null) {
return new ValueSetExpansionOutcome("No server available", TerminologyServiceErrorClass.INTERNAL_ERROR, true);
}
Parameters p = constructParameters(tc, vs, hierarchical);
Parameters p = constructParameters(opCtxt, tc, vs, hierarchical);
for (ConceptSetComponent incl : vs.getCompose().getInclude()) {
codeSystemsUsed.add(incl.getSystem());
}
@ -880,7 +881,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
p.addParameter("count", expandCodesLimit);
p.addParameter("offset", 0);
txLog("$expand on "+txCache.summary(vs)+" on "+tc.getAddress());
if (addDependentResources(tc, p, vs)) {
if (addDependentResources(opCtxt, tc, p, vs)) {
p.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId()));
}
@ -932,10 +933,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
p.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId()));
TerminologyClientContext tc = terminologyClientManager.chooseServer(url, true);
txLog("$expand "+url+" on "+tc.getAddress());
try {
if (tc == null) {
throw new FHIRException("Unable to find a server to expand '"+url+"'");
}
txLog("$expand "+url+" on "+tc.getAddress());
ValueSet result = tc.getClient().expandValueset(null, p);
if (result != null) {
if (!result.hasUrl()) {
@ -1043,7 +1046,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
p.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId()));
Set<String> systems = findRelevantSystems(vs);
TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, true);
addDependentResources(tc, p, vs);
addDependentResources(null, tc, p, vs);
txLog("$expand on "+txCache.summary(vs)+" on "+tc.getAddress());
@ -1534,12 +1537,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
return new ValueSetValidator(this, new TerminologyOperationContext(this, options, "validation"), options, vs, expParameters, terminologyClientManager);
}
protected Parameters constructParameters(TerminologyClientContext tcd, ValueSet vs, boolean hierarchical) {
protected Parameters constructParameters(ITerminologyOperationDetails opCtxt, TerminologyClientContext tcd, ValueSet vs, boolean hierarchical) {
Parameters p = expParameters.copy();
p.setParameter("includeDefinition", false);
p.setParameter("excludeNested", !hierarchical);
addDependentResources(tcd, p, vs);
addDependentResources(opCtxt, tcd, p, vs);
p.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId()));
return p;
}
@ -1789,7 +1792,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
}
addServerValidationParameters(tc, vs, pin, options, systems);
addServerValidationParameters(null, tc, vs, pin, options, systems);
if (txLog != null) {
txLog.clearLastId();
@ -1806,11 +1809,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
return processValidationResult(pOut, vs == null ? null : vs.getUrl(), tc.getClient().getAddress());
}
protected void addServerValidationParameters(TerminologyClientContext terminologyClientContext, ValueSet vs, Parameters pin, ValidationOptions options) {
addServerValidationParameters(terminologyClientContext, vs, pin, options, null);
protected void addServerValidationParameters(ITerminologyOperationDetails opCtxt, TerminologyClientContext terminologyClientContext, ValueSet vs, Parameters pin, ValidationOptions options) {
addServerValidationParameters(opCtxt, terminologyClientContext, vs, pin, options, null);
}
protected void addServerValidationParameters(TerminologyClientContext terminologyClientContext, ValueSet vs, Parameters pin, ValidationOptions options, Set<String> systems) {
protected void addServerValidationParameters(ITerminologyOperationDetails opCtxt, TerminologyClientContext terminologyClientContext, ValueSet vs, Parameters pin, ValidationOptions options, Set<String> systems) {
boolean cache = false;
if (vs != null) {
if (terminologyClientContext != null && terminologyClientContext.isTxCaching() && terminologyClientContext.getCacheId() != null && vs.getUrl() != null && terminologyClientContext.getCached().contains(vs.getUrl()+"|"+ vs.getVersion())) {
@ -1831,11 +1834,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
}
cache = true;
addDependentResources(terminologyClientContext, pin, vs);
addDependentResources(opCtxt, terminologyClientContext, pin, vs);
}
if (systems != null) {
for (String s : systems) {
cache = addDependentCodeSystem(terminologyClientContext, pin, s, null) || cache;
cache = addDependentCodeSystem(opCtxt, terminologyClientContext, pin, s, null) || cache;
}
}
pin.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId()));
@ -1855,29 +1858,32 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
pin.addParameter("diagnostics", true);
}
private boolean addDependentResources(TerminologyClientContext tc, Parameters pin, ValueSet vs) {
private boolean addDependentResources(ITerminologyOperationDetails opCtxt, TerminologyClientContext tc, Parameters pin, ValueSet vs) {
boolean cache = false;
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
cache = addDependentResources(tc, pin, inc, vs) || cache;
cache = addDependentResources(opCtxt, tc, pin, inc, vs) || cache;
}
for (ConceptSetComponent inc : vs.getCompose().getExclude()) {
cache = addDependentResources(tc, pin, inc, vs) || cache;
cache = addDependentResources(opCtxt, tc, pin, inc, vs) || cache;
}
return cache;
}
private boolean addDependentResources(TerminologyClientContext tc, Parameters pin, ConceptSetComponent inc, Resource src) {
private boolean addDependentResources(ITerminologyOperationDetails opCtxt, TerminologyClientContext tc, Parameters pin, ConceptSetComponent inc, Resource src) {
boolean cache = false;
for (CanonicalType c : inc.getValueSet()) {
ValueSet vs = fetchResource(ValueSet.class, c.getValue(), src);
if (vs != null && !hasCanonicalResource(pin, "tx-resource", vs.getVUrl())) {
cache = checkAddToParams(tc, pin, vs) || cache;
addDependentResources(tc, pin, vs);
addDependentResources(opCtxt, tc, pin, vs);
for (Extension ext : vs.getExtensionsByUrl(ToolingExtensions.EXT_VS_CS_SUPPL_NEEDED)) {
if (ext.hasValueCanonicalType()) {
String url = ext.getValueCanonicalType().asStringValue();
CodeSystem supp = fetchResource(CodeSystem.class, url);
if (supp != null) {
if (opCtxt != null) {
opCtxt.seeSupplement(supp);
}
cache = checkAddToParams(tc, pin, supp) || cache;
}
}
@ -1885,25 +1891,50 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
}
String sys = inc.getSystem();
cache = addDependentCodeSystem(tc, pin, sys, src) || cache;
cache = addDependentCodeSystem(opCtxt, tc, pin, sys, src) || cache;
return cache;
}
public boolean addDependentCodeSystem(TerminologyClientContext tc, Parameters pin, String sys, Resource src) {
public boolean addDependentCodeSystem(ITerminologyOperationDetails opCtxt, TerminologyClientContext tc, Parameters pin, String sys, Resource src) {
boolean cache = false;
CodeSystem cs = fetchResource(CodeSystem.class, sys, src);
if (cs != null && !hasCanonicalResource(pin, "tx-resource", cs.getVUrl()) && (cs.getContent() == CodeSystemContentMode.COMPLETE || cs.getContent() == CodeSystemContentMode.FRAGMENT)) {
cache = checkAddToParams(tc, pin, cs) || cache;
}
for (CodeSystem supp : codeSystems.getSupplements(cs)) {
//if (supp.getContent() == CodeSystemContentMode.SUPPLEMENT && supp.getSupplements().equals(inc.getSystem())) {
assert supp.getContent() == CodeSystemContentMode.SUPPLEMENT && supp.getSupplements().equals(sys);
opCtxt.seeSupplement(supp);
cache = checkAddToParams(tc, pin, supp) || cache;
}
if (sys != null) {
// we also have to look at this by version because the resource might not be versioned or we might not have a copy
for (CodeSystem supp : codeSystems.getSupplements(sys)) {
opCtxt.seeSupplement(supp);
cache = checkAddToParams(tc, pin, supp) || cache;
//}
}
if (!sys.contains("!")) {
sys = getFixedVersion(sys, pin);
if (sys != null) {
for (CodeSystem supp : codeSystems.getSupplements(sys)) {
opCtxt.seeSupplement(supp);
cache = checkAddToParams(tc, pin, supp) || cache;
}
}
}
}
return cache;
}
private String getFixedVersion(String sys, Parameters pin) {
for (ParametersParameterComponent p : pin.getParameter()) {
if (Utilities.existsInList(p.getName(), "system-version", "force-system-version", "default-system-version")) {
if (p.hasValuePrimitive() && p.getValue().primitiveValue() != null && p.getValue().primitiveValue().startsWith(sys)) {
return p.getValue().primitiveValue();
}
}
}
return null;
}
private boolean checkAddToParams(TerminologyClientContext tc, Parameters pin, CanonicalResource cr) {
boolean cache = false;
boolean addToParams = false;