001package org.hl7.fhir.r5.context; 002 003import java.io.File; 004 005/* 006 Copyright (c) 2011+, HL7, Inc. 007 All rights reserved. 008 009 Redistribution and use in source and binary forms, with or without modification, 010 are permitted provided that the following conditions are met: 011 012 * Redistributions of source code must retain the above copyright notice, this 013 list of conditions and the following disclaimer. 014 * Redistributions in binary form must reproduce the above copyright notice, 015 this list of conditions and the following disclaimer in the documentation 016 and/or other materials provided with the distribution. 017 * Neither the name of HL7 nor the names of its contributors may be used to 018 endorse or promote products derived from this software without specific 019 prior written permission. 020 021 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 022 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 023 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 024 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 025 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 026 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 027 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 028 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 029 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 030 POSSIBILITY OF SUCH DAMAGE. 031 032 */ 033 034 035import java.io.FileNotFoundException; 036import java.io.IOException; 037import java.sql.Connection; 038import java.sql.DriverManager; 039import java.sql.PreparedStatement; 040import java.sql.ResultSet; 041import java.util.ArrayList; 042import java.util.Collections; 043import java.util.Comparator; 044import java.util.Date; 045import java.util.HashMap; 046import java.util.HashSet; 047import java.util.List; 048import java.util.Locale; 049import java.util.Map; 050import java.util.Set; 051import java.util.UUID; 052 053import lombok.Getter; 054import org.apache.commons.lang3.StringUtils; 055import org.fhir.ucum.UcumService; 056import org.hl7.fhir.exceptions.DefinitionException; 057import org.hl7.fhir.exceptions.FHIRException; 058import org.hl7.fhir.exceptions.TerminologyServiceException; 059import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; 060import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy; 061import org.hl7.fhir.r5.context.ILoggingService.LogCategory; 062import org.hl7.fhir.r5.model.ActorDefinition; 063import org.hl7.fhir.r5.model.BooleanType; 064import org.hl7.fhir.r5.model.Bundle; 065import org.hl7.fhir.r5.model.CanonicalResource; 066import org.hl7.fhir.r5.model.CanonicalType; 067import org.hl7.fhir.r5.model.CapabilityStatement; 068import org.hl7.fhir.r5.model.CodeSystem; 069import org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode; 070import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent; 071import org.hl7.fhir.r5.model.CodeableConcept; 072import org.hl7.fhir.r5.model.Coding; 073import org.hl7.fhir.r5.model.ConceptMap; 074import org.hl7.fhir.r5.model.Constants; 075import org.hl7.fhir.r5.model.DomainResource; 076import org.hl7.fhir.r5.model.ElementDefinition; 077import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; 078import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; 079import org.hl7.fhir.r5.model.Extension; 080import org.hl7.fhir.r5.model.IdType; 081import org.hl7.fhir.r5.model.Identifier; 082import org.hl7.fhir.r5.model.IntegerType; 083import org.hl7.fhir.r5.model.ImplementationGuide; 084import org.hl7.fhir.r5.model.Library; 085import org.hl7.fhir.r5.model.Measure; 086import org.hl7.fhir.r5.model.NamingSystem; 087import org.hl7.fhir.r5.model.NamingSystem.NamingSystemIdentifierType; 088import org.hl7.fhir.r5.model.NamingSystem.NamingSystemType; 089import org.hl7.fhir.r5.model.NamingSystem.NamingSystemUniqueIdComponent; 090import org.hl7.fhir.r5.model.OperationDefinition; 091import org.hl7.fhir.r5.model.OperationOutcome; 092import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; 093import org.hl7.fhir.r5.model.PackageInformation; 094import org.hl7.fhir.r5.model.Parameters; 095import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent; 096import org.hl7.fhir.r5.model.PlanDefinition; 097import org.hl7.fhir.r5.model.PrimitiveType; 098import org.hl7.fhir.r5.model.Questionnaire; 099import org.hl7.fhir.r5.model.Requirements; 100import org.hl7.fhir.r5.model.Resource; 101import org.hl7.fhir.r5.model.SearchParameter; 102import org.hl7.fhir.r5.model.StringType; 103import org.hl7.fhir.r5.model.StructureDefinition; 104import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; 105import org.hl7.fhir.r5.model.StructureMap; 106 107import org.hl7.fhir.r5.model.UriType; 108import org.hl7.fhir.r5.model.UrlType; 109import org.hl7.fhir.r5.model.ValueSet; 110import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; 111import org.hl7.fhir.r5.model.Bundle.BundleType; 112import org.hl7.fhir.r5.model.Bundle.HTTPVerb; 113import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; 114import org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent; 115import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy; 116import org.hl7.fhir.r5.profilemodel.PEBuilder; 117import org.hl7.fhir.r5.renderers.OperationOutcomeRenderer; 118import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; 119import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpander; 120import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; 121import org.hl7.fhir.r5.terminologies.utilities.CodingValidationRequest; 122import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache; 123import org.hl7.fhir.r5.terminologies.utilities.TerminologyOperationContext; 124import org.hl7.fhir.r5.terminologies.utilities.TerminologyOperationContext.TerminologyServiceProtectionException; 125import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass; 126import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; 127import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.CacheToken; 128import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.SourcedCodeSystem; 129import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.SourcedValueSet; 130import org.hl7.fhir.r5.terminologies.validation.VSCheckerException; 131import org.hl7.fhir.r5.terminologies.validation.ValueSetValidator; 132import org.hl7.fhir.r5.terminologies.ValueSetUtilities; 133import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager; 134import org.hl7.fhir.r5.terminologies.client.TerminologyClientR5; 135import org.hl7.fhir.r5.terminologies.client.TerminologyClientContext; 136import org.hl7.fhir.r5.utils.PackageHackerR5; 137import org.hl7.fhir.r5.utils.ResourceUtilities; 138import org.hl7.fhir.r5.utils.ToolingExtensions; 139import org.hl7.fhir.r5.utils.client.EFhirClientException; 140import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; 141import org.hl7.fhir.utilities.FhirPublication; 142import org.hl7.fhir.utilities.TimeTracker; 143import org.hl7.fhir.utilities.ToolingClientLogger; 144import org.hl7.fhir.utilities.Utilities; 145import org.hl7.fhir.utilities.VersionUtilities; 146import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; 147import org.hl7.fhir.utilities.i18n.I18nBase; 148import org.hl7.fhir.utilities.i18n.I18nConstants; 149import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 150import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; 151import org.hl7.fhir.utilities.validation.ValidationOptions; 152 153import com.google.gson.JsonObject; 154 155import javax.annotation.Nonnull; 156 157public abstract class BaseWorkerContext extends I18nBase implements IWorkerContext { 158 159 class OIDSource { 160 private String folder; 161 private Connection db; 162 private String pid; 163 protected OIDSource(String folder, String pid) { 164 super(); 165 this.folder = folder; 166 this.pid = pid; 167 } 168 169 } 170 171 private static final boolean QA_CHECK_REFERENCE_SOURCE = false; // see comments below 172 173 public static class ResourceProxy { 174 private Resource resource; 175 private CanonicalResourceProxy proxy; 176 177 public ResourceProxy(Resource resource) { 178 super(); 179 this.resource = resource; 180 } 181 public ResourceProxy(CanonicalResourceProxy proxy) { 182 super(); 183 this.proxy = proxy; 184 } 185 186 public Resource getResource() { 187 return resource != null ? resource : proxy.getResource(); 188 } 189 190 public CanonicalResourceProxy getProxy() { 191 return proxy; 192 } 193 194 public String getUrl() { 195 if (resource == null) { 196 return proxy.getUrl(); 197 } else if (resource instanceof CanonicalResource) { 198 return ((CanonicalResource) resource).getUrl(); 199 } else { 200 return null; 201 } 202 } 203 204 } 205 206 public class MetadataResourceVersionComparator<T extends CanonicalResource> implements Comparator<T> { 207 208 final private List<T> list; 209 210 public MetadataResourceVersionComparator(List<T> list) { 211 this.list = list; 212 } 213 214 @Override 215 public int compare(T arg1, T arg2) { 216 String v1 = arg1.getVersion(); 217 String v2 = arg2.getVersion(); 218 if (v1 == null && v2 == null) { 219 return Integer.compare(list.indexOf(arg1), list.indexOf(arg2)); // retain original order 220 } else if (v1 == null) { 221 return -1; 222 } else if (v2 == null) { 223 return 1; 224 } else { 225 String mm1 = VersionUtilities.getMajMin(v1); 226 String mm2 = VersionUtilities.getMajMin(v2); 227 if (mm1 == null || mm2 == null) { 228 return v1.compareTo(v2); 229 } else { 230 return mm1.compareTo(mm2); 231 } 232 } 233 } 234 } 235 236 private Object lock = new Object(); // used as a lock for the data that follows 237 protected String version; // although the internal resources are all R5, the version of FHIR they describe may not be 238 239 protected final TerminologyClientManager terminologyClientManager = new TerminologyClientManager(new TerminologyClientR5.TerminologyClientR5Factory(), UUID.randomUUID().toString()); 240 private boolean minimalMemory = false; 241 242 private Map<String, Map<String, ResourceProxy>> allResourcesById = new HashMap<String, Map<String, ResourceProxy>>(); 243 // all maps are to the full URI 244 private CanonicalResourceManager<CodeSystem> codeSystems = new CanonicalResourceManager<CodeSystem>(false, minimalMemory); 245 private final Set<String> supportedCodeSystems = new HashSet<String>(); 246 private final Set<String> unsupportedCodeSystems = new HashSet<String>(); // know that the terminology server doesn't support them 247 private CanonicalResourceManager<ValueSet> valueSets = new CanonicalResourceManager<ValueSet>(false, minimalMemory); 248 private CanonicalResourceManager<ConceptMap> maps = new CanonicalResourceManager<ConceptMap>(false, minimalMemory); 249 protected CanonicalResourceManager<StructureMap> transforms = new CanonicalResourceManager<StructureMap>(false, minimalMemory); 250 private CanonicalResourceManager<StructureDefinition> structures = new CanonicalResourceManager<StructureDefinition>(false, minimalMemory); 251 private TypeManager typeManager = new TypeManager(structures); 252 private final CanonicalResourceManager<Measure> measures = new CanonicalResourceManager<Measure>(false, minimalMemory); 253 private final CanonicalResourceManager<Library> libraries = new CanonicalResourceManager<Library>(false, minimalMemory); 254 private CanonicalResourceManager<ImplementationGuide> guides = new CanonicalResourceManager<ImplementationGuide>(false, minimalMemory); 255 private final CanonicalResourceManager<CapabilityStatement> capstmts = new CanonicalResourceManager<CapabilityStatement>(false, minimalMemory); 256 private final CanonicalResourceManager<SearchParameter> searchParameters = new CanonicalResourceManager<SearchParameter>(false, minimalMemory); 257 private final CanonicalResourceManager<Questionnaire> questionnaires = new CanonicalResourceManager<Questionnaire>(false, minimalMemory); 258 private final CanonicalResourceManager<OperationDefinition> operations = new CanonicalResourceManager<OperationDefinition>(false, minimalMemory); 259 private final CanonicalResourceManager<PlanDefinition> plans = new CanonicalResourceManager<PlanDefinition>(false, minimalMemory); 260 private final CanonicalResourceManager<ActorDefinition> actors = new CanonicalResourceManager<ActorDefinition>(false, minimalMemory); 261 private final CanonicalResourceManager<Requirements> requirements = new CanonicalResourceManager<Requirements>(false, minimalMemory); 262 private final CanonicalResourceManager<NamingSystem> systems = new CanonicalResourceManager<NamingSystem>(false, minimalMemory); 263 private Map<String, NamingSystem> systemUrlMap; 264 265 266 private UcumService ucumService; 267 protected Map<String, byte[]> binaries = new HashMap<String, byte[]>(); 268 protected Map<String, Set<OIDDefinition>> oidCacheManual = new HashMap<>(); 269 protected List<OIDSource> oidSources = new ArrayList<>(); 270 271 protected Map<String, Map<String, ValidationResult>> validationCache = new HashMap<String, Map<String,ValidationResult>>(); 272 protected String name; 273 private boolean allowLoadingDuplicates; 274 275 private final Set<String> codeSystemsUsed = new HashSet<>(); 276 protected ToolingClientLogger txLog; 277 protected boolean canRunWithoutTerminology; 278 protected boolean noTerminologyServer; 279 private int expandCodesLimit = 1000; 280 protected org.hl7.fhir.r5.context.ILoggingService logger = new SystemOutLoggingService(); 281 protected Parameters expParameters; 282 private Map<String, PackageInformation> packages = new HashMap<>(); 283 284 @Getter 285 protected TerminologyCache txCache = new TerminologyCache(this, null); 286 protected TimeTracker clock; 287 private boolean tlogging = true; 288 private IWorkerContextManager.ICanonicalResourceLocator locator; 289 protected String userAgent; 290 291 protected BaseWorkerContext() throws FileNotFoundException, IOException, FHIRException { 292 setValidationMessageLanguage(getLocale()); 293 clock = new TimeTracker(); 294 } 295 296 protected BaseWorkerContext(Locale locale) throws FileNotFoundException, IOException, FHIRException { 297 setValidationMessageLanguage(locale); 298 clock = new TimeTracker(); 299 } 300 301 protected BaseWorkerContext(CanonicalResourceManager<CodeSystem> codeSystems, CanonicalResourceManager<ValueSet> valueSets, CanonicalResourceManager<ConceptMap> maps, CanonicalResourceManager<StructureDefinition> profiles, 302 CanonicalResourceManager<ImplementationGuide> guides) throws FileNotFoundException, IOException, FHIRException { 303 this(); 304 this.codeSystems = codeSystems; 305 this.valueSets = valueSets; 306 this.maps = maps; 307 this.structures = profiles; 308 this.typeManager = new TypeManager(structures); 309 this.guides = guides; 310 clock = new TimeTracker(); 311 } 312 313 protected void copy(BaseWorkerContext other) { 314 synchronized (other.lock) { // tricky, because you need to lock this as well, but it's really not in use yet 315 allResourcesById.putAll(other.allResourcesById); 316 codeSystems.copy(other.codeSystems); 317 valueSets.copy(other.valueSets); 318 maps.copy(other.maps); 319 transforms.copy(other.transforms); 320 structures.copy(other.structures); 321 typeManager = new TypeManager(structures); 322 searchParameters.copy(other.searchParameters); 323 plans.copy(other.plans); 324 questionnaires.copy(other.questionnaires); 325 operations.copy(other.operations); 326 systems.copy(other.systems); 327 systemUrlMap = null; 328 guides.copy(other.guides); 329 capstmts.copy(other.capstmts); 330 measures.copy(other.measures); 331 libraries.copy(libraries); 332 333 allowLoadingDuplicates = other.allowLoadingDuplicates; 334 name = other.name; 335 txLog = other.txLog; 336 canRunWithoutTerminology = other.canRunWithoutTerminology; 337 noTerminologyServer = other.noTerminologyServer; 338 if (other.txCache != null) 339 txCache = other.txCache; // no copy. for now? 340 expandCodesLimit = other.expandCodesLimit; 341 logger = other.logger; 342 expParameters = other.expParameters; 343 version = other.version; 344 supportedCodeSystems.addAll(other.supportedCodeSystems); 345 unsupportedCodeSystems.addAll(other.unsupportedCodeSystems); 346 codeSystemsUsed.addAll(other.codeSystemsUsed); 347 ucumService = other.ucumService; 348 binaries.putAll(other.binaries); 349 oidSources.addAll(other.oidSources); 350 oidCacheManual.putAll(other.oidCacheManual); 351 validationCache.putAll(other.validationCache); 352 tlogging = other.tlogging; 353 locator = other.locator; 354 userAgent = other.userAgent; 355 terminologyClientManager.copy(other.terminologyClientManager); 356 cachingAllowed = other.cachingAllowed; 357 } 358 } 359 360 361 public void cacheResource(Resource r) throws FHIRException { 362 cacheResourceFromPackage(r, null); 363 } 364 365 366 public void registerResourceFromPackage(CanonicalResourceProxy r, PackageInformation packageInfo) throws FHIRException { 367 PackageHackerR5.fixLoadedResource(r, packageInfo); 368 369 synchronized (lock) { 370 if (packageInfo != null) { 371 packages.put(packageInfo.getVID(), packageInfo); 372 } 373 if (r.getId() != null) { 374 Map<String, ResourceProxy> map = allResourcesById.get(r.getType()); 375 if (map == null) { 376 map = new HashMap<String, ResourceProxy>(); 377 allResourcesById.put(r.getType(), map); 378 } 379 if ((packageInfo == null || !packageInfo.isExamplesPackage()) || !map.containsKey(r.getId())) { 380 map.put(r.getId(), new ResourceProxy(r)); 381 } 382 } 383 384 String url = r.getUrl(); 385 if (!allowLoadingDuplicates && hasResourceVersion(r.getType(), url, r.getVersion()) && !packageInfo.isHTO()) { 386 // special workaround for known problems with existing packages 387 if (Utilities.existsInList(url, "http://hl7.org/fhir/SearchParameter/example")) { 388 return; 389 } 390 CanonicalResource ex = fetchResourceWithException(r.getType(), url); 391 throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url, r.getVersion(), ex.getVersion(), 392 ex.fhirType())); 393 } 394 switch(r.getType()) { 395 case "StructureDefinition": 396 if ("1.4.0".equals(version)) { 397 StructureDefinition sd = (StructureDefinition) r.getResource(); 398 fixOldSD(sd); 399 } 400 structures.register(r, packageInfo); 401 typeManager.see(r); 402 break; 403 case "ValueSet": 404 valueSets.register(r, packageInfo); 405 break; 406 case "CodeSystem": 407 codeSystems.register(r, packageInfo); 408 break; 409 case "ImplementationGuide": 410 guides.register(r, packageInfo); 411 break; 412 case "CapabilityStatement": 413 capstmts.register(r, packageInfo); 414 break; 415 case "Measure": 416 measures.register(r, packageInfo); 417 break; 418 case "Library": 419 libraries.register(r, packageInfo); 420 break; 421 case "SearchParameter": 422 searchParameters.register(r, packageInfo); 423 break; 424 case "PlanDefinition": 425 plans.register(r, packageInfo); 426 break; 427 case "OperationDefinition": 428 operations.register(r, packageInfo); 429 break; 430 case "Questionnaire": 431 questionnaires.register(r, packageInfo); 432 break; 433 case "ConceptMap": 434 maps.register(r, packageInfo); 435 break; 436 case "StructureMap": 437 transforms.register(r, packageInfo); 438 break; 439 case "NamingSystem": 440 systems.register(r, packageInfo); 441 break; 442 case "Requirements": 443 requirements.register(r, packageInfo); 444 break; 445 case "ActorDefinition": 446 actors.register(r, packageInfo); 447 break; 448 } 449 } 450 } 451 452 public void cacheResourceFromPackage(Resource r, PackageInformation packageInfo) throws FHIRException { 453 454 synchronized (lock) { 455 if (packageInfo != null) { 456 packages.put(packageInfo.getVID(), packageInfo); 457 } 458 459 if (r.getId() != null) { 460 Map<String, ResourceProxy> map = allResourcesById.get(r.fhirType()); 461 if (map == null) { 462 map = new HashMap<String, ResourceProxy>(); 463 allResourcesById.put(r.fhirType(), map); 464 } 465 if ((packageInfo == null || !packageInfo.isExamplesPackage()) || !map.containsKey(r.getId())) { 466 map.put(r.getId(), new ResourceProxy(r)); 467 } else { 468 logger.logDebugMessage(LogCategory.PROGRESS,"Ignore "+r.fhirType()+"/"+r.getId()+" from package "+packageInfo.toString()); 469 } 470 } 471 472 if (r instanceof CodeSystem || r instanceof NamingSystem) { 473 String url = null; 474 Set<String> oids = new HashSet<String>(); 475 if (r instanceof CodeSystem) { 476 CodeSystem cs = (CodeSystem) r; 477 url = cs.getUrl(); 478 for (Identifier id : cs.getIdentifier()) { 479 if (id.hasValue() && id.getValue().startsWith("urn:oid:")) { 480 oids.add(id.getValue().substring(8)); 481 } 482 } 483 } 484 if (r instanceof NamingSystem) { 485 NamingSystem ns = ((NamingSystem) r); 486 if (ns.getKind() == NamingSystemType.CODESYSTEM) { 487 for (NamingSystemUniqueIdComponent id : ns.getUniqueId()) { 488 if (id.getType() == NamingSystemIdentifierType.URI) { 489 url = id.getValue(); 490 } 491 if (id.getType() == NamingSystemIdentifierType.OID) { 492 oids.add(id.getValue()); 493 } 494 } 495 } 496 } 497 if (url != null) { 498 for (String s : oids) { 499 if (!oidCacheManual.containsKey(s)) { 500 oidCacheManual.put(s, new HashSet<>()); 501 } 502 oidCacheManual.get(s).add(new OIDDefinition(r.fhirType(), s, url, ((CanonicalResource) r).getVersion(), null, null)); 503 } 504 } 505 } 506 507 if (r instanceof CanonicalResource) { 508 CanonicalResource m = (CanonicalResource) r; 509 String url = m.getUrl(); 510 if (!allowLoadingDuplicates && hasResource(r.getClass(), url)) { 511 // special workaround for known problems with existing packages 512 if (Utilities.existsInList(url, "http://hl7.org/fhir/SearchParameter/example")) { 513 return; 514 } 515 CanonicalResource ex = (CanonicalResource) fetchResourceWithException(r.getClass(), url); 516 throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url, ((CanonicalResource) r).getVersion(), ex.getVersion(), 517 ex.fhirType())); 518 } 519 if (r instanceof StructureDefinition) { 520 StructureDefinition sd = (StructureDefinition) m; 521 if ("1.4.0".equals(version)) { 522 fixOldSD(sd); 523 } 524 structures.see(sd, packageInfo); 525 typeManager.see(sd); 526 } else if (r instanceof ValueSet) { 527 valueSets.see((ValueSet) m, packageInfo); 528 } else if (r instanceof CodeSystem) { 529 CodeSystemUtilities.crossLinkCodeSystem((CodeSystem) r); 530 codeSystems.see((CodeSystem) m, packageInfo); 531 } else if (r instanceof ImplementationGuide) { 532 guides.see((ImplementationGuide) m, packageInfo); 533 } else if (r instanceof CapabilityStatement) { 534 capstmts.see((CapabilityStatement) m, packageInfo); 535 } else if (r instanceof Measure) { 536 measures.see((Measure) m, packageInfo); 537 } else if (r instanceof Library) { 538 libraries.see((Library) m, packageInfo); 539 } else if (r instanceof SearchParameter) { 540 searchParameters.see((SearchParameter) m, packageInfo); 541 } else if (r instanceof PlanDefinition) { 542 plans.see((PlanDefinition) m, packageInfo); 543 } else if (r instanceof OperationDefinition) { 544 operations.see((OperationDefinition) m, packageInfo); 545 } else if (r instanceof Questionnaire) { 546 questionnaires.see((Questionnaire) m, packageInfo); 547 } else if (r instanceof ConceptMap) { 548 maps.see((ConceptMap) m, packageInfo); 549 } else if (r instanceof StructureMap) { 550 transforms.see((StructureMap) m, packageInfo); 551 } else if (r instanceof NamingSystem) { 552 systems.see((NamingSystem) m, packageInfo); 553 systemUrlMap = null; 554 } else if (r instanceof Requirements) { 555 requirements.see((Requirements) m, packageInfo); 556 } else if (r instanceof ActorDefinition) { 557 actors.see((ActorDefinition) m, packageInfo); 558 systemUrlMap = null; 559 } 560 } 561 } 562 } 563 564 public Map<String, NamingSystem> getNSUrlMap() { 565 if (systemUrlMap == null) { 566 systemUrlMap = new HashMap<>(); 567 try { 568 List<NamingSystem> nsl = systems.getList(); 569 for (NamingSystem ns : nsl) { 570 for (NamingSystemUniqueIdComponent uid : ns.getUniqueId()) { 571 if (uid.getType() == NamingSystemIdentifierType.URI && uid.hasValue()) { 572 systemUrlMap.put(uid.getValue(), ns) ; 573 } 574 } 575 } 576 } catch (Exception e) { 577 if (!nsFailHasFailed) { 578 e.printStackTrace(); 579 nsFailHasFailed = true; 580 } 581 } 582 } 583 return systemUrlMap; 584 } 585 586 587 public void fixOldSD(StructureDefinition sd) { 588 if (sd.getDerivation() == TypeDerivationRule.CONSTRAINT && sd.getType().equals("Extension") && sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/")) { 589 sd.setSnapshot(null); 590 } 591 for (ElementDefinition ed : sd.getDifferential().getElement()) { 592 if (ed.getPath().equals("Extension.url") || ed.getPath().endsWith(".extension.url") ) { 593 ed.setMin(1); 594 if (ed.hasBase()) { 595 ed.getBase().setMin(1); 596 } 597 } 598 if ("extension".equals(ed.getSliceName())) { 599 ed.setSliceName(null); 600 } 601 } 602 } 603 604 /* 605 * Compare business versions, returning "true" if the candidate newer version is in fact newer than the oldVersion 606 * Comparison will work for strictly numeric versions as well as multi-level versions separated by ., -, _, : or space 607 * Failing that, it will do unicode-based character ordering. 608 * E.g. 1.5.3 < 1.14.3 609 * 2017-3-10 < 2017-12-7 610 * A3 < T2 611 */ 612 private boolean laterVersion(String newVersion, String oldVersion) { 613 // Compare business versions, retur 614 newVersion = newVersion.trim(); 615 oldVersion = oldVersion.trim(); 616 if (StringUtils.isNumeric(newVersion) && StringUtils.isNumeric(oldVersion)) { 617 return Double.parseDouble(newVersion) > Double.parseDouble(oldVersion); 618 } else if (hasDelimiter(newVersion, oldVersion, ".")) { 619 return laterDelimitedVersion(newVersion, oldVersion, "\\."); 620 } else if (hasDelimiter(newVersion, oldVersion, "-")) { 621 return laterDelimitedVersion(newVersion, oldVersion, "\\-"); 622 } else if (hasDelimiter(newVersion, oldVersion, "_")) { 623 return laterDelimitedVersion(newVersion, oldVersion, "\\_"); 624 } else if (hasDelimiter(newVersion, oldVersion, ":")) { 625 return laterDelimitedVersion(newVersion, oldVersion, "\\:"); 626 } else if (hasDelimiter(newVersion, oldVersion, " ")) { 627 return laterDelimitedVersion(newVersion, oldVersion, "\\ "); 628 } else { 629 return newVersion.compareTo(oldVersion) > 0; 630 } 631 } 632 633 /* 634 * Returns true if both strings include the delimiter and have the same number of occurrences of it 635 */ 636 private boolean hasDelimiter(String s1, String s2, String delimiter) { 637 return s1.contains(delimiter) && s2.contains(delimiter) && s1.split(delimiter).length == s2.split(delimiter).length; 638 } 639 640 private boolean laterDelimitedVersion(String newVersion, String oldVersion, String delimiter) { 641 String[] newParts = newVersion.split(delimiter); 642 String[] oldParts = oldVersion.split(delimiter); 643 for (int i = 0; i < newParts.length; i++) { 644 if (!newParts[i].equals(oldParts[i])) { 645 return laterVersion(newParts[i], oldParts[i]); 646 } 647 } 648 // This should never happen 649 throw new Error(formatMessage(I18nConstants.DELIMITED_VERSIONS_HAVE_EXACT_MATCH_FOR_DELIMITER____VS_, delimiter, newParts, oldParts)); 650 } 651 652 protected <T extends CanonicalResource> void seeMetadataResource(T r, Map<String, T> map, List<T> list, boolean addId) throws FHIRException { 653// if (addId) 654 // map.put(r.getId(), r); // todo: why? 655 list.add(r); 656 if (r.hasUrl()) { 657 // first, this is the correct reosurce for this version (if it has a version) 658 if (r.hasVersion()) { 659 map.put(r.getUrl()+"|"+r.getVersion(), r); 660 } 661 // if we haven't get anything for this url, it's the correct version 662 if (!map.containsKey(r.getUrl())) { 663 map.put(r.getUrl(), r); 664 } else { 665 List<T> rl = new ArrayList<T>(); 666 for (T t : list) { 667 if (t.getUrl().equals(r.getUrl()) && !rl.contains(t)) { 668 rl.add(t); 669 } 670 } 671 Collections.sort(rl, new MetadataResourceVersionComparator<T>(list)); 672 map.put(r.getUrl(), rl.get(rl.size()-1)); 673 T latest = null; 674 for (T t : rl) { 675 if (VersionUtilities.versionsCompatible(t.getVersion(), r.getVersion())) { 676 latest = t; 677 } 678 } 679 if (latest != null) { // might be null if it's not using semver 680 map.put(r.getUrl()+"|"+VersionUtilities.getMajMin(latest.getVersion()), rl.get(rl.size()-1)); 681 } 682 } 683 } 684 } 685 686 @Override 687 public CodeSystem fetchCodeSystem(String system, FhirPublication fhirVersion) { 688 return fetchCodeSystem(system); 689 } 690 691 @Override 692 public CodeSystem fetchCodeSystem(String system) { 693 if (system == null) { 694 return null; 695 } 696 if (system.contains("|")) { 697 String s = system.substring(0, system.indexOf("|")); 698 String v = system.substring(system.indexOf("|")+1); 699 return fetchCodeSystem(s, v); 700 } 701 CodeSystem cs; 702 synchronized (lock) { 703 cs = codeSystems.get(system); 704 } 705 if (cs == null && locator != null) { 706 locator.findResource(this, system); 707 synchronized (lock) { 708 cs = codeSystems.get(system); 709 } 710 } 711 return cs; 712 } 713 714 715 public CodeSystem fetchCodeSystem(String system, String version, FhirPublication fhirVersion) { 716 return fetchCodeSystem(system, version); 717 } 718 719 public CodeSystem fetchCodeSystem(String system, String version) { 720 if (version == null) { 721 return fetchCodeSystem(system); 722 } 723 CodeSystem cs; 724 synchronized (lock) { 725 cs = codeSystems.get(system, version); 726 } 727 if (cs == null && locator != null) { 728 locator.findResource(this, system); 729 synchronized (lock) { 730 cs = codeSystems.get(system); 731 } 732 } 733 return cs; 734 } 735 736 737 public CodeSystem fetchSupplementedCodeSystem(String system, FhirPublication fhirVersion) { 738 return fetchSupplementedCodeSystem(system); 739 } 740 741 public CodeSystem fetchSupplementedCodeSystem(String system, String version, FhirPublication fhirVersion) { 742 return fetchSupplementedCodeSystem(system, version); 743 } 744 745 @Override 746 public CodeSystem fetchSupplementedCodeSystem(String system) { 747 CodeSystem cs = fetchCodeSystem(system); 748 if (cs != null) { 749 List<CodeSystem> supplements = codeSystems.getSupplements(cs); 750 if (supplements.size() > 0) { 751 cs = CodeSystemUtilities.mergeSupplements(cs, supplements); 752 } 753 } 754 return cs; 755 } 756 757 @Override 758 public CodeSystem fetchSupplementedCodeSystem(String system, String version) { 759 CodeSystem cs = fetchCodeSystem(system, version); 760 if (cs != null) { 761 List<CodeSystem> supplements = codeSystems.getSupplements(cs); 762 if (supplements.size() > 0) { 763 cs = CodeSystemUtilities.mergeSupplements(cs, supplements); 764 } 765 } 766 return cs; 767 } 768 769 770 public boolean supportsSystem(String system, FhirPublication fhirVersion) throws TerminologyServiceException { 771 return supportsSystem(system); 772 } 773 774 @Override 775 public boolean supportsSystem(String system) throws TerminologyServiceException { 776 synchronized (lock) { 777 if (codeSystems.has(system) && codeSystems.get(system).getContent() != CodeSystemContentMode.NOTPRESENT) { 778 return true; 779 } else if (supportedCodeSystems.contains(system)) { 780 return true; 781 } else if (system.startsWith("http://example.org") || system.startsWith("http://acme.com") || system.startsWith("http://hl7.org/fhir/valueset-") || system.startsWith("urn:oid:")) { 782 return false; 783 } else { 784 if (noTerminologyServer) { 785 return false; 786 } 787 if (terminologyClientManager != null) { 788 try { 789 if (terminologyClientManager.supportsSystem(system)) { 790 supportedCodeSystems.add(system); 791 } 792 } catch (Exception e) { 793 if (canRunWithoutTerminology) { 794 noTerminologyServer = true; 795 logger.logMessage("==============!! Running without terminology server !! =============="); 796 if (terminologyClientManager.getMasterClient() != null) { 797 logger.logMessage("txServer = "+ terminologyClientManager.getMasterClient().getId()); 798 logger.logMessage("Error = "+e.getMessage()+""); 799 } 800 logger.logMessage("====================================================================="); 801 return false; 802 } else { 803 e.printStackTrace(); 804 throw new TerminologyServiceException(e); 805 } 806 } 807 if (supportedCodeSystems.contains(system)) { 808 return true; 809 } 810 } 811 } 812 return false; 813 } 814 } 815 816 817 public boolean isServerSideSystem(String url) { 818 boolean check = supportsSystem(url); 819 return check && supportedCodeSystems.contains(url); 820 } 821 822 823 protected void txLog(String msg) { 824 if (tlogging ) { 825 logger.logDebugMessage(LogCategory.TX, msg); 826 } 827 } 828 829 // --- expansion support ------------------------------------------------------------------------------------------------------------ 830 831 public int getExpandCodesLimit() { 832 return expandCodesLimit; 833 } 834 835 public void setExpandCodesLimit(int expandCodesLimit) { 836 this.expandCodesLimit = expandCodesLimit; 837 } 838 839 @Override 840 public ValueSetExpansionOutcome expandVS(Resource src, ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heirarchical) throws FHIRException { 841 ValueSet vs = null; 842 vs = fetchResource(ValueSet.class, binding.getValueSet(), src); 843 if (vs == null) { 844 throw new FHIRException(formatMessage(I18nConstants.UNABLE_TO_RESOLVE_VALUE_SET_, binding.getValueSet())); 845 } 846 return expandVS(vs, cacheOk, heirarchical); 847 } 848 849 850 @Override 851 public ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean hierarchical, boolean noInactive) throws TerminologyServiceException { 852 ValueSet vs = new ValueSet(); 853 vs.setStatus(PublicationStatus.ACTIVE); 854 vs.setCompose(new ValueSetComposeComponent()); 855 vs.getCompose().setInactive(!noInactive); 856 vs.getCompose().getInclude().add(inc); 857 CacheToken cacheToken = txCache.generateExpandToken(vs, hierarchical); 858 ValueSetExpansionOutcome res; 859 res = txCache.getExpansion(cacheToken); 860 if (res != null) { 861 return res; 862 } 863 Set<String> systems = findRelevantSystems(vs); 864 TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, true); 865 if (tc == null) { 866 return new ValueSetExpansionOutcome("No server available", TerminologyServiceErrorClass.INTERNAL_ERROR, true); 867 } 868 Parameters p = constructParameters(tc, vs, hierarchical); 869 for (ConceptSetComponent incl : vs.getCompose().getInclude()) { 870 codeSystemsUsed.add(incl.getSystem()); 871 } 872 for (ConceptSetComponent incl : vs.getCompose().getExclude()) { 873 codeSystemsUsed.add(incl.getSystem()); 874 } 875 876 if (noTerminologyServer) { 877 return new ValueSetExpansionOutcome(formatMessage(I18nConstants.ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE, false); 878 } 879 p.addParameter("count", expandCodesLimit); 880 p.addParameter("offset", 0); 881 txLog("$expand on "+txCache.summary(vs)+" on "+tc.getAddress()); 882 if (addDependentResources(tc, p, vs)) { 883 p.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId())); 884 } 885 886 try { 887 ValueSet result = tc.getClient().expandValueset(vs, p); 888 res = new ValueSetExpansionOutcome(result).setTxLink(txLog.getLastId()); 889 } catch (Exception e) { 890 res = new ValueSetExpansionOutcome(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), TerminologyServiceErrorClass.UNKNOWN, true); 891 if (txLog != null) { 892 res.setTxLink(txLog.getLastId()); 893 } 894 } 895 txCache.cacheExpansion(cacheToken, res, TerminologyCache.PERMANENT); 896 return res; 897 } 898 899 @Override 900 public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical) { 901 if (expParameters == null) 902 throw new Error(formatMessage(I18nConstants.NO_EXPANSION_PARAMETERS_PROVIDED)); 903 Parameters p = expParameters.copy(); 904 return expandVS(vs, cacheOk, heirarchical, false, p); 905 } 906 907 @Override 908 public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical, boolean incompleteOk) { 909 if (expParameters == null) 910 throw new Error(formatMessage(I18nConstants.NO_EXPANSION_PARAMETERS_PROVIDED)); 911 Parameters p = expParameters.copy(); 912 return expandVS(vs, cacheOk, heirarchical, incompleteOk, p); 913 } 914 915 public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean hierarchical, boolean incompleteOk, Parameters pIn) { 916 return expandVS(vs, cacheOk, hierarchical, incompleteOk, pIn, false); 917 } 918 919 public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean hierarchical, boolean incompleteOk, Parameters pIn, boolean noLimits) { 920 if (pIn == null) { 921 throw new Error(formatMessage(I18nConstants.NO_PARAMETERS_PROVIDED_TO_EXPANDVS)); 922 } 923 if (vs.hasUrl() && (vs.getUrl().equals("http://hl7.org/fhir/ValueSet/all-time-units") || vs.getUrl().equals("http://hl7.org/fhir/ValueSet/all-distance-units"))) { 924 return new ValueSetExpansionOutcome("This value set is not expanded correctly at this time (will be fixed in a future version)", TerminologyServiceErrorClass.VALUESET_UNSUPPORTED, false); 925 } 926 927 Parameters p = pIn.copy(); 928 p.setParameter("_limit",new IntegerType("10000")); 929 p.setParameter("_incomplete", new BooleanType("true")); 930 if (vs.hasExpansion()) { 931 return new ValueSetExpansionOutcome(vs.copy()); 932 } 933 if (!vs.hasUrl()) { 934 throw new Error(formatMessage(I18nConstants.NO_VALUE_SET_IN_URL)); 935 } 936 for (ConceptSetComponent inc : vs.getCompose().getInclude()) { 937 if (inc.hasSystem()) { 938 codeSystemsUsed.add(inc.getSystem()); 939 } 940 } 941 for (ConceptSetComponent inc : vs.getCompose().getExclude()) { 942 if (inc.hasSystem()) { 943 codeSystemsUsed.add(inc.getSystem()); 944 } 945 } 946 947 CacheToken cacheToken = txCache.generateExpandToken(vs, hierarchical); 948 ValueSetExpansionOutcome res; 949 if (cacheOk) { 950 res = txCache.getExpansion(cacheToken); 951 if (res != null) { 952 return res; 953 } 954 } 955 956 if (!noLimits) { 957 p.addParameter("count", expandCodesLimit); 958 p.addParameter("offset", 0); 959 } 960 p.setParameter("excludeNested", !hierarchical); 961 if (incompleteOk) { 962 p.setParameter("incomplete-ok", true); 963 } 964 965 List<String> allErrors = new ArrayList<>(); 966 967 // ok, first we try to expand locally 968 ValueSetExpander vse = constructValueSetExpanderSimple(new ValidationOptions(vs.getFHIRPublicationVersion())); 969 res = null; 970 try { 971 res = vse.expand(vs, p); 972 } catch (Exception e) { 973 allErrors.addAll(vse.getAllErrors()); 974 e.printStackTrace(); 975 res = new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.UNKNOWN, e instanceof EFhirClientException); 976 } 977 allErrors.addAll(vse.getAllErrors()); 978 if (res.getValueset() != null) { 979 if (!res.getValueset().hasUrl()) { 980 throw new Error(formatMessage(I18nConstants.NO_URL_IN_EXPAND_VALUE_SET)); 981 } 982 txCache.cacheExpansion(cacheToken, res, TerminologyCache.TRANSIENT); 983 return res; 984 } 985 if (res.getErrorClass() == TerminologyServiceErrorClass.INTERNAL_ERROR || isNoTerminologyServer()) { // this class is created specifically to say: don't consult the server 986 return new ValueSetExpansionOutcome(res.getError(), res.getErrorClass(), false); 987 } 988 989 // if that failed, we try to expand on the server 990 if (noTerminologyServer) { 991 return new ValueSetExpansionOutcome(formatMessage(I18nConstants.ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE, allErrors, false); 992 } 993 994 p.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId())); 995 Set<String> systems = findRelevantSystems(vs); 996 TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, true); 997 addDependentResources(tc, p, vs); 998 999 1000 txLog("$expand on "+txCache.summary(vs)+" on "+tc.getAddress()); 1001 1002 try { 1003 ValueSet result = tc.getClient().expandValueset(vs, p); 1004 if (result != null) { 1005 if (!result.hasUrl()) { 1006 result.setUrl(vs.getUrl()); 1007 } 1008 if (!result.hasUrl()) { 1009 throw new Error(formatMessage(I18nConstants.NO_URL_IN_EXPAND_VALUE_SET_2)); 1010 } 1011 } 1012 res = new ValueSetExpansionOutcome(result).setTxLink(txLog.getLastId()); 1013 } catch (Exception e) { 1014 if (res != null && !res.isFromServer()) { 1015 res = new ValueSetExpansionOutcome(res.getError()+" (and "+e.getMessage()+")", res.getErrorClass(), false); 1016 } else { 1017 res = new ValueSetExpansionOutcome((e.getMessage() == null ? e.getClass().getName() : e.getMessage()), TerminologyServiceErrorClass.UNKNOWN, allErrors, true).setTxLink(txLog == null ? null : txLog.getLastId()); 1018 } 1019 } 1020 txCache.cacheExpansion(cacheToken, res, TerminologyCache.PERMANENT); 1021 return res; 1022 } 1023 1024// private boolean hasTooCostlyExpansion(ValueSet valueset) { 1025// return valueset != null && valueset.hasExpansion() && ToolingExtensions.hasExtension(valueset.getExpansion(), ToolingExtensions.EXT_EXP_TOOCOSTLY); 1026// } 1027 1028 // --- validate code ------------------------------------------------------------------------------- 1029 1030 @Override 1031 public ValidationResult validateCode(ValidationOptions options, String system, String version, String code, String display) { 1032 assert options != null; 1033 Coding c = new Coding(system, version, code, display); 1034 return validateCode(options, c, null); 1035 } 1036 1037 @Override 1038 public ValidationResult validateCode(ValidationOptions options, String system, String version, String code, String display, ValueSet vs) { 1039 assert options != null; 1040 Coding c = new Coding(system, version, code, display); 1041 ValidationResult ret = validateCode(options, "$", c, vs); 1042 ret.trimPath("$"); 1043 return ret; 1044 } 1045 1046 @Override 1047 public ValidationResult validateCode(ValidationOptions options, String code, ValueSet vs) { 1048 assert options != null; 1049 Coding c = new Coding(null, code, null); 1050 return validateCode(options.withGuessSystem(), c, vs); 1051 } 1052 1053 1054 @Override 1055 public void validateCodeBatch(ValidationOptions options, List<? extends CodingValidationRequest> codes, ValueSet vs) { 1056 if (options == null) { 1057 options = ValidationOptions.defaults(); 1058 } 1059 // 1st pass: what is in the cache? 1060 // 2nd pass: What can we do internally 1061 // 3rd pass: hit the server 1062 for (CodingValidationRequest t : codes) { 1063 t.setCacheToken(txCache != null ? txCache.generateValidationToken(options, t.getCoding(), vs == null ? t.getVsObj() : vs, expParameters) : null); 1064 if (t.getCoding().hasSystem()) { 1065 codeSystemsUsed.add(t.getCoding().getSystem()); 1066 } 1067 if (txCache != null) { 1068 t.setResult(txCache.getValidation(t.getCacheToken())); 1069 } 1070 } 1071 if (options.isUseClient()) { 1072 for (CodingValidationRequest t : codes) { 1073 if (!t.hasResult()) { 1074 try { 1075 ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs == null ? t.getVsObj() : vs); 1076 vsc.setThrowToServer(options.isUseServer() && terminologyClientManager.hasClient()); 1077 ValidationResult res = vsc.validateCode("Coding", t.getCoding()); 1078 if (txCache != null) { 1079 txCache.cacheValidation(t.getCacheToken(), res, TerminologyCache.TRANSIENT); 1080 } 1081 t.setResult(res); 1082 } catch (Exception e) { 1083 } 1084 } 1085 } 1086 } 1087 1088 for (CodingValidationRequest t : codes) { 1089 if (!t.hasResult()) { 1090 String codeKey = t.getCoding().hasVersion() ? t.getCoding().getSystem()+"|"+t.getCoding().getVersion() : t.getCoding().getSystem(); 1091 if (!options.isUseServer()) { 1092 t.setResult(new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, null)); 1093 } else if (unsupportedCodeSystems.contains(codeKey)) { 1094 t.setResult(new ValidationResult(IssueSeverity.ERROR,formatMessage(I18nConstants.UNKNOWN_CODESYSTEM, t.getCoding().getSystem()), TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED, null)); 1095 } else if (noTerminologyServer) { 1096 t.setResult(new ValidationResult(IssueSeverity.ERROR,formatMessage(I18nConstants.ERROR_VALIDATING_CODE_RUNNING_WITHOUT_TERMINOLOGY_SERVICES, t.getCoding().getCode(), t.getCoding().getSystem()), TerminologyServiceErrorClass.NOSERVICE, null)); 1097 } 1098 } 1099 } 1100 1101 if (expParameters == null) 1102 throw new Error(formatMessage(I18nConstants.NO_EXPANSIONPROFILE_PROVIDED)); 1103 // for those that that failed, we try to validate on the server 1104 Bundle batch = new Bundle(); 1105 batch.setType(BundleType.BATCH); 1106 Set<String> systems = findRelevantSystems(vs); 1107 for (CodingValidationRequest codingValidationRequest : codes) { 1108 if (!codingValidationRequest.hasResult()) { 1109 Parameters pIn = constructParameters(options, codingValidationRequest, vs == null ? codingValidationRequest.getVsObj() : vs); 1110 setTerminologyOptions(options, pIn); 1111 BundleEntryComponent be = batch.addEntry(); 1112 be.setResource(pIn); 1113 be.getRequest().setMethod(HTTPVerb.POST); 1114 if (vs != null || codingValidationRequest.getVsObj() != null) { 1115 be.getRequest().setUrl("ValueSet/$validate-code"); 1116 } else { 1117 be.getRequest().setUrl("CodeSystem/$validate-code"); 1118 } 1119 be.setUserData("source", codingValidationRequest); 1120 systems.add(codingValidationRequest.getCoding().getSystem()); 1121 findRelevantSystems(systems, codingValidationRequest.getCoding()); 1122 } 1123 } 1124 1125 if (batch.getEntry().size() > 0) { 1126 TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, false); 1127 Bundle resp = processBatch(tc, batch, systems); 1128 for (int i = 0; i < batch.getEntry().size(); i++) { 1129 CodingValidationRequest t = (CodingValidationRequest) batch.getEntry().get(i).getUserData("source"); 1130 BundleEntryComponent r = resp.getEntry().get(i); 1131 1132 if (r.getResource() instanceof Parameters) { 1133 t.setResult(processValidationResult((Parameters) r.getResource(), vs != null ? vs.getUrl() : t.getVsObj() != null ? t.getVsObj().getUrl() : null, tc.getAddress())); 1134 if (txCache != null) { 1135 txCache.cacheValidation(t.getCacheToken(), t.getResult(), TerminologyCache.PERMANENT); 1136 } 1137 } else { 1138 t.setResult(new ValidationResult(IssueSeverity.ERROR, getResponseText(r.getResource()), null).setTxLink(txLog == null ? null : txLog.getLastId())); 1139 } 1140 } 1141 } 1142 } 1143 1144 private Bundle processBatch(TerminologyClientContext tc, Bundle batch, Set<String> systems) { 1145 txLog("$batch validate for "+batch.getEntry().size()+" codes on systems "+systems.toString()); 1146 if (terminologyClientManager == null) { 1147 throw new FHIRException(formatMessage(I18nConstants.ATTEMPT_TO_USE_TERMINOLOGY_SERVER_WHEN_NO_TERMINOLOGY_SERVER_IS_AVAILABLE)); 1148 } 1149 if (txLog != null) { 1150 txLog.clearLastId(); 1151 } 1152 Bundle resp = tc.getClient().validateBatch(batch); 1153 if (resp == null) { 1154 throw new FHIRException(formatMessage(I18nConstants.TX_SERVER_NO_BATCH_RESPONSE)); 1155 } 1156 return resp; 1157 } 1158 1159 @Override 1160 public void validateCodeBatchByRef(ValidationOptions options, List<? extends CodingValidationRequest> codes, String vsUrl) { 1161 if (options == null) { 1162 options = ValidationOptions.defaults(); 1163 } 1164 // 1st pass: what is in the cache? 1165 // 2nd pass: What can we do internally 1166 // 3rd pass: hit the server 1167 for (CodingValidationRequest t : codes) { 1168 t.setCacheToken(txCache != null ? txCache.generateValidationToken(options, t.getCoding(), vsUrl, expParameters) : null); 1169 if (t.getCoding().hasSystem()) { 1170 codeSystemsUsed.add(t.getCoding().getSystem()); 1171 } 1172 if (txCache != null) { 1173 t.setResult(txCache.getValidation(t.getCacheToken())); 1174 } 1175 } 1176 ValueSet vs = fetchResource(ValueSet.class, vsUrl); 1177 if (options.isUseClient()) { 1178 if (vs != null) { 1179 for (CodingValidationRequest t : codes) { 1180 if (!t.hasResult()) { 1181 try { 1182 ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs); 1183 vsc.setThrowToServer(options.isUseServer() && terminologyClientManager.hasClient()); 1184 ValidationResult res = vsc.validateCode("Coding", t.getCoding()); 1185 if (txCache != null) { 1186 txCache.cacheValidation(t.getCacheToken(), res, TerminologyCache.TRANSIENT); 1187 } 1188 t.setResult(res); 1189 } catch (Exception e) { 1190 } 1191 } 1192 } 1193 } 1194 } 1195 1196 for (CodingValidationRequest t : codes) { 1197 if (!t.hasResult()) { 1198 String codeKey = t.getCoding().hasVersion() ? t.getCoding().getSystem()+"|"+t.getCoding().getVersion() : t.getCoding().getSystem(); 1199 if (!options.isUseServer()) { 1200 t.setResult(new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, null)); 1201 } else if (unsupportedCodeSystems.contains(codeKey)) { 1202 t.setResult(new ValidationResult(IssueSeverity.ERROR,formatMessage(I18nConstants.UNKNOWN_CODESYSTEM, t.getCoding().getSystem()), TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED, null)); 1203 } else if (noTerminologyServer) { 1204 t.setResult(new ValidationResult(IssueSeverity.ERROR,formatMessage(I18nConstants.ERROR_VALIDATING_CODE_RUNNING_WITHOUT_TERMINOLOGY_SERVICES, t.getCoding().getCode(), t.getCoding().getSystem()), TerminologyServiceErrorClass.NOSERVICE, null)); 1205 } 1206 } 1207 } 1208 1209 if (expParameters == null) 1210 throw new Error(formatMessage(I18nConstants.NO_EXPANSIONPROFILE_PROVIDED)); 1211 // for those that that failed, we try to validate on the server 1212 Bundle batch = new Bundle(); 1213 batch.setType(BundleType.BATCH); 1214 Set<String> systems = vs != null ? findRelevantSystems(vs) : new HashSet<>(); 1215 for (CodingValidationRequest codingValidationRequest : codes) { 1216 if (!codingValidationRequest.hasResult()) { 1217 Parameters pIn = constructParameters(options, codingValidationRequest, vsUrl); 1218 setTerminologyOptions(options, pIn); 1219 BundleEntryComponent be = batch.addEntry(); 1220 be.setResource(pIn); 1221 be.getRequest().setMethod(HTTPVerb.POST); 1222 if (vsUrl != null) { 1223 be.getRequest().setUrl("ValueSet/$validate-code"); 1224 } else { 1225 be.getRequest().setUrl("CodeSystem/$validate-code"); 1226 } 1227 be.setUserData("source", codingValidationRequest); 1228 systems.add(codingValidationRequest.getCoding().getSystem()); 1229 } 1230 } 1231 TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, false); 1232 1233 if (batch.getEntry().size() > 0) { 1234 Bundle resp = processBatch(tc, batch, systems); 1235 for (int i = 0; i < batch.getEntry().size(); i++) { 1236 CodingValidationRequest t = (CodingValidationRequest) batch.getEntry().get(i).getUserData("source"); 1237 BundleEntryComponent r = resp.getEntry().get(i); 1238 1239 if (r.getResource() instanceof Parameters) { 1240 t.setResult(processValidationResult((Parameters) r.getResource(), vsUrl, tc.getAddress())); 1241 if (txCache != null) { 1242 txCache.cacheValidation(t.getCacheToken(), t.getResult(), TerminologyCache.PERMANENT); 1243 } 1244 } else { 1245 t.setResult(new ValidationResult(IssueSeverity.ERROR, getResponseText(r.getResource()), null).setTxLink(txLog == null ? null : txLog.getLastId())); 1246 } 1247 } 1248 } 1249 } 1250 1251 private String getResponseText(Resource resource) { 1252 if (resource instanceof OperationOutcome) { 1253 return OperationOutcomeRenderer.toString((OperationOutcome) resource); 1254 } 1255 return "Todo"; 1256 } 1257 1258 @Override 1259 public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs) { 1260 ValidationContextCarrier ctxt = new ValidationContextCarrier(); 1261 return validateCode(options, "Coding", code, vs, ctxt); 1262 } 1263 1264 public ValidationResult validateCode(ValidationOptions options, String path, Coding code, ValueSet vs) { 1265 ValidationContextCarrier ctxt = new ValidationContextCarrier(); 1266 return validateCode(options, path, code, vs, ctxt); 1267 } 1268 1269 private final String getCodeKey(Coding code) { 1270 return code.hasVersion() ? code.getSystem()+"|"+code.getVersion() : code.getSystem(); 1271 } 1272 1273 @Override 1274 public ValidationResult validateCode(final ValidationOptions optionsArg, final Coding code, final ValueSet vs, final ValidationContextCarrier ctxt) { 1275 return validateCode(optionsArg, "Coding", code, vs, ctxt); 1276 } 1277 1278 public ValidationResult validateCode(final ValidationOptions optionsArg, String path, final Coding code, final ValueSet vs, final ValidationContextCarrier ctxt) { 1279 1280 ValidationOptions options = optionsArg != null ? optionsArg : ValidationOptions.defaults(); 1281 1282 if (code.hasSystem()) { 1283 codeSystemsUsed.add(code.getSystem()); 1284 } 1285 1286 final CacheToken cacheToken = cachingAllowed && txCache != null ? txCache.generateValidationToken(options, code, vs, expParameters) : null; 1287 ValidationResult res = null; 1288 if (cachingAllowed && txCache != null) { 1289 res = txCache.getValidation(cacheToken); 1290 } 1291 if (res != null) { 1292 updateUnsupportedCodeSystems(res, code, getCodeKey(code)); 1293 return res; 1294 } 1295 1296 List<OperationOutcomeIssueComponent> issues = new ArrayList<>(); 1297 Set<String> unknownSystems = new HashSet<>(); 1298 1299 String localError = null; 1300 String localWarning = null; 1301 TerminologyServiceErrorClass type = TerminologyServiceErrorClass.UNKNOWN; 1302 if (options.isUseClient()) { 1303 // ok, first we try to validate locally 1304 try { 1305 ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs, ctxt); 1306 if (vsc.getOpContext() != null) { 1307 vsc.getOpContext().note("Validate "+code.toString()+" @ "+path+" against "+(vs == null ? "null" : vs.getVersionedUrl())); 1308 } 1309 vsc.setUnknownSystems(unknownSystems); 1310 vsc.setThrowToServer(options.isUseServer() && terminologyClientManager.hasClient()); 1311 if (!ValueSetUtilities.isServerSide(code.getSystem())) { 1312 res = vsc.validateCode(path, code.copy()); 1313 if (txCache != null && cachingAllowed) { 1314 txCache.cacheValidation(cacheToken, res, TerminologyCache.TRANSIENT); 1315 } 1316 return res; 1317 } 1318 } catch (VSCheckerException e) { 1319 if (e.isWarning()) { 1320 localWarning = e.getMessage(); 1321 } else { 1322 localError = e.getMessage(); 1323 } 1324 if (e.getIssues() != null) { 1325 issues.addAll(e.getIssues()); 1326 } 1327 type = e.getType(); 1328 } catch (TerminologyServiceProtectionException e) { 1329 OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR, e.getType()); 1330 iss.getDetails().setText(e.getMessage()); 1331 issues.add(iss); 1332 return new ValidationResult(IssueSeverity.FATAL, e.getMessage(), e.getError(), issues); 1333 } catch (Exception e) { 1334// e.printStackTrace(); 1335 localError = e.getMessage(); 1336 } 1337 } 1338 1339 if (localError != null && !terminologyClientManager.hasClient()) { 1340 if (unknownSystems.size() > 0) { 1341 return new ValidationResult(IssueSeverity.ERROR, localError, TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED, issues).setUnknownSystems(unknownSystems); 1342 } else { 1343 return new ValidationResult(IssueSeverity.ERROR, localError, TerminologyServiceErrorClass.UNKNOWN, issues); 1344 } 1345 } 1346 if (localWarning != null && !terminologyClientManager.hasClient()) { 1347 return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER, localWarning), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, issues); 1348 } 1349 if (!options.isUseServer()) { 1350 if (localWarning != null) { 1351 return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER, localWarning), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, issues); 1352 } else { 1353 return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER, localError), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, issues); 1354 } 1355 } 1356 String codeKey = getCodeKey(code); 1357 if (unsupportedCodeSystems.contains(codeKey)) { 1358 return new ValidationResult(IssueSeverity.ERROR,formatMessage(I18nConstants.UNKNOWN_CODESYSTEM, code.getSystem()), TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED, issues); 1359 } 1360 1361 // if that failed, we try to validate on the server 1362 if (noTerminologyServer) { 1363 return new ValidationResult(IssueSeverity.ERROR,formatMessage(I18nConstants.ERROR_VALIDATING_CODE_RUNNING_WITHOUT_TERMINOLOGY_SERVICES, code.getCode(), code.getSystem()), TerminologyServiceErrorClass.NOSERVICE, issues); 1364 } 1365 1366 Set<String> systems = findRelevantSystems(code, vs); 1367 TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, false); 1368 1369 String csumm = cachingAllowed && txCache != null ? txCache.summary(code) : null; 1370 if (cachingAllowed && txCache != null) { 1371 txLog("$validate "+csumm+(vs == null ? "" : " for "+ txCache.summary(vs))+" on "+tc.getAddress()); 1372 } else { 1373 txLog("$validate "+csumm+" before cache exists on "+tc.getAddress()); 1374 } 1375 try { 1376 Parameters pIn = constructParameters(options, code); 1377 res = validateOnServer(tc, vs, pIn, options); 1378 } catch (Exception e) { 1379 res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage(), null).setTxLink(txLog == null ? null : txLog.getLastId()).setErrorClass(TerminologyServiceErrorClass.SERVER_ERROR); 1380 } 1381 if (!res.isOk() && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED && (localError != null && !localError.equals(ValueSetValidator.NO_TRY_THE_SERVER))) { 1382 res = new ValidationResult(IssueSeverity.ERROR, localError, null).setTxLink(txLog == null ? null : txLog.getLastId()).setErrorClass(type); 1383 } 1384 if (!res.isOk() && localError != null) { 1385 res.setDiagnostics("Local Error: "+localError.trim()+". Server Error: "+res.getMessage()); 1386 } else if (!res.isOk() && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED && res.getUnknownSystems() != null && res.getUnknownSystems().contains(codeKey) && localWarning != null) { 1387 // we had some problem evaluating locally, but the server doesn't know the code system, so we'll just go with the local error 1388 res = new ValidationResult(IssueSeverity.WARNING, localWarning, null); 1389 res.setDiagnostics("Local Warning: "+localWarning.trim()+". Server Error: "+res.getMessage()); 1390 return res; 1391 } 1392 updateUnsupportedCodeSystems(res, code, codeKey); 1393 if (cachingAllowed && txCache != null) { // we never cache unsupported code systems - we always keep trying (but only once per run) 1394 txCache.cacheValidation(cacheToken, res, TerminologyCache.PERMANENT); 1395 } 1396 return res; 1397 } 1398 1399 1400 /** 1401 * ask the terminology system whether parent subsumes child. 1402 * 1403 * @return true if it does, false if it doesn't, and null if it's not know whether it does 1404 */ 1405 public Boolean subsumes(ValidationOptions optionsArg, Coding parent, Coding child) { 1406 ValidationOptions options = optionsArg != null ? optionsArg : ValidationOptions.defaults(); 1407 1408 if (parent.hasSystem()) { 1409 codeSystemsUsed.add(parent.getSystem()); 1410 } else { 1411 return null; 1412 } 1413 if (child.hasSystem()) { 1414 codeSystemsUsed.add(child.getSystem()); 1415 } else { 1416 return null; 1417 } 1418 1419 final CacheToken cacheToken = cachingAllowed && txCache != null ? txCache.generateSubsumesToken(options, parent, child, expParameters) : null; 1420 if (cachingAllowed && txCache != null) { 1421 Boolean res = txCache.getSubsumes(cacheToken); 1422 if (res != null) { 1423 return res; 1424 } 1425 } 1426 1427 if (options.isUseClient() && parent.getSystem().equals(child.getSystem())) { 1428 CodeSystem cs = fetchCodeSystem(parent.getSystem()); 1429 if (cs != null) { 1430 Boolean b = CodeSystemUtilities.subsumes(cs, parent.getCode(), child.getCode()); 1431 if (txCache != null && cachingAllowed) { 1432 txCache.cacheSubsumes(cacheToken, b, true); 1433 } 1434 return b; 1435 } 1436 } 1437 1438 if (!terminologyClientManager.hasClient() || !options.isUseServer() || unsupportedCodeSystems.contains(parent.getSystem()) || unsupportedCodeSystems.contains(child.getSystem()) || noTerminologyServer) { 1439 return null; 1440 } 1441 1442 Set<String> systems = new HashSet<>(); 1443 systems.add(parent.getSystem()); 1444 systems.add(child.getSystem()); 1445 TerminologyClientContext tc = terminologyClientManager.chooseServer(null, systems, false); 1446 1447 txLog("$subsumes "+parent.toString()+" > "+child.toString()+" on "+tc.getAddress()); 1448 1449 try { 1450 Parameters pIn = new Parameters(); 1451 pIn.addParameter().setName("codingA").setValue(parent); 1452 pIn.addParameter().setName("codingB").setValue(child); 1453 if (txLog != null) { 1454 txLog.clearLastId(); 1455 } 1456 Parameters pOut = tc.getClient().subsumes(pIn); 1457 return processSubsumesResult(pOut, tc.getClient().getAddress()); 1458 } catch (Exception e) { 1459 // e.printStackTrace(); 1460 } 1461 return null; 1462 } 1463 1464 1465 public Boolean processSubsumesResult(Parameters pOut, String server) { 1466 for (ParametersParameterComponent p : pOut.getParameter()) { 1467 if (p.hasValue()) { 1468 if (p.getName().equals("outcome")) { 1469 return Utilities.existsInList(p.getValue().primitiveValue(), "equivalent", "subsumes"); 1470 } 1471 } 1472 } 1473 return null; 1474 } 1475 1476 protected ValueSetExpander constructValueSetExpanderSimple(ValidationOptions options) { 1477 return new ValueSetExpander(this, new TerminologyOperationContext(this, options, "expansion")).setDebug(logger.isDebugLogging()); 1478 } 1479 1480 protected ValueSetValidator constructValueSetCheckerSimple(ValidationOptions options, ValueSet vs, ValidationContextCarrier ctxt) { 1481 return new ValueSetValidator(this, new TerminologyOperationContext(this, options, "validation"), options, vs, ctxt, expParameters, terminologyClientManager); 1482 } 1483 1484 protected ValueSetValidator constructValueSetCheckerSimple( ValidationOptions options, ValueSet vs) { 1485 return new ValueSetValidator(this, new TerminologyOperationContext(this, options, "validation"), options, vs, expParameters, terminologyClientManager); 1486 } 1487 1488 protected Parameters constructParameters(TerminologyClientContext tcd, ValueSet vs, boolean hierarchical) { 1489 Parameters p = expParameters.copy(); 1490 p.setParameter("includeDefinition", false); 1491 p.setParameter("excludeNested", !hierarchical); 1492 1493 addDependentResources(tcd, p, vs); 1494 p.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId())); 1495 return p; 1496 } 1497 1498 protected Parameters constructParameters(ValidationOptions options, Coding coding) { 1499 Parameters pIn = new Parameters(); 1500 if (options.isGuessSystem()) { 1501 pIn.addParameter().setName("inferSystem").setValue(new BooleanType(true)); 1502 pIn.addParameter().setName("code").setValue(coding.getCodeElement()); 1503 } else { 1504 pIn.addParameter().setName("coding").setValue(coding); 1505 } 1506 setTerminologyOptions(options, pIn); 1507 return pIn; 1508 } 1509 1510 protected Parameters constructParameters(ValidationOptions options, CodeableConcept codeableConcept) { 1511 Parameters pIn = new Parameters(); 1512 pIn.addParameter().setName("codeableConcept").setValue(codeableConcept); 1513 setTerminologyOptions(options, pIn); 1514 return pIn; 1515 } 1516 1517 protected Parameters constructParameters(ValidationOptions options, CodingValidationRequest codingValidationRequest, ValueSet valueSet) { 1518 Parameters pIn = new Parameters(); 1519 if (options.isGuessSystem()) { 1520 pIn.addParameter().setName("inferSystem").setValue(new BooleanType(true)); 1521 pIn.addParameter().setName("code").setValue(codingValidationRequest.getCoding().getCodeElement()); 1522 } else { 1523 pIn.addParameter().setName("coding").setValue(codingValidationRequest.getCoding()); 1524 } 1525 if (valueSet != null) { 1526 pIn.addParameter().setName("valueSet").setResource(valueSet); 1527 } 1528 1529 pIn.addParameters(expParameters); 1530 return pIn; 1531 } 1532 1533 protected Parameters constructParameters(ValidationOptions options, CodingValidationRequest codingValidationRequest, String vsUrl) { 1534 Parameters pIn = new Parameters(); 1535 if (options.isGuessSystem()) { 1536 pIn.addParameter().setName("inferSystem").setValue(new BooleanType(true)); 1537 pIn.addParameter().setName("code").setValue(codingValidationRequest.getCoding().getCodeElement()); 1538 } else { 1539 pIn.addParameter().setName("coding").setValue(codingValidationRequest.getCoding()); 1540 } 1541 if (vsUrl != null) { 1542 pIn.addParameter().setName("url").setValue(new CanonicalType(vsUrl)); 1543 } 1544 pIn.addParameters(expParameters); 1545 return pIn; 1546 } 1547 1548 private void updateUnsupportedCodeSystems(ValidationResult res, Coding code, String codeKey) { 1549 if (res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED && !code.hasVersion() && fetchCodeSystem(codeKey) == null) { 1550 unsupportedCodeSystems.add(codeKey); 1551 } 1552 } 1553 1554 private void setTerminologyOptions(ValidationOptions options, Parameters pIn) { 1555 if (options.hasLanguages()) { 1556 pIn.addParameter("displayLanguage", options.getLanguages().toString()); 1557 } 1558 if (options.isMembershipOnly()) { 1559 pIn.addParameter("valueset-membership-only", true); 1560 } 1561 if (options.isDisplayWarningMode()) { 1562 pIn.addParameter("lenient-display-validation", true); 1563 } 1564 if (options.isVersionFlexible()) { 1565 pIn.addParameter("default-to-latest-version", true); 1566 } 1567 } 1568 1569 @Override 1570 public ValidationResult validateCode(ValidationOptions options, CodeableConcept code, ValueSet vs) { 1571 CacheToken cacheToken = txCache.generateValidationToken(options, code, vs, expParameters); 1572 ValidationResult res = null; 1573 if (cachingAllowed) { 1574 res = txCache.getValidation(cacheToken); 1575 if (res != null) { 1576 return res; 1577 } 1578 } 1579 for (Coding c : code.getCoding()) { 1580 if (c.hasSystem()) { 1581 codeSystemsUsed.add(c.getSystem()); 1582 } 1583 } 1584 Set<String> unknownSystems = new HashSet<>(); 1585 1586 List<OperationOutcomeIssueComponent> issues = new ArrayList<>(); 1587 1588 String localError = null; 1589 String localWarning = null; 1590 1591 if (options.isUseClient()) { 1592 // ok, first we try to validate locally 1593 try { 1594 ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs); 1595 vsc.setUnknownSystems(unknownSystems); 1596 vsc.setThrowToServer(options.isUseServer() && terminologyClientManager.hasClient()); 1597 res = vsc.validateCode("CodeableConcept", code); 1598 if (cachingAllowed) { 1599 txCache.cacheValidation(cacheToken, res, TerminologyCache.TRANSIENT); 1600 } 1601 return res; 1602 } catch (VSCheckerException e) { 1603 if (e.isWarning()) { 1604 localWarning = e.getMessage(); 1605 } else { 1606 localError = e.getMessage(); 1607 } 1608 if (e.getIssues() != null) { 1609 issues.addAll(e.getIssues()); 1610 } 1611 } catch (TerminologyServiceProtectionException e) { 1612 OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR, e.getType()); 1613 iss.getDetails().setText(e.getMessage()); 1614 issues.add(iss); 1615 return new ValidationResult(IssueSeverity.FATAL, e.getMessage(), e.getError(), issues); 1616 } catch (Exception e) { 1617// e.printStackTrace(); 1618 localError = e.getMessage(); 1619 } 1620 } 1621 1622 if (localError != null && !terminologyClientManager.hasClient()) { 1623 if (unknownSystems.size() > 0) { 1624 return new ValidationResult(IssueSeverity.ERROR, localError, TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED, issues).setUnknownSystems(unknownSystems); 1625 } else { 1626 return new ValidationResult(IssueSeverity.ERROR, localError, TerminologyServiceErrorClass.UNKNOWN, issues); 1627 } 1628 } 1629 if (localWarning != null && !terminologyClientManager.hasClient()) { 1630 return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER, localWarning), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, issues); 1631 } 1632 1633 if (!options.isUseServer()) { 1634 return new ValidationResult(IssueSeverity.WARNING, "Unable to validate code without using server", TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, null); 1635 } 1636 1637 // if that failed, we try to validate on the server 1638 if (noTerminologyServer) { 1639 return new ValidationResult(IssueSeverity.ERROR, "Error validating code: running without terminology services", TerminologyServiceErrorClass.NOSERVICE, null); 1640 } 1641 Set<String> systems = findRelevantSystems(code, vs); 1642 TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, false); 1643 1644 txLog("$validate "+txCache.summary(code)+" for "+ txCache.summary(vs)+" on "+tc.getAddress()); 1645 try { 1646 Parameters pIn = constructParameters(options, code); 1647 res = validateOnServer(tc, vs, pIn, options); 1648 } catch (Exception e) { 1649 issues.clear(); 1650 OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXCEPTION); 1651 iss.getDetails().setText(e.getMessage()); 1652 issues.add(iss); 1653 res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage(), issues).setTxLink(txLog == null ? null : txLog.getLastId()).setErrorClass(TerminologyServiceErrorClass.SERVER_ERROR); 1654 } 1655 if (cachingAllowed) { 1656 txCache.cacheValidation(cacheToken, res, TerminologyCache.PERMANENT); 1657 } 1658 return res; 1659 } 1660 1661 private Set<String> findRelevantSystems(ValueSet vs) { 1662 Set<String> set = new HashSet<>(); 1663 if (vs != null) { 1664 findRelevantSystems(set, vs); 1665 } 1666 return set; 1667 } 1668 1669 private Set<String> findRelevantSystems(CodeableConcept code, ValueSet vs) { 1670 Set<String> set = new HashSet<>(); 1671 if (vs != null) { 1672 findRelevantSystems(set, vs); 1673 } 1674 for (Coding c : code.getCoding()) { 1675 findRelevantSystems(set, c); 1676 } 1677 return set; 1678 } 1679 1680 private Set<String> findRelevantSystems(Coding code, ValueSet vs) { 1681 Set<String> set = new HashSet<>(); 1682 if (vs != null) { 1683 findRelevantSystems(set, vs); 1684 } 1685 if (code != null) { 1686 findRelevantSystems(set, code); 1687 } 1688 return set; 1689 } 1690 1691 private void findRelevantSystems(Set<String> set, ValueSet vs) { 1692 for (ConceptSetComponent inc : vs.getCompose().getInclude()) { 1693 findRelevantSystems(set, inc); 1694 } 1695 for (ConceptSetComponent inc : vs.getCompose().getExclude()) { 1696 findRelevantSystems(set, inc); 1697 } 1698 } 1699 1700 private void findRelevantSystems(Set<String> set, ConceptSetComponent inc) { 1701 if (inc.hasSystem()) { 1702 if (inc.hasVersion()) { 1703 set.add(inc.getSystem()+"|"+inc.getVersion()); 1704 } else { 1705 set.add(inc.getSystem()); 1706 } 1707 } 1708 for (CanonicalType u : inc.getValueSet()) { 1709 ValueSet vs = fetchResource(ValueSet.class, u.getValue()); 1710 if (vs != null) { 1711 findRelevantSystems(set, vs); 1712 } else { 1713 set.add(TerminologyClientManager.UNRESOLVED_VALUESET); 1714 } 1715 } 1716 } 1717 1718 private void findRelevantSystems(Set<String> set, Coding c) { 1719 if (c.hasSystem()) { 1720 if (c.hasVersion()) { 1721 set.add(c.getSystem()+"|"+c.getVersion()); 1722 } else { 1723 set.add(c.getSystem()); 1724 } 1725 } 1726 } 1727 1728 protected ValidationResult validateOnServer(TerminologyClientContext tc, ValueSet vs, Parameters pin, ValidationOptions options) throws FHIRException { 1729 1730 if (vs != null) { 1731 for (ConceptSetComponent inc : vs.getCompose().getInclude()) { 1732 codeSystemsUsed.add(inc.getSystem()); 1733 } 1734 for (ConceptSetComponent inc : vs.getCompose().getExclude()) { 1735 codeSystemsUsed.add(inc.getSystem()); 1736 } 1737 } 1738 1739 addServerValidationParameters(tc, vs, pin, options); 1740 1741 if (txLog != null) { 1742 txLog.clearLastId(); 1743 } 1744 if (tc == null) { 1745 throw new FHIRException(formatMessage(I18nConstants.ATTEMPT_TO_USE_TERMINOLOGY_SERVER_WHEN_NO_TERMINOLOGY_SERVER_IS_AVAILABLE)); 1746 } 1747 Parameters pOut; 1748 if (vs == null) { 1749 pOut = tc.getClient().validateCS(pin); 1750 } else { 1751 pOut = tc.getClient().validateVS(pin); 1752 } 1753 return processValidationResult(pOut, vs == null ? null : vs.getUrl(), tc.getClient().getAddress()); 1754 } 1755 1756 protected void addServerValidationParameters(TerminologyClientContext terminologyClientContext, ValueSet vs, Parameters pin, ValidationOptions options) { 1757 boolean cache = false; 1758 if (vs != null) { 1759 if (terminologyClientContext != null && terminologyClientContext.isTxCaching() && terminologyClientContext.getCacheId() != null && vs.getUrl() != null && terminologyClientContext.getCached().contains(vs.getUrl()+"|"+ vs.getVersion())) { 1760 pin.addParameter().setName("url").setValue(new UriType(vs.getUrl())); 1761 if (vs.hasVersion()) { 1762 pin.addParameter().setName("valueSetVersion").setValue(new StringType(vs.getVersion())); 1763 } 1764 } else if (options.getVsAsUrl()){ 1765 pin.addParameter().setName("url").setValue(new UriType(vs.getUrl())); 1766 } else { 1767 if (vs.hasCompose() && vs.hasExpansion()) { 1768 vs = vs.copy(); 1769 vs.setExpansion(null); 1770 } 1771 pin.addParameter().setName("valueSet").setResource(vs); 1772 if (vs.getUrl() != null) { 1773 terminologyClientContext.getCached().add(vs.getUrl()+"|"+ vs.getVersion()); 1774 } 1775 } 1776 cache = true; 1777 addDependentResources(terminologyClientContext, pin, vs); 1778 } 1779 pin.addParameter().setName("cache-id").setValue(new IdType(terminologyClientManager.getCacheId())); 1780 for (ParametersParameterComponent pp : pin.getParameter()) { 1781 if (pp.getName().equals("profile")) { 1782 throw new Error(formatMessage(I18nConstants.CAN_ONLY_SPECIFY_PROFILE_IN_THE_CONTEXT)); 1783 } 1784 } 1785 if (expParameters == null) { 1786 throw new Error(formatMessage(I18nConstants.NO_EXPANSIONPROFILE_PROVIDED)); 1787 } 1788 pin.addParameters(expParameters); 1789 1790 if (options.isDisplayWarningMode()) { 1791 pin.addParameter("mode","lenient-display-validation"); 1792 } 1793 pin.addParameter("diagnostics", true); 1794 } 1795 1796 private boolean addDependentResources(TerminologyClientContext tc, Parameters pin, ValueSet vs) { 1797 boolean cache = false; 1798 for (ConceptSetComponent inc : vs.getCompose().getInclude()) { 1799 cache = addDependentResources(tc, pin, inc, vs) || cache; 1800 } 1801 for (ConceptSetComponent inc : vs.getCompose().getExclude()) { 1802 cache = addDependentResources(tc, pin, inc, vs) || cache; 1803 } 1804 return cache; 1805 } 1806 1807 private boolean addDependentResources(TerminologyClientContext tc, Parameters pin, ConceptSetComponent inc, Resource src) { 1808 boolean cache = false; 1809 for (CanonicalType c : inc.getValueSet()) { 1810 ValueSet vs = fetchResource(ValueSet.class, c.getValue(), src); 1811 if (vs != null && !hasCanonicalResource(pin, "tx-resource", vs.getVUrl())) { 1812 cache = checkAddToParams(tc, pin, vs) || cache; 1813 addDependentResources(tc, pin, vs); 1814 for (Extension ext : vs.getExtensionsByUrl(ToolingExtensions.EXT_VS_CS_SUPPL_NEEDED)) { 1815 if (ext.hasValueCanonicalType()) { 1816 String url = ext.getValueCanonicalType().asStringValue(); 1817 CodeSystem supp = fetchResource(CodeSystem.class, url); 1818 if (supp != null) { 1819 cache = checkAddToParams(tc, pin, supp) || cache; 1820 } 1821 } 1822 } 1823 } 1824 } 1825 CodeSystem cs = fetchResource(CodeSystem.class, inc.getSystem(), src); 1826 if (cs != null && !hasCanonicalResource(pin, "tx-resource", cs.getVUrl()) && (cs.getContent() == CodeSystemContentMode.COMPLETE || cs.getContent() == CodeSystemContentMode.FRAGMENT)) { 1827 cache = checkAddToParams(tc, pin, cs) || cache; 1828 } 1829 for (CodeSystem supp : codeSystems.getSupplements(cs)) { 1830 //if (supp.getContent() == CodeSystemContentMode.SUPPLEMENT && supp.getSupplements().equals(inc.getSystem())) { 1831 assert supp.getContent() == CodeSystemContentMode.SUPPLEMENT && supp.getSupplements().equals(inc.getSystem()); 1832 cache = checkAddToParams(tc, pin, supp) || cache; 1833 //} 1834 } 1835 return cache; 1836 } 1837 1838 private boolean checkAddToParams(TerminologyClientContext tc, Parameters pin, CanonicalResource cr) { 1839 boolean cache = false; 1840 boolean addToParams = false; 1841 if (tc.usingCache()) { 1842 if (!tc.alreadyCached(cr)) { 1843 tc.addToCache(cr); 1844 if (logger.isDebugLogging()) { 1845 logger.logMessage("add to cache: "+cr.getVUrl()); 1846 } 1847 addToParams = true; 1848 cache = true; 1849 } else { 1850 if (logger.isDebugLogging()) { 1851 logger.logMessage("already cached: "+cr.getVUrl()); 1852 } 1853 } 1854 } else { 1855 addToParams = true; 1856 } 1857 if (addToParams) { 1858 pin.addParameter().setName("tx-resource").setResource(cr); 1859 } 1860 return cache; 1861 } 1862 1863 private boolean hasCanonicalResource(Parameters pin, String name, String vUrl) { 1864 for (ParametersParameterComponent p : pin.getParameter()) { 1865 if (name.equals(p.getName()) && p.hasResource() && 1866 p.getResource() instanceof CanonicalResource && vUrl.equals(((CanonicalResource) p.getResource()).getVUrl())) { 1867 return true; 1868 } 1869 } 1870 return false; 1871 } 1872 1873 public ValidationResult processValidationResult(Parameters pOut, String vs, String server) { 1874 boolean ok = false; 1875 String message = "No Message returned"; 1876 String display = null; 1877 String system = null; 1878 String code = null; 1879 String version = null; 1880 boolean inactive = false; 1881 String status = null; 1882 List<OperationOutcomeIssueComponent> issues = new ArrayList<>(); 1883 Set<String> unknownSystems = new HashSet<>(); 1884 1885 TerminologyServiceErrorClass err = TerminologyServiceErrorClass.UNKNOWN; 1886 for (ParametersParameterComponent p : pOut.getParameter()) { 1887 if (p.hasValue()) { 1888 if (p.getName().equals("result")) { 1889 ok = ((BooleanType) p.getValue()).getValue().booleanValue(); 1890 } else if (p.getName().equals("message")) { 1891 message = p.getValue().primitiveValue(); 1892 } else if (p.getName().equals("display")) { 1893 display = p.getValue().primitiveValue(); 1894 } else if (p.getName().equals("system")) { 1895 system = ((PrimitiveType<?>) p.getValue()).asStringValue(); 1896 } else if (p.getName().equals("version")) { 1897 version = ((PrimitiveType<?>) p.getValue()).asStringValue(); 1898 } else if (p.getName().equals("code")) { 1899 code = ((PrimitiveType<?>) p.getValue()).asStringValue(); 1900 } else if (p.getName().equals("inactive")) { 1901 inactive = "true".equals(((PrimitiveType<?>) p.getValue()).asStringValue()); 1902 } else if (p.getName().equals("status")) { 1903 status = ((PrimitiveType<?>) p.getValue()).asStringValue(); 1904 } else if (p.getName().equals("x-caused-by-unknown-system")) { 1905 String unkSystem = ((PrimitiveType<?>) p.getValue()).asStringValue(); 1906 if (unkSystem != null && unkSystem.contains("|")) { 1907 err = TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED_VERSION; 1908 system = unkSystem.substring(0, unkSystem.indexOf("|")); 1909 version = unkSystem.substring(unkSystem.indexOf("|")+1); 1910 } else { 1911 err = TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED; 1912 unknownSystems.add(unkSystem); 1913 } 1914 } else if (p.getName().equals("x-unknown-system")) { 1915 unknownSystems.add(((PrimitiveType<?>) p.getValue()).asStringValue()); 1916 } else if (p.getName().equals("warning-withdrawn")) { 1917 String msg = ((PrimitiveType<?>) p.getValue()).asStringValue(); 1918 OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.BUSINESSRULE); 1919 iss.getDetails().setText(formatMessage(vs == null ? I18nConstants.MSG_WITHDRAWN : I18nConstants.MSG_WITHDRAWN_SRC, msg, vs, impliedType(msg))); 1920 issues.add(iss); 1921 } else if (p.getName().equals("warning-deprecated")) { 1922 String msg = ((PrimitiveType<?>) p.getValue()).asStringValue(); 1923 OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.BUSINESSRULE); 1924 iss.getDetails().setText(formatMessage(vs == null ? I18nConstants.MSG_DEPRECATED : I18nConstants.MSG_DEPRECATED_SRC, msg, vs, impliedType(msg))); 1925 issues.add(iss); 1926 } else if (p.getName().equals("warning-retired")) { 1927 String msg = ((PrimitiveType<?>) p.getValue()).asStringValue(); 1928 OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.BUSINESSRULE); 1929 iss.getDetails().setText(formatMessage(vs == null ? I18nConstants.MSG_RETIRED : I18nConstants.MSG_RETIRED_SRC, msg, vs, impliedType(msg))); 1930 issues.add(iss); 1931 } else if (p.getName().equals("warning-experimental")) { 1932 String msg = ((PrimitiveType<?>) p.getValue()).asStringValue(); 1933 OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.BUSINESSRULE); 1934 iss.getDetails().setText(formatMessage(vs == null ? I18nConstants.MSG_EXPERIMENTAL : I18nConstants.MSG_EXPERIMENTAL_SRC, msg, vs, impliedType(msg))); 1935 issues.add(iss); 1936 } else if (p.getName().equals("warning-draft")) { 1937 String msg = ((PrimitiveType<?>) p.getValue()).asStringValue(); 1938 OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.BUSINESSRULE); 1939 iss.getDetails().setText(formatMessage(vs == null ? I18nConstants.MSG_DRAFT : I18nConstants.MSG_DRAFT_SRC, msg, vs, impliedType(msg))); 1940 issues.add(iss); 1941 } else if (p.getName().equals("cause")) { 1942 try { 1943 IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue()); 1944 if (it == IssueType.UNKNOWN) { 1945 err = TerminologyServiceErrorClass.UNKNOWN; 1946 } else if (it == IssueType.NOTFOUND) { 1947 err = TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED; 1948 } else if (it == IssueType.NOTSUPPORTED) { 1949 err = TerminologyServiceErrorClass.VALUESET_UNSUPPORTED; 1950 } else { 1951 err = null; 1952 } 1953 } catch (FHIRException e) { 1954 } 1955 } 1956 } else if (p.hasResource()) { 1957 if (p.getName().equals("issues")) { 1958 OperationOutcome oo = (OperationOutcome) p.getResource(); 1959 for (OperationOutcomeIssueComponent iss : oo.getIssue()) { 1960 iss.addExtension(ToolingExtensions.EXT_ISSUE_SERVER, new UrlType(server)); 1961 issues.add(iss); 1962 } 1963 } else { 1964 // nothing? 1965 } 1966 } 1967 } 1968 ValidationResult res = null; 1969 if (!ok) { 1970 res = new ValidationResult(IssueSeverity.ERROR, message, err, null).setTxLink(txLog.getLastId()); 1971 if (code != null) { 1972 res.setDefinition(new ConceptDefinitionComponent().setDisplay(display).setCode(code)); 1973 res.setDisplay(display); 1974 } 1975 if (system != null) { 1976 res.setSystem(system); 1977 } 1978 if (version != null) { 1979 res.setVersion(version); 1980 } 1981 } else if (message != null && !message.equals("No Message returned")) { 1982 res = new ValidationResult(IssueSeverity.WARNING, message, system, version, new ConceptDefinitionComponent().setDisplay(display).setCode(code), display, null).setTxLink(txLog.getLastId()); 1983 } else if (display != null) { 1984 res = new ValidationResult(system, version, new ConceptDefinitionComponent().setDisplay(display).setCode(code), display).setTxLink(txLog.getLastId()); 1985 } else { 1986 res = new ValidationResult(system, version, new ConceptDefinitionComponent().setCode(code), null).setTxLink(txLog.getLastId()); 1987 } 1988 res.setIssues(issues); 1989 res.setStatus(inactive, status); 1990 res.setUnknownSystems(unknownSystems); 1991 res.setServer(server); 1992 return res; 1993 } 1994 1995 // -------------------------------------------------------------------------------------------------------------------------------------------------------- 1996 1997 private Object impliedType(String msg) { 1998 if (msg.contains("/CodeSystem")) { 1999 return "CodeSystem"; 2000 } 2001 if (msg.contains("/ValueSet")) { 2002 return "ValueSet"; 2003 } 2004 return "item"; 2005 } 2006 2007 public void initTxCache(String cachePath) throws FileNotFoundException, FHIRException, IOException { 2008 if (cachePath != null) { 2009 txCache = new TerminologyCache(lock, cachePath); 2010 initTxCache(txCache); 2011 } 2012 } 2013 2014 public void initTxCache(TerminologyCache cache) { 2015 txCache = cache; 2016 terminologyClientManager.setCache(txCache); 2017 } 2018 2019 public void clearTSCache(String url) throws Exception { 2020 txCache.removeCS(url); 2021 } 2022 2023 public boolean isCanRunWithoutTerminology() { 2024 return canRunWithoutTerminology; 2025 } 2026 2027 public void setCanRunWithoutTerminology(boolean canRunWithoutTerminology) { 2028 this.canRunWithoutTerminology = canRunWithoutTerminology; 2029 } 2030 2031 public void setLogger(@Nonnull org.hl7.fhir.r5.context.ILoggingService logger) { 2032 this.logger = logger; 2033 } 2034 2035 public Parameters getExpansionParameters() { 2036 return expParameters; 2037 } 2038 2039 public void setExpansionParameters(Parameters expParameters) { 2040 this.expParameters = expParameters; 2041 this.terminologyClientManager.setExpansionParameters(expParameters); 2042 } 2043 2044 @Override 2045 public boolean isNoTerminologyServer() { 2046 return noTerminologyServer || !terminologyClientManager.hasClient(); 2047 } 2048 2049 public void setNoTerminologyServer(boolean noTerminologyServer) { 2050 this.noTerminologyServer = noTerminologyServer; 2051 } 2052 2053 public String getName() { 2054 return name; 2055 } 2056 2057 public void setName(String name) { 2058 this.name = name; 2059 } 2060 2061 2062 public List<String> getResourceNames(FhirPublication fhirVersion) { 2063 return getResourceNames(); 2064 } 2065 2066 public Set<String> getResourceNamesAsSet(FhirPublication fhirVersion) { 2067 return getResourceNamesAsSet(); 2068 } 2069 2070 @Override 2071 public Set<String> getResourceNamesAsSet() { 2072 Set<String> res = new HashSet<String>(); 2073 res.addAll(getResourceNames()); 2074 return res; 2075 } 2076 2077 public boolean isAllowLoadingDuplicates() { 2078 return allowLoadingDuplicates; 2079 } 2080 2081 public void setAllowLoadingDuplicates(boolean allowLoadingDuplicates) { 2082 this.allowLoadingDuplicates = allowLoadingDuplicates; 2083 } 2084 2085 @Override 2086 public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException { 2087 return fetchResourceWithException(class_, uri, null); 2088 } 2089 2090 public <T extends Resource> T fetchResourceWithException(String cls, String uri) throws FHIRException { 2091 return fetchResourceWithExceptionByVersion(cls, uri, null, null); 2092 } 2093 2094 public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri, Resource sourceForReference) throws FHIRException { 2095 return fetchResourceWithExceptionByVersion(class_, uri, null, sourceForReference); 2096 } 2097 2098 @SuppressWarnings("unchecked") 2099 public <T extends Resource> T fetchResourceWithExceptionByVersion(Class<T> class_, String uri, String version, Resource sourceForReference) throws FHIRException { 2100 if (uri == null) { 2101 return null; 2102 } 2103 if (uri.startsWith("#")) { 2104 if (sourceForReference != null && sourceForReference instanceof DomainResource) { 2105 for (Resource r : ((DomainResource) sourceForReference).getContained()) { 2106 if (r.getClass() == class_ &&( "#"+r.getIdBase()).equals(uri)) { 2107 if (r instanceof CanonicalResource) { 2108 CanonicalResource cr = (CanonicalResource) r; 2109 if (!cr.hasUrl()) { 2110 cr.setUrl(Utilities.makeUuidUrn()); 2111 } 2112 } 2113 return (T) r; 2114 } 2115 } 2116 } 2117 return null; 2118 } 2119 2120 if (QA_CHECK_REFERENCE_SOURCE) { 2121 // it can be tricky to trace the source of a reference correctly. The code isn't water tight, 2122 // particularly around snapshot generation. Enable this code to check that the references are 2123 // correct (but it's slow) 2124 if (sourceForReference != null && uri.contains("ValueSet")) { 2125 if (!ResourceUtilities.hasURL(uri, sourceForReference)) { 2126 System.out.print("Claimed source doesn't have url in it: "+sourceForReference.fhirType()+"/"+sourceForReference.getIdPart()+" -> "+uri); 2127 System.out.println(); 2128 } 2129 } 2130 } 2131 2132 List<String> pvlist = new ArrayList<>(); 2133 if (sourceForReference != null && sourceForReference.getSourcePackage() != null) { 2134 populatePVList(pvlist, sourceForReference.getSourcePackage()); 2135 } 2136 2137 if (class_ == StructureDefinition.class) { 2138 uri = ProfileUtilities.sdNs(uri, null); 2139 } 2140 synchronized (lock) { 2141 2142 if (version == null) { 2143 if (uri.contains("|")) { 2144 version = uri.substring(uri.lastIndexOf("|")+1); 2145 uri = uri.substring(0, uri.lastIndexOf("|")); 2146 } 2147 } else { 2148 assert !uri.contains("|"); 2149 } 2150 if (uri.contains("#")) { 2151 uri = uri.substring(0, uri.indexOf("#")); 2152 } 2153 if (class_ == Resource.class || class_ == null) { 2154 if (structures.has(uri)) { 2155 return (T) structures.get(uri, version, pvlist); 2156 } 2157 if (guides.has(uri)) { 2158 return (T) guides.get(uri, version, pvlist); 2159 } 2160 if (capstmts.has(uri)) { 2161 return (T) capstmts.get(uri, version, pvlist); 2162 } 2163 if (measures.has(uri)) { 2164 return (T) measures.get(uri, version, pvlist); 2165 } 2166 if (libraries.has(uri)) { 2167 return (T) libraries.get(uri, version, pvlist); 2168 } 2169 if (valueSets.has(uri)) { 2170 return (T) valueSets.get(uri, version, pvlist); 2171 } 2172 if (codeSystems.has(uri)) { 2173 return (T) codeSystems.get(uri, version, pvlist); 2174 } 2175 if (systems.has(uri)) { 2176 return (T) systems.get(uri, version, pvlist); 2177 } 2178 if (operations.has(uri)) { 2179 return (T) operations.get(uri, version, pvlist); 2180 } 2181 if (searchParameters.has(uri)) { 2182 return (T) searchParameters.get(uri, version, pvlist); 2183 } 2184 if (plans.has(uri)) { 2185 return (T) plans.get(uri, version, pvlist); 2186 } 2187 if (maps.has(uri)) { 2188 return (T) maps.get(uri, version, pvlist); 2189 } 2190 if (transforms.has(uri)) { 2191 return (T) transforms.get(uri, version, pvlist); 2192 } 2193 if (actors.has(uri)) { 2194 return (T) transforms.get(uri, version, pvlist); 2195 } 2196 if (requirements.has(uri)) { 2197 return (T) transforms.get(uri, version, pvlist); 2198 } 2199 if (questionnaires.has(uri)) { 2200 return (T) questionnaires.get(uri, version, pvlist); 2201 } 2202 2203 for (Map<String, ResourceProxy> rt : allResourcesById.values()) { 2204 for (ResourceProxy r : rt.values()) { 2205 if (uri.equals(r.getUrl())) { 2206 if (version == null || version == r.getResource().getMeta().getVersionId()) { 2207 return (T) r.getResource(); 2208 } 2209 } 2210 } 2211 } 2212 if (uri.matches(Constants.URI_REGEX) && !uri.contains("ValueSet")) { 2213 return null; 2214 } 2215 2216 // it might be a special URL. 2217// if (Utilities.isAbsoluteUrl(uri) || uri.startsWith("ValueSet/")) { 2218// Resource res = null; // findTxValueSet(uri); 2219// if (res != null) { 2220// return (T) res; 2221// } 2222// } 2223 return null; 2224 } else if (class_ == ImplementationGuide.class) { 2225 return (T) guides.get(uri, version, pvlist); 2226 } else if (class_ == CapabilityStatement.class) { 2227 return (T) capstmts.get(uri, version, pvlist); 2228 } else if (class_ == Measure.class) { 2229 return (T) measures.get(uri, version, pvlist); 2230 } else if (class_ == Library.class) { 2231 return (T) libraries.get(uri, version, pvlist); 2232 } else if (class_ == StructureDefinition.class) { 2233 return (T) structures.get(uri, version, pvlist); 2234 } else if (class_ == StructureMap.class) { 2235 return (T) transforms.get(uri, version, pvlist); 2236 } else if (class_ == NamingSystem.class) { 2237 return (T) systems.get(uri, version, pvlist); 2238 } else if (class_ == ValueSet.class) { 2239 return (T) valueSets.get(uri, version, pvlist); 2240 } else if (class_ == CodeSystem.class) { 2241 return (T) codeSystems.get(uri, version, pvlist); 2242 } else if (class_ == ConceptMap.class) { 2243 return (T) maps.get(uri, version, pvlist); 2244 } else if (class_ == ActorDefinition.class) { 2245 return (T) actors.get(uri, version, pvlist); 2246 } else if (class_ == Requirements.class) { 2247 return (T) requirements.get(uri, version, pvlist); 2248 } else if (class_ == PlanDefinition.class) { 2249 return (T) plans.get(uri, version, pvlist); 2250 } else if (class_ == OperationDefinition.class) { 2251 OperationDefinition od = operations.get(uri, version); 2252 return (T) od; 2253 } else if (class_ == Questionnaire.class) { 2254 return (T) questionnaires.get(uri, version, pvlist); 2255 } else if (class_ == SearchParameter.class) { 2256 SearchParameter res = searchParameters.get(uri, version, pvlist); 2257 return (T) res; 2258 } 2259 if (class_ == CodeSystem.class && codeSystems.has(uri)) { 2260 return (T) codeSystems.get(uri, version, pvlist); 2261 } 2262 if (class_ == ValueSet.class && valueSets.has(uri)) { 2263 return (T) valueSets.get(uri, version, pvlist); 2264 } 2265 2266 if (class_ == Questionnaire.class) { 2267 return (T) questionnaires.get(uri, version, pvlist); 2268 } 2269 if (supportedCodeSystems.contains(uri)) { 2270 return null; 2271 } 2272 throw new FHIRException(formatMessage(I18nConstants.NOT_DONE_YET_CANT_FETCH_, uri)); 2273 } 2274 } 2275 2276 private void populatePVList(List<String> pvlist, PackageInformation sourcePackage) { 2277 pvlist.add(sourcePackage.getVID()); 2278 List<String> toadd = new ArrayList<>(); 2279 do { 2280 toadd.clear(); 2281 for (String s : pvlist) { 2282 PackageInformation pi = packages.get(s); 2283 if (pi != null) { 2284 for (String v : pi.getDependencies()) { 2285 if (!pvlist.contains(v) && !toadd.contains(v)) { 2286 toadd.add(v); 2287 } 2288 } 2289 } 2290 } 2291 pvlist.addAll(toadd); 2292 } while (toadd.size() > 0); 2293 } 2294 2295 public PackageInformation getPackageForUrl(String uri) { 2296 if (uri == null) { 2297 return null; 2298 } 2299 uri = ProfileUtilities.sdNs(uri, null); 2300 2301 synchronized (lock) { 2302 2303 String version = null; 2304 if (uri.contains("|")) { 2305 version = uri.substring(uri.lastIndexOf("|")+1); 2306 uri = uri.substring(0, uri.lastIndexOf("|")); 2307 } 2308 if (uri.contains("#")) { 2309 uri = uri.substring(0, uri.indexOf("#")); 2310 } 2311 if (structures.has(uri)) { 2312 return structures.getPackageInfo(uri, version); 2313 } 2314 if (guides.has(uri)) { 2315 return guides.getPackageInfo(uri, version); 2316 } 2317 if (capstmts.has(uri)) { 2318 return capstmts.getPackageInfo(uri, version); 2319 } 2320 if (measures.has(uri)) { 2321 return measures.getPackageInfo(uri, version); 2322 } 2323 if (libraries.has(uri)) { 2324 return libraries.getPackageInfo(uri, version); 2325 } 2326 if (valueSets.has(uri)) { 2327 return valueSets.getPackageInfo(uri, version); 2328 } 2329 if (codeSystems.has(uri)) { 2330 return codeSystems.getPackageInfo(uri, version); 2331 } 2332 if (operations.has(uri)) { 2333 return operations.getPackageInfo(uri, version); 2334 } 2335 if (searchParameters.has(uri)) { 2336 return searchParameters.getPackageInfo(uri, version); 2337 } 2338 if (plans.has(uri)) { 2339 return plans.getPackageInfo(uri, version); 2340 } 2341 if (maps.has(uri)) { 2342 return maps.getPackageInfo(uri, version); 2343 } 2344 if (transforms.has(uri)) { 2345 return transforms.getPackageInfo(uri, version); 2346 } 2347 if (actors.has(uri)) { 2348 return actors.getPackageInfo(uri, version); 2349 } 2350 if (requirements.has(uri)) { 2351 return requirements.getPackageInfo(uri, version); 2352 } 2353 if (questionnaires.has(uri)) { 2354 return questionnaires.getPackageInfo(uri, version); 2355 } 2356 return null; 2357 } 2358 } 2359 2360 @SuppressWarnings("unchecked") 2361 public <T extends Resource> T fetchResourceWithExceptionByVersion(String cls, String uri, String version, CanonicalResource source) throws FHIRException { 2362 if (uri == null) { 2363 return null; 2364 } 2365 2366 if ("StructureDefinition".equals(cls)) { 2367 uri = ProfileUtilities.sdNs(uri, null); 2368 } 2369 synchronized (lock) { 2370 2371 if (version == null) { 2372 if (uri.contains("|")) { 2373 version = uri.substring(uri.lastIndexOf("|")+1); 2374 uri = uri.substring(0, uri.lastIndexOf("|")); 2375 } 2376 } else { 2377 boolean b = !uri.contains("|"); 2378 assert b; 2379 } 2380 if (uri.contains("#")) { 2381 uri = uri.substring(0, uri.indexOf("#")); 2382 } 2383 if (cls == null || "Resource".equals(cls)) { 2384 if (structures.has(uri)) { 2385 return (T) structures.get(uri, version); 2386 } 2387 if (guides.has(uri)) { 2388 return (T) guides.get(uri, version); 2389 } 2390 if (capstmts.has(uri)) { 2391 return (T) capstmts.get(uri, version); 2392 } 2393 if (measures.has(uri)) { 2394 return (T) measures.get(uri, version); 2395 } 2396 if (libraries.has(uri)) { 2397 return (T) libraries.get(uri, version); 2398 } 2399 if (valueSets.has(uri)) { 2400 return (T) valueSets.get(uri, version); 2401 } 2402 if (codeSystems.has(uri)) { 2403 return (T) codeSystems.get(uri, version); 2404 } 2405 if (operations.has(uri)) { 2406 return (T) operations.get(uri, version); 2407 } 2408 if (searchParameters.has(uri)) { 2409 return (T) searchParameters.get(uri, version); 2410 } 2411 if (plans.has(uri)) { 2412 return (T) plans.get(uri, version); 2413 } 2414 if (maps.has(uri)) { 2415 return (T) maps.get(uri, version); 2416 } 2417 if (transforms.has(uri)) { 2418 return (T) transforms.get(uri, version); 2419 } 2420 if (actors.has(uri)) { 2421 return (T) actors.get(uri, version); 2422 } 2423 if (requirements.has(uri)) { 2424 return (T) requirements.get(uri, version); 2425 } 2426 if (questionnaires.has(uri)) { 2427 return (T) questionnaires.get(uri, version); 2428 } 2429 for (Map<String, ResourceProxy> rt : allResourcesById.values()) { 2430 for (ResourceProxy r : rt.values()) { 2431 if (uri.equals(r.getUrl())) { 2432 return (T) r.getResource(); 2433 } 2434 } 2435 } 2436 } else if ("ImplementationGuide".equals(cls)) { 2437 return (T) guides.get(uri, version); 2438 } else if ("CapabilityStatement".equals(cls)) { 2439 return (T) capstmts.get(uri, version); 2440 } else if ("Measure".equals(cls)) { 2441 return (T) measures.get(uri, version); 2442 } else if ("Library".equals(cls)) { 2443 return (T) libraries.get(uri, version); 2444 } else if ("StructureDefinition".equals(cls)) { 2445 return (T) structures.get(uri, version); 2446 } else if ("StructureMap".equals(cls)) { 2447 return (T) transforms.get(uri, version); 2448 } else if ("Requirements".equals(cls)) { 2449 return (T) requirements.get(uri, version); 2450 } else if ("ActorDefinition".equals(cls)) { 2451 return (T) actors.get(uri, version); 2452 } else if ("ValueSet".equals(cls)) { 2453 return (T) valueSets.get(uri, version); 2454 } else if ("CodeSystem".equals(cls)) { 2455 return (T) codeSystems.get(uri, version); 2456 } else if ("ConceptMap".equals(cls)) { 2457 return (T) maps.get(uri, version); 2458 } else if ("PlanDefinition".equals(cls)) { 2459 return (T) plans.get(uri, version); 2460 } else if ("OperationDefinition".equals(cls)) { 2461 OperationDefinition od = operations.get(uri, version); 2462 return (T) od; 2463 } else if ("Questionnaire.class".equals(cls)) { 2464 return (T) questionnaires.get(uri, version); 2465 } else if ("SearchParameter.class".equals(cls)) { 2466 SearchParameter res = searchParameters.get(uri, version); 2467 return (T) res; 2468 } 2469 if ("CodeSystem".equals(cls) && codeSystems.has(uri)) { 2470 return (T) codeSystems.get(uri, version); 2471 } 2472 if ("ValueSet".equals(cls) && valueSets.has(uri)) { 2473 return (T) valueSets.get(uri, version); 2474 } 2475 2476 if ("Questionnaire".equals(cls)) { 2477 return (T) questionnaires.get(uri, version); 2478 } 2479 if (cls == null) { 2480 if (uri.matches(Constants.URI_REGEX) && !uri.contains("ValueSet")) { 2481 return null; 2482 } 2483 2484 // it might be a special URL. 2485 if (Utilities.isAbsoluteUrl(uri) || uri.startsWith("ValueSet/")) { 2486 Resource res = null; // findTxValueSet(uri); 2487 if (res != null) { 2488 return (T) res; 2489 } 2490 } 2491 return null; 2492 } 2493 if (supportedCodeSystems.contains(uri)) { 2494 return null; 2495 } 2496 throw new FHIRException(formatMessage(I18nConstants.NOT_DONE_YET_CANT_FETCH_, uri)); 2497 } 2498 } 2499 2500 public <T extends Resource> List<T> fetchResourcesByType(Class<T> class_, FhirPublication fhirVersion) { 2501 return fetchResourcesByType(class_); 2502 } 2503 2504 @SuppressWarnings("unchecked") 2505 public <T extends Resource> List<T> fetchResourcesByType(Class<T> class_) { 2506 2507 List<T> res = new ArrayList<>(); 2508 2509 synchronized (lock) { 2510 2511 if (class_ == Resource.class || class_ == DomainResource.class || class_ == CanonicalResource.class || class_ == null) { 2512 res.addAll((List<T>) structures.getList()); 2513 res.addAll((List<T>) guides.getList()); 2514 res.addAll((List<T>) capstmts.getList()); 2515 res.addAll((List<T>) measures.getList()); 2516 res.addAll((List<T>) libraries.getList()); 2517 res.addAll((List<T>) valueSets.getList()); 2518 res.addAll((List<T>) codeSystems.getList()); 2519 res.addAll((List<T>) operations.getList()); 2520 res.addAll((List<T>) searchParameters.getList()); 2521 res.addAll((List<T>) plans.getList()); 2522 res.addAll((List<T>) maps.getList()); 2523 res.addAll((List<T>) transforms.getList()); 2524 res.addAll((List<T>) questionnaires.getList()); 2525 res.addAll((List<T>) systems.getList()); 2526 res.addAll((List<T>) actors.getList()); 2527 res.addAll((List<T>) requirements.getList()); 2528 } else if (class_ == ImplementationGuide.class) { 2529 res.addAll((List<T>) guides.getList()); 2530 } else if (class_ == CapabilityStatement.class) { 2531 res.addAll((List<T>) capstmts.getList()); 2532 } else if (class_ == Measure.class) { 2533 res.addAll((List<T>) measures.getList()); 2534 } else if (class_ == Library.class) { 2535 res.addAll((List<T>) libraries.getList()); 2536 } else if (class_ == StructureDefinition.class) { 2537 res.addAll((List<T>) structures.getList()); 2538 } else if (class_ == StructureMap.class) { 2539 res.addAll((List<T>) transforms.getList()); 2540 } else if (class_ == ValueSet.class) { 2541 res.addAll((List<T>) valueSets.getList()); 2542 } else if (class_ == CodeSystem.class) { 2543 res.addAll((List<T>) codeSystems.getList()); 2544 } else if (class_ == NamingSystem.class) { 2545 res.addAll((List<T>) systems.getList()); 2546 } else if (class_ == ActorDefinition.class) { 2547 res.addAll((List<T>) actors.getList()); 2548 } else if (class_ == Requirements.class) { 2549 res.addAll((List<T>) requirements.getList()); 2550 } else if (class_ == ConceptMap.class) { 2551 res.addAll((List<T>) maps.getList()); 2552 } else if (class_ == PlanDefinition.class) { 2553 res.addAll((List<T>) plans.getList()); 2554 } else if (class_ == OperationDefinition.class) { 2555 res.addAll((List<T>) operations.getList()); 2556 } else if (class_ == Questionnaire.class) { 2557 res.addAll((List<T>) questionnaires.getList()); 2558 } else if (class_ == SearchParameter.class) { 2559 res.addAll((List<T>) searchParameters.getList()); 2560 } 2561 } 2562 return res; 2563 } 2564 2565 private Set<String> notCanonical = new HashSet<String>(); 2566 2567 protected IWorkerContextManager.IPackageLoadingTracker packageTracker; 2568 private boolean forPublication; 2569 private boolean cachingAllowed = true; 2570 private static boolean nsFailHasFailed; 2571 2572 public Resource fetchResourceById(String type, String uri, FhirPublication fhirVersion) { 2573 return fetchResourceById(type, uri); 2574 } 2575 2576 @Override 2577 public Resource fetchResourceById(String type, String uri) { 2578 synchronized (lock) { 2579 String[] parts = uri.split("\\/"); 2580 if (!Utilities.noString(type) && parts.length == 1) { 2581 if (allResourcesById.containsKey(type)) { 2582 ResourceProxy res = allResourcesById.get(type).get(parts[0]); 2583 return res == null ? null : res.getResource(); 2584 } else { 2585 return null; 2586 } 2587 } 2588 if (parts.length >= 2) { 2589 if (!Utilities.noString(type)) { 2590 if (!type.equals(parts[parts.length-2])) { 2591 throw new Error(formatMessage(I18nConstants.RESOURCE_TYPE_MISMATCH_FOR___, type, uri)); 2592 } 2593 } 2594 return allResourcesById.get(parts[parts.length-2]).get(parts[parts.length-1]).getResource(); 2595 } else { 2596 throw new Error(formatMessage(I18nConstants.UNABLE_TO_PROCESS_REQUEST_FOR_RESOURCE_FOR___, type, uri)); 2597 } 2598 } 2599 } 2600 2601 public <T extends Resource> T fetchResource(Class<T> class_, String uri, Resource sourceForReference) { 2602 try { 2603 return fetchResourceWithException(class_, uri, sourceForReference); 2604 } catch (FHIRException e) { 2605 throw new Error(e); 2606 } 2607 } 2608 2609 public <T extends Resource> T fetchResource(Class<T> class_, String uri, FhirPublication fhirVersion) { 2610 return fetchResource(class_, uri); 2611 } 2612 2613 public <T extends Resource> T fetchResource(Class<T> class_, String uri) { 2614 try { 2615 return fetchResourceWithException(class_, uri, null); 2616 } catch (FHIRException e) { 2617 throw new Error(e); 2618 } 2619 } 2620 2621 public <T extends Resource> T fetchResource(Class<T> class_, String uri, String version, FhirPublication fhirVersion) { 2622 return fetchResource(class_, uri, version); 2623 } 2624 public <T extends Resource> T fetchResource(Class<T> class_, String uri, String version) { 2625 try { 2626 return fetchResourceWithExceptionByVersion(class_, uri, version, null); 2627 } catch (FHIRException e) { 2628 throw new Error(e); 2629 } 2630 } 2631 2632 @Override 2633 public <T extends Resource> boolean hasResource(Class<T> class_, String uri) { 2634 try { 2635 return fetchResourceWithException(class_, uri) != null; 2636 } catch (Exception e) { 2637 return false; 2638 } 2639 } 2640 2641 public <T extends Resource> boolean hasResource(String cls, String uri) { 2642 try { 2643 return fetchResourceWithException(cls, uri) != null; 2644 } catch (Exception e) { 2645 return false; 2646 } 2647 } 2648 2649 public <T extends Resource> boolean hasResourceVersion(Class<T> class_, String uri, String version) { 2650 try { 2651 return fetchResourceWithExceptionByVersion(class_, uri, version, null) != null; 2652 } catch (Exception e) { 2653 return false; 2654 } 2655 } 2656 2657 public <T extends Resource> boolean hasResourceVersion(String cls, String uri, String version) { 2658 try { 2659 return fetchResourceWithExceptionByVersion(cls, uri, version, null) != null; 2660 } catch (Exception e) { 2661 return false; 2662 } 2663 } 2664 2665 @Override 2666 public <T extends Resource> boolean hasResource(Class<T> class_, String uri, FhirPublication fhirVersion) { 2667 try { 2668 return fetchResourceWithException(class_, uri) != null; 2669 } catch (Exception e) { 2670 return false; 2671 } 2672 } 2673 2674 public <T extends Resource> boolean hasResource(String cls, String uri, FhirPublication fhirVersion) { 2675 try { 2676 return fetchResourceWithException(cls, uri) != null; 2677 } catch (Exception e) { 2678 return false; 2679 } 2680 } 2681 2682 public <T extends Resource> boolean hasResourceVersion(Class<T> class_, String uri, String version, FhirPublication fhirVersion) { 2683 try { 2684 return fetchResourceWithExceptionByVersion(class_, uri, version, null) != null; 2685 } catch (Exception e) { 2686 return false; 2687 } 2688 } 2689 2690 public <T extends Resource> boolean hasResourceVersion(String cls, String uri, String version, FhirPublication fhirVersion) { 2691 try { 2692 return fetchResourceWithExceptionByVersion(cls, uri, version, null) != null; 2693 } catch (Exception e) { 2694 return false; 2695 } 2696 } 2697 2698 public <T extends Resource> boolean hasResource(Class<T> class_, String uri, Resource sourceOfReference) { 2699 try { 2700 return fetchResourceWithExceptionByVersion(class_, uri, version, null) != null; 2701 } catch (Exception e) { 2702 return false; 2703 } 2704 } 2705 2706 public void reportStatus(JsonObject json) { 2707 synchronized (lock) { 2708 json.addProperty("codeystem-count", codeSystems.size()); 2709 json.addProperty("valueset-count", valueSets.size()); 2710 json.addProperty("conceptmap-count", maps.size()); 2711 json.addProperty("transforms-count", transforms.size()); 2712 json.addProperty("structures-count", structures.size()); 2713 json.addProperty("guides-count", guides.size()); 2714 json.addProperty("statements-count", capstmts.size()); 2715 json.addProperty("measures-count", measures.size()); 2716 json.addProperty("libraries-count", libraries.size()); 2717 } 2718 } 2719 2720 2721 public void dropResource(Resource r) throws FHIRException { 2722 dropResource(r.fhirType(), r.getId()); 2723 } 2724 2725 public void dropResource(String fhirType, String id) { 2726 synchronized (lock) { 2727 2728 Map<String, ResourceProxy> map = allResourcesById.get(fhirType); 2729 if (map == null) { 2730 map = new HashMap<String, ResourceProxy>(); 2731 allResourcesById.put(fhirType, map); 2732 } 2733 if (map.containsKey(id)) { 2734 map.remove(id); // this is a challenge because we might have more than one resource with this id (different versions) 2735 } 2736 2737 if (fhirType.equals("StructureDefinition")) { 2738 structures.drop(id); 2739 typeManager.reload(); 2740 } else if (fhirType.equals("ImplementationGuide")) { 2741 guides.drop(id); 2742 } else if (fhirType.equals("CapabilityStatement")) { 2743 capstmts.drop(id); 2744 } else if (fhirType.equals("Measure")) { 2745 measures.drop(id); 2746 } else if (fhirType.equals("Library")) { 2747 libraries.drop(id); 2748 } else if (fhirType.equals("ValueSet")) { 2749 valueSets.drop(id); 2750 } else if (fhirType.equals("CodeSystem")) { 2751 codeSystems.drop(id); 2752 } else if (fhirType.equals("OperationDefinition")) { 2753 operations.drop(id); 2754 } else if (fhirType.equals("Questionnaire")) { 2755 questionnaires.drop(id); 2756 } else if (fhirType.equals("ConceptMap")) { 2757 maps.drop(id); 2758 } else if (fhirType.equals("StructureMap")) { 2759 transforms.drop(id); 2760 } else if (fhirType.equals("NamingSystem")) { 2761 systems.drop(id); 2762 systemUrlMap = null; 2763 } else if (fhirType.equals("ActorDefinition")) { 2764 actors.drop(id); 2765 } else if (fhirType.equals("Requirements")) { 2766 requirements.drop(id); 2767 } 2768 } 2769 } 2770 2771 private <T extends CanonicalResource> void dropMetadataResource(Map<String, T> map, String id) { 2772 T res = map.get(id); 2773 if (res != null) { 2774 map.remove(id); 2775 if (map.containsKey(res.getUrl())) { 2776 map.remove(res.getUrl()); 2777 } 2778 if (res.getVersion() != null) { 2779 if (map.containsKey(res.getUrl()+"|"+res.getVersion())) { 2780 map.remove(res.getUrl()+"|"+res.getVersion()); 2781 } 2782 } 2783 } 2784 } 2785 2786 2787 public String listSupportedSystems() { 2788 synchronized (lock) { 2789 String sl = null; 2790 for (String s : supportedCodeSystems) { 2791 sl = sl == null ? s : sl + "\r\n" + s; 2792 } 2793 return sl; 2794 } 2795 } 2796 2797 2798 public int totalCount() { 2799 synchronized (lock) { 2800 return valueSets.size() + maps.size() + structures.size() + transforms.size(); 2801 } 2802 } 2803 2804 public List<ConceptMap> listMaps() { 2805 List<ConceptMap> m = new ArrayList<ConceptMap>(); 2806 synchronized (lock) { 2807 maps.listAll(m); 2808 } 2809 return m; 2810 } 2811 2812 public List<StructureDefinition> listStructures() { 2813 List<StructureDefinition> m = new ArrayList<StructureDefinition>(); 2814 synchronized (lock) { 2815 structures.listAll(m); 2816 } 2817 return m; 2818 } 2819 2820 public StructureDefinition getStructure(String code) { 2821 synchronized (lock) { 2822 return structures.get(code); 2823 } 2824 } 2825 2826 private String getUri(NamingSystem ns) { 2827 for (NamingSystemUniqueIdComponent id : ns.getUniqueId()) { 2828 if (id.getType() == NamingSystemIdentifierType.URI) { 2829 return id.getValue(); 2830 } 2831 } 2832 return null; 2833 } 2834 2835 private boolean hasOid(NamingSystem ns, String oid) { 2836 for (NamingSystemUniqueIdComponent id : ns.getUniqueId()) { 2837 if (id.getType() == NamingSystemIdentifierType.OID && id.getValue().equals(oid)) { 2838 return true; 2839 } 2840 } 2841 return false; 2842 } 2843 2844 public void cacheVS(JsonObject json, Map<String, ValidationResult> t) { 2845 synchronized (lock) { 2846 validationCache.put(json.get("url").getAsString(), t); 2847 } 2848 } 2849 2850 public SearchParameter getSearchParameter(String code) { 2851 synchronized (lock) { 2852 return searchParameters.get(code); 2853 } 2854 } 2855 2856 @Override 2857 public org.hl7.fhir.r5.context.ILoggingService getLogger() { 2858 return logger; 2859 } 2860 2861 2862 public StructureDefinition fetchTypeDefinition(String typeName, FhirPublication fhirVersion) { 2863 return fetchTypeDefinition(typeName); 2864 } 2865 2866 @Override 2867 public StructureDefinition fetchTypeDefinition(String typeName) { 2868 if (Utilities.isAbsoluteUrl(typeName)) { 2869 StructureDefinition res = fetchResource(StructureDefinition.class, typeName); 2870 if (res != null) { 2871 return res; 2872 } 2873 } 2874 StructureDefinition p = typeManager.fetchTypeDefinition(typeName); 2875 if (p != null && !p.isGeneratedSnapshot()) { 2876 if (p.isGeneratingSnapshot()) { 2877 throw new FHIRException("Attempt to fetch the profile "+p.getVersionedUrl()+" while generating the snapshot for it"); 2878 } 2879 try { 2880 if (logger.isDebugLogging()) { 2881 System.out.println("Generating snapshot for "+p.getVersionedUrl()); 2882 } 2883 p.setGeneratingSnapshot(true); 2884 try { 2885 new ContextUtilities(this).generateSnapshot(p); 2886 } finally { 2887 p.setGeneratingSnapshot(false); 2888 } 2889 } catch (Exception e) { 2890 // not sure what to do in this case? 2891 System.out.println("Unable to generate snapshot @5 for "+p.getVersionedUrl()+": "+e.getMessage()); 2892 if (logger.isDebugLogging()) { 2893 e.printStackTrace(); 2894 } 2895 } 2896 } 2897 return p; 2898 } 2899 2900 @Override 2901 public List<StructureDefinition> fetchTypeDefinitions(String typeName) { 2902 return typeManager.getDefinitions(typeName); 2903 } 2904 2905 @Override 2906 public List<StructureDefinition> fetchTypeDefinitions(String typeName, FhirPublication fhirVersion) { 2907 return typeManager.getDefinitions(typeName); 2908 } 2909 2910 2911 public boolean isPrimitiveType(String type) { 2912 return typeManager.isPrimitive(type); 2913 } 2914 2915 public boolean isDataType(String type) { 2916 return typeManager.isDataType(type); 2917 } 2918 2919 public boolean isTlogging() { 2920 return tlogging; 2921 } 2922 2923 public void setTlogging(boolean tlogging) { 2924 this.tlogging = tlogging; 2925 } 2926 2927 public UcumService getUcumService() { 2928 return ucumService; 2929 } 2930 2931 public void setUcumService(UcumService ucumService) { 2932 this.ucumService = ucumService; 2933 } 2934 2935 public String getLinkForUrl(String corePath, String url) { 2936 if (url == null) { 2937 return null; 2938 } 2939 2940 if (codeSystems.has(url)) { 2941 return codeSystems.get(url).getWebPath(); 2942 } 2943 2944 if (valueSets.has(url)) { 2945 return valueSets.get(url).getWebPath(); 2946 } 2947 2948 if (maps.has(url)) { 2949 return maps.get(url).getWebPath(); 2950 } 2951 2952 if (transforms.has(url)) { 2953 return transforms.get(url).getWebPath(); 2954 } 2955 2956 if (actors.has(url)) { 2957 return actors.get(url).getWebPath(); 2958 } 2959 2960 if (requirements.has(url)) { 2961 return requirements.get(url).getWebPath(); 2962 } 2963 2964 if (structures.has(url)) { 2965 return structures.get(url).getWebPath(); 2966 } 2967 2968 if (guides.has(url)) { 2969 return guides.get(url).getWebPath(); 2970 } 2971 2972 if (capstmts.has(url)) { 2973 return capstmts.get(url).getWebPath(); 2974 } 2975 2976 if (measures.has(url)) { 2977 return measures.get(url).getWebPath(); 2978 } 2979 2980 if (libraries.has(url)) { 2981 return libraries.get(url).getWebPath(); 2982 } 2983 2984 if (searchParameters.has(url)) { 2985 return searchParameters.get(url).getWebPath(); 2986 } 2987 2988 if (questionnaires.has(url)) { 2989 return questionnaires.get(url).getWebPath(); 2990 } 2991 2992 if (operations.has(url)) { 2993 return operations.get(url).getWebPath(); 2994 } 2995 2996 if (plans.has(url)) { 2997 return plans.get(url).getWebPath(); 2998 } 2999 3000 if (url.equals("http://loinc.org")) { 3001 return corePath+"loinc.html"; 3002 } 3003 if (url.equals("http://unitsofmeasure.org")) { 3004 return corePath+"ucum.html"; 3005 } 3006 if (url.equals("http://snomed.info/sct")) { 3007 return corePath+"snomed.html"; 3008 } 3009 return null; 3010 } 3011 3012 public List<ImplementationGuide> allImplementationGuides() { 3013 List<ImplementationGuide> res = new ArrayList<>(); 3014 guides.listAll(res); 3015 return res; 3016 } 3017 3018 @Override 3019 public Set<String> getBinaryKeysAsSet() { return binaries.keySet(); } 3020 3021 @Override 3022 public boolean hasBinaryKey(String binaryKey) { 3023 return binaries.containsKey(binaryKey); 3024 } 3025 3026 @Override 3027 public byte[] getBinaryForKey(String binaryKey) { 3028 return binaries.get(binaryKey); 3029 } 3030 3031 public void finishLoading(boolean genSnapshots) { 3032 if (!hasResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Base")) { 3033 cacheResource(ProfileUtilities.makeBaseDefinition(version)); 3034 } 3035 if(genSnapshots) { 3036 for (StructureDefinition sd : listStructures()) { 3037 try { 3038 if (sd.getSnapshot().isEmpty()) { 3039 new ContextUtilities(this).generateSnapshot(sd); 3040 // new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(Utilities.path("[tmp]", "snapshot", tail(sd.getUrl())+".xml")), sd); 3041 } 3042 } catch (Exception e) { 3043 System.out.println("Unable to generate snapshot @1 for "+tail(sd.getUrl()) +" from "+tail(sd.getBaseDefinition())+" because "+e.getMessage()); 3044 if (logger.isDebugLogging()) { 3045 e.printStackTrace(); 3046 } 3047 } 3048 } 3049 } 3050 3051 codeSystems.setVersion(version); 3052 valueSets.setVersion(version); 3053 maps.setVersion(version); 3054 transforms.setVersion(version); 3055 structures.setVersion(version); 3056 typeManager.reload(); 3057 measures.setVersion(version); 3058 libraries.setVersion(version); 3059 guides.setVersion(version); 3060 capstmts.setVersion(version); 3061 searchParameters.setVersion(version); 3062 questionnaires.setVersion(version); 3063 operations.setVersion(version); 3064 plans.setVersion(version); 3065 systems.setVersion(version); 3066 actors.setVersion(version); 3067 requirements.setVersion(version); 3068 } 3069 3070 protected String tail(String url) { 3071 if (Utilities.noString(url)) { 3072 return "noname"; 3073 } 3074 if (url.contains("/")) { 3075 return url.substring(url.lastIndexOf("/")+1); 3076 } 3077 return url; 3078 } 3079 3080 public int getClientRetryCount() { 3081 return terminologyClientManager.getRetryCount(); 3082 } 3083 3084 public IWorkerContext setClientRetryCount(int value) { 3085 terminologyClientManager.setRetryCount(value); 3086 return this; 3087 } 3088 3089 public TerminologyClientManager getTxClientManager() { 3090 return terminologyClientManager; 3091 } 3092 3093 public String getCacheId() { 3094 return terminologyClientManager.getCacheId(); 3095 } 3096 3097 public TimeTracker clock() { 3098 return clock; 3099 } 3100 3101 public int countAllCaches() { 3102 return codeSystems.size() + valueSets.size() + maps.size() + transforms.size() + structures.size() + measures.size() + libraries.size() + 3103 guides.size() + capstmts.size() + searchParameters.size() + questionnaires.size() + operations.size() + plans.size() + 3104 systems.size()+ actors.size()+ requirements.size(); 3105 } 3106 3107 public Set<String> getCodeSystemsUsed() { 3108 return codeSystemsUsed ; 3109 } 3110 3111 public IWorkerContextManager.ICanonicalResourceLocator getLocator() { 3112 return locator; 3113 } 3114 3115 public void setLocator(IWorkerContextManager.ICanonicalResourceLocator locator) { 3116 this.locator = locator; 3117 } 3118 3119 public String getUserAgent() { 3120 return userAgent; 3121 } 3122 3123 protected void setUserAgent(String userAgent) { 3124 this.userAgent = userAgent; 3125 terminologyClientManager.setUserAgent(userAgent); 3126 } 3127 3128 3129 public IWorkerContextManager.IPackageLoadingTracker getPackageTracker() { 3130 return packageTracker; 3131 } 3132 3133 public IWorkerContext setPackageTracker(IWorkerContextManager.IPackageLoadingTracker packageTracker) { 3134 this.packageTracker = packageTracker; 3135 return this; 3136 } 3137 3138 3139 @Override 3140 public PEBuilder getProfiledElementBuilder(PEElementPropertiesPolicy elementProps, boolean fixedProps) { 3141 // TODO Auto-generated method stub 3142 return new PEBuilder(this, elementProps, fixedProps); 3143 } 3144 3145 public boolean isForPublication() { 3146 return forPublication; 3147 } 3148 3149 public void setForPublication(boolean value) { 3150 forPublication = value; 3151 } 3152 3153 public boolean isCachingAllowed() { 3154 return cachingAllowed; 3155 } 3156 3157 public void setCachingAllowed(boolean cachingAllowed) { 3158 this.cachingAllowed = cachingAllowed; 3159 } 3160 3161 @Override 3162 public OIDSummary urlsForOid(String oid, String resourceType) { 3163 OIDSummary set = urlsForOid(oid, resourceType, true); 3164 if (set.getDefinitions().size() > 1) { 3165 set = urlsForOid(oid, resourceType, false); 3166 } 3167 return set; 3168 } 3169 3170 public OIDSummary urlsForOid(String oid, String resourceType, boolean retired) { 3171 OIDSummary summary = new OIDSummary(); 3172 if (oid != null) { 3173 if (oidCacheManual.containsKey(oid)) { 3174 summary.addOIDs(oidCacheManual.get(oid)); 3175 } 3176 for (OIDSource os : oidSources) { 3177 if (os.db == null) { 3178 os.db = connectToOidSource(os.folder); 3179 } 3180 if (os.db != null) { 3181 try { 3182 PreparedStatement psql = resourceType == null ? 3183 os.db.prepareStatement("Select TYPE, URL, VERSION, Status from OIDMap where OID = ?") : 3184 os.db.prepareStatement("Select TYPE, URL, VERSION, Status from OIDMap where TYPE = '"+resourceType+"' and OID = ?"); 3185 psql.setString(1, oid); 3186 ResultSet rs = psql.executeQuery(); 3187 while (rs.next()) { 3188 if (retired || !"retired".equals(rs.getString(4))) { 3189 String rt = rs.getString(1); 3190 String url = rs.getString(2); 3191 String version = rs.getString(3); 3192 String status = rs.getString(4); 3193 summary.addOID(new OIDDefinition(rt, oid, url, version, os.pid, status)); 3194 } 3195 } 3196 } catch (Exception e) { 3197 // nothing, there would alreagy have been an error 3198 // e.printStackTrace(); 3199 } 3200 } 3201 } 3202 3203 switch (oid) { 3204 case "2.16.840.1.113883.6.1" : 3205 summary.addOID(new OIDDefinition("CodeSystem", "2.16.840.1.113883.6.1", "http://loinc.org", null, null, null)); 3206 break; 3207 case "2.16.840.1.113883.6.8" : 3208 summary.addOID(new OIDDefinition("CodeSystem", "2.16.840.1.113883.6.8", "http://unitsofmeasure.org", null, null, null)); 3209 break; 3210 case "2.16.840.1.113883.6.96" : 3211 summary.addOID(new OIDDefinition("CodeSystem", "2.16.840.1.113883.6.96", "http://snomed.info/sct", null, null, null)); 3212 break; 3213 default: 3214 } 3215 } 3216 summary.sort(); 3217 return summary; 3218 } 3219 3220 private Connection connectToOidSource(String folder) { 3221 try { 3222 File ff = ManagedFileAccess.file(folder); 3223 File of = ManagedFileAccess.file(Utilities.path(ff.getAbsolutePath(), ".oid-map-2.db")); 3224 if (!of.exists()) { 3225 OidIndexBuilder oidBuilder = new OidIndexBuilder(ff, of); 3226 oidBuilder.build(); 3227 } 3228 return DriverManager.getConnection("jdbc:sqlite:"+of.getAbsolutePath()); 3229 } catch (Exception e) { 3230 return null; 3231 } 3232 } 3233 3234 3235 public void unload() { 3236 3237 codeSystems.unload(); 3238 valueSets.unload(); 3239 maps.unload(); 3240 transforms.unload(); 3241 structures.unload(); 3242 typeManager.unload(); 3243 measures.unload(); 3244 libraries.unload(); 3245 guides.unload(); 3246 capstmts.unload(); 3247 searchParameters.unload(); 3248 questionnaires.unload(); 3249 operations.unload(); 3250 plans.unload(); 3251 actors.unload(); 3252 requirements.unload(); 3253 systems.unload(); 3254 3255 binaries.clear(); 3256 validationCache.clear(); 3257 txCache.unload(); 3258} 3259 3260 private <T extends Resource> T doFindTxResource(Class<T> class_, String canonical) { 3261 // well, we haven't found it locally. We're going look it up 3262 if (class_ == ValueSet.class) { 3263 SourcedValueSet svs = null; 3264 if (txCache.hasValueSet(canonical)) { 3265 svs = txCache.getValueSet(canonical); 3266 } else { 3267 svs = terminologyClientManager.findValueSetOnServer(canonical); 3268 txCache.cacheValueSet(canonical, svs); 3269 } 3270 if (svs != null) { 3271 String web = ToolingExtensions.readStringExtension(svs.getVs(), ToolingExtensions.EXT_WEB_SOURCE); 3272 if (web == null) { 3273 web = Utilities.pathURL(svs.getServer(), "ValueSet", svs.getVs().getIdBase()); 3274 } 3275 svs.getVs().setWebPath(web); 3276 svs.getVs().setUserData("External.Link", svs.getServer()); // so we can render it differently 3277 } 3278 if (svs == null) { 3279 return null; 3280 } else { 3281 cacheResource(svs.getVs()); 3282 return (T) svs.getVs(); 3283 } 3284 } else if (class_ == CodeSystem.class) { 3285 SourcedCodeSystem scs = null; 3286 if (txCache.hasCodeSystem(canonical)) { 3287 scs = txCache.getCodeSystem(canonical); 3288 } else { 3289 scs = terminologyClientManager.findCodeSystemOnServer(canonical); 3290 txCache.cacheCodeSystem(canonical, scs); 3291 } 3292 if (scs != null) { 3293 String web = ToolingExtensions.readStringExtension(scs.getCs(), ToolingExtensions.EXT_WEB_SOURCE); 3294 if (web == null) { 3295 web = Utilities.pathURL(scs.getServer(), "ValueSet", scs.getCs().getIdBase()); 3296 } 3297 scs.getCs().setWebPath(web); 3298 scs.getCs().setUserData("External.Link", scs.getServer()); // so we can render it differently 3299 } 3300 if (scs == null) { 3301 return null; 3302 } else { 3303 cacheResource(scs.getCs()); 3304 return (T) scs.getCs(); 3305 } 3306 } else { 3307 throw new Error("Not supported"); 3308 } 3309 } 3310 3311 public <T extends Resource> T findTxResource(Class<T> class_, String canonical, Resource sourceOfReference) { 3312 if (canonical == null) { 3313 return null; 3314 } 3315 T result = fetchResource(class_, canonical, sourceOfReference); 3316 if (result == null) { 3317 result = doFindTxResource(class_, canonical); 3318 } 3319 return result; 3320 } 3321 3322 public <T extends Resource> T findTxResource(Class<T> class_, String canonical) { 3323 if (canonical == null) { 3324 return null; 3325 } 3326 T result = fetchResource(class_, canonical); 3327 if (result == null) { 3328 result = doFindTxResource(class_, canonical); 3329 } 3330 return result; 3331 } 3332 3333 public <T extends Resource> T findTxResource(Class<T> class_, String canonical, String version) { 3334 if (canonical == null) { 3335 return null; 3336 } 3337 T result = fetchResource(class_, canonical, version); 3338 if (result == null) { 3339 result = doFindTxResource(class_, canonical+"|"+version); 3340 } 3341 return result; 3342 } 3343 3344 @Override 3345 public <T extends Resource> List<T> fetchResourcesByUrl(Class<T> class_, String uri) { 3346 List<T> res = new ArrayList<>(); 3347 if (uri != null && !uri.startsWith("#")) { 3348 if (class_ == StructureDefinition.class) { 3349 uri = ProfileUtilities.sdNs(uri, null); 3350 } 3351 assert !uri.contains("|"); 3352 if (uri.contains("#")) { 3353 uri = uri.substring(0, uri.indexOf("#")); 3354 } 3355 synchronized (lock) { 3356 if (class_ == Resource.class || class_ == null) { 3357 for (Map<String, ResourceProxy> rt : allResourcesById.values()) { 3358 for (ResourceProxy r : rt.values()) { 3359 if (uri.equals(r.getUrl())) { 3360 res.add((T) r.getResource()); 3361 } 3362 } 3363 } 3364 } 3365 if (class_ == ImplementationGuide.class || class_ == Resource.class || class_ == null) { 3366 for (ImplementationGuide cr : guides.getForUrl(uri)) { 3367 res.add((T) cr); 3368 } 3369 } else if (class_ == CapabilityStatement.class || class_ == Resource.class || class_ == null) { 3370 for (CapabilityStatement cr : capstmts.getForUrl(uri)) { 3371 res.add((T) cr); 3372 } 3373 } else if (class_ == Measure.class || class_ == Resource.class || class_ == null) { 3374 for (Measure cr : measures.getForUrl(uri)) { 3375 res.add((T) cr); 3376 } 3377 } else if (class_ == Library.class || class_ == Resource.class || class_ == null) { 3378 for (Library cr : libraries.getForUrl(uri)) { 3379 res.add((T) cr); 3380 } 3381 } else if (class_ == StructureDefinition.class || class_ == Resource.class || class_ == null) { 3382 for (StructureDefinition cr : structures.getForUrl(uri)) { 3383 res.add((T) cr); 3384 } 3385 } else if (class_ == StructureMap.class || class_ == Resource.class || class_ == null) { 3386 for (StructureMap cr : transforms.getForUrl(uri)) { 3387 res.add((T) cr); 3388 } 3389 } else if (class_ == NamingSystem.class || class_ == Resource.class || class_ == null) { 3390 for (NamingSystem cr : systems.getForUrl(uri)) { 3391 res.add((T) cr); 3392 } 3393 } else if (class_ == ValueSet.class || class_ == Resource.class || class_ == null) { 3394 for (ValueSet cr : valueSets.getForUrl(uri)) { 3395 res.add((T) cr); 3396 } 3397 } else if (class_ == CodeSystem.class || class_ == Resource.class || class_ == null) { 3398 for (CodeSystem cr : codeSystems.getForUrl(uri)) { 3399 res.add((T) cr); 3400 } 3401 } else if (class_ == ConceptMap.class || class_ == Resource.class || class_ == null) { 3402 for (ConceptMap cr : maps.getForUrl(uri)) { 3403 res.add((T) cr); 3404 } 3405 } else if (class_ == ActorDefinition.class || class_ == Resource.class || class_ == null) { 3406 for (ActorDefinition cr : actors.getForUrl(uri)) { 3407 res.add((T) cr); 3408 } 3409 } else if (class_ == Requirements.class || class_ == Resource.class || class_ == null) { 3410 for (Requirements cr : requirements.getForUrl(uri)) { 3411 res.add((T) cr); 3412 } 3413 } else if (class_ == PlanDefinition.class || class_ == Resource.class || class_ == null) { 3414 for (PlanDefinition cr : plans.getForUrl(uri)) { 3415 res.add((T) cr); 3416 } 3417 } else if (class_ == OperationDefinition.class || class_ == Resource.class || class_ == null) { 3418 for (OperationDefinition cr : operations.getForUrl(uri)) { 3419 res.add((T) cr); 3420 } 3421 } else if (class_ == Questionnaire.class || class_ == Resource.class || class_ == null) { 3422 for (Questionnaire cr : questionnaires.getForUrl(uri)) { 3423 res.add((T) cr); 3424 } 3425 } else if (class_ == SearchParameter.class || class_ == Resource.class || class_ == null) { 3426 for (SearchParameter cr : searchParameters.getForUrl(uri)) { 3427 res.add((T) cr); 3428 } 3429 } 3430 } 3431 } 3432 return res; 3433 } 3434 3435}