001package org.hl7.fhir.dstu3.terminologies; 002 003import static org.apache.commons.lang3.StringUtils.isNotBlank; 004 005import java.io.FileNotFoundException; 006import java.io.IOException; 007import java.util.ArrayList; 008import java.util.HashMap; 009import java.util.HashSet; 010import java.util.List; 011import java.util.Map; 012import java.util.Set; 013import java.util.UUID; 014 015/* 016 Copyright (c) 2011+, HL7, Inc. 017 All rights reserved. 018 019 Redistribution and use in source and binary forms, with or without modification, 020 are permitted provided that the following conditions are met: 021 022 * Redistributions of source code must retain the above copyright notice, this 023 list of conditions and the following disclaimer. 024 * Redistributions in binary form must reproduce the above copyright notice, 025 this list of conditions and the following disclaimer in the documentation 026 and/or other materials provided with the distribution. 027 * Neither the name of HL7 nor the names of its contributors may be used to 028 endorse or promote products derived from this software without specific 029 prior written permission. 030 031 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 032 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 033 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 034 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 035 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 036 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 037 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 038 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 039 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 040 POSSIBILITY OF SUCH DAMAGE. 041 042 */ 043 044 045 046import org.apache.commons.lang3.NotImplementedException; 047import org.hl7.fhir.dstu3.context.IWorkerContext; 048import org.hl7.fhir.dstu3.model.CodeSystem; 049import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode; 050import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent; 051import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionDesignationComponent; 052import org.hl7.fhir.dstu3.model.DateTimeType; 053import org.hl7.fhir.dstu3.model.ExpansionProfile; 054import org.hl7.fhir.dstu3.model.Factory; 055import org.hl7.fhir.dstu3.model.PrimitiveType; 056import org.hl7.fhir.dstu3.model.Type; 057import org.hl7.fhir.dstu3.model.UriType; 058import org.hl7.fhir.dstu3.model.ValueSet; 059import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent; 060import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceDesignationComponent; 061import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent; 062import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetFilterComponent; 063import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator; 064import org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent; 065import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent; 066import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent; 067import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionParameterComponent; 068import org.hl7.fhir.dstu3.utils.ToolingExtensions; 069import org.hl7.fhir.exceptions.FHIRException; 070import org.hl7.fhir.exceptions.FHIRFormatError; 071import org.hl7.fhir.exceptions.NoTerminologyServiceException; 072import org.hl7.fhir.exceptions.TerminologyServiceException; 073import org.hl7.fhir.utilities.Utilities; 074 075/* 076 * Copyright (c) 2011+, HL7, Inc 077 * All rights reserved. 078 * 079 * Redistribution and use in source and binary forms, with or without modification, 080 * are permitted provided that the following conditions are met: 081 * 082 * Redistributions of source code must retain the above copyright notice, this 083 * list of conditions and the following disclaimer. 084 * Redistributions in binary form must reproduce the above copyright notice, 085 * this list of conditions and the following disclaimer in the documentation 086 * and/or other materials provided with the distribution. 087 * Neither the name of HL7 nor the names of its contributors may be used to 088 * endorse or promote products derived from this software without specific 089 * prior written permission. 090 * 091 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 092 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 093 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 094 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 095 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 096 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 097 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 098 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 099 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 100 * POSSIBILITY OF SUCH DAMAGE. 101 * 102 */ 103 104public class ValueSetExpanderSimple implements ValueSetExpander { 105 106 private List<ValueSetExpansionContainsComponent> codes = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>(); 107 private List<ValueSetExpansionContainsComponent> roots = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>(); 108 private Map<String, ValueSetExpansionContainsComponent> map = new HashMap<String, ValueSet.ValueSetExpansionContainsComponent>(); 109 private IWorkerContext context; 110 private boolean canBeHeirarchy = true; 111 private Set<String> excludeKeys = new HashSet<String>(); 112 private Set<String> excludeSystems = new HashSet<String>(); 113 private ValueSetExpanderFactory factory; 114 private ValueSet focus; 115 private int maxExpansionSize = 500; 116 117 private int total; 118 119 public ValueSetExpanderSimple(IWorkerContext context, ValueSetExpanderFactory factory) { 120 super(); 121 this.context = context; 122 this.factory = factory; 123 } 124 125 public void setMaxExpansionSize(int theMaxExpansionSize) { 126 maxExpansionSize = theMaxExpansionSize; 127 } 128 129 private ValueSetExpansionContainsComponent addCode(String system, String code, String display, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations, 130 ExpansionProfile profile, boolean isAbstract, boolean inactive, List<ValueSet> filters) { 131 if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code)) 132 return null; 133 ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent(); 134 n.setSystem(system); 135 n.setCode(code); 136 if (isAbstract) 137 n.setAbstract(true); 138 if (inactive) 139 n.setInactive(true); 140 141 if (profile.getIncludeDesignations() && designations != null) { 142 for (ConceptDefinitionDesignationComponent t : designations) { 143 ToolingExtensions.addLanguageTranslation(n, t.getLanguage(), t.getValue()); 144 } 145 } 146 ConceptDefinitionDesignationComponent t = profile.hasLanguage() ? getMatchingLang(designations, profile.getLanguage()) : null; 147 if (t == null) 148 n.setDisplay(display); 149 else 150 n.setDisplay(t.getValue()); 151 152 String s = key(n); 153 if (map.containsKey(s) || excludeKeys.contains(s)) { 154 canBeHeirarchy = false; 155 } else { 156 codes.add(n); 157 map.put(s, n); 158 total++; 159 } 160 if (canBeHeirarchy && parent != null) { 161 parent.getContains().add(n); 162 } else { 163 roots.add(n); 164 } 165 return n; 166 } 167 168 private boolean filterContainsCode(List<ValueSet> filters, String system, String code) { 169 for (ValueSet vse : filters) 170 if (expansionContainsCode(vse.getExpansion().getContains(), system, code)) 171 return true; 172 return false; 173 } 174 175 private boolean expansionContainsCode(List<ValueSetExpansionContainsComponent> contains, String system, String code) { 176 for (ValueSetExpansionContainsComponent cc : contains) { 177 if (system.equals(cc.getSystem()) && code.equals(cc.getCode())) 178 return true; 179 if (expansionContainsCode(cc.getContains(), system, code)) 180 return true; 181 } 182 return false; 183 } 184 185 private ConceptDefinitionDesignationComponent getMatchingLang(List<ConceptDefinitionDesignationComponent> list, String lang) { 186 for (ConceptDefinitionDesignationComponent t : list) 187 if (t.getLanguage().equals(lang)) 188 return t; 189 for (ConceptDefinitionDesignationComponent t : list) 190 if (t.getLanguage().startsWith(lang)) 191 return t; 192 return null; 193 } 194 195 private void addCodeAndDescendents(CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filters) 196 throws FHIRException { 197 if (!CodeSystemUtilities.isDeprecated(cs, def)) { 198 ValueSetExpansionContainsComponent np = null; 199 boolean abs = CodeSystemUtilities.isNotSelectable(cs, def); 200 boolean inc = CodeSystemUtilities.isInactive(cs, def); 201 if (canBeHeirarchy || !abs) 202 np = addCode(system, def.getCode(), def.getDisplay(), parent, def.getDesignation(), profile, abs, inc, filters); 203 for (ConceptDefinitionComponent c : def.getConcept()) 204 addCodeAndDescendents(cs, system, c, np, profile, filters); 205 } else 206 for (ConceptDefinitionComponent c : def.getConcept()) 207 addCodeAndDescendents(cs, system, c, null, profile, filters); 208 209 } 210 211 private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile, List<ValueSet> filters) throws ETooCostly { 212 if (expand.getContains().size() > maxExpansionSize) 213 throw new ETooCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")"); 214 for (ValueSetExpansionParameterComponent p : expand.getParameter()) { 215 if (!existsInParams(params, p.getName(), p.getValue())) 216 params.add(p); 217 } 218 219 copyImportContains(expand.getContains(), null, profile, filters); 220 } 221 222 private void excludeCode(String theSystem, String theCode) { 223 ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent(); 224 n.setSystem(theSystem); 225 n.setCode(theCode); 226 String s = key(n); 227 excludeKeys.add(s); 228 } 229 230 private void excludeCodes(ConceptSetComponent exc, List<ValueSetExpansionParameterComponent> params) throws TerminologyServiceException { 231 if (exc.hasSystem() && exc.getConcept().size() == 0 && exc.getFilter().size() == 0) { 232 excludeSystems.add(exc.getSystem()); 233 } 234 235 if (exc.hasValueSet()) 236 throw new Error("Processing Value set references in exclude is not yet done"); 237 // importValueSet(imp.getValue(), params, profile); 238 239 CodeSystem cs = context.fetchCodeSystem(exc.getSystem()); 240 if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem())) { 241 excludeCodes(context.expandVS(exc, false), params); 242 return; 243 } 244 245 for (ConceptReferenceComponent c : exc.getConcept()) { 246 excludeCode(exc.getSystem(), c.getCode()); 247 } 248 249 if (exc.getFilter().size() > 0) 250 throw new NotImplementedException("not done yet"); 251 } 252 253 private void excludeCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) { 254 for (ValueSetExpansionContainsComponent c : expand.getContains()) { 255 excludeCode(c.getSystem(), c.getCode()); 256 } 257 } 258 259 private boolean existsInParams(List<ValueSetExpansionParameterComponent> params, String name, Type value) { 260 for (ValueSetExpansionParameterComponent p : params) { 261 if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false)) 262 return true; 263 } 264 return false; 265 } 266 267 @Override 268 public ValueSetExpansionOutcome expand(ValueSet source, ExpansionProfile profile) { 269 270 if (profile == null) 271 profile = makeDefaultExpansion(); 272 try { 273 focus = source.copy(); 274 focus.setExpansion(new ValueSet.ValueSetExpansionComponent()); 275 focus.getExpansion().setTimestampElement(DateTimeType.now()); 276 focus.getExpansion().setIdentifier(Factory.createUUID()); 277 if (!profile.getUrl().startsWith("urn:uuid:")) 278 focus.getExpansion().addParameter().setName("profile").setValue(new UriType(profile.getUrl())); 279 280 if (source.hasCompose()) 281 handleCompose(source.getCompose(), focus.getExpansion().getParameter(), profile); 282 283 if (canBeHeirarchy) { 284 for (ValueSetExpansionContainsComponent c : roots) { 285 focus.getExpansion().getContains().add(c); 286 } 287 } else { 288 for (ValueSetExpansionContainsComponent c : codes) { 289 if (map.containsKey(key(c)) && !c.getAbstract()) { // we may have added abstract codes earlier while we still thought it might be heirarchical, but later we gave up, so now ignore them 290 focus.getExpansion().getContains().add(c); 291 c.getContains().clear(); // make sure any heirarchy is wiped 292 } 293 } 294 } 295 296 if (total > 0) { 297 focus.getExpansion().setTotal(total); 298 } 299 300 return new ValueSetExpansionOutcome(focus); 301 } catch (NoTerminologyServiceException e) { 302 // well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set 303 // that might fail too, but it might not, later. 304 return new ValueSetExpansionOutcome(new ValueSetCheckerSimple(source, factory, context), e.getMessage(), TerminologyServiceErrorClass.NOSERVICE); 305 } catch (RuntimeException e) { 306 // TODO: we should put something more specific instead of just Exception below, since 307 // it swallows bugs.. what would be expected to be caught there? 308 throw e; 309 } catch (Exception e) { 310 // well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set 311 // that might fail too, but it might not, later. 312 return new ValueSetExpansionOutcome(new ValueSetCheckerSimple(source, factory, context), e.getMessage(), TerminologyServiceErrorClass.UNKNOWN); 313 } 314 } 315 316 private ExpansionProfile makeDefaultExpansion() { 317 ExpansionProfile res = new ExpansionProfile(); 318 res.setUrl("urn:uuid:" + UUID.randomUUID().toString().toLowerCase()); 319 res.setExcludeNested(true); 320 res.setIncludeDesignations(false); 321 return res; 322 } 323 324 private void addToHeirarchy(List<ValueSetExpansionContainsComponent> target, List<ValueSetExpansionContainsComponent> source) { 325 for (ValueSetExpansionContainsComponent s : source) { 326 target.add(s); 327 } 328 } 329 330 private String getCodeDisplay(CodeSystem cs, String code) throws TerminologyServiceException { 331 ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), code); 332 if (def == null) 333 throw new TerminologyServiceException("Unable to find code '" + code + "' in code system " + cs.getUrl()); 334 return def.getDisplay(); 335 } 336 337 private ConceptDefinitionComponent getConceptForCode(List<ConceptDefinitionComponent> clist, String code) { 338 for (ConceptDefinitionComponent c : clist) { 339 if (code.equals(c.getCode())) 340 return c; 341 ConceptDefinitionComponent v = getConceptForCode(c.getConcept(), code); 342 if (v != null) 343 return v; 344 } 345 return null; 346 } 347 348 private void handleCompose(ValueSetComposeComponent compose, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) 349 throws ETooCostly, FileNotFoundException, IOException, FHIRException { 350 // Exclude comes first because we build up a map of things to exclude 351 for (ConceptSetComponent inc : compose.getExclude()) 352 excludeCodes(inc, params); 353 canBeHeirarchy = !profile.getExcludeNested() && excludeKeys.isEmpty() && excludeSystems.isEmpty(); 354 boolean first = true; 355 for (ConceptSetComponent inc : compose.getInclude()) { 356 if (first == true) 357 first = false; 358 else 359 canBeHeirarchy = false; 360 includeCodes(inc, params, profile); 361 } 362 363 } 364 365 private ValueSet importValueSet(String value, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) 366 throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException, FHIRFormatError { 367 if (value == null) 368 throw new TerminologyServiceException("unable to find value set with no identity"); 369 ValueSet vs = context.fetchResource(ValueSet.class, value); 370 if (vs == null) 371 throw new TerminologyServiceException("Unable to find imported value set " + value); 372 ValueSetExpansionOutcome vso = factory.getExpander().expand(vs, profile); 373 if (vso.getError() != null) 374 throw new TerminologyServiceException("Unable to expand imported value set: " + vso.getError()); 375 if (vso.getService() != null) 376 throw new TerminologyServiceException("Unable to expand imported value set " + value); 377 if (vs.hasVersion()) 378 if (!existsInParams(params, "version", new UriType(vs.getUrl() + "|" + vs.getVersion()))) 379 params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(vs.getUrl() + "|" + vs.getVersion()))); 380 for (ValueSetExpansionParameterComponent p : vso.getValueset().getExpansion().getParameter()) { 381 if (!existsInParams(params, p.getName(), p.getValue())) 382 params.add(p); 383 } 384 canBeHeirarchy = false; // if we're importing a value set, we have to be combining, so we won't try for a heirarchy 385 return vso.getValueset(); 386 } 387 388 private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filter) { 389 for (ValueSetExpansionContainsComponent c : list) { 390 ValueSetExpansionContainsComponent np = addCode(c.getSystem(), c.getCode(), c.getDisplay(), parent, null, profile, c.getAbstract(), c.getInactive(), filter); 391 copyImportContains(c.getContains(), np, profile, filter); 392 } 393 } 394 395 private void includeCodes(ConceptSetComponent inc, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) throws ETooCostly, FileNotFoundException, IOException, FHIRException { 396 List<ValueSet> imports = new ArrayList<ValueSet>(); 397 for (UriType imp : inc.getValueSet()) 398 imports.add(importValueSet(imp.getValue(), params, profile)); 399 400 if (!inc.hasSystem()) { 401 if (imports.isEmpty()) // though this is not supposed to be the case 402 return; 403 ValueSet base = imports.get(0); 404 imports.remove(0); 405 copyImportContains(base.getExpansion().getContains(), null, profile, imports); 406 } else { 407 CodeSystem cs = context.fetchCodeSystem(inc.getSystem()); 408 if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(inc.getSystem())) { 409 addCodes(context.expandVS(inc, canBeHeirarchy), params, profile, imports); 410 return; 411 } 412 413 if (cs == null) { 414 if (context.isNoTerminologyServer()) 415 throw new NoTerminologyServiceException("unable to find code system " + inc.getSystem().toString()); 416 else 417 throw new TerminologyServiceException("unable to find code system " + inc.getSystem().toString()); 418 } 419 if (cs.getContent() != CodeSystemContentMode.COMPLETE) 420 throw new TerminologyServiceException("Code system " + inc.getSystem().toString() + " is incomplete"); 421 if (cs.hasVersion()) 422 if (!existsInParams(params, "version", new UriType(cs.getUrl() + "|" + cs.getVersion()))) 423 params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl() + "|" + cs.getVersion()))); 424 425 if (inc.getConcept().size() == 0 && inc.getFilter().size() == 0) { 426 // special case - add all the code system 427 for (ConceptDefinitionComponent def : cs.getConcept()) { 428 addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports); 429 } 430 } 431 432 if (!inc.getConcept().isEmpty()) { 433 canBeHeirarchy = false; 434 for (ConceptReferenceComponent c : inc.getConcept()) { 435 addCode(inc.getSystem(), c.getCode(), Utilities.noString(c.getDisplay()) ? getCodeDisplay(cs, c.getCode()) : c.getDisplay(), null, convertDesignations(c.getDesignation()), profile, false, 436 CodeSystemUtilities.isInactive(cs, c.getCode()), imports); 437 } 438 } 439 if (inc.getFilter().size() > 1) { 440 canBeHeirarchy = false; // which will bt the case if we get around to supporting this 441 throw new TerminologyServiceException("Multiple filters not handled yet"); // need to and them, and this isn't done yet. But this shouldn't arise in non loinc and snomed value sets 442 } 443 if (inc.getFilter().size() == 1) { 444 ConceptSetFilterComponent fc = inc.getFilter().get(0); 445 if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISA) { 446 // special: all codes in the target code system under the value 447 ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue()); 448 if (def == null) 449 throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'"); 450 addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports); 451 } else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.DESCENDENTOF) { 452 // special: all codes in the target code system under the value 453 ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue()); 454 if (def == null) 455 throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'"); 456 for (ConceptDefinitionComponent c : def.getConcept()) 457 addCodeAndDescendents(cs, inc.getSystem(), c, null, profile, imports); 458 } else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) { 459 // gg; note: wtf is this: if the filter is display=v, look up the code 'v', and see if it's diplsay is 'v'? 460 canBeHeirarchy = false; 461 ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue()); 462 if (def != null) { 463 if (isNotBlank(def.getDisplay()) && isNotBlank(fc.getValue())) { 464 if (def.getDisplay().contains(fc.getValue())) { 465 addCode(inc.getSystem(), def.getCode(), def.getDisplay(), null, def.getDesignation(), profile, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def), 466 imports); 467 } 468 } 469 } 470 } else 471 throw new NotImplementedException("Search by property[" + fc.getProperty() + "] and op[" + fc.getOp() + "] is not supported yet"); 472 } 473 } 474 } 475 476 private List<ConceptDefinitionDesignationComponent> convertDesignations(List<ConceptReferenceDesignationComponent> list) { 477 List<ConceptDefinitionDesignationComponent> res = new ArrayList<CodeSystem.ConceptDefinitionDesignationComponent>(); 478 for (ConceptReferenceDesignationComponent t : list) { 479 ConceptDefinitionDesignationComponent c = new ConceptDefinitionDesignationComponent(); 480 c.setLanguage(t.getLanguage()); 481 c.setUse(t.getUse()); 482 c.setValue(t.getValue()); 483 } 484 return res; 485 } 486 487 private String key(String uri, String code) { 488 return "{" + uri + "}" + code; 489 } 490 491 private String key(ValueSetExpansionContainsComponent c) { 492 return key(c.getSystem(), c.getCode()); 493 } 494 495}