Add support for subsumes in tx client
This commit is contained in:
parent
981d201046
commit
df3456d293
|
@ -117,6 +117,13 @@ public class TerminologyClientR2 implements ITerminologyClient {
|
|||
p2 = client.operateType(org.hl7.fhir.dstu2.model.ValueSet.class, "validate-code", p2);
|
||||
return (Parameters) VersionConvertorFactory_10_50.convertResource(p2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameters subsumes(Parameters pin) throws FHIRException {
|
||||
org.hl7.fhir.dstu2.model.Parameters p2 = (org.hl7.fhir.dstu2.model.Parameters) VersionConvertorFactory_10_50.convertResource(pin);
|
||||
p2 = client.operateType(org.hl7.fhir.dstu2.model.ValueSet.class, "subsumes", p2);
|
||||
return (Parameters) VersionConvertorFactory_10_50.convertResource(p2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameters validateVS(Parameters pin) throws FHIRException {
|
||||
|
@ -238,4 +245,5 @@ public class TerminologyClientR2 implements ITerminologyClient {
|
|||
org.hl7.fhir.dstu2.model.Bundle result = client.search(type, criteria);
|
||||
return result == null ? null : (Bundle) VersionConvertorFactory_10_50.convertResource(result);
|
||||
}
|
||||
|
||||
}
|
|
@ -242,4 +242,11 @@ public class TerminologyClientR3 implements ITerminologyClient {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameters subsumes(Parameters pin) throws FHIRException {
|
||||
org.hl7.fhir.dstu3.model.Parameters p2 = (org.hl7.fhir.dstu3.model.Parameters) VersionConvertorFactory_30_50.convertResource(pin);
|
||||
p2 = client.operateType(org.hl7.fhir.dstu3.model.CodeSystem.class, "subsumes", p2);
|
||||
return (Parameters) VersionConvertorFactory_30_50.convertResource(p2);
|
||||
}
|
||||
|
||||
}
|
|
@ -111,6 +111,25 @@ public class TerminologyClientR4 implements ITerminologyClient {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Parameters subsumes(Parameters pin) throws FHIRException {
|
||||
try {
|
||||
org.hl7.fhir.r4.model.Parameters p2 = (org.hl7.fhir.r4.model.Parameters) VersionConvertorFactory_40_50.convertResource(pin);
|
||||
p2 = client.operateType(org.hl7.fhir.r4.model.CodeSystem.class, "subsumes", p2);
|
||||
return (Parameters) VersionConvertorFactory_40_50.convertResource(p2);
|
||||
} catch (EFhirClientException e) {
|
||||
if (e.getServerErrors().size() == 1) {
|
||||
OperationOutcome op = (OperationOutcome) VersionConvertorFactory_40_50.convertResource(e.getServerErrors().get(0));
|
||||
throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getMessage(), op, e);
|
||||
} else {
|
||||
throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getMessage(), e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new FHIRException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameters validateVS(Parameters pin) throws FHIRException {
|
||||
try {
|
||||
|
@ -249,6 +268,5 @@ public class TerminologyClientR4 implements ITerminologyClient {
|
|||
org.hl7.fhir.r4.model.Bundle result = client.search(type, criteria);
|
||||
return result == null ? null : (Bundle) VersionConvertorFactory_40_50.convertResource(result);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1347,7 +1347,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
Set<String> systems = findRelevantSystems(code, vs);
|
||||
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) {
|
||||
txLog("$validate "+csumm+(vs == null ? "" : " for "+ txCache.summary(vs))+" on "+tc.getAddress());
|
||||
} else {
|
||||
|
@ -1377,6 +1377,83 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ask the terminology system whether parent subsumes child.
|
||||
*
|
||||
* @return true if it does, false if it doesn't, and null if it's not know whether it does
|
||||
*/
|
||||
public Boolean subsumes(ValidationOptions optionsArg, Coding parent, Coding child) {
|
||||
ValidationOptions options = optionsArg != null ? optionsArg : ValidationOptions.defaults();
|
||||
|
||||
if (parent.hasSystem()) {
|
||||
codeSystemsUsed.add(parent.getSystem());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (child.hasSystem()) {
|
||||
codeSystemsUsed.add(child.getSystem());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
final CacheToken cacheToken = cachingAllowed && txCache != null ? txCache.generateSubsumesToken(options, parent, child, expParameters) : null;
|
||||
if (cachingAllowed && txCache != null) {
|
||||
Boolean res = txCache.getSubsumes(cacheToken);
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.isUseClient() && parent.getSystem().equals(child.getSystem())) {
|
||||
CodeSystem cs = fetchCodeSystem(parent.getSystem());
|
||||
if (cs != null) {
|
||||
Boolean b = CodeSystemUtilities.subsumes(cs, parent.getCode(), child.getCode());
|
||||
if (txCache != null && cachingAllowed) {
|
||||
txCache.cacheSubsumes(cacheToken, b, true);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
if (!terminologyClientManager.hasClient() || !options.isUseServer() || unsupportedCodeSystems.contains(parent.getSystem()) || unsupportedCodeSystems.contains(child.getSystem()) || noTerminologyServer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<String> systems = new HashSet<>();
|
||||
systems.add(parent.getSystem());
|
||||
systems.add(child.getSystem());
|
||||
TerminologyClientContext tc = terminologyClientManager.chooseServer(null, systems, false);
|
||||
|
||||
txLog("$subsumes "+parent.toString()+" > "+child.toString()+" on "+tc.getAddress());
|
||||
|
||||
try {
|
||||
Parameters pIn = new Parameters();
|
||||
pIn.addParameter().setName("codingA").setValue(parent);
|
||||
pIn.addParameter().setName("codingB").setValue(child);
|
||||
if (txLog != null) {
|
||||
txLog.clearLastId();
|
||||
}
|
||||
Parameters pOut = tc.getClient().subsumes(pIn);
|
||||
return processSubsumesResult(pOut, tc.getClient().getAddress());
|
||||
} catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Boolean processSubsumesResult(Parameters pOut, String server) {
|
||||
for (ParametersParameterComponent p : pOut.getParameter()) {
|
||||
if (p.hasValue()) {
|
||||
if (p.getName().equals("outcome")) {
|
||||
return Utilities.existsInList(p.getValue().primitiveValue(), "equivalent", "subsumes");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ValueSetExpander constructValueSetExpanderSimple(ValidationOptions options) {
|
||||
return new ValueSetExpander(this, new TerminologyOperationContext(this, options)).setDebug(logger.isDebugLogging());
|
||||
}
|
||||
|
|
|
@ -640,4 +640,11 @@ public interface IWorkerContext {
|
|||
public <T extends Resource> T findTxResource(Class<T> class_, String canonical);
|
||||
public <T extends Resource> T findTxResource(Class<T> class_, String canonical, String version);
|
||||
|
||||
/**
|
||||
* ask the terminology system whether parent subsumes child.
|
||||
*
|
||||
* @return true if it does, false if it doesn't, and null if it's not know whether it does
|
||||
*/
|
||||
public Boolean subsumes(ValidationOptions options, Coding parent, Coding child);
|
||||
|
||||
}
|
|
@ -54,6 +54,7 @@ public interface ITerminologyClient {
|
|||
ValueSet expandValueset(ValueSet vs, Parameters p) throws FHIRException;
|
||||
Parameters validateCS(Parameters pin) throws FHIRException;
|
||||
Parameters validateVS(Parameters pin) throws FHIRException;
|
||||
Parameters subsumes(Parameters pin) throws FHIRException;
|
||||
ITerminologyClient setTimeoutFactor(int i) throws FHIRException;
|
||||
ToolingClientLogger getLogger();
|
||||
ITerminologyClient setLogger(ToolingClientLogger txLog) throws FHIRException;
|
||||
|
|
|
@ -135,6 +135,11 @@ public class TerminologyClientR5 implements ITerminologyClient {
|
|||
return client.operateType(CodeSystem.class, "validate-code", pin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameters subsumes(Parameters pin) {
|
||||
return client.operateType(CodeSystem.class, "subsumes", pin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameters validateVS(Parameters pin) {
|
||||
return client.operateType(ValueSet.class, "validate-code", pin);
|
||||
|
@ -256,4 +261,5 @@ public class TerminologyClientR5 implements ITerminologyClient {
|
|||
return client.search(type, criteria);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -148,6 +148,21 @@ public class TerminologyCache {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SubsumesResult {
|
||||
|
||||
private Boolean result;
|
||||
|
||||
protected SubsumesResult(Boolean result) {
|
||||
super();
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public Boolean getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected SystemNameKeyGenerator getSystemNameKeyGenerator() {
|
||||
return systemNameKeyGenerator;
|
||||
}
|
||||
|
@ -218,6 +233,7 @@ public class TerminologyCache {
|
|||
private boolean persistent;
|
||||
private ValidationResult v;
|
||||
private ValueSetExpansionOutcome e;
|
||||
private SubsumesResult s;
|
||||
}
|
||||
|
||||
private class NamedCache {
|
||||
|
@ -381,9 +397,9 @@ public class TerminologyCache {
|
|||
if (code.hasSystem()) {
|
||||
ct.setName(code.getSystem());
|
||||
ct.hasVersion = code.hasVersion();
|
||||
}
|
||||
else
|
||||
} else {
|
||||
ct.name = NAME_FOR_NO_SYSTEM;
|
||||
}
|
||||
ct.setName(vsUrl);
|
||||
JsonParser json = new JsonParser();
|
||||
json.setOutputStyle(OutputStyle.PRETTY);
|
||||
|
@ -633,6 +649,9 @@ public class TerminologyCache {
|
|||
if (ce.e.getValueset() != null)
|
||||
sw.write(" \"valueSet\" : "+json.composeString(ce.e.getValueset()).trim()+",\r\n");
|
||||
sw.write(" \"error\" : \""+Utilities.escapeJson(ce.e.getError()).trim()+"\"\r\n}\r\n");
|
||||
} else if (ce.s != null) {
|
||||
sw.write("s: {\r\n");
|
||||
sw.write(" \"result\" : "+ce.s.result+"\r\n}\r\n");
|
||||
} else {
|
||||
sw.write("v: {\r\n");
|
||||
boolean first = true;
|
||||
|
@ -743,15 +762,17 @@ public class TerminologyCache {
|
|||
CacheEntry ce = new CacheEntry();
|
||||
ce.persistent = true;
|
||||
ce.request = request;
|
||||
boolean e = resultString.charAt(0) == 'e';
|
||||
char e = resultString.charAt(0);
|
||||
resultString = resultString.substring(3);
|
||||
JsonObject o = (JsonObject) new com.google.gson.JsonParser().parse(resultString);
|
||||
String error = loadJS(o.get("error"));
|
||||
if (e) {
|
||||
if (e == 'e') {
|
||||
if (o.has("valueSet"))
|
||||
ce.e = new ValueSetExpansionOutcome((ValueSet) new JsonParser().parse(o.getAsJsonObject("valueSet")), error, TerminologyServiceErrorClass.UNKNOWN, o.has("from-server"));
|
||||
else
|
||||
ce.e = new ValueSetExpansionOutcome(error, TerminologyServiceErrorClass.UNKNOWN, o.has("from-server"));
|
||||
} else if (e == 's') {
|
||||
ce.s = new SubsumesResult(o.get("result").getAsBoolean());
|
||||
} else {
|
||||
String t = loadJS(o.get("severity"));
|
||||
IssueSeverity severity = t == null ? null : IssueSeverity.fromCode(t);
|
||||
|
@ -934,15 +955,15 @@ public class TerminologyCache {
|
|||
|
||||
public Map<String, String> servers() {
|
||||
Map<String, String> servers = new HashMap<>();
|
||||
servers.put("http://local.fhir.org/r2", "tx.fhir.org");
|
||||
servers.put("http://local.fhir.org/r3", "tx.fhir.org");
|
||||
servers.put("http://local.fhir.org/r4", "tx.fhir.org");
|
||||
servers.put("http://local.fhir.org/r5", "tx.fhir.org");
|
||||
|
||||
servers.put("http://tx-dev.fhir.org/r2", "tx.fhir.org");
|
||||
servers.put("http://tx-dev.fhir.org/r3", "tx.fhir.org");
|
||||
servers.put("http://tx-dev.fhir.org/r4", "tx.fhir.org");
|
||||
servers.put("http://tx-dev.fhir.org/r5", "tx.fhir.org");
|
||||
// servers.put("http://local.fhir.org/r2", "tx.fhir.org");
|
||||
// servers.put("http://local.fhir.org/r3", "tx.fhir.org");
|
||||
// servers.put("http://local.fhir.org/r4", "tx.fhir.org");
|
||||
// servers.put("http://local.fhir.org/r5", "tx.fhir.org");
|
||||
//
|
||||
// servers.put("http://tx-dev.fhir.org/r2", "tx.fhir.org");
|
||||
// servers.put("http://tx-dev.fhir.org/r3", "tx.fhir.org");
|
||||
// servers.put("http://tx-dev.fhir.org/r4", "tx.fhir.org");
|
||||
// servers.put("http://tx-dev.fhir.org/r5", "tx.fhir.org");
|
||||
|
||||
servers.put("http://tx.fhir.org/r2", "tx.fhir.org");
|
||||
servers.put("http://tx.fhir.org/r3", "tx.fhir.org");
|
||||
|
@ -1002,5 +1023,58 @@ public class TerminologyCache {
|
|||
}
|
||||
}
|
||||
|
||||
public CacheToken generateSubsumesToken(ValidationOptions options, Coding parent, Coding child, Parameters expParameters) {
|
||||
try {
|
||||
CacheToken ct = new CacheToken();
|
||||
if (parent.hasSystem()) {
|
||||
ct.setName(parent.getSystem());
|
||||
}
|
||||
if (child.hasSystem()) {
|
||||
ct.setName(child.getSystem());
|
||||
}
|
||||
ct.hasVersion = parent.hasVersion() || child.hasVersion();
|
||||
JsonParser json = new JsonParser();
|
||||
json.setOutputStyle(OutputStyle.PRETTY);
|
||||
String expJS = json.composeString(expParameters);
|
||||
ct.request = "{\"op\": \"subsumes\", \"parent\" : "+json.composeString(parent, "code")+", \"child\" :"+json.composeString(child, "code")+(options == null ? "" : ", "+options.toJson())+", \"profile\": "+expJS+"}";
|
||||
ct.key = String.valueOf(hashJson(ct.request));
|
||||
return ct;
|
||||
} catch (IOException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean getSubsumes(CacheToken cacheToken) {
|
||||
if (cacheToken.key == null) {
|
||||
return null;
|
||||
}
|
||||
synchronized (lock) {
|
||||
requestCount++;
|
||||
NamedCache nc = getNamedCache(cacheToken);
|
||||
CacheEntry e = nc.map.get(cacheToken.key);
|
||||
if (e == null) {
|
||||
networkCount++;
|
||||
return null;
|
||||
} else {
|
||||
hitCount++;
|
||||
return e.s.result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void cacheSubsumes(CacheToken cacheToken, Boolean b, boolean persistent) {
|
||||
if (cacheToken.key != null) {
|
||||
synchronized (lock) {
|
||||
NamedCache nc = getNamedCache(cacheToken);
|
||||
CacheEntry e = new CacheEntry();
|
||||
e.request = cacheToken.request;
|
||||
e.persistent = persistent;
|
||||
e.s = new SubsumesResult(b);
|
||||
store(cacheToken, persistent, nc, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue