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