001package org.hl7.fhir.instance.terminologies; 002 003import java.util.List; 004 005import org.hl7.fhir.instance.model.UriType; 006import org.hl7.fhir.instance.model.ValueSet; 007import org.hl7.fhir.instance.model.ValueSet.ConceptDefinitionComponent; 008import org.hl7.fhir.instance.model.ValueSet.ConceptReferenceComponent; 009import org.hl7.fhir.instance.model.ValueSet.ConceptSetComponent; 010import org.hl7.fhir.instance.model.ValueSet.ConceptSetFilterComponent; 011import org.hl7.fhir.instance.model.ValueSet.ValueSetExpansionContainsComponent; 012import org.hl7.fhir.instance.terminologies.ValueSetExpander.ETooCostly; 013import org.hl7.fhir.instance.terminologies.ValueSetExpander.ValueSetExpansionOutcome; 014import org.hl7.fhir.instance.utils.EOperationOutcome; 015import org.hl7.fhir.instance.utils.IWorkerContext; 016import org.hl7.fhir.instance.utils.IWorkerContext.ValidationResult; 017 018public class ValueSetCheckerSimple implements ValueSetChecker { 019 020 private ValueSet valueset; 021 private ValueSetExpanderFactory factory; 022 private IWorkerContext context; 023 024 public ValueSetCheckerSimple(ValueSet source, ValueSetExpanderFactory factory, IWorkerContext context) { 025 this.valueset = source; 026 this.factory = factory; 027 this.context = context; 028 } 029 030 @Override 031 public boolean codeInValueSet(String system, String code) throws EOperationOutcome, Exception { 032 if (valueset.hasCodeSystem() && system.equals(valueset.getCodeSystem().getSystem()) && codeInDefine(valueset.getCodeSystem().getConcept(), code, valueset.getCodeSystem().getCaseSensitive())) 033 return true; 034 035 if (valueset.hasCompose()) { 036 boolean ok = false; 037 for (UriType uri : valueset.getCompose().getImport()) { 038 ok = ok || inImport(uri.getValue(), system, code); 039 } 040 for (ConceptSetComponent vsi : valueset.getCompose().getInclude()) { 041 ok = ok || inComponent(vsi, system, code); 042 } 043 for (ConceptSetComponent vsi : valueset.getCompose().getExclude()) { 044 ok = ok && !inComponent(vsi, system, code); 045 } 046 } 047 048 return false; 049 } 050 051 private boolean inImport(String uri, String system, String code) throws EOperationOutcome, Exception { 052 ValueSet vs = context.fetchResource(ValueSet.class, uri); 053 if (vs == null) 054 return false ; // we can't tell 055 return codeInExpansion(factory.getExpander().expand(vs), system, code); 056 } 057 058 private boolean codeInExpansion(ValueSetExpansionOutcome vso, String system, String code) throws EOperationOutcome, Exception { 059 if (vso.getService() != null) { 060 return vso.getService().codeInValueSet(system, code); 061 } else { 062 for (ValueSetExpansionContainsComponent c : vso.getValueset().getExpansion().getContains()) { 063 if (code.equals(c.getCode()) && (system == null || system.equals(c.getSystem()))) 064 return true; 065 if (codeinExpansion(c, system, code)) 066 return true; 067 } 068 } 069 return false; 070 } 071 072 private boolean codeinExpansion(ValueSetExpansionContainsComponent cnt, String system, String code) { 073 for (ValueSetExpansionContainsComponent c : cnt.getContains()) { 074 if (code.equals(c.getCode()) && system.equals(c.getSystem().toString())) 075 return true; 076 if (codeinExpansion(c, system, code)) 077 return true; 078 } 079 return false; 080 } 081 082 083 private boolean inComponent(ConceptSetComponent vsi, String system, String code) throws Exception { 084 if (!vsi.getSystem().equals(system)) 085 return false; 086 // whether we know the system or not, we'll accept the stated codes at face value 087 for (ConceptReferenceComponent cc : vsi.getConcept()) 088 if (cc.getCode().equals(code)) { 089 return true; 090 } 091 092 ValueSet def = context.fetchCodeSystem(system); 093 if (def != null) { 094 if (!def.getCodeSystem().getCaseSensitive()) { 095 // well, ok, it's not case sensitive - we'll check that too now 096 for (ConceptReferenceComponent cc : vsi.getConcept()) 097 if (cc.getCode().equalsIgnoreCase(code)) { 098 return false; 099 } 100 } 101 if (vsi.getConcept().isEmpty() && vsi.getFilter().isEmpty()) { 102 return codeInDefine(def.getCodeSystem().getConcept(), code, def.getCodeSystem().getCaseSensitive()); 103 } 104 for (ConceptSetFilterComponent f: vsi.getFilter()) 105 throw new Error("not done yet: "+f.getValue()); 106 107 return false; 108 } else if (context.supportsSystem(system)) { 109 ValidationResult vv = context.validateCode(system, code, null, vsi); 110 return vv.isOk(); 111 } else 112 // we don't know this system, and can't resolve it 113 return false; 114 } 115 116 private boolean codeInDefine(List<ConceptDefinitionComponent> concepts, String code, boolean caseSensitive) { 117 for (ConceptDefinitionComponent c : concepts) { 118 if (caseSensitive && code.equals(c.getCode())) 119 return true; 120 if (!caseSensitive && code.equalsIgnoreCase(c.getCode())) 121 return true; 122 if (codeInDefine(c.getConcept(), code, caseSensitive)) 123 return true; 124 } 125 return false; 126 } 127 128}