001package org.hl7.fhir.dstu2.terminologies; 002 003/*- 004 * #%L 005 * org.hl7.fhir.dstu2 006 * %% 007 * Copyright (C) 2014 - 2019 Health Level 7 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023 024import java.util.List; 025 026import org.hl7.fhir.dstu2.model.UriType; 027import org.hl7.fhir.dstu2.model.ValueSet; 028import org.hl7.fhir.dstu2.model.ValueSet.ConceptDefinitionComponent; 029import org.hl7.fhir.dstu2.model.ValueSet.ConceptReferenceComponent; 030import org.hl7.fhir.dstu2.model.ValueSet.ConceptSetComponent; 031import org.hl7.fhir.dstu2.model.ValueSet.ConceptSetFilterComponent; 032import org.hl7.fhir.dstu2.model.ValueSet.ValueSetExpansionContainsComponent; 033import org.hl7.fhir.dstu2.terminologies.ValueSetExpander.ValueSetExpansionOutcome; 034import org.hl7.fhir.dstu2.utils.EOperationOutcome; 035import org.hl7.fhir.dstu2.utils.IWorkerContext; 036import org.hl7.fhir.dstu2.utils.IWorkerContext.ValidationResult; 037 038public class ValueSetCheckerSimple implements ValueSetChecker { 039 040 private ValueSet valueset; 041 private ValueSetExpanderFactory factory; 042 private IWorkerContext context; 043 044 public ValueSetCheckerSimple(ValueSet source, ValueSetExpanderFactory factory, IWorkerContext context) { 045 this.valueset = source; 046 this.factory = factory; 047 this.context = context; 048 } 049 050 @Override 051 public boolean codeInValueSet(String system, String code) throws EOperationOutcome, Exception { 052 if (valueset.hasCodeSystem() && system.equals(valueset.getCodeSystem().getSystem()) && codeInDefine(valueset.getCodeSystem().getConcept(), code, valueset.getCodeSystem().getCaseSensitive())) 053 return true; 054 055 if (valueset.hasCompose()) { 056 boolean ok = false; 057 for (UriType uri : valueset.getCompose().getImport()) { 058 ok = ok || inImport(uri.getValue(), system, code); 059 } 060 for (ConceptSetComponent vsi : valueset.getCompose().getInclude()) { 061 ok = ok || inComponent(vsi, system, code); 062 } 063 for (ConceptSetComponent vsi : valueset.getCompose().getExclude()) { 064 ok = ok && !inComponent(vsi, system, code); 065 } 066 } 067 068 return false; 069 } 070 071 private boolean inImport(String uri, String system, String code) throws EOperationOutcome, Exception { 072 ValueSet vs = context.fetchResource(ValueSet.class, uri); 073 if (vs == null) 074 return false ; // we can't tell 075 return codeInExpansion(factory.getExpander().expand(vs), system, code); 076 } 077 078 private boolean codeInExpansion(ValueSetExpansionOutcome vso, String system, String code) throws EOperationOutcome, Exception { 079 if (vso.getService() != null) { 080 return vso.getService().codeInValueSet(system, code); 081 } else { 082 for (ValueSetExpansionContainsComponent c : vso.getValueset().getExpansion().getContains()) { 083 if (code.equals(c.getCode()) && (system == null || system.equals(c.getSystem()))) 084 return true; 085 if (codeinExpansion(c, system, code)) 086 return true; 087 } 088 } 089 return false; 090 } 091 092 private boolean codeinExpansion(ValueSetExpansionContainsComponent cnt, String system, String code) { 093 for (ValueSetExpansionContainsComponent c : cnt.getContains()) { 094 if (code.equals(c.getCode()) && system.equals(c.getSystem().toString())) 095 return true; 096 if (codeinExpansion(c, system, code)) 097 return true; 098 } 099 return false; 100 } 101 102 103 private boolean inComponent(ConceptSetComponent vsi, String system, String code) { 104 if (!vsi.getSystem().equals(system)) 105 return false; 106 // whether we know the system or not, we'll accept the stated codes at face value 107 for (ConceptReferenceComponent cc : vsi.getConcept()) 108 if (cc.getCode().equals(code)) { 109 return true; 110 } 111 112 ValueSet def = context.fetchCodeSystem(system); 113 if (def != null) { 114 if (!def.getCodeSystem().getCaseSensitive()) { 115 // well, ok, it's not case sensitive - we'll check that too now 116 for (ConceptReferenceComponent cc : vsi.getConcept()) 117 if (cc.getCode().equalsIgnoreCase(code)) { 118 return false; 119 } 120 } 121 if (vsi.getConcept().isEmpty() && vsi.getFilter().isEmpty()) { 122 return codeInDefine(def.getCodeSystem().getConcept(), code, def.getCodeSystem().getCaseSensitive()); 123 } 124 for (ConceptSetFilterComponent f: vsi.getFilter()) 125 throw new Error("not done yet: "+f.getValue()); 126 127 return false; 128 } else if (context.supportsSystem(system)) { 129 ValidationResult vv = context.validateCode(system, code, null, vsi); 130 return vv.isOk(); 131 } else 132 // we don't know this system, and can't resolve it 133 return false; 134 } 135 136 private boolean codeInDefine(List<ConceptDefinitionComponent> concepts, String code, boolean caseSensitive) { 137 for (ConceptDefinitionComponent c : concepts) { 138 if (caseSensitive && code.equals(c.getCode())) 139 return true; 140 if (!caseSensitive && code.equalsIgnoreCase(c.getCode())) 141 return true; 142 if (codeInDefine(c.getConcept(), code, caseSensitive)) 143 return true; 144 } 145 return false; 146 } 147 148}