Add support for locally processed special case code systems (and an example - rgb)
This commit is contained in:
parent
1212b85b5e
commit
10d560c859
|
@ -827,21 +827,26 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
|
||||
// ok, first we try to expand locally
|
||||
ValueSetExpanderSimple vse = constructValueSetExpanderSimple();
|
||||
res = null;
|
||||
try {
|
||||
res = vse.expand(vs, p);
|
||||
allErrors.addAll(vse.getAllErrors());
|
||||
if (res.getValueset() != null) {
|
||||
if (!res.getValueset().hasUrl()) {
|
||||
throw new Error(formatMessage(I18nConstants.NO_URL_IN_EXPAND_VALUE_SET));
|
||||
}
|
||||
txCache.cacheExpansion(cacheToken, res, TerminologyCache.TRANSIENT);
|
||||
return res;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
allErrors.addAll(vse.getAllErrors());
|
||||
e.printStackTrace();
|
||||
res = new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.UNKNOWN);
|
||||
}
|
||||
|
||||
allErrors.addAll(vse.getAllErrors());
|
||||
if (res.getValueset() != null) {
|
||||
if (!res.getValueset().hasUrl()) {
|
||||
throw new Error(formatMessage(I18nConstants.NO_URL_IN_EXPAND_VALUE_SET));
|
||||
}
|
||||
txCache.cacheExpansion(cacheToken, res, TerminologyCache.TRANSIENT);
|
||||
return res;
|
||||
}
|
||||
if (res.getErrorClass() == TerminologyServiceErrorClass.INTERNAL_ERROR) { // this class is created specifically to say: don't consult the server
|
||||
return new ValueSetExpansionOutcome(res.getError(), res.getErrorClass());
|
||||
}
|
||||
|
||||
// if that failed, we try to expand on the server
|
||||
if (addDependentResources(p, vs)) {
|
||||
p.addParameter().setName("cache-id").setValue(new StringType(cacheId));
|
||||
|
|
|
@ -343,7 +343,7 @@ public class StructureMapRenderer extends TerminologyRenderer {
|
|||
}
|
||||
}
|
||||
if (r.getTarget().size() > 1) {
|
||||
x.b().tx(" -> ");
|
||||
x.color(COLOR_SYNTAX).b().tx(" -> ");
|
||||
boolean first = true;
|
||||
for (StructureMapGroupRuleTargetComponent rt : r.getTarget()) {
|
||||
if (first)
|
||||
|
@ -360,7 +360,7 @@ public class StructureMapRenderer extends TerminologyRenderer {
|
|||
renderTarget(x, rt, false);
|
||||
}
|
||||
} else if (r.hasTarget()) {
|
||||
x.b().tx(" -> ");
|
||||
x.color(COLOR_SYNTAX).b().tx(" -> ");
|
||||
renderTarget(x, r.getTarget().get(0), canBeAbbreviated);
|
||||
}
|
||||
if (r.hasRule()) {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package org.hl7.fhir.r5.terminologies;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.Parameters;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionPropertyComponent;
|
||||
import org.hl7.fhir.r5.terminologies.providers.CodeSystemProviderExtension;
|
||||
import org.hl7.fhir.r5.terminologies.providers.ColorRGBProvider;
|
||||
|
||||
/**
|
||||
* For special code systems where the code system resource isn't enough, but we can support them internall
|
||||
* Usually, small grammar based code systems
|
||||
*
|
||||
* @author grahamegrieve
|
||||
*
|
||||
*/
|
||||
public abstract class CodeSystemProvider {
|
||||
|
||||
public static CodeSystemProvider factory(String system) {
|
||||
switch (system) {
|
||||
case "http://hl7.org/fhir/color-rgb" : return new ColorRGBProvider();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void includeCodes(ConceptSetComponent inc, boolean heirarchical, ValueSetExpansionComponent exp,
|
||||
List<ValueSet> imports, Parameters expParams, List<Extension> extensions, boolean noInactive,
|
||||
List<ValueSetExpansionPropertyComponent> vsProps) throws CodeSystemProviderExtension;
|
||||
|
||||
protected abstract Boolean checkCode(String code);
|
||||
|
||||
}
|
|
@ -601,39 +601,50 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
problems.add(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_INCLUDE_WITH_NO_SYSTEM, valueset.getVersionedUrl(), i, vsi.getSystem()));
|
||||
return false;
|
||||
}
|
||||
CodeSystem cs = resolveCodeSystem(vsi.getSystem(), vsi.getVersion());
|
||||
if (cs != null && cs.getContent() == CodeSystemContentMode.COMPLETE) {
|
||||
CodeSystemProvider csp = CodeSystemProvider.factory(vsi.getSystem());
|
||||
if (csp != null) {
|
||||
Boolean ok = csp.checkCode(code);
|
||||
if (ok == null) {
|
||||
problems.add(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SYSTEM_SYSTEM_IS_INDETERMINATE, valueset.getVersionedUrl(), vsi.getSystem()));
|
||||
sys.add(vsi.getSystem());
|
||||
} else if (ok) {
|
||||
sys.add(vsi.getSystem());
|
||||
}
|
||||
} else {
|
||||
CodeSystem cs = resolveCodeSystem(vsi.getSystem(), vsi.getVersion());
|
||||
if (cs != null && cs.getContent() == CodeSystemContentMode.COMPLETE) {
|
||||
|
||||
if (vsi.hasConcept()) {
|
||||
if (vsi.hasConcept()) {
|
||||
for (ConceptReferenceComponent cc : vsi.getConcept()) {
|
||||
boolean match = cs.getCaseSensitive() ? cc.getCode().equals(code) : cc.getCode().equalsIgnoreCase(code);
|
||||
if (match) {
|
||||
sys.add(vsi.getSystem());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ConceptDefinitionComponent cc = findCodeInConcept(cs.getConcept(), code);
|
||||
if (cc != null) {
|
||||
sys.add(vsi.getSystem());
|
||||
}
|
||||
}
|
||||
} else if (vsi.hasConcept()) {
|
||||
for (ConceptReferenceComponent cc : vsi.getConcept()) {
|
||||
boolean match = cs.getCaseSensitive() ? cc.getCode().equals(code) : cc.getCode().equalsIgnoreCase(code);
|
||||
boolean match = cc.getCode().equals(code);
|
||||
if (match) {
|
||||
sys.add(vsi.getSystem());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ConceptDefinitionComponent cc = findCodeInConcept(cs.getConcept(), code);
|
||||
if (cc != null) {
|
||||
sys.add(vsi.getSystem());
|
||||
}
|
||||
}
|
||||
} else if (vsi.hasConcept()) {
|
||||
for (ConceptReferenceComponent cc : vsi.getConcept()) {
|
||||
boolean match = cc.getCode().equals(code);
|
||||
if (match) {
|
||||
sys.add(vsi.getSystem());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we'll try to expand this one then
|
||||
ValueSetExpansionOutcome vse = context.expandVS(vsi, false, false);
|
||||
if (vse.isOk()) {
|
||||
if (!checkSystems(vse.getValueset().getExpansion().getContains(), code, sys, problems)) {
|
||||
// we'll try to expand this one then
|
||||
ValueSetExpansionOutcome vse = context.expandVS(vsi, false, false);
|
||||
if (vse.isOk()) {
|
||||
if (!checkSystems(vse.getValueset().getExpansion().getContains(), code, sys, problems)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
problems.add(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_INCLUDE_WITH_UNKNOWN_SYSTEM, valueset.getVersionedUrl(), i, vsi.getSystem(), vse.getAllErrors().toString()));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
problems.add(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_INCLUDE_WITH_UNKNOWN_SYSTEM, valueset.getVersionedUrl(), i, vsi.getSystem(), vse.getAllErrors().toString()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ import org.hl7.fhir.r5.model.ValueSet;
|
|||
|
||||
public interface ValueSetExpander {
|
||||
public enum TerminologyServiceErrorClass {
|
||||
UNKNOWN, NOSERVICE, SERVER_ERROR, VALUESET_UNSUPPORTED, CODESYSTEM_UNSUPPORTED, BLOCKED_BY_OPTIONS;
|
||||
UNKNOWN, NOSERVICE, SERVER_ERROR, VALUESET_UNSUPPORTED, CODESYSTEM_UNSUPPORTED, BLOCKED_BY_OPTIONS, INTERNAL_ERROR;
|
||||
|
||||
public boolean isInfrastructure() {
|
||||
return this == NOSERVICE || this == SERVER_ERROR || this == VALUESET_UNSUPPORTED;
|
||||
|
|
|
@ -109,6 +109,7 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
|
|||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionPropertyComponent;
|
||||
import org.hl7.fhir.r5.terminologies.providers.CodeSystemProviderExtension;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
|
@ -407,6 +408,10 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx
|
|||
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
|
||||
// that might fail too, but it might not, later.
|
||||
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.NOSERVICE, allErrors);
|
||||
} catch (CodeSystemProviderExtension e) {
|
||||
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
|
||||
// that might fail too, but it might not, later.
|
||||
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.INTERNAL_ERROR, allErrors);
|
||||
} catch (Exception e) {
|
||||
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
|
||||
// that might fail too, but it might not, later.
|
||||
|
@ -414,11 +419,11 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx
|
|||
}
|
||||
}
|
||||
|
||||
public ValueSetExpansionOutcome expandInternal(ValueSet source, Parameters expParams) throws FHIRException, FileNotFoundException, ETooCostly, IOException {
|
||||
public ValueSetExpansionOutcome expandInternal(ValueSet source, Parameters expParams) throws FHIRException, FileNotFoundException, ETooCostly, IOException, CodeSystemProviderExtension {
|
||||
return doExpand(source, expParams);
|
||||
}
|
||||
|
||||
public ValueSetExpansionOutcome doExpand(ValueSet source, Parameters expParams) throws FHIRException, ETooCostly, FileNotFoundException, IOException {
|
||||
public ValueSetExpansionOutcome doExpand(ValueSet source, Parameters expParams) throws FHIRException, ETooCostly, FileNotFoundException, IOException, CodeSystemProviderExtension {
|
||||
if (expParams == null)
|
||||
expParams = makeDefaultExpansion();
|
||||
source.checkNoModifiers("ValueSet", "expanding");
|
||||
|
@ -474,7 +479,7 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx
|
|||
}
|
||||
|
||||
private void handleCompose(ValueSetComposeComponent compose, ValueSetExpansionComponent exp, Parameters expParams, String ctxt, List<Extension> extensions, ValueSet valueSet)
|
||||
throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
||||
throws ETooCostly, FileNotFoundException, IOException, FHIRException, CodeSystemProviderExtension {
|
||||
compose.checkNoModifiers("ValueSet.compose", "expanding");
|
||||
// Exclude comes first because we build up a map of things to exclude
|
||||
for (ConceptSetComponent inc : compose.getExclude())
|
||||
|
@ -594,7 +599,7 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx
|
|||
}
|
||||
}
|
||||
|
||||
private void includeCodes(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, boolean heirarchical, boolean noInactive, List<Extension> extensions, ValueSet valueSet) throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
||||
private void includeCodes(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, boolean heirarchical, boolean noInactive, List<Extension> extensions, ValueSet valueSet) throws ETooCostly, FileNotFoundException, IOException, FHIRException, CodeSystemProviderExtension {
|
||||
inc.checkNoModifiers("Compose.include", "expanding");
|
||||
List<ValueSet> imports = new ArrayList<ValueSet>();
|
||||
for (UriType imp : inc.getValueSet()) {
|
||||
|
@ -618,7 +623,13 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx
|
|||
}
|
||||
}
|
||||
|
||||
private void doServerIncludeCodes(ConceptSetComponent inc, boolean heirarchical, ValueSetExpansionComponent exp, List<ValueSet> imports, Parameters expParams, List<Extension> extensions, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps) throws FHIRException {
|
||||
private void doServerIncludeCodes(ConceptSetComponent inc, boolean heirarchical, ValueSetExpansionComponent exp, List<ValueSet> imports, Parameters expParams, List<Extension> extensions, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps) throws FHIRException, CodeSystemProviderExtension {
|
||||
CodeSystemProvider csp = CodeSystemProvider.factory(inc.getSystem());
|
||||
if (csp != null) {
|
||||
csp.includeCodes(inc, heirarchical, exp, imports, expParams, extensions, noInactive, vsProps);
|
||||
return;
|
||||
}
|
||||
|
||||
ValueSetExpansionOutcome vso = context.expandVS(inc, heirarchical, noInactive);
|
||||
if (vso.getError() != null) {
|
||||
throw failTSE("Unable to expand imported value set: " + vso.getError());
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package org.hl7.fhir.r5.terminologies.providers;
|
||||
|
||||
public class CodeSystemProviderExtension extends Exception {
|
||||
|
||||
public CodeSystemProviderExtension(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.hl7.fhir.r5.terminologies.providers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.Parameters;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionPropertyComponent;
|
||||
import org.hl7.fhir.r5.terminologies.CodeSystemProvider;
|
||||
|
||||
public class ColorRGBProvider extends CodeSystemProvider {
|
||||
|
||||
@Override
|
||||
public void includeCodes(ConceptSetComponent inc, boolean heirarchical, ValueSetExpansionComponent exp,
|
||||
List<ValueSet> imports, Parameters expParams, List<Extension> extensions, boolean noInactive,
|
||||
List<ValueSetExpansionPropertyComponent> vsProps) throws CodeSystemProviderExtension {
|
||||
throw new CodeSystemProviderExtension("There are 16777216 colors, so the full list of colors is not displayed");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean checkCode(String code) {
|
||||
return code.matches("^\\#[0-9a-fA-F]{6}$");
|
||||
}
|
||||
|
||||
}
|
|
@ -849,6 +849,7 @@ public class I18nConstants {
|
|||
public static final String SM_GROUP_NAME_DUPLICATE = "SM_GROUP_NAME_DUPLICATE";
|
||||
public static final String CONCEPTMAP_GROUP_SOURCE_INCOMPLETE = "CONCEPTMAP_GROUP_SOURCE_INCOMPLETE";
|
||||
public static final String CONCEPTMAP_GROUP_TARGET_INCOMPLETE = "CONCEPTMAP_GROUP_TARGET_INCOMPLETE";
|
||||
public static final String UNABLE_TO_RESOLVE_SYSTEM_SYSTEM_IS_INDETERMINATE = "UNABLE_TO_RESOLVE_SYSTEM_SYSTEM_IS_INDETERMINATE";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -470,6 +470,7 @@ Coding_has_no_system__cannot_validate = Coding has no system - cannot validate
|
|||
Unable_to_handle_system__concept_filter_with_op__ = Unable to handle system {0} concept filter with op = {1}
|
||||
Unable_to_handle_system__filter_with_property__ = Unable to handle system {0} filter with property = {1}
|
||||
Unable_to_resolve_system__value_set_has_include_with_no_system = Unable to resolve system - value set {0} include #{1} has no system
|
||||
UNABLE_TO_RESOLVE_SYSTEM_SYSTEM_IS_INDETERMINATE = The code system {1} referred to from value set {0} has a grammar, and the code might be valid in it
|
||||
Unable_to_resolve_system__value_set_has_include_with_unknown_system = Unable to resolve system - value set {0} include #{1} has system {2} which is unknown, and the server return error {3}
|
||||
Unable_to_resolve_system__value_set_has_include_with_filter = Unable to resolve system - value set {0} include #{1} has a filter on system {2}
|
||||
Unable_to_resolve_system__value_set_has_imports = Unable to resolve system - value set has imports
|
||||
|
|
Loading…
Reference in New Issue