Merge pull request #1558 from hapifhir/2024-01-gg-tx-fixes
2024 01 gg tx fixes
This commit is contained in:
commit
6cf7f5de2e
|
@ -85,13 +85,13 @@ public class ResourceUtilities {
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
for (OperationOutcomeIssueComponent t : error.getIssue())
|
for (OperationOutcomeIssueComponent t : error.getIssue())
|
||||||
if (t.getSeverity() == IssueSeverity.ERROR)
|
if (t.getSeverity() == IssueSeverity.ERROR)
|
||||||
b.append("Error:" +gen(t.getDetails())+"\r\n");
|
b.append("Error: " +gen(t.getDetails())+"\r\n");
|
||||||
else if (t.getSeverity() == IssueSeverity.FATAL)
|
else if (t.getSeverity() == IssueSeverity.FATAL)
|
||||||
b.append("Fatal:" +gen(t.getDetails())+"\r\n");
|
b.append("Fatal: " +gen(t.getDetails())+"\r\n");
|
||||||
else if (t.getSeverity() == IssueSeverity.WARNING)
|
else if (t.getSeverity() == IssueSeverity.WARNING)
|
||||||
b.append("Warning:" +gen(t.getDetails())+"\r\n");
|
b.append("Warning: " +gen(t.getDetails())+"\r\n");
|
||||||
else if (t.getSeverity() == IssueSeverity.INFORMATION)
|
else if (t.getSeverity() == IssueSeverity.INFORMATION)
|
||||||
b.append("Information:" +gen(t.getDetails())+"\r\n");
|
b.append("Information: " +gen(t.getDetails())+"\r\n");
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,13 +81,13 @@ public class ResourceUtilities {
|
||||||
if (first) first = false; else b.append("\r\n");
|
if (first) first = false; else b.append("\r\n");
|
||||||
String txt = t.hasDiagnostics() ? t.getDiagnostics() : gen(t.getDetails());
|
String txt = t.hasDiagnostics() ? t.getDiagnostics() : gen(t.getDetails());
|
||||||
if (t.getSeverity() == IssueSeverity.ERROR)
|
if (t.getSeverity() == IssueSeverity.ERROR)
|
||||||
b.append("Error:" + txt);
|
b.append("Error: " + txt);
|
||||||
else if (t.getSeverity() == IssueSeverity.FATAL)
|
else if (t.getSeverity() == IssueSeverity.FATAL)
|
||||||
b.append("Fatal:" + txt);
|
b.append("Fatal: " + txt);
|
||||||
else if (t.getSeverity() == IssueSeverity.WARNING)
|
else if (t.getSeverity() == IssueSeverity.WARNING)
|
||||||
b.append("Warning:" + txt);
|
b.append("Warning: " + txt);
|
||||||
else if (t.getSeverity() == IssueSeverity.INFORMATION)
|
else if (t.getSeverity() == IssueSeverity.INFORMATION)
|
||||||
b.append("Information:" + txt);
|
b.append("Information: " + txt);
|
||||||
}
|
}
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,13 +79,13 @@ public class ResourceUtilities {
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
for (OperationOutcomeIssueComponent t : error.getIssue()) {
|
for (OperationOutcomeIssueComponent t : error.getIssue()) {
|
||||||
if (t.getSeverity() == IssueSeverity.ERROR) {
|
if (t.getSeverity() == IssueSeverity.ERROR) {
|
||||||
b.append("Error:" + gen(t.getDetails()) + "\r\n");
|
b.append("Error: " + gen(t.getDetails()) + "\r\n");
|
||||||
} else if (t.getSeverity() == IssueSeverity.FATAL) {
|
} else if (t.getSeverity() == IssueSeverity.FATAL) {
|
||||||
b.append("Fatal:" + gen(t.getDetails()) + "\r\n");
|
b.append("Fatal: " + gen(t.getDetails()) + "\r\n");
|
||||||
} else if (t.getSeverity() == IssueSeverity.WARNING) {
|
} else if (t.getSeverity() == IssueSeverity.WARNING) {
|
||||||
b.append("Warning:" + gen(t.getDetails()) + "\r\n");
|
b.append("Warning: " + gen(t.getDetails()) + "\r\n");
|
||||||
} else if (t.getSeverity() == IssueSeverity.INFORMATION) {
|
} else if (t.getSeverity() == IssueSeverity.INFORMATION) {
|
||||||
b.append("Information:" + gen(t.getDetails()) + "\r\n");
|
b.append("Information: " + gen(t.getDetails()) + "\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b.toString();
|
return b.toString();
|
||||||
|
|
|
@ -849,7 +849,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
Set<String> systems = findRelevantSystems(vs);
|
Set<String> systems = findRelevantSystems(vs);
|
||||||
TerminologyClientContext tc = terminologyClientManager.chooseServer(systems, true);
|
TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, true);
|
||||||
if (tc == null) {
|
if (tc == null) {
|
||||||
return new ValueSetExpansionOutcome("No server available", TerminologyServiceErrorClass.INTERNAL_ERROR, true);
|
return new ValueSetExpansionOutcome("No server available", TerminologyServiceErrorClass.INTERNAL_ERROR, true);
|
||||||
}
|
}
|
||||||
|
@ -977,7 +977,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
|
|
||||||
p.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId()));
|
p.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId()));
|
||||||
Set<String> systems = findRelevantSystems(vs);
|
Set<String> systems = findRelevantSystems(vs);
|
||||||
TerminologyClientContext tc = terminologyClientManager.chooseServer(systems, true);
|
TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, true);
|
||||||
addDependentResources(tc, p, vs);
|
addDependentResources(tc, p, vs);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1107,7 +1107,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batch.getEntry().size() > 0) {
|
if (batch.getEntry().size() > 0) {
|
||||||
TerminologyClientContext tc = terminologyClientManager.chooseServer(systems, false);
|
TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, false);
|
||||||
Bundle resp = processBatch(tc, batch, systems);
|
Bundle resp = processBatch(tc, batch, systems);
|
||||||
for (int i = 0; i < batch.getEntry().size(); i++) {
|
for (int i = 0; i < batch.getEntry().size(); i++) {
|
||||||
CodingValidationRequest t = (CodingValidationRequest) batch.getEntry().get(i).getUserData("source");
|
CodingValidationRequest t = (CodingValidationRequest) batch.getEntry().get(i).getUserData("source");
|
||||||
|
@ -1212,7 +1212,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
systems.add(codingValidationRequest.getCoding().getSystem());
|
systems.add(codingValidationRequest.getCoding().getSystem());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminologyClientContext tc = terminologyClientManager.chooseServer(systems, false);
|
TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, false);
|
||||||
|
|
||||||
if (batch.getEntry().size() > 0) {
|
if (batch.getEntry().size() > 0) {
|
||||||
Bundle resp = processBatch(tc, batch, systems);
|
Bundle resp = processBatch(tc, batch, systems);
|
||||||
|
@ -1345,7 +1345,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> systems = findRelevantSystems(code, vs);
|
Set<String> systems = findRelevantSystems(code, vs);
|
||||||
TerminologyClientContext tc = terminologyClientManager.chooseServer(systems, false);
|
TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, false);
|
||||||
|
|
||||||
String csumm =cachingAllowed && txCache != null ? txCache.summary(code) : null;
|
String csumm =cachingAllowed && txCache != null ? txCache.summary(code) : null;
|
||||||
if (cachingAllowed && txCache != null) {
|
if (cachingAllowed && txCache != null) {
|
||||||
|
@ -1364,7 +1364,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
}
|
}
|
||||||
if (!res.isOk() && localError != null) {
|
if (!res.isOk() && localError != null) {
|
||||||
res.setDiagnostics("Local Error: "+localError.trim()+". Server Error: "+res.getMessage());
|
res.setDiagnostics("Local Error: "+localError.trim()+". Server Error: "+res.getMessage());
|
||||||
} else if (!res.isOk() && res.getUnknownSystems() != null && res.getUnknownSystems().contains(codeKey) && localWarning != null) {
|
} else if (!res.isOk() && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED && res.getUnknownSystems() != null && res.getUnknownSystems().contains(codeKey) && localWarning != null) {
|
||||||
// we had some problem evaluating locally, but the server doesn't know the code system, so we'll just go with the local error
|
// we had some problem evaluating locally, but the server doesn't know the code system, so we'll just go with the local error
|
||||||
res = new ValidationResult(IssueSeverity.WARNING, localWarning, null);
|
res = new ValidationResult(IssueSeverity.WARNING, localWarning, null);
|
||||||
res.setDiagnostics("Local Warning: "+localWarning.trim()+". Server Error: "+res.getMessage());
|
res.setDiagnostics("Local Warning: "+localWarning.trim()+". Server Error: "+res.getMessage());
|
||||||
|
@ -1537,7 +1537,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
return new ValidationResult(IssueSeverity.ERROR, "Error validating code: running without terminology services", TerminologyServiceErrorClass.NOSERVICE, null);
|
return new ValidationResult(IssueSeverity.ERROR, "Error validating code: running without terminology services", TerminologyServiceErrorClass.NOSERVICE, null);
|
||||||
}
|
}
|
||||||
Set<String> systems = findRelevantSystems(code, vs);
|
Set<String> systems = findRelevantSystems(code, vs);
|
||||||
TerminologyClientContext tc = terminologyClientManager.chooseServer(systems, false);
|
TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, false);
|
||||||
|
|
||||||
txLog("$validate "+txCache.summary(code)+" for "+ txCache.summary(vs)+" on "+tc.getAddress());
|
txLog("$validate "+txCache.summary(code)+" for "+ txCache.summary(vs)+" on "+tc.getAddress());
|
||||||
try {
|
try {
|
||||||
|
@ -1779,6 +1779,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
} else if (p.getName().equals("x-caused-by-unknown-system")) {
|
} else if (p.getName().equals("x-caused-by-unknown-system")) {
|
||||||
err = TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED;
|
err = TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED;
|
||||||
unknownSystems.add(((PrimitiveType<?>) p.getValue()).asStringValue());
|
unknownSystems.add(((PrimitiveType<?>) p.getValue()).asStringValue());
|
||||||
|
} else if (p.getName().equals("x-unknown-system")) {
|
||||||
|
unknownSystems.add(((PrimitiveType<?>) p.getValue()).asStringValue());
|
||||||
} else if (p.getName().equals("warning-withdrawn")) {
|
} else if (p.getName().equals("warning-withdrawn")) {
|
||||||
String msg = ((PrimitiveType<?>) p.getValue()).asStringValue();
|
String msg = ((PrimitiveType<?>) p.getValue()).asStringValue();
|
||||||
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.BUSINESSRULE);
|
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.BUSINESSRULE);
|
||||||
|
|
|
@ -1212,8 +1212,8 @@ public class DataRenderer extends Renderer implements CodeResolver {
|
||||||
s = ii.getType().getCoding().get(0).getDisplay()+": "+s;
|
s = ii.getType().getCoding().get(0).getDisplay()+": "+s;
|
||||||
else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasCode())
|
else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasCode())
|
||||||
s = lookupCode(ii.getType().getCoding().get(0).getSystem(), ii.getType().getCoding().get(0).getVersion(), ii.getType().getCoding().get(0).getCode())+": "+s;
|
s = lookupCode(ii.getType().getCoding().get(0).getSystem(), ii.getType().getCoding().get(0).getVersion(), ii.getType().getCoding().get(0).getCode())+": "+s;
|
||||||
} else {
|
} else if (ii.hasSystem()) {
|
||||||
s = "id:\u00A0"+s;
|
s = ii.getSystem()+"#"+s;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ii.hasUse() || ii.hasPeriod()) {
|
if (ii.hasUse() || ii.hasPeriod()) {
|
||||||
|
@ -1234,24 +1234,32 @@ public class DataRenderer extends Renderer implements CodeResolver {
|
||||||
|
|
||||||
protected void renderIdentifier(XhtmlNode x, Identifier ii) {
|
protected void renderIdentifier(XhtmlNode x, Identifier ii) {
|
||||||
if (ii.hasType()) {
|
if (ii.hasType()) {
|
||||||
if (ii.getType().hasText())
|
if (ii.getType().hasText()) {
|
||||||
x.tx(ii.getType().getText()+":");
|
x.tx(ii.getType().getText());
|
||||||
else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasDisplay())
|
} else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasDisplay()) {
|
||||||
x.tx(ii.getType().getCoding().get(0).getDisplay()+":");
|
x.tx(ii.getType().getCoding().get(0).getDisplay());
|
||||||
else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasCode())
|
} else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasCode()) {
|
||||||
x.tx(lookupCode(ii.getType().getCoding().get(0).getSystem(), ii.getType().getCoding().get(0).getVersion(), ii.getType().getCoding().get(0).getCode())+":");
|
x.tx(lookupCode(ii.getType().getCoding().get(0).getSystem(), ii.getType().getCoding().get(0).getVersion(), ii.getType().getCoding().get(0).getCode()));
|
||||||
} else {
|
|
||||||
x.tx("id:");
|
|
||||||
}
|
|
||||||
x.nbsp();
|
|
||||||
|
|
||||||
NamingSystem ns = context.getContext().getNSUrlMap().get(ii.getSystem());
|
|
||||||
if (ns != null) {
|
|
||||||
if (ns.hasWebPath()) {
|
|
||||||
x.ah(ns.getWebPath()).tx("#");
|
|
||||||
} else {
|
|
||||||
x.tx(ns.present()+"#");
|
|
||||||
}
|
}
|
||||||
|
x.tx("/");
|
||||||
|
} else if (ii.hasSystem()) {
|
||||||
|
NamingSystem ns = context.getContext().getNSUrlMap().get(ii.getSystem());
|
||||||
|
if (ns != null) {
|
||||||
|
if (ns.hasWebPath()) {
|
||||||
|
x.ah(ns.getWebPath(), ns.getDescription()).tx(ns.present());
|
||||||
|
} else {
|
||||||
|
x.tx(ns.present());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (ii.getSystem()) {
|
||||||
|
case "urn:oid:2.51.1.3":
|
||||||
|
x.ah("https://www.gs1.org/standards/id-keys/gln", "Global Location Number").tx("GLN");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
x.code(ii.getSystem());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x.tx("/");
|
||||||
}
|
}
|
||||||
x.tx(Utilities.noString(ii.getValue()) ? "?ngen-9?" : ii.getValue());
|
x.tx(Utilities.noString(ii.getValue()) ? "?ngen-9?" : ii.getValue());
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,12 @@ public class TerminologyClientContext {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void seeUse(Set<String> systems, TerminologyClientContextUseType useType) {
|
||||||
|
for (String s : systems) {
|
||||||
|
seeUse(s, useType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void seeUse(String s, TerminologyClientContextUseType useType) {
|
public void seeUse(String s, TerminologyClientContextUseType useType) {
|
||||||
TerminologyClientContextUseCount uc = useCounts.get(s);
|
TerminologyClientContextUseCount uc = useCounts.get(s);
|
||||||
if (uc == null) {
|
if (uc == null) {
|
||||||
|
@ -185,4 +191,11 @@ public class TerminologyClientContext {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return client.getAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,15 +24,53 @@ import org.hl7.fhir.r5.model.TerminologyCapabilities;
|
||||||
import org.hl7.fhir.r5.model.ValueSet;
|
import org.hl7.fhir.r5.model.ValueSet;
|
||||||
import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
|
import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
|
||||||
import org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.TerminologyClientContextUseType;
|
import org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.TerminologyClientContextUseType;
|
||||||
|
import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager.ServerOptionList;
|
||||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache;
|
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache;
|
||||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.SourcedValueSet;
|
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.SourcedValueSet;
|
||||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||||
|
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||||
import org.hl7.fhir.utilities.json.parser.JsonParser;
|
import org.hl7.fhir.utilities.json.parser.JsonParser;
|
||||||
|
|
||||||
public class TerminologyClientManager {
|
public class TerminologyClientManager {
|
||||||
|
public class ServerOptionList {
|
||||||
|
private List<String> authoritative = new ArrayList<String>();
|
||||||
|
private List<String> candidates = new ArrayList<String>();
|
||||||
|
|
||||||
|
public ServerOptionList(String address) {
|
||||||
|
candidates.add(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerOptionList() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerOptionList(List<String> auth, List<String> cand) {
|
||||||
|
authoritative.addAll(auth);
|
||||||
|
candidates.addAll(cand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void replace(String src, String dst) {
|
||||||
|
for (int i = 0; i < candidates.size(); i++) {
|
||||||
|
if (candidates.get(i).contains("://"+src)) {
|
||||||
|
candidates.set(i, candidates.get(i).replace("://"+src, "://"+dst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < authoritative.size(); i++) {
|
||||||
|
if (authoritative.get(i).contains("://"+src)) {
|
||||||
|
authoritative.set(i, authoritative.get(i).replace("://"+src, "://"+dst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "auth = " + CommaSeparatedStringBuilder.join("|", authoritative)+ ", candidates=" + CommaSeparatedStringBuilder.join("|", candidates);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public ITerminologyClientFactory getFactory() {
|
public ITerminologyClientFactory getFactory() {
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
@ -50,8 +88,8 @@ public class TerminologyClientManager {
|
||||||
private String cacheId;
|
private String cacheId;
|
||||||
private List<TerminologyClientContext> serverList = new ArrayList<>(); // clients by server address
|
private List<TerminologyClientContext> serverList = new ArrayList<>(); // clients by server address
|
||||||
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, ServerOptionList> resMap = new HashMap<>(); // client resolution list
|
||||||
private List<String> internalErrors = new ArrayList<>();
|
private List<String> internalLog = new ArrayList<>();
|
||||||
protected Parameters expParameters;
|
protected Parameters expParameters;
|
||||||
|
|
||||||
private TerminologyCache cache;
|
private TerminologyCache cache;
|
||||||
|
@ -82,40 +120,92 @@ public class TerminologyClientManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public TerminologyClientContext chooseServer(Set<String> systems, boolean expand) throws TerminologyServiceException {
|
public TerminologyClientContext chooseServer(ValueSet vs, Set<String> systems, boolean expand) throws TerminologyServiceException {
|
||||||
if (serverList.isEmpty()) {
|
if (serverList.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (systems.contains(UNRESOLVED_VALUESET)) {
|
if (systems.contains(UNRESOLVED_VALUESET) || systems.isEmpty()) {
|
||||||
return serverList.get(0);
|
return serverList.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<TerminologyClientContext> clients = new HashSet<>();
|
List<ServerOptionList> choices = new ArrayList<>();
|
||||||
for (String s : systems) {
|
for (String s : systems) {
|
||||||
clients.add(findServerForSystem(s, expand));
|
choices.add(findServerForSystem(s, expand));
|
||||||
|
}
|
||||||
|
|
||||||
|
// first we look for a server that's authoritative for all of them
|
||||||
|
for (ServerOptionList ol : choices) {
|
||||||
|
for (String s : ol.authoritative) {
|
||||||
|
boolean ok = true;
|
||||||
|
for (ServerOptionList t : choices) {
|
||||||
|
if (!t.authoritative.contains(s)) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
return findClient(s, systems, expand);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (clients.size() == 1) {
|
|
||||||
return clients.iterator().next();
|
// now we look for a server that's authoritative for one of them and a candidate for the others
|
||||||
|
for (ServerOptionList ol : choices) {
|
||||||
|
for (String s : ol.authoritative) {
|
||||||
|
boolean ok = true;
|
||||||
|
for (ServerOptionList t : choices) {
|
||||||
|
if (!t.candidates.contains(s)) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
return findClient(s, systems, expand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we look for a server that's a candidate for all of them
|
||||||
|
for (ServerOptionList ol : choices) {
|
||||||
|
for (String s : ol.candidates) {
|
||||||
|
boolean ok = true;
|
||||||
|
for (ServerOptionList t : choices) {
|
||||||
|
if (!t.candidates.contains(s)) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
return findClient(s, systems, expand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no agreement? Then what we do depends
|
||||||
|
if (vs != null) {
|
||||||
|
if (vs.hasUserData("External.Link")) {
|
||||||
|
if (systems.size() == 1) {
|
||||||
|
internalLog.add(vs.getVersionedUrl()+" uses the system "+systems.toString()+" not handled by any servers. Using source @ '"+vs.getUserString("External.Link")+"'");
|
||||||
|
} else {
|
||||||
|
internalLog.add(vs.getVersionedUrl()+" includes multiple systems "+systems.toString()+" best handled by multiple servers: "+choices.toString()+". Using source @ '"+vs.getUserString("External.Link")+"'");
|
||||||
|
}
|
||||||
|
return findClient(vs.getUserString("External.Link"), systems, expand);
|
||||||
|
} else {
|
||||||
|
if (systems.size() == 1) {
|
||||||
|
internalLog.add(vs.getVersionedUrl()+" uses the system "+systems.toString()+" not handled by any servers. Using master @ '"+serverList.get(0)+"'");
|
||||||
|
} else {
|
||||||
|
internalLog.add(vs.getVersionedUrl()+" includes multiple systems "+systems.toString()+" best handled by multiple servers: "+choices.toString()+". Using master @ '"+serverList.get(0)+"'");
|
||||||
|
}
|
||||||
|
return findClient(serverList.get(0).getAddress(), systems, expand);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
System.out.println("systems: "+systems.toString());
|
if (systems.size() == 1) {
|
||||||
return serverList.get(0);
|
internalLog.add("Request for system "+systems.toString()+" not handled by any servers. Using master @ '"+serverList.get(0)+"'");
|
||||||
|
} else {
|
||||||
|
internalLog.add("Request for multiple systems "+systems.toString()+" best handled by multiple servers: "+choices.toString()+". Using master @ '"+serverList.get(0)+"'");
|
||||||
|
}
|
||||||
|
return findClient(serverList.get(0).getAddress(), systems, expand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TerminologyClientContext findServerForSystem(String s, boolean expand) throws TerminologyServiceException {
|
private TerminologyClientContext findClient(String server, Set<String> systems, boolean expand) {
|
||||||
String server = resMap.get(s);
|
|
||||||
if (server == null) {
|
|
||||||
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);
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
TerminologyClientContext client = serverMap.get(server);
|
TerminologyClientContext client = serverMap.get(server);
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
try {
|
try {
|
||||||
|
@ -127,13 +217,28 @@ public class TerminologyClientManager {
|
||||||
serverList.add(client);
|
serverList.add(client);
|
||||||
serverMap.put(server, client);
|
serverMap.put(server, client);
|
||||||
}
|
}
|
||||||
client.seeUse(s, expand ? TerminologyClientContextUseType.expand : TerminologyClientContextUseType.validate);
|
client.seeUse(systems, expand ? TerminologyClientContextUseType.expand : TerminologyClientContextUseType.validate);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String decideWhichServer(String url) {
|
private ServerOptionList findServerForSystem(String s, boolean expand) throws TerminologyServiceException {
|
||||||
|
ServerOptionList serverList = resMap.get(s);
|
||||||
|
if (serverList == null) {
|
||||||
|
serverList = decideWhichServer(s);
|
||||||
|
// testing support
|
||||||
|
try {
|
||||||
|
serverList.replace("tx.fhir.org", new URL(getMasterClient().getAddress()).getHost());
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
}
|
||||||
|
resMap.put(s, serverList);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
return serverList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerOptionList decideWhichServer(String url) {
|
||||||
if (IGNORE_TX_REGISTRY) {
|
if (IGNORE_TX_REGISTRY) {
|
||||||
return getMasterClient().getAddress();
|
return new ServerOptionList(getMasterClient().getAddress());
|
||||||
}
|
}
|
||||||
if (expParameters != null) {
|
if (expParameters != null) {
|
||||||
if (!url.contains("|")) {
|
if (!url.contains("|")) {
|
||||||
|
@ -157,23 +262,25 @@ public class TerminologyClientManager {
|
||||||
request = request + "&usage="+usage;
|
request = request + "&usage="+usage;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
ServerOptionList ret = new ServerOptionList();
|
||||||
JsonObject json = JsonParser.parseObjectFromUrl(request);
|
JsonObject json = JsonParser.parseObjectFromUrl(request);
|
||||||
for (JsonObject item : json.getJsonObjects("authoritative")) {
|
for (JsonObject item : json.getJsonObjects("authoritative")) {
|
||||||
return item.asString("url");
|
ret.authoritative.add(item.asString("url"));
|
||||||
}
|
}
|
||||||
for (JsonObject item : json.getJsonObjects("candidates")) {
|
for (JsonObject item : json.getJsonObjects("candidates")) {
|
||||||
return item.asString("url");
|
ret.candidates.add(item.asString("url"));
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String msg = "Error resolving system "+url+": "+e.getMessage()+" ("+request+")";
|
String msg = "Error resolving system "+url+": "+e.getMessage()+" ("+request+")";
|
||||||
if (!internalErrors.contains(msg)) {
|
if (!internalLog.contains(msg)) {
|
||||||
internalErrors.add(msg);
|
internalLog.add(msg);
|
||||||
}
|
}
|
||||||
if (!monitorServiceURL.contains("tx.fhir.org")) {
|
if (!monitorServiceURL.contains("tx.fhir.org")) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getMasterClient().getAddress();
|
return new ServerOptionList( getMasterClient().getAddress());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +355,11 @@ public class TerminologyClientManager {
|
||||||
if (cacheFile.exists()) {
|
if (cacheFile.exists()) {
|
||||||
JsonObject json = JsonParser.parseObject(cacheFile);
|
JsonObject json = JsonParser.parseObject(cacheFile);
|
||||||
for (JsonObject pair : json.getJsonObjects("systems")) {
|
for (JsonObject pair : json.getJsonObjects("systems")) {
|
||||||
resMap.put(pair.asString("system"), pair.asString("server"));
|
if (pair.has("server")) {
|
||||||
|
resMap.put(pair.asString("system"), new ServerOptionList(pair.asString("server")));
|
||||||
|
} else {
|
||||||
|
resMap.put(pair.asString("system"), new ServerOptionList(pair.getStrings("authoritative"), pair.getStrings("candidates")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -264,7 +375,8 @@ public class TerminologyClientManager {
|
||||||
JsonObject si = new JsonObject();
|
JsonObject si = new JsonObject();
|
||||||
json.forceArray("systems").add(si);
|
json.forceArray("systems").add(si);
|
||||||
si.add("system", s);
|
si.add("system", s);
|
||||||
si.add("server", resMap.get(s));
|
si.add("authoritative", resMap.get(s).authoritative);
|
||||||
|
si.add("candidates", resMap.get(s).candidates);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
JsonParser.compose(json, cacheFile, true);
|
JsonParser.compose(json, cacheFile, true);
|
||||||
|
@ -273,8 +385,8 @@ public class TerminologyClientManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getInternalErrors() {
|
public List<String> getInternalLog() {
|
||||||
return internalErrors;
|
return internalLog;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TerminologyClientContext> getServerList() {
|
public List<TerminologyClientContext> getServerList() {
|
||||||
|
@ -377,8 +489,8 @@ public class TerminologyClientManager {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
String msg = "Error resolving valueSet "+canonical+": "+e.getMessage()+" ("+request+")";
|
String msg = "Error resolving valueSet "+canonical+": "+e.getMessage()+" ("+request+")";
|
||||||
if (!internalErrors.contains(msg)) {
|
if (!internalLog.contains(msg)) {
|
||||||
internalErrors.add(msg);
|
internalLog.add(msg);
|
||||||
}
|
}
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
|
@ -393,5 +505,5 @@ public class TerminologyClientManager {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,6 +356,9 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
||||||
res.setVersion(foundCoding.hasVersion() ? foundCoding.getVersion() : foundCoding.hasUserData("cs") ? ((CodeSystem) foundCoding.getUserData("cs")).getVersion() : null);
|
res.setVersion(foundCoding.hasVersion() ? foundCoding.getVersion() : foundCoding.hasUserData("cs") ? ((CodeSystem) foundCoding.getUserData("cs")).getVersion() : null);
|
||||||
res.setDisplay(cd.getDisplay());
|
res.setDisplay(cd.getDisplay());
|
||||||
}
|
}
|
||||||
|
if (info.getErr() != null) {
|
||||||
|
res.setErrorClass(info.getErr());
|
||||||
|
}
|
||||||
res.setUnknownSystems(unknownSystems);
|
res.setUnknownSystems(unknownSystems);
|
||||||
res.addCodeableConcept(vcc);
|
res.addCodeableConcept(vcc);
|
||||||
return res;
|
return res;
|
||||||
|
@ -669,7 +672,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
||||||
res.setDefinition(null);
|
res.setDefinition(null);
|
||||||
res.setSystem(null);
|
res.setSystem(null);
|
||||||
res.setDisplay(null);
|
res.setDisplay(null);
|
||||||
res.setUnknownSystems(unknownSystems);
|
res.setUnknownSystems(unknownSystems);
|
||||||
// }
|
// }
|
||||||
} else if (warningMessage!=null) {
|
} else if (warningMessage!=null) {
|
||||||
String msg = context.formatMessage(I18nConstants.CODE_FOUND_IN_EXPANSION_HOWEVER_, warningMessage);
|
String msg = context.formatMessage(I18nConstants.CODE_FOUND_IN_EXPANSION_HOWEVER_, warningMessage);
|
||||||
|
@ -1309,6 +1312,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
||||||
}
|
}
|
||||||
return res.isOk();
|
return res.isOk();
|
||||||
} else {
|
} else {
|
||||||
|
info.setErr(TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED);
|
||||||
if (unknownSystems != null) {
|
if (unknownSystems != null) {
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
unknownSystems.add(system);
|
unknownSystems.add(system);
|
||||||
|
|
|
@ -79,13 +79,13 @@ public class ResourceUtilities {
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
for (OperationOutcomeIssueComponent t : error.getIssue()) {
|
for (OperationOutcomeIssueComponent t : error.getIssue()) {
|
||||||
if (t.getSeverity() == IssueSeverity.ERROR) {
|
if (t.getSeverity() == IssueSeverity.ERROR) {
|
||||||
b.append("Error:" +gen(t.getDetails())+"\r\n");
|
b.append("Error: " +gen(t.getDetails())+"\r\n");
|
||||||
} else if (t.getSeverity() == IssueSeverity.FATAL) {
|
} else if (t.getSeverity() == IssueSeverity.FATAL) {
|
||||||
b.append("Fatal:" +gen(t.getDetails())+"\r\n");
|
b.append("Fatal: " +gen(t.getDetails())+"\r\n");
|
||||||
} else if (t.getSeverity() == IssueSeverity.WARNING) {
|
} else if (t.getSeverity() == IssueSeverity.WARNING) {
|
||||||
b.append("Warning:" +gen(t.getDetails())+"\r\n");
|
b.append("Warning: " +gen(t.getDetails())+"\r\n");
|
||||||
} else if (t.getSeverity() == IssueSeverity.INFORMATION) {
|
} else if (t.getSeverity() == IssueSeverity.INFORMATION) {
|
||||||
b.append("Information:" +gen(t.getDetails())+"\r\n");
|
b.append("Information: " +gen(t.getDetails())+"\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b.toString();
|
return b.toString();
|
||||||
|
|
|
@ -68,6 +68,16 @@ public class JsonObject extends JsonElement {
|
||||||
return add(name, value == null ? new JsonNull() : new JsonString(value));
|
return add(name, value == null ? new JsonNull() : new JsonString(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JsonObject add(String name, List<String> values) throws JsonException {
|
||||||
|
check(name != null, "Name is null");
|
||||||
|
JsonArray arr = new JsonArray();
|
||||||
|
add(name, arr);
|
||||||
|
for (String v : values) {
|
||||||
|
arr.add(v);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public JsonObject addIfNotNull(String name, String value) throws JsonException {
|
public JsonObject addIfNotNull(String name, String value) throws JsonException {
|
||||||
check(name != null, "Name is null");
|
check(name != null, "Name is null");
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
|
|
@ -910,7 +910,7 @@ public class StructureDefinitionValidator extends BaseValidator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean serverSupportsValueSet(String ref) {
|
private boolean serverSupportsValueSet(String ref) {
|
||||||
ValidationResult vr = context.validateCode(new ValidationOptions(FhirPublication.R5).withCheckValueSetOnly().withVsAsUrl().withNoClient(), new Coding("http://loinc.org", "5792-7", null), new ValueSet().setUrl(ref));
|
ValidationResult vr = context.validateCode(new ValidationOptions(FhirPublication.R5).withCheckValueSetOnly().withNoClient(), new Coding("http://loinc.org", "5792-7", null), new ValueSet().setUrl(ref));
|
||||||
return vr.getErrorClass() == null || vr.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN;
|
return vr.getErrorClass() == null || vr.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.hl7.fhir.r5.model.UriType;
|
||||||
import org.hl7.fhir.r5.model.ValueSet;
|
import org.hl7.fhir.r5.model.ValueSet;
|
||||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
|
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
|
||||||
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
|
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
|
||||||
|
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
|
||||||
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
|
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
|
||||||
import org.hl7.fhir.r5.test.utils.CompareUtilities;
|
import org.hl7.fhir.r5.test.utils.CompareUtilities;
|
||||||
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
||||||
|
@ -375,7 +376,7 @@ public class TerminologyServiceTests {
|
||||||
}
|
}
|
||||||
if (vm.getUnknownSystems() != null) {
|
if (vm.getUnknownSystems() != null) {
|
||||||
for (String s : vm.getUnknownSystems()) {
|
for (String s : vm.getUnknownSystems()) {
|
||||||
res.addParameter("x-caused-by-unknown-system", new CanonicalType(s));
|
res.addParameter(vm.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED ? "x-caused-by-unknown-system" : "x-unknown-system", new CanonicalType(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vm.getIssues().size() > 0) {
|
if (vm.getIssues().size() > 0) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
2
pom.xml
2
pom.xml
|
@ -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.27</validator_test_case_version>
|
<validator_test_case_version>1.4.28-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>
|
||||||
|
|
Loading…
Reference in New Issue