
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 104@Deprecated 105public class ValueSetExpanderSimple implements ValueSetExpander { 106 107 private List<ValueSetExpansionContainsComponent> codes = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>(); 108 private List<ValueSetExpansionContainsComponent> roots = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>(); 109 private Map<String, ValueSetExpansionContainsComponent> map = new HashMap<String, ValueSet.ValueSetExpansionContainsComponent>(); 110 private IWorkerContext context; 111 private boolean canBeHierarchy = true; 112 private Set<String> excludeKeys = new HashSet<String>(); 113 private Set<String> excludeSystems = new HashSet<String>(); 114 private ValueSetExpanderFactory factory; 115 private ValueSet focus; 116 private int maxExpansionSize = 500; 117 118 private int total; 119 120 public ValueSetExpanderSimple(IWorkerContext context, ValueSetExpanderFactory factory) { 121 super(); 122 this.context = context; 123 this.factory = factory; 124 } 125 126 public void setMaxExpansionSize(int theMaxExpansionSize) { 127 maxExpansionSize = theMaxExpansionSize; 128 } 129 130 private ValueSetExpansionContainsComponent addCode(String system, String code, String display, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations, 131 ExpansionProfile profile, boolean isAbstract, boolean inactive, List<ValueSet> filters) { 132 if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code)) 133 return null; 134 ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent(); 135 n.setSystem(system); 136 n.setCode(code); 137 if (isAbstract) 138 n.setAbstract(true); 139 if (inactive) 140 n.setInactive(true); 141 142 if (profile.getIncludeDesignations() && designations != null) { 143 for (ConceptDefinitionDesignationComponent t : designations) { 144 ToolingExtensions.addLanguageTranslation(n, t.getLanguage(), t.getValue()); 145 } 146 } 147 ConceptDefinitionDesignationComponent t = profile.hasLanguage() ? getMatchingLang(designations, profile.getLanguage()) : null; 148 if (t == null) 149 n.setDisplay(display); 150 else 151 n.setDisplay(t.getValue()); 152 153 String s = key(n); 154 if (map.containsKey(s) || excludeKeys.contains(s)) { 155 canBeHierarchy = false; 156 } else { 157 codes.add(n); 158 map.put(s, n); 159 total++; 160 } 161 if (canBeHierarchy && parent != null) { 162 parent.getContains().add(n); 163 } else { 164 roots.add(n); 165 } 166 return n; 167 } 168 169 private boolean filterContainsCode(List<ValueSet> filters, String system, String code) { 170 for (ValueSet vse : filters) 171 if (expansionContainsCode(vse.getExpansion().getContains(), system, code)) 172 return true; 173 return false; 174 } 175 176 private boolean expansionContainsCode(List<ValueSetExpansionContainsComponent> contains, String system, String code) { 177 for (ValueSetExpansionContainsComponent cc : contains) { 178 if (system.equals(cc.getSystem()) && code.equals(cc.getCode())) 179 return true; 180 if (expansionContainsCode(cc.getContains(), system, code)) 181 return true; 182 } 183 return false; 184 } 185 186 private ConceptDefinitionDesignationComponent getMatchingLang(List<ConceptDefinitionDesignationComponent> list, String lang) { 187 for (ConceptDefinitionDesignationComponent t : list) 188 if (t.getLanguage().equals(lang)) 189 return t; 190 for (ConceptDefinitionDesignationComponent t : list) 191 if (t.getLanguage().startsWith(lang)) 192 return t; 193 return null; 194 } 195 196 private void addCodeAndDescendents(CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filters) 197 throws FHIRException { 198 if (!CodeSystemUtilities.isDeprecated(cs, def)) { 199 ValueSetExpansionContainsComponent np = null; 200 boolean abs = CodeSystemUtilities.isNotSelectable(cs, def); 201 boolean inc = CodeSystemUtilities.isInactive(cs, def); 202 if (canBeHierarchy || !abs) 203 np = addCode(system, def.getCode(), def.getDisplay(), parent, def.getDesignation(), profile, abs, inc, filters); 204 for (ConceptDefinitionComponent c : def.getConcept()) 205 addCodeAndDescendents(cs, system, c, np, profile, filters); 206 } else 207 for (ConceptDefinitionComponent c : def.getConcept()) 208 addCodeAndDescendents(cs, system, c, null, profile, filters); 209 210 } 211 212 private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile, List<ValueSet> filters) throws ETooCostly { 213 if (expand.getContains().size() > maxExpansionSize) 214 throw new ETooCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")"); 215 for (ValueSetExpansionParameterComponent p : expand.getParameter()) { 216 if (!existsInParams(params, p.getName(), p.getValue())) 217 params.add(p); 218 } 219 220 copyImportContains(expand.getContains(), null, profile, filters); 221 } 222 223 private void excludeCode(String theSystem, String theCode) { 224 ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent(); 225 n.setSystem(theSystem); 226 n.setCode(theCode); 227 String s = key(n); 228 excludeKeys.add(s); 229 } 230 231 private void excludeCodes(ConceptSetComponent exc, List<ValueSetExpansionParameterComponent> params) throws TerminologyServiceException { 232 if (exc.hasSystem() && exc.getConcept().size() == 0 && exc.getFilter().size() == 0) { 233 excludeSystems.add(exc.getSystem()); 234 } 235 236 if (exc.hasValueSet()) 237 throw new Error("Processing Value set references in exclude is not yet done"); 238 // importValueSet(imp.getValue(), params, profile); 239 240 CodeSystem cs = context.fetchCodeSystem(exc.getSystem()); 241 if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem())) { 242 excludeCodes(context.expandVS(exc, false), params); 243 return; 244 } 245 246 for (ConceptReferenceComponent c : exc.getConcept()) { 247 excludeCode(exc.getSystem(), c.getCode()); 248 } 249 250 if (exc.getFilter().size() > 0) 251 throw new NotImplementedException("not done yet"); 252 } 253 254 private void excludeCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) { 255 for (ValueSetExpansionContainsComponent c : expand.getContains()) { 256 excludeCode(c.getSystem(), c.getCode()); 257 } 258 } 259 260 private boolean existsInParams(List<ValueSetExpansionParameterComponent> params, String name, Type value) { 261 for (ValueSetExpansionParameterComponent p : params) { 262 if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false)) 263 return true; 264 } 265 return false; 266 } 267 268 @Override 269 public ValueSetExpansionOutcome expand(ValueSet source, ExpansionProfile profile) { 270 271 if (profile == null) 272 profile = makeDefaultExpansion(); 273 try { 274 focus = source.copy(); 275 focus.setExpansion(new ValueSet.ValueSetExpansionComponent()); 276 focus.getExpansion().setTimestampElement(DateTimeType.now()); 277 focus.getExpansion().setIdentifier(Factory.createUUID()); 278 if (!profile.getUrl().startsWith("urn:uuid:")) 279 focus.getExpansion().addParameter().setName("profile").setValue(new UriType(profile.getUrl())); 280 281 if (source.hasCompose()) 282 handleCompose(source.getCompose(), focus.getExpansion().getParameter(), profile); 283 284 if (canBeHierarchy) { 285 for (ValueSetExpansionContainsComponent c : roots) { 286 focus.getExpansion().getContains().add(c); 287 } 288 } else { 289 for (ValueSetExpansionContainsComponent c : codes) { 290 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 291 focus.getExpansion().getContains().add(c); 292 c.getContains().clear(); // make sure any hierarchy is wiped 293 } 294 } 295 } 296 297 if (total > 0) { 298 focus.getExpansion().setTotal(total); 299 } 300 301 return new ValueSetExpansionOutcome(focus); 302 } catch (NoTerminologyServiceException e) { 303 // well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set 304 // that might fail too, but it might not, later. 305 return new ValueSetExpansionOutcome(new ValueSetCheckerSimple(source, factory, context), e.getMessage(), TerminologyServiceErrorClass.NOSERVICE); 306 } catch (RuntimeException e) { 307 // TODO: we should put something more specific instead of just Exception below, since 308 // it swallows bugs.. what would be expected to be caught there? 309 throw e; 310 } catch (Exception e) { 311 // well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set 312 // that might fail too, but it might not, later. 313 return new ValueSetExpansionOutcome(new ValueSetCheckerSimple(source, factory, context), e.getMessage(), TerminologyServiceErrorClass.UNKNOWN); 314 } 315 } 316 317 private ExpansionProfile makeDefaultExpansion() { 318 ExpansionProfile res = new ExpansionProfile(); 319 res.setUrl("urn:uuid:" + UUID.randomUUID().toString().toLowerCase()); 320 res.setExcludeNested(true); 321 res.setIncludeDesignations(false); 322 return res; 323 } 324 325 private String getCodeDisplay(CodeSystem cs, String code) throws TerminologyServiceException { 326 ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), code); 327 if (def == null) 328 throw new TerminologyServiceException("Unable to find code '" + code + "' in code system " + cs.getUrl()); 329 return def.getDisplay(); 330 } 331 332 private ConceptDefinitionComponent getConceptForCode(List<ConceptDefinitionComponent> clist, String code) { 333 for (ConceptDefinitionComponent c : clist) { 334 if (code.equals(c.getCode())) 335 return c; 336 ConceptDefinitionComponent v = getConceptForCode(c.getConcept(), code); 337 if (v != null) 338 return v; 339 } 340 return null; 341 } 342 343 private void handleCompose(ValueSetComposeComponent compose, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) 344 throws ETooCostly, FileNotFoundException, IOException, FHIRException { 345 // Exclude comes first because we build up a map of things to exclude 346 for (ConceptSetComponent inc : compose.getExclude()) 347 excludeCodes(inc, params); 348 canBeHierarchy = !profile.getExcludeNested() && excludeKeys.isEmpty() && excludeSystems.isEmpty(); 349 boolean first = true; 350 for (ConceptSetComponent inc : compose.getInclude()) { 351 if (first == true) 352 first = false; 353 else 354 canBeHierarchy = false; 355 includeCodes(inc, params, profile); 356 } 357 358 } 359 360 private ValueSet importValueSet(String value, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) 361 throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException, FHIRFormatError { 362 if (value == null) 363 throw new TerminologyServiceException("unable to find value set with no identity"); 364 ValueSet vs = context.fetchResource(ValueSet.class, value); 365 if (vs == null) 366 throw new TerminologyServiceException("Unable to find imported value set " + value); 367 ValueSetExpansionOutcome vso = factory.getExpander().expand(vs, profile); 368 if (vso.getError() != null) 369 throw new TerminologyServiceException("Unable to expand imported value set: " + vso.getError()); 370 if (vso.getService() != null) 371 throw new TerminologyServiceException("Unable to expand imported value set " + value); 372 if (vs.hasVersion()) 373 if (!existsInParams(params, "version", new UriType(vs.getUrl() + "|" + vs.getVersion()))) 374 params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(vs.getUrl() + "|" + vs.getVersion()))); 375 for (ValueSetExpansionParameterComponent p : vso.getValueset().getExpansion().getParameter()) { 376 if (!existsInParams(params, p.getName(), p.getValue())) 377 params.add(p); 378 } 379 canBeHierarchy = false; // if we're importing a value set, we have to be combining, so we won't try for a hierarchy 380 return vso.getValueset(); 381 } 382 383 private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filter) { 384 for (ValueSetExpansionContainsComponent c : list) { 385 ValueSetExpansionContainsComponent np = addCode(c.getSystem(), c.getCode(), c.getDisplay(), parent, null, profile, c.getAbstract(), c.getInactive(), filter); 386 copyImportContains(c.getContains(), np, profile, filter); 387 } 388 } 389 390 private void includeCodes(ConceptSetComponent inc, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) throws ETooCostly, FileNotFoundException, IOException, FHIRException { 391 List<ValueSet> imports = new ArrayList<ValueSet>(); 392 for (UriType imp : inc.getValueSet()) 393 imports.add(importValueSet(imp.getValue(), params, profile)); 394 395 if (!inc.hasSystem()) { 396 if (imports.isEmpty()) // though this is not supposed to be the case 397 return; 398 ValueSet base = imports.get(0); 399 imports.remove(0); 400 copyImportContains(base.getExpansion().getContains(), null, profile, imports); 401 } else { 402 CodeSystem cs = context.fetchCodeSystem(inc.getSystem()); 403 if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(inc.getSystem())) { 404 addCodes(context.expandVS(inc, canBeHierarchy), params, profile, imports); 405 return; 406 } 407 408 if (cs == null) { 409 if (context.isNoTerminologyServer()) 410 throw new NoTerminologyServiceException("unable to find code system " + inc.getSystem().toString()); 411 else 412 throw new TerminologyServiceException("unable to find code system " + inc.getSystem().toString()); 413 } 414 if (cs.getContent() != CodeSystemContentMode.COMPLETE) 415 throw new TerminologyServiceException("Code system " + inc.getSystem().toString() + " is incomplete"); 416 if (cs.hasVersion()) 417 if (!existsInParams(params, "version", new UriType(cs.getUrl() + "|" + cs.getVersion()))) 418 params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl() + "|" + cs.getVersion()))); 419 420 if (inc.getConcept().size() == 0 && inc.getFilter().size() == 0) { 421 // special case - add all the code system 422 for (ConceptDefinitionComponent def : cs.getConcept()) { 423 addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports); 424 } 425 } 426 427 if (!inc.getConcept().isEmpty()) { 428 canBeHierarchy = false; 429 for (ConceptReferenceComponent c : inc.getConcept()) { 430 addCode(inc.getSystem(), c.getCode(), Utilities.noString(c.getDisplay()) ? getCodeDisplay(cs, c.getCode()) : c.getDisplay(), null, convertDesignations(c.getDesignation()), profile, false, 431 CodeSystemUtilities.isInactive(cs, c.getCode()), imports); 432 } 433 } 434 if (inc.getFilter().size() > 1) { 435 canBeHierarchy = false; // which will bt the case if we get around to supporting this 436 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 437 } 438 if (inc.getFilter().size() == 1) { 439 ConceptSetFilterComponent fc = inc.getFilter().get(0); 440 if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISA) { 441 // special: all codes in the target code system under the value 442 ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue()); 443 if (def == null) 444 throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'"); 445 addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports); 446 } else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.DESCENDENTOF) { 447 // special: all codes in the target code system under the value 448 ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue()); 449 if (def == null) 450 throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'"); 451 for (ConceptDefinitionComponent c : def.getConcept()) 452 addCodeAndDescendents(cs, inc.getSystem(), c, null, profile, imports); 453 } else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) { 454 // gg; note: wtf is this: if the filter is display=v, look up the code 'v', and see if it's diplsay is 'v'? 455 canBeHierarchy = false; 456 ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue()); 457 if (def != null) { 458 if (isNotBlank(def.getDisplay()) && isNotBlank(fc.getValue())) { 459 if (def.getDisplay().contains(fc.getValue())) { 460 addCode(inc.getSystem(), def.getCode(), def.getDisplay(), null, def.getDesignation(), profile, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def), 461 imports); 462 } 463 } 464 } 465 } else 466 throw new NotImplementedException("Search by property[" + fc.getProperty() + "] and op[" + fc.getOp() + "] is not supported yet"); 467 } 468 } 469 } 470 471 private List<ConceptDefinitionDesignationComponent> convertDesignations(List<ConceptReferenceDesignationComponent> list) { 472 List<ConceptDefinitionDesignationComponent> res = new ArrayList<CodeSystem.ConceptDefinitionDesignationComponent>(); 473 for (ConceptReferenceDesignationComponent t : list) { 474 ConceptDefinitionDesignationComponent c = new ConceptDefinitionDesignationComponent(); 475 c.setLanguage(t.getLanguage()); 476 c.setUse(t.getUse()); 477 c.setValue(t.getValue()); 478 } 479 return res; 480 } 481 482 private String key(String uri, String code) { 483 return "{" + uri + "}" + code; 484 } 485 486 private String key(ValueSetExpansionContainsComponent c) { 487 return key(c.getSystem(), c.getCode()); 488 } 489 490}