
001package org.hl7.fhir.r4.context; 002 003import java.io.FileNotFoundException; 004import java.io.IOException; 005import java.util.ArrayList; 006import java.util.Collection; 007import java.util.Date; 008import java.util.HashMap; 009import java.util.HashSet; 010import java.util.List; 011import java.util.Locale; 012import java.util.Map; 013import java.util.ResourceBundle; 014import java.util.Set; 015 016import lombok.extern.slf4j.Slf4j; 017import org.apache.commons.lang3.StringUtils; 018import org.fhir.ucum.UcumService; 019import org.hl7.fhir.exceptions.DefinitionException; 020import org.hl7.fhir.exceptions.FHIRException; 021import org.hl7.fhir.exceptions.TerminologyServiceException; 022import org.hl7.fhir.r4.conformance.ProfileUtilities; 023import org.hl7.fhir.r4.context.TerminologyCache.CacheToken; 024import org.hl7.fhir.r4.model.BooleanType; 025import org.hl7.fhir.r4.model.CapabilityStatement; 026import org.hl7.fhir.r4.model.CodeSystem; 027import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode; 028import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent; 029import org.hl7.fhir.r4.model.CodeableConcept; 030import org.hl7.fhir.r4.model.Coding; 031import org.hl7.fhir.r4.model.ConceptMap; 032import org.hl7.fhir.r4.model.Constants; 033import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent; 034import org.hl7.fhir.r4.model.ImplementationGuide; 035import org.hl7.fhir.r4.model.IntegerType; 036import org.hl7.fhir.r4.model.MetadataResource; 037import org.hl7.fhir.r4.model.NamingSystem; 038import org.hl7.fhir.r4.model.NamingSystem.NamingSystemIdentifierType; 039import org.hl7.fhir.r4.model.NamingSystem.NamingSystemUniqueIdComponent; 040import org.hl7.fhir.r4.model.OperationDefinition; 041import org.hl7.fhir.r4.model.Parameters; 042import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent; 043import org.hl7.fhir.r4.model.PlanDefinition; 044import org.hl7.fhir.r4.model.Questionnaire; 045import org.hl7.fhir.r4.model.Reference; 046import org.hl7.fhir.r4.model.Resource; 047import org.hl7.fhir.r4.model.SearchParameter; 048import org.hl7.fhir.r4.model.StringType; 049import org.hl7.fhir.r4.model.StructureDefinition; 050import org.hl7.fhir.r4.model.StructureMap; 051import org.hl7.fhir.r4.model.TerminologyCapabilities; 052import org.hl7.fhir.r4.model.TerminologyCapabilities.TerminologyCapabilitiesCodeSystemComponent; 053import org.hl7.fhir.r4.model.ValueSet; 054import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent; 055import org.hl7.fhir.r4.model.ValueSet.ValueSetComposeComponent; 056import org.hl7.fhir.r4.terminologies.TerminologyClient; 057import org.hl7.fhir.r4.terminologies.ValueSetCheckerSimple; 058import org.hl7.fhir.r4.terminologies.ValueSetExpander.TerminologyServiceErrorClass; 059import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome; 060import org.hl7.fhir.r4.terminologies.ValueSetExpanderSimple; 061import org.hl7.fhir.r4.utils.ToolingExtensions; 062import org.hl7.fhir.r4.model.DomainResource; 063import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 064import org.hl7.fhir.utilities.OIDUtilities; 065import org.hl7.fhir.utilities.TranslationServices; 066import org.hl7.fhir.utilities.UUIDUtilities; 067import org.hl7.fhir.utilities.Utilities; 068import org.hl7.fhir.utilities.i18n.I18nBase; 069import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 070import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; 071import org.hl7.fhir.utilities.validation.ValidationOptions; 072 073/* 074 Copyright (c) 2011+, HL7, Inc. 075 All rights reserved. 076 077 Redistribution and use in source and binary forms, with or without modification, 078 are permitted provided that the following conditions are met: 079 080 * Redistributions of source code must retain the above copyright notice, this 081 list of conditions and the following disclaimer. 082 * Redistributions in binary form must reproduce the above copyright notice, 083 this list of conditions and the following disclaimer in the documentation 084 and/or other materials provided with the distribution. 085 * Neither the name of HL7 nor the names of its contributors may be used to 086 endorse or promote products derived from this software without specific 087 prior written permission. 088 089 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 090 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 091 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 092 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 093 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 094 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 095 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 096 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 097 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 098 POSSIBILITY OF SUCH DAMAGE. 099 100 */ 101 102import com.google.gson.JsonObject; 103 104@MarkedToMoveToAdjunctPackage 105@Slf4j 106public abstract class BaseWorkerContext extends I18nBase implements IWorkerContext { 107 108 109 private Object lock = new Object(); // used as a lock for the data that follows 110 111 private Map<String, Map<String, Resource>> allResourcesById = new HashMap<String, Map<String, Resource>>(); 112 // all maps are to the full URI 113 private Map<String, CodeSystem> codeSystems = new HashMap<String, CodeSystem>(); 114 private Set<String> supportedCodeSystems = new HashSet<String>(); 115 private Map<String, ValueSet> valueSets = new HashMap<String, ValueSet>(); 116 private Map<String, ConceptMap> maps = new HashMap<String, ConceptMap>(); 117 protected Map<String, StructureMap> transforms = new HashMap<String, StructureMap>(); 118 private Map<String, StructureDefinition> structures = new HashMap<String, StructureDefinition>(); 119 private Map<String, ImplementationGuide> guides = new HashMap<String, ImplementationGuide>(); 120 private Map<String, CapabilityStatement> capstmts = new HashMap<String, CapabilityStatement>(); 121 private Map<String, SearchParameter> searchParameters = new HashMap<String, SearchParameter>(); 122 private Map<String, Questionnaire> questionnaires = new HashMap<String, Questionnaire>(); 123 private Map<String, OperationDefinition> operations = new HashMap<String, OperationDefinition>(); 124 private Map<String, PlanDefinition> plans = new HashMap<String, PlanDefinition>(); 125 private List<NamingSystem> systems = new ArrayList<NamingSystem>(); 126 private UcumService ucumService; 127 128 protected Map<String, Map<String, ValidationResult>> validationCache = new HashMap<String, Map<String, ValidationResult>>(); 129 protected String tsServer; 130 protected String name; 131 private boolean allowLoadingDuplicates; 132 133 protected TerminologyClient txClient; 134 protected HTMLClientLogger txLog; 135 private TerminologyCapabilities txcaps; 136 private boolean canRunWithoutTerminology; 137 protected boolean noTerminologyServer; 138 private int expandCodesLimit = 1000; 139 140 protected Parameters expParameters; 141 private TranslationServices translator = new NullTranslator(); 142 protected TerminologyCache txCache; 143 144 private boolean tlogging = true; 145 private Locale locale; 146 private ResourceBundle i18Nmessages; 147 148 public BaseWorkerContext() throws FileNotFoundException, IOException, FHIRException { 149 super(); 150 txCache = new TerminologyCache(lock, null); 151 } 152 153 public BaseWorkerContext(Map<String, CodeSystem> codeSystems, Map<String, ValueSet> valueSets, 154 Map<String, ConceptMap> maps, Map<String, StructureDefinition> profiles, Map<String, ImplementationGuide> guides) 155 throws FileNotFoundException, IOException, FHIRException { 156 super(); 157 this.codeSystems = codeSystems; 158 this.valueSets = valueSets; 159 this.maps = maps; 160 this.structures = profiles; 161 this.guides = guides; 162 txCache = new TerminologyCache(lock, null); 163 } 164 165 protected void copy(BaseWorkerContext other) { 166 synchronized (other.lock) { // tricky, because you need to lock this as well, but it's really not in use yet 167 allResourcesById.putAll(other.allResourcesById); 168 translator = other.translator; 169 codeSystems.putAll(other.codeSystems); 170 txcaps = other.txcaps; 171 valueSets.putAll(other.valueSets); 172 maps.putAll(other.maps); 173 transforms.putAll(other.transforms); 174 structures.putAll(other.structures); 175 searchParameters.putAll(other.searchParameters); 176 plans.putAll(other.plans); 177 questionnaires.putAll(other.questionnaires); 178 operations.putAll(other.operations); 179 systems.addAll(other.systems); 180 guides.putAll(other.guides); 181 capstmts.putAll(other.capstmts); 182 183 allowLoadingDuplicates = other.allowLoadingDuplicates; 184 tsServer = other.tsServer; 185 name = other.name; 186 txClient = other.txClient; 187 txLog = other.txLog; 188 txcaps = other.txcaps; 189 canRunWithoutTerminology = other.canRunWithoutTerminology; 190 noTerminologyServer = other.noTerminologyServer; 191 if (other.txCache != null) 192 txCache = other.txCache.copy(); 193 expandCodesLimit = other.expandCodesLimit; 194 195 expParameters = other.expParameters; 196 } 197 } 198 199 public void cacheResource(Resource r) throws FHIRException { 200 synchronized (lock) { 201 Map<String, Resource> map = allResourcesById.get(r.fhirType()); 202 if (map == null) { 203 map = new HashMap<String, Resource>(); 204 allResourcesById.put(r.fhirType(), map); 205 } 206 map.put(r.getId(), r); 207 208 if (r instanceof MetadataResource) { 209 MetadataResource m = (MetadataResource) r; 210 String url = m.getUrl(); 211 if (!allowLoadingDuplicates && hasResource(r.getClass(), url)) 212 throw new DefinitionException("Duplicate Resource " + url); 213 if (r instanceof StructureDefinition) 214 seeMetadataResource((StructureDefinition) m, structures, false); 215 else if (r instanceof ValueSet) 216 seeMetadataResource((ValueSet) m, valueSets, false); 217 else if (r instanceof CodeSystem) 218 seeMetadataResource((CodeSystem) m, codeSystems, false); 219 else if (r instanceof ImplementationGuide) 220 seeMetadataResource((ImplementationGuide) m, guides, false); 221 else if (r instanceof CapabilityStatement) 222 seeMetadataResource((CapabilityStatement) m, capstmts, false); 223 else if (r instanceof SearchParameter) 224 seeMetadataResource((SearchParameter) m, searchParameters, false); 225 else if (r instanceof PlanDefinition) 226 seeMetadataResource((PlanDefinition) m, plans, false); 227 else if (r instanceof OperationDefinition) 228 seeMetadataResource((OperationDefinition) m, operations, false); 229 else if (r instanceof Questionnaire) 230 seeMetadataResource((Questionnaire) m, questionnaires, true); 231 else if (r instanceof ConceptMap) 232 seeMetadataResource((ConceptMap) m, maps, false); 233 else if (r instanceof StructureMap) 234 seeMetadataResource((StructureMap) m, transforms, false); 235 else if (r instanceof NamingSystem) 236 systems.add((NamingSystem) r); 237 } 238 } 239 } 240 241 /* 242 * Compare business versions, returning "true" if the candidate newer version is 243 * in fact newer than the oldVersion Comparison will work for strictly numeric 244 * versions as well as multi-level versions separated by ., -, _, : or space 245 * Failing that, it will do unicode-based character ordering. E.g. 1.5.3 < 246 * 1.14.3 2017-3-10 < 2017-12-7 A3 < T2 247 */ 248 private boolean laterVersion(String newVersion, String oldVersion) { 249 // Compare business versions, retur 250 newVersion = newVersion.trim(); 251 oldVersion = oldVersion.trim(); 252 if (StringUtils.isNumeric(newVersion) && StringUtils.isNumeric(oldVersion)) 253 return Double.parseDouble(newVersion) > Double.parseDouble(oldVersion); 254 else if (hasDelimiter(newVersion, oldVersion, ".")) 255 return laterDelimitedVersion(newVersion, oldVersion, "\\."); 256 else if (hasDelimiter(newVersion, oldVersion, "-")) 257 return laterDelimitedVersion(newVersion, oldVersion, "\\-"); 258 else if (hasDelimiter(newVersion, oldVersion, "_")) 259 return laterDelimitedVersion(newVersion, oldVersion, "\\_"); 260 else if (hasDelimiter(newVersion, oldVersion, ":")) 261 return laterDelimitedVersion(newVersion, oldVersion, "\\:"); 262 else if (hasDelimiter(newVersion, oldVersion, " ")) 263 return laterDelimitedVersion(newVersion, oldVersion, "\\ "); 264 else { 265 return newVersion.compareTo(oldVersion) > 0; 266 } 267 } 268 269 /* 270 * Returns true if both strings include the delimiter and have the same number 271 * of occurrences of it 272 */ 273 private boolean hasDelimiter(String s1, String s2, String delimiter) { 274 return s1.contains(delimiter) && s2.contains(delimiter) && s1.split(delimiter).length == s2.split(delimiter).length; 275 } 276 277 private boolean laterDelimitedVersion(String newVersion, String oldVersion, String delimiter) { 278 String[] newParts = newVersion.split(delimiter); 279 String[] oldParts = oldVersion.split(delimiter); 280 for (int i = 0; i < newParts.length; i++) { 281 if (!newParts[i].equals(oldParts[i])) 282 return laterVersion(newParts[i], oldParts[i]); 283 } 284 // This should never happen 285 throw new Error( 286 "Delimited versions have exact match for delimiter '" + delimiter + "' : " + newParts + " vs " + oldParts); 287 } 288 289 protected <T extends MetadataResource> void seeMetadataResource(T r, Map<String, T> map, boolean addId) 290 throws FHIRException { 291 if (addId) 292 map.put(r.getId(), r); // todo: why? 293 if (!map.containsKey(r.getUrl())) 294 map.put(r.getUrl(), r); 295 else { 296 // If this resource already exists, see if it's the newest business version. The 297 // default resource to return if not qualified is the most recent business 298 // version 299 MetadataResource existingResource = (MetadataResource) map.get(r.getUrl()); 300 if (r.hasVersion() && existingResource.hasVersion() && !r.getVersion().equals(existingResource.getVersion())) { 301 if (laterVersion(r.getVersion(), existingResource.getVersion())) { 302 map.remove(r.getUrl()); 303 map.put(r.getUrl(), r); 304 } 305 } else 306 map.remove(r.getUrl()); 307 map.put(r.getUrl(), r); 308// throw new FHIRException("Multiple declarations of resource with same canonical URL (" + r.getUrl() + ") and version (" + (r.hasVersion() ? r.getVersion() : "" ) + ")"); 309 } 310 if (r.hasVersion()) 311 map.put(r.getUrl() + "|" + r.getVersion(), r); 312 } 313 314 @Override 315 public CodeSystem fetchCodeSystem(String system) { 316 synchronized (lock) { 317 return codeSystems.get(system); 318 } 319 } 320 321 @Override 322 public boolean supportsSystem(String system) throws TerminologyServiceException { 323 synchronized (lock) { 324 if (codeSystems.containsKey(system) && codeSystems.get(system).getContent() != CodeSystemContentMode.NOTPRESENT) 325 return true; 326 else if (supportedCodeSystems.contains(system)) 327 return true; 328 else if (system.startsWith("http://example.org") || system.startsWith("http://acme.com") 329 || system.startsWith("http://hl7.org/fhir/valueset-") || system.startsWith("urn:oid:")) 330 return false; 331 else { 332 if (noTerminologyServer) 333 return false; 334 if (txcaps == null) { 335 try { 336 log.info("Terminology server: Check for supported code systems for " + system); 337 txcaps = txClient.getTerminologyCapabilities(); 338 } catch (Exception e) { 339 if (canRunWithoutTerminology) { 340 noTerminologyServer = true; 341 log.info("==============!! Running without terminology server !! =============="); 342 if (txClient != null) { 343 log.info("txServer = " + txClient.getAddress()); 344 log.info("Error = " + e.getMessage() + ""); 345 } 346 log.info("====================================================================="); 347 return false; 348 } else 349 throw new TerminologyServiceException(e); 350 } 351 if (txcaps != null) { 352 for (TerminologyCapabilitiesCodeSystemComponent tccs : txcaps.getCodeSystem()) { 353 supportedCodeSystems.add(tccs.getUri()); 354 } 355 } 356 if (supportedCodeSystems.contains(system)) 357 return true; 358 } 359 } 360 return false; 361 } 362 } 363 364 protected void tlog(String msg) { 365 if (tlogging) 366 log.info("-tx cache miss: " + msg); 367 } 368 369 // --- expansion support 370 // ------------------------------------------------------------------------------------------------------------ 371 372 public int getExpandCodesLimit() { 373 return expandCodesLimit; 374 } 375 376 public void setExpandCodesLimit(int expandCodesLimit) { 377 this.expandCodesLimit = expandCodesLimit; 378 } 379 380 @Override 381 public ValueSetExpansionOutcome expandVS(ElementDefinitionBindingComponent binding, boolean cacheOk, 382 boolean heirarchical) throws FHIRException { 383 ValueSet vs = null; 384 vs = fetchResource(ValueSet.class, binding.getValueSet()); 385 if (vs == null) 386 throw new FHIRException("Unable to resolve value Set " + binding.getValueSet()); 387 return expandVS(vs, cacheOk, heirarchical); 388 } 389 390 @Override 391 public ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean heirachical) 392 throws TerminologyServiceException { 393 ValueSet vs = new ValueSet(); 394 vs.setCompose(new ValueSetComposeComponent()); 395 vs.getCompose().getInclude().add(inc); 396 CacheToken cacheToken = txCache.generateExpandToken(vs, heirachical); 397 ValueSetExpansionOutcome res; 398 res = txCache.getExpansion(cacheToken); 399 if (res != null) 400 return res; 401 Parameters p = expParameters.copy(); 402 p.setParameter("includeDefinition", false); 403 p.setParameter("excludeNested", !heirachical); 404 405 if (noTerminologyServer) 406 return new ValueSetExpansionOutcome("Error expanding ValueSet: running without terminology services", 407 TerminologyServiceErrorClass.NOSERVICE); 408 409 p.addParameter().setName("_limit").setValue(new IntegerType(expandCodesLimit)); 410 p.addParameter().setName("_incomplete").setValue(new BooleanType("true")); 411 412 tlog("$expand on " + txCache.summary(vs)); 413 try { 414 ValueSet result = txClient.expandValueset(vs, p); 415 res = new ValueSetExpansionOutcome(result).setTxLink(txLog == null ? null : txLog.getLastId()); 416 } catch (Exception e) { 417 res = new ValueSetExpansionOutcome(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), 418 TerminologyServiceErrorClass.UNKNOWN); 419 if (txLog != null) 420 res.setTxLink(txLog.getLastId()); 421 } 422 txCache.cacheExpansion(cacheToken, res, TerminologyCache.PERMANENT); 423 return res; 424 425 } 426 427 @Override 428 public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical) { 429 if (expParameters == null) 430 throw new Error("No Expansion Parameters provided"); 431 Parameters p = expParameters.copy(); 432 return expandVS(vs, cacheOk, heirarchical, p); 433 } 434 435 public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical, Parameters p) { 436 if (p == null) 437 throw new Error("No Parameters provided to expandVS"); 438 if (vs.hasExpansion()) { 439 return new ValueSetExpansionOutcome(vs.copy()); 440 } 441 if (!vs.hasUrl()) 442 throw new Error("no value set"); 443 444 CacheToken cacheToken = txCache.generateExpandToken(vs, heirarchical); 445 ValueSetExpansionOutcome res; 446 if (cacheOk) { 447 res = txCache.getExpansion(cacheToken); 448 if (res != null) 449 return res; 450 } 451 p.setParameter("includeDefinition", false); 452 p.setParameter("excludeNested", !heirarchical); 453 454 // ok, first we try to expand locally 455 try { 456 ValueSetExpanderSimple vse = new ValueSetExpanderSimple(this); 457 res = vse.doExpand(vs, p); 458 if (!res.getValueset().hasUrl()) 459 throw new Error("no url in expand value set"); 460 txCache.cacheExpansion(cacheToken, res, TerminologyCache.TRANSIENT); 461 return res; 462 } catch (Exception e) { 463 } 464 465 // if that failed, we try to expand on the server 466 if (noTerminologyServer) 467 return new ValueSetExpansionOutcome("Error expanding ValueSet: running without terminology services", 468 TerminologyServiceErrorClass.NOSERVICE); 469 470 p.addParameter().setName("_limit").setValue(new IntegerType(expandCodesLimit)); 471 p.addParameter().setName("_incomplete").setValue(new BooleanType("true")); 472 473 tlog("$expand on " + txCache.summary(vs)); 474 try { 475 ValueSet result = txClient.expandValueset(vs, p); 476 if (result != null) { 477 if (!result.hasUrl()) 478 result.setUrl(vs.getUrl()); 479 if (!result.hasUrl()) 480 throw new Error("no url in expand value set 2"); 481 } 482 res = new ValueSetExpansionOutcome(result).setTxLink(txLog == null ? null : txLog.getLastId()); 483 } catch (Exception e) { 484 res = new ValueSetExpansionOutcome(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), 485 TerminologyServiceErrorClass.UNKNOWN).setTxLink(txLog == null ? null : txLog.getLastId()); 486 } 487 txCache.cacheExpansion(cacheToken, res, TerminologyCache.PERMANENT); 488 return res; 489 } 490 491 private boolean hasTooCostlyExpansion(ValueSet valueset) { 492 return valueset != null && valueset.hasExpansion() && ToolingExtensions.hasExtension(valueset.getExpansion(), 493 "http://hl7.org/fhir/StructureDefinition/valueset-toocostly"); 494 } 495 // --- validate code 496 // ------------------------------------------------------------------------------- 497 498 @Override 499 public ValidationResult validateCode(ValidationOptions options, String system, String code, String display) { 500 Coding c = new Coding(system, code, display); 501 return validateCode(options, c, null); 502 } 503 504 @Override 505 public ValidationResult validateCode(ValidationOptions options, String system, String code, String display, 506 ValueSet vs) { 507 Coding c = new Coding(system, code, display); 508 return validateCode(options, c, vs); 509 } 510 511 @Override 512 public ValidationResult validateCode(ValidationOptions options, String code, ValueSet vs) { 513 Coding c = new Coding(null, code, null); 514 return doValidateCode(options, c, vs, true); 515 } 516 517 @Override 518 public ValidationResult validateCode(ValidationOptions options, String system, String code, String display, 519 ConceptSetComponent vsi) { 520 Coding c = new Coding(system, code, display); 521 ValueSet vs = new ValueSet(); 522 vs.setUrl(UUIDUtilities.makeUuidUrn()); 523 vs.getCompose().addInclude(vsi); 524 return validateCode(options, c, vs); 525 } 526 527 @Override 528 public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs) { 529 return doValidateCode(options, code, vs, false); 530 } 531 532 public ValidationResult doValidateCode(ValidationOptions options, Coding code, ValueSet vs, boolean inferSystem) { 533 CacheToken cacheToken = txCache != null ? txCache.generateValidationToken(options, code, vs) : null; 534 ValidationResult res = null; 535 if (txCache != null) 536 res = txCache.getValidation(cacheToken); 537 if (res != null) 538 return res; 539 540 // ok, first we try to validate locally 541 try { 542 ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, this); 543 res = vsc.validateCode(code); 544 if (txCache != null) 545 txCache.cacheValidation(cacheToken, res, TerminologyCache.TRANSIENT); 546 return res; 547 } catch (Exception e) { 548 } 549 550 // if that failed, we try to validate on the server 551 if (noTerminologyServer) 552 return new ValidationResult(IssueSeverity.ERROR, "Error validating code: running without terminology services", 553 TerminologyServiceErrorClass.NOSERVICE); 554 String csumm = txCache != null ? txCache.summary(code) : null; 555 if (txCache != null) 556 tlog("$validate " + csumm + " for " + txCache.summary(vs)); 557 else 558 tlog("$validate " + csumm + " before cache exists"); 559 try { 560 Parameters pIn = new Parameters(); 561 pIn.addParameter().setName("coding").setValue(code); 562 if (inferSystem) 563 pIn.addParameter().setName("inferSystem").setValue(new BooleanType(true)); 564 if (options != null) 565 setTerminologyOptions(options, pIn); 566 res = validateOnServer(vs, pIn); 567 } catch (Exception e) { 568 res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage()) 569 .setTxLink(txLog == null ? null : txLog.getLastId()); 570 } 571 if (txCache != null) 572 txCache.cacheValidation(cacheToken, res, TerminologyCache.PERMANENT); 573 return res; 574 } 575 576 private void setTerminologyOptions(ValidationOptions options, Parameters pIn) { 577 if (options != null && options.hasLanguages()) { 578 pIn.addParameter("displayLanguage", options.getLanguages().toString()); 579 } 580 } 581 582 @Override 583 public ValidationResult validateCode(ValidationOptions options, CodeableConcept code, ValueSet vs) { 584 CacheToken cacheToken = txCache.generateValidationToken(options, code, vs); 585 ValidationResult res = txCache.getValidation(cacheToken); 586 if (res != null) 587 return res; 588 589 // ok, first we try to validate locally 590 try { 591 ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, this); 592 res = vsc.validateCode(code); 593 txCache.cacheValidation(cacheToken, res, TerminologyCache.TRANSIENT); 594 return res; 595 } catch (Exception e) { 596 } 597 598 // if that failed, we try to validate on the server 599 if (noTerminologyServer) 600 return new ValidationResult(IssueSeverity.ERROR, "Error validating code: running without terminology services", 601 TerminologyServiceErrorClass.NOSERVICE); 602 tlog("$validate " + txCache.summary(code) + " for " + txCache.summary(vs)); 603 try { 604 Parameters pIn = new Parameters(); 605 pIn.addParameter().setName("codeableConcept").setValue(code); 606 if (options != null) 607 setTerminologyOptions(options, pIn); 608 res = validateOnServer(vs, pIn); 609 } catch (Exception e) { 610 res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage()) 611 .setTxLink(txLog == null ? null : txLog.getLastId()); 612 } 613 txCache.cacheValidation(cacheToken, res, TerminologyCache.PERMANENT); 614 return res; 615 } 616 617 private ValidationResult validateOnServer(ValueSet vs, Parameters pin) throws FHIRException { 618 if (vs != null) 619 pin.addParameter().setName("valueSet").setResource(vs); 620 for (ParametersParameterComponent pp : pin.getParameter()) 621 if (pp.getName().equals("profile")) 622 throw new Error("Can only specify profile in the context"); 623 if (expParameters == null) 624 throw new Error("No ExpansionProfile provided"); 625 pin.addParameter().setName("profile").setResource(expParameters); 626 txLog.clearLastId(); 627 Parameters pOut; 628 if (vs == null) 629 pOut = txClient.validateCS(pin); 630 else 631 pOut = txClient.validateVS(pin); 632 boolean ok = false; 633 String message = "No Message returned"; 634 String display = null; 635 TerminologyServiceErrorClass err = TerminologyServiceErrorClass.UNKNOWN; 636 for (ParametersParameterComponent p : pOut.getParameter()) { 637 if (p.getName().equals("result")) 638 ok = ((BooleanType) p.getValue()).getValue().booleanValue(); 639 else if (p.getName().equals("message")) 640 message = ((StringType) p.getValue()).getValue(); 641 else if (p.getName().equals("display")) 642 display = ((StringType) p.getValue()).getValue(); 643 else if (p.getName().equals("cause")) { 644 try { 645 IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue()); 646 if (it == IssueType.UNKNOWN) 647 err = TerminologyServiceErrorClass.UNKNOWN; 648 else if (it == IssueType.NOTSUPPORTED) 649 err = TerminologyServiceErrorClass.VALUESET_UNSUPPORTED; 650 } catch (FHIRException e) { 651 } 652 } 653 } 654 if (!ok) 655 return new ValidationResult(IssueSeverity.ERROR, message, err).setTxLink(txLog == null ? null : txLog.getLastId()); 656 else if (message != null && !message.equals("No Message returned")) 657 return new ValidationResult(IssueSeverity.WARNING, message, new ConceptDefinitionComponent().setDisplay(display)).setTxLink(txLog == null ? null : txLog.getLastId()); 658 else if (display != null) 659 return new ValidationResult(new ConceptDefinitionComponent().setDisplay(display)).setTxLink(txLog == null ? null : txLog.getLastId()); 660 else 661 return new ValidationResult(new ConceptDefinitionComponent()).setTxLink(txLog == null ? null : txLog.getLastId()); 662 } 663 664 // -------------------------------------------------------------------------------------------------------------------------------------------------------- 665 666 public void initTS(String cachePath) throws Exception { 667 txCache = new TerminologyCache(lock, cachePath); 668 } 669 670 @Override 671 public List<ConceptMap> findMapsForSource(String url) throws FHIRException { 672 synchronized (lock) { 673 List<ConceptMap> res = new ArrayList<ConceptMap>(); 674 for (ConceptMap map : maps.values()) 675 if (((Reference) map.getSource()).getReference().equals(url)) 676 res.add(map); 677 return res; 678 } 679 } 680 681 public boolean isCanRunWithoutTerminology() { 682 return canRunWithoutTerminology; 683 } 684 685 public void setCanRunWithoutTerminology(boolean canRunWithoutTerminology) { 686 this.canRunWithoutTerminology = canRunWithoutTerminology; 687 } 688 689 @Deprecated 690 public void setLogger(ILoggingService logger) { 691 692 } 693 694 public Parameters getExpansionParameters() { 695 return expParameters; 696 } 697 698 public void setExpansionProfile(Parameters expParameters) { 699 this.expParameters = expParameters; 700 } 701 702 @Override 703 public boolean isNoTerminologyServer() { 704 return noTerminologyServer; 705 } 706 707 public String getName() { 708 return name; 709 } 710 711 public void setName(String name) { 712 this.name = name; 713 } 714 715 @Override 716 public Set<String> getResourceNamesAsSet() { 717 Set<String> res = new HashSet<String>(); 718 res.addAll(getResourceNames()); 719 return res; 720 } 721 722 public boolean isAllowLoadingDuplicates() { 723 return allowLoadingDuplicates; 724 } 725 726 public void setAllowLoadingDuplicates(boolean allowLoadingDuplicates) { 727 this.allowLoadingDuplicates = allowLoadingDuplicates; 728 } 729 730 @SuppressWarnings("unchecked") 731 @Override 732 public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException { 733 if (class_ == StructureDefinition.class) 734 uri = ProfileUtilities.sdNs(uri, getOverrideVersionNs()); 735 synchronized (lock) { 736 737 if (uri.startsWith("http:") || uri.startsWith("https:")) { 738 String version = null; 739 if (uri.contains("|")) { 740 version = uri.substring(uri.lastIndexOf("|") + 1); 741 uri = uri.substring(0, uri.lastIndexOf("|")); 742 } 743 if (uri.contains("#")) 744 uri = uri.substring(0, uri.indexOf("#")); 745 if (class_ == Resource.class || class_ == null) { 746 if (structures.containsKey(uri)) 747 return (T) structures.get(uri); 748 if (guides.containsKey(uri)) 749 return (T) guides.get(uri); 750 if (capstmts.containsKey(uri)) 751 return (T) capstmts.get(uri); 752 if (valueSets.containsKey(uri)) 753 return (T) valueSets.get(uri); 754 if (codeSystems.containsKey(uri)) 755 return (T) codeSystems.get(uri); 756 if (operations.containsKey(uri)) 757 return (T) operations.get(uri); 758 if (searchParameters.containsKey(uri)) 759 return (T) searchParameters.get(uri); 760 if (plans.containsKey(uri)) 761 return (T) plans.get(uri); 762 if (maps.containsKey(uri)) 763 return (T) maps.get(uri); 764 if (transforms.containsKey(uri)) 765 return (T) transforms.get(uri); 766 if (questionnaires.containsKey(uri)) 767 return (T) questionnaires.get(uri); 768 for (Map<String, Resource> rt : allResourcesById.values()) { 769 for (Resource r : rt.values()) { 770 if (r instanceof MetadataResource) { 771 MetadataResource mr = (MetadataResource) r; 772 if (uri.equals(mr.getUrl())) 773 return (T) mr; 774 } 775 } 776 } 777 return null; 778 } else if (class_ == ImplementationGuide.class) { 779 return (T) guides.get(uri); 780 } else if (class_ == CapabilityStatement.class) { 781 return (T) capstmts.get(uri); 782 } else if (class_ == StructureDefinition.class) { 783 return (T) structures.get(uri); 784 } else if (class_ == StructureMap.class) { 785 return (T) transforms.get(uri); 786 } else if (class_ == ValueSet.class) { 787 if (valueSets.containsKey(uri + "|" + version)) 788 return (T) valueSets.get(uri + "|" + version); 789 else 790 return (T) valueSets.get(uri); 791 } else if (class_ == CodeSystem.class) { 792 if (codeSystems.containsKey(uri + "|" + version)) 793 return (T) codeSystems.get(uri + "|" + version); 794 else 795 return (T) codeSystems.get(uri); 796 } else if (class_ == ConceptMap.class) { 797 return (T) maps.get(uri); 798 } else if (class_ == PlanDefinition.class) { 799 return (T) plans.get(uri); 800 } else if (class_ == OperationDefinition.class) { 801 OperationDefinition od = operations.get(uri); 802 return (T) od; 803 } else if (class_ == SearchParameter.class) { 804 SearchParameter res = searchParameters.get(uri); 805 if (res == null) { 806 StringBuilder b = new StringBuilder(); 807 for (String s : searchParameters.keySet()) { 808 b.append(s); 809 b.append("\r\n"); 810 } 811 } 812 return (T) res; 813 } 814 } 815 if (class_ == CodeSystem.class && codeSystems.containsKey(uri)) 816 return (T) codeSystems.get(uri); 817 818 if (class_ == Questionnaire.class) 819 return (T) questionnaires.get(uri); 820 if (class_ == null) { 821 if (uri.matches(Constants.URI_REGEX) && !uri.contains("ValueSet")) 822 return null; 823 824 // it might be a special URL. 825 if (Utilities.isAbsoluteUrl(uri) || uri.startsWith("ValueSet/")) { 826 Resource res = null; // findTxValueSet(uri); 827 if (res != null) 828 return (T) res; 829 } 830 return null; 831 } 832 if (supportedCodeSystems.contains(uri)) 833 return null; 834 throw new FHIRException("not done yet: can't fetch " + uri); 835 } 836 } 837 838 private Set<String> notCanonical = new HashSet<String>(); 839 840 private String overrideVersionNs; 841 842// private MetadataResource findTxValueSet(String uri) { 843// MetadataResource res = expansionCache.getStoredResource(uri); 844// if (res != null) 845// return res; 846// synchronized (lock) { 847// if (notCanonical.contains(uri)) 848// return null; 849// } 850// try { 851// tlog("get canonical "+uri); 852// res = txServer.getCanonical(ValueSet.class, uri); 853// } catch (Exception e) { 854// synchronized (lock) { 855// notCanonical.add(uri); 856// } 857// return null; 858// } 859// if (res != null) 860// try { 861// expansionCache.storeResource(res); 862// } catch (IOException e) { 863// } 864// return res; 865// } 866 867 @Override 868 public Resource fetchResourceById(String type, String uri) { 869 synchronized (lock) { 870 String[] parts = uri.split("\\/"); 871 if (!Utilities.noString(type) && parts.length == 1) { 872 if (allResourcesById.containsKey(type)) 873 return allResourcesById.get(type).get(parts[0]); 874 else 875 return null; 876 } 877 if (parts.length >= 2) { 878 if (!Utilities.noString(type)) 879 if (!type.equals(parts[parts.length - 2])) 880 throw new Error("Resource type mismatch for " + type + " / " + uri); 881 return allResourcesById.get(parts[parts.length - 2]).get(parts[parts.length - 1]); 882 } else 883 throw new Error("Unable to process request for resource for " + type + " / " + uri); 884 } 885 } 886 887 public <T extends Resource> T fetchResource(Class<T> class_, String uri) { 888 try { 889 return fetchResourceWithException(class_, uri); 890 } catch (FHIRException e) { 891 throw new Error(e); 892 } 893 } 894 895 @Override 896 public <T extends Resource> T fetchResource(Class<T> class_, String uri, Resource source) { 897 return fetchResource(class_, uri); 898 } 899 900 @Override 901 public List<StructureDefinition> fetchTypeDefinitions(String n) { 902 List<StructureDefinition> types = new ArrayList<>(); 903 for (StructureDefinition sd : fetchResourcesByType(StructureDefinition.class)) { 904 if (n.equals(sd.getTypeTail())) { 905 types.add(sd); 906 } 907 } 908 return types; 909 } 910 911 public <T extends Resource> T fetchResource(Class<T> class_, String uri, String version) { 912 try { 913 return fetchResourceWithException(class_, uri+"|"+version); 914 } catch (FHIRException e) { 915 throw new Error(e); 916 } 917 } 918 919 @Override 920 public <T extends Resource> boolean hasResource(Class<T> class_, String uri) { 921 try { 922 return fetchResourceWithException(class_, uri) != null; 923 } catch (Exception e) { 924 return false; 925 } 926 } 927 928 public TranslationServices translator() { 929 return translator; 930 } 931 932 public void setTranslator(TranslationServices translator) { 933 this.translator = translator; 934 } 935 936 public class NullTranslator implements TranslationServices { 937 938 @Override 939 public String translate(String context, String value, String targetLang) { 940 return value; 941 } 942 943 @Override 944 public String translate(String context, String value) { 945 return value; 946 } 947 948 @Override 949 public String toStr(float value) { 950 return null; 951 } 952 953 @Override 954 public String toStr(Date value) { 955 return null; 956 } 957 958 @Override 959 public String translateAndFormat(String contest, String lang, String value, Object... args) { 960 return String.format(value, args); 961 } 962 963 @Override 964 public Map<String, String> translations(String value) { 965 // TODO Auto-generated method stub 966 return null; 967 } 968 969 @Override 970 public Set<String> listTranslations(String category) { 971 // TODO Auto-generated method stub 972 return null; 973 } 974 975 } 976 977 public void reportStatus(JsonObject json) { 978 synchronized (lock) { 979 json.addProperty("codeystem-count", codeSystems.size()); 980 json.addProperty("valueset-count", valueSets.size()); 981 json.addProperty("conceptmap-count", maps.size()); 982 json.addProperty("transforms-count", transforms.size()); 983 json.addProperty("structures-count", structures.size()); 984 json.addProperty("guides-count", guides.size()); 985 json.addProperty("statements-count", capstmts.size()); 986 } 987 } 988 989 public void dropResource(Resource r) throws FHIRException { 990 dropResource(r.fhirType(), r.getId()); 991 } 992 993 public void dropResource(String fhirType, String id) { 994 synchronized (lock) { 995 996 Map<String, Resource> map = allResourcesById.get(fhirType); 997 if (map == null) { 998 map = new HashMap<String, Resource>(); 999 allResourcesById.put(fhirType, map); 1000 } 1001 if (map.containsKey(id)) 1002 map.remove(id); 1003 1004 if (fhirType.equals("StructureDefinition")) 1005 dropMetadataResource(structures, id); 1006 else if (fhirType.equals("ImplementationGuide")) 1007 dropMetadataResource(guides, id); 1008 else if (fhirType.equals("CapabilityStatement")) 1009 dropMetadataResource(capstmts, id); 1010 else if (fhirType.equals("ValueSet")) 1011 dropMetadataResource(valueSets, id); 1012 else if (fhirType.equals("CodeSystem")) 1013 dropMetadataResource(codeSystems, id); 1014 else if (fhirType.equals("OperationDefinition")) 1015 dropMetadataResource(operations, id); 1016 else if (fhirType.equals("Questionnaire")) 1017 dropMetadataResource(questionnaires, id); 1018 else if (fhirType.equals("ConceptMap")) 1019 dropMetadataResource(maps, id); 1020 else if (fhirType.equals("StructureMap")) 1021 dropMetadataResource(transforms, id); 1022 else if (fhirType.equals("NamingSystem")) 1023 for (int i = systems.size() - 1; i >= 0; i--) { 1024 if (systems.get(i).getId().equals(id)) 1025 systems.remove(i); 1026 } 1027 } 1028 } 1029 1030 private <T extends MetadataResource> void dropMetadataResource(Map<String, T> map, String id) { 1031 T res = map.get(id); 1032 if (res != null) { 1033 map.remove(id); 1034 if (map.containsKey(res.getUrl())) 1035 map.remove(res.getUrl()); 1036 if (res.getVersion() != null) 1037 if (map.containsKey(res.getUrl() + "|" + res.getVersion())) 1038 map.remove(res.getUrl() + "|" + res.getVersion()); 1039 } 1040 } 1041 1042 @Override 1043 public List<MetadataResource> allConformanceResources() { 1044 synchronized (lock) { 1045 List<MetadataResource> result = new ArrayList<MetadataResource>(); 1046 result.addAll(structures.values()); 1047 result.addAll(guides.values()); 1048 result.addAll(capstmts.values()); 1049 result.addAll(codeSystems.values()); 1050 result.addAll(valueSets.values()); 1051 result.addAll(maps.values()); 1052 result.addAll(transforms.values()); 1053 result.addAll(plans.values()); 1054 result.addAll(questionnaires.values()); 1055 return result; 1056 } 1057 } 1058 1059 public String listSupportedSystems() { 1060 synchronized (lock) { 1061 String sl = null; 1062 for (String s : supportedCodeSystems) 1063 sl = sl == null ? s : sl + "\r\n" + s; 1064 return sl; 1065 } 1066 } 1067 1068 public int totalCount() { 1069 synchronized (lock) { 1070 return valueSets.size() + maps.size() + structures.size() + transforms.size(); 1071 } 1072 } 1073 1074 public List<ConceptMap> listMaps() { 1075 List<ConceptMap> m = new ArrayList<ConceptMap>(); 1076 synchronized (lock) { 1077 m.addAll(maps.values()); 1078 } 1079 return m; 1080 } 1081 1082 public List<StructureMap> listTransforms() { 1083 List<StructureMap> m = new ArrayList<StructureMap>(); 1084 synchronized (lock) { 1085 m.addAll(transforms.values()); 1086 } 1087 return m; 1088 } 1089 1090 public StructureMap getTransform(String code) { 1091 synchronized (lock) { 1092 return transforms.get(code); 1093 } 1094 } 1095 1096 public List<StructureDefinition> listStructures() { 1097 List<StructureDefinition> m = new ArrayList<StructureDefinition>(); 1098 synchronized (lock) { 1099 m.addAll(structures.values()); 1100 } 1101 return m; 1102 } 1103 1104 public StructureDefinition getStructure(String code) { 1105 synchronized (lock) { 1106 return structures.get(code); 1107 } 1108 } 1109 1110 @Override 1111 public String oid2Uri(String oid) { 1112 synchronized (lock) { 1113 String uri = OIDUtilities.getUriForOid(oid); 1114 if (uri != null) 1115 return uri; 1116 for (NamingSystem ns : systems) { 1117 if (hasOid(ns, oid)) { 1118 uri = getUri(ns); 1119 if (uri != null) 1120 return null; 1121 } 1122 } 1123 } 1124 return null; 1125 } 1126 1127 private String getUri(NamingSystem ns) { 1128 for (NamingSystemUniqueIdComponent id : ns.getUniqueId()) { 1129 if (id.getType() == NamingSystemIdentifierType.URI) 1130 return id.getValue(); 1131 } 1132 return null; 1133 } 1134 1135 private boolean hasOid(NamingSystem ns, String oid) { 1136 for (NamingSystemUniqueIdComponent id : ns.getUniqueId()) { 1137 if (id.getType() == NamingSystemIdentifierType.OID && id.getValue().equals(oid)) 1138 return true; 1139 } 1140 return false; 1141 } 1142 1143 public void cacheVS(JsonObject json, Map<String, ValidationResult> t) { 1144 synchronized (lock) { 1145 validationCache.put(json.get("url").getAsString(), t); 1146 } 1147 } 1148 1149 public SearchParameter getSearchParameter(String code) { 1150 synchronized (lock) { 1151 return searchParameters.get(code); 1152 } 1153 } 1154 1155 @Override 1156 public String getOverrideVersionNs() { 1157 return overrideVersionNs; 1158 } 1159 1160 @Override 1161 public void setOverrideVersionNs(String value) { 1162 overrideVersionNs = value; 1163 } 1164 1165 @Override 1166 @Deprecated 1167 public ILoggingService getLogger() { 1168 return null; 1169 } 1170 1171 @Override 1172 public StructureDefinition fetchTypeDefinition(String typeName) { 1173 if (Utilities.isAbsoluteUrl(typeName)) 1174 return fetchResource(StructureDefinition.class, typeName); 1175 else 1176 return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName); 1177 } 1178 1179 1180 public boolean isPrimitiveType(String type) { 1181 return Utilities.existsInList(type, "boolean", "integer", "integer64", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime", "time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "uuid", "xhtml", "url", "canonical"); 1182 } 1183 1184 public boolean isDataType(String type) { 1185 return Utilities.existsInList(type, "Address", "Age", "Annotation", "Attachment", "CodeableConcept", "Coding", "ContactPoint", "Count", "Distance", "Duration", "HumanName", "Identifier", "Money", "Period", "Quantity", "Range", "Ratio", "Reference", "SampledData", "Signature", "Timing", 1186 "ContactDetail", "Contributor", "DataRequirement", "Expression", "ParameterDefinition", "RelatedArtifact", "TriggerDefinition", "UsageContext"); 1187 } 1188 1189 1190 public boolean isTlogging() { 1191 return tlogging; 1192 } 1193 1194 public void setTlogging(boolean tlogging) { 1195 this.tlogging = tlogging; 1196 } 1197 1198 public UcumService getUcumService() { 1199 return ucumService; 1200 } 1201 1202 public void setUcumService(UcumService ucumService) { 1203 this.ucumService = ucumService; 1204 } 1205 1206 @Override 1207 public List<StructureDefinition> getStructures() { 1208 List<StructureDefinition> res = new ArrayList<>(); 1209 synchronized (lock) { // tricky, because you need to lock this as well, but it's really not in use yet 1210 res.addAll(structures.values()); 1211 } 1212 return res; 1213 } 1214 1215 public String getLinkForUrl(String corePath, String url) { 1216 for (CodeSystem r : codeSystems.values()) 1217 if (url.equals(r.getUrl())) 1218 return r.getUserString("path"); 1219 1220 for (ValueSet r : valueSets.values()) 1221 if (url.equals(r.getUrl())) 1222 return r.getUserString("path"); 1223 1224 for (ConceptMap r : maps.values()) 1225 if (url.equals(r.getUrl())) 1226 return r.getUserString("path"); 1227 1228 for (StructureMap r : transforms.values()) 1229 if (url.equals(r.getUrl())) 1230 return r.getUserString("path"); 1231 1232 for (StructureDefinition r : structures.values()) 1233 if (url.equals(r.getUrl())) 1234 return r.getUserString("path"); 1235 1236 for (ImplementationGuide r : guides.values()) 1237 if (url.equals(r.getUrl())) 1238 return r.getUserString("path"); 1239 1240 for (CapabilityStatement r : capstmts.values()) 1241 if (url.equals(r.getUrl())) 1242 return r.getUserString("path"); 1243 1244 for (SearchParameter r : searchParameters.values()) 1245 if (url.equals(r.getUrl())) 1246 return r.getUserString("path"); 1247 1248 for (Questionnaire r : questionnaires.values()) 1249 if (url.equals(r.getUrl())) 1250 return r.getUserString("path"); 1251 1252 for (OperationDefinition r : operations.values()) 1253 if (url.equals(r.getUrl())) 1254 return r.getUserString("path"); 1255 1256 for (PlanDefinition r : plans.values()) 1257 if (url.equals(r.getUrl())) 1258 return r.getUserString("path"); 1259 1260 if (url.equals("http://loinc.org")) 1261 return corePath + "loinc.html"; 1262 if (url.equals("http://unitsofmeasure.org")) 1263 return corePath + "ucum.html"; 1264 if (url.equals("http://snomed.info/sct")) 1265 return corePath + "snomed.html"; 1266 return null; 1267 } 1268 1269 @SuppressWarnings("unchecked") 1270 public <T extends Resource> List<T> fetchResourcesByType(Class<T> class_) { 1271 1272 List<T> res = new ArrayList<>(); 1273 1274 synchronized (lock) { 1275 1276 if (class_ == Resource.class || class_ == DomainResource.class || class_ == null) { 1277 res.addAll((Collection<T>) structures.values()); 1278 res.addAll((Collection<T>) guides.values()); 1279 res.addAll((Collection<T>) capstmts.values()); 1280 res.addAll((Collection<T>) valueSets.values()); 1281 res.addAll((Collection<T>) codeSystems.values()); 1282 res.addAll((Collection<T>) operations.values()); 1283 res.addAll((Collection<T>) searchParameters.values()); 1284 res.addAll((Collection<T>) plans.values()); 1285 res.addAll((Collection<T>) maps.values()); 1286 res.addAll((Collection<T>) transforms.values()); 1287 res.addAll((Collection<T>) questionnaires.values()); 1288 } else if (class_ == ImplementationGuide.class) { 1289 res.addAll((Collection<T>) guides.values()); 1290 } else if (class_ == CapabilityStatement.class) { 1291 res.addAll((Collection<T>) capstmts.values()); 1292 } else if (class_ == StructureDefinition.class) { 1293 res.addAll((Collection<T>) structures.values()); 1294 } else if (class_ == StructureMap.class) { 1295 res.addAll((Collection<T>) transforms.values()); 1296 } else if (class_ == ValueSet.class) { 1297 res.addAll((Collection<T>) valueSets.values()); 1298 } else if (class_ == CodeSystem.class) { 1299 res.addAll((Collection<T>) codeSystems.values()); 1300 } else if (class_ == ConceptMap.class) { 1301 res.addAll((Collection<T>) maps.values()); 1302 } else if (class_ == PlanDefinition.class) { 1303 res.addAll((Collection<T>) plans.values()); 1304 } else if (class_ == OperationDefinition.class) { 1305 res.addAll((Collection<T>) operations.values()); 1306 } else if (class_ == Questionnaire.class) { 1307 res.addAll((Collection<T>) questionnaires.values()); 1308 } else if (class_ == SearchParameter.class) { 1309 res.addAll((Collection<T>) searchParameters.values()); 1310 } 1311 } 1312 return res; 1313 } 1314 1315}