
001package org.hl7.fhir.r5.context; 002 003/* 004 Copyright (c) 2011+, HL7, Inc. 005 All rights reserved. 006 007 Redistribution and use in source and binary forms, with or without modification, 008 are permitted provided that the following conditions are met: 009 010 * Redistributions of source code must retain the above copyright notice, this 011 list of conditions and the following disclaimer. 012 * Redistributions in binary form must reproduce the above copyright notice, 013 this list of conditions and the following disclaimer in the documentation 014 and/or other materials provided with the distribution. 015 * Neither the name of HL7 nor the names of its contributors may be used to 016 endorse or promote products derived from this software without specific 017 prior written permission. 018 019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 POSSIBILITY OF SUCH DAMAGE. 029 030 */ 031 032import java.io.ByteArrayInputStream; 033import java.io.File; 034import java.io.FileInputStream; 035import java.io.FileNotFoundException; 036import java.io.IOException; 037import java.io.InputStream; 038import java.util.ArrayList; 039import java.util.Collections; 040import java.util.HashSet; 041import java.util.List; 042import java.util.Locale; 043import java.util.Map; 044import java.util.Set; 045import java.util.zip.ZipEntry; 046import java.util.zip.ZipInputStream; 047 048import lombok.AccessLevel; 049import lombok.AllArgsConstructor; 050import lombok.With; 051import org.apache.commons.io.IOUtils; 052import org.hl7.fhir.exceptions.DefinitionException; 053import org.hl7.fhir.exceptions.FHIRException; 054import org.hl7.fhir.exceptions.FHIRFormatError; 055import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy; 056import org.hl7.fhir.r5.context.IWorkerContext.ILoggingService.LogCategory; 057import org.hl7.fhir.r5.formats.IParser; 058import org.hl7.fhir.r5.formats.JsonParser; 059import org.hl7.fhir.r5.formats.XmlParser; 060import org.hl7.fhir.r5.model.*; 061import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; 062import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; 063import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; 064import org.hl7.fhir.r5.model.StructureMap.StructureMapModelMode; 065import org.hl7.fhir.r5.model.StructureMap.StructureMapStructureComponent; 066import org.hl7.fhir.r5.profilemodel.PEDefinition; 067import org.hl7.fhir.r5.profilemodel.PEBuilder; 068import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; 069import org.hl7.fhir.r5.terminologies.JurisdictionUtilities; 070import org.hl7.fhir.r5.terminologies.client.ITerminologyClient; 071import org.hl7.fhir.r5.utils.validation.IResourceValidator; 072import org.hl7.fhir.r5.utils.R5Hacker; 073import org.hl7.fhir.r5.utils.XVerExtensionManager; 074import org.hl7.fhir.utilities.ByteProvider; 075import org.hl7.fhir.utilities.CSFileInputStream; 076import org.hl7.fhir.utilities.MagicResources; 077import org.hl7.fhir.utilities.TextFile; 078import org.hl7.fhir.utilities.TimeTracker; 079import org.hl7.fhir.utilities.Utilities; 080import org.hl7.fhir.utilities.VersionUtilities; 081import org.hl7.fhir.utilities.i18n.I18nConstants; 082import org.hl7.fhir.utilities.npm.BasePackageCacheManager; 083import org.hl7.fhir.utilities.npm.NpmPackage; 084import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation; 085 086import ca.uhn.fhir.parser.DataFormatException; 087 088/* 089 * This is a stand alone implementation of worker context for use inside a tool. 090 * It loads from the validation package (validation-min.xml.zip), and has a 091 * very light client to connect to an open unauthenticated terminology service 092 */ 093 094public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerContext { 095 096 public static class PackageResourceLoader extends CanonicalResourceProxy { 097 098 private final String filename; 099 private final IContextResourceLoader loader; 100 101 public PackageResourceLoader(PackageResourceInformation pri, IContextResourceLoader loader) { 102 super(pri.getResourceType(), pri.getId(), loader == null ? pri.getUrl() :loader.patchUrl(pri.getUrl(), pri.getResourceType()), pri.getVersion(), pri.getSupplements()); 103 this.filename = pri.getFilename(); 104 this.loader = loader; 105 } 106 107 @Override 108 public CanonicalResource loadResource() { 109 try { 110 FileInputStream f = new FileInputStream(filename); 111 try { 112 if (loader != null) { 113 return R5Hacker.fixR5BrokenResource((CanonicalResource) loader.loadResource(f, true)); 114 } else { 115 return R5Hacker.fixR5BrokenResource((CanonicalResource) new JsonParser().parse(f)); 116 } 117 } finally { 118 f.close(); 119 } 120 } catch (Exception e) { 121 throw new FHIRException("Error loading "+filename+": "+e.getMessage(), e); 122 } 123 } 124 } 125 126 public interface ILoadFilter { 127 boolean isOkToLoad(Resource resource); 128 boolean isOkToLoad(String resourceType); 129 } 130 131 public interface IValidatorFactory { 132 IResourceValidator makeValidator(IWorkerContext ctxt) throws FHIRException; 133 IResourceValidator makeValidator(IWorkerContext ctxts, XVerExtensionManager xverManager) throws FHIRException; 134 } 135 136 private Questionnaire questionnaire; 137 private String revision; 138 private String date; 139 private IValidatorFactory validatorFactory; 140 private boolean progress; 141 private final List<String> loadedPackages = new ArrayList<>(); 142 private boolean canNoTS; 143 private XVerExtensionManager xverManager; 144 private boolean allowLazyLoading = true; 145 146 private SimpleWorkerContext() throws IOException, FHIRException { 147 super(); 148 } 149 150 private SimpleWorkerContext(Locale locale) throws IOException, FHIRException { 151 super(locale); 152 } 153 154 public SimpleWorkerContext(SimpleWorkerContext other) throws IOException, FHIRException { 155 super(); 156 copy(other); 157 } 158 159 private SimpleWorkerContext(SimpleWorkerContext other, Locale locale) throws IOException, FHIRException { 160 super(locale); 161 copy(other); 162 } 163 164 protected void copy(SimpleWorkerContext other) { 165 super.copy(other); 166 binaries.putAll(other.binaries); 167 version = other.version; 168 revision = other.revision; 169 date = other.date; 170 validatorFactory = other.validatorFactory; 171 progress = other.progress; 172 loadedPackages.addAll(other.loadedPackages); 173 canNoTS = other.canNoTS; 174 xverManager = other.xverManager; 175 allowLazyLoading = other.allowLazyLoading; 176 } 177 178 179 public List<String> getLoadedPackages() { 180 return loadedPackages; 181 } 182 183 // -- Initializations 184 @AllArgsConstructor(access = AccessLevel.PRIVATE) 185 public static class SimpleWorkerContextBuilder { 186 187 188 @With 189 private final String terminologyCachePath; 190 @With 191 private final boolean cacheTerminologyClientErrors; 192 @With 193 private final boolean alwaysUseTerminologyServer; 194 @With 195 private final boolean readOnlyCache; 196 197 @With 198 private final Locale locale; 199 200 @With 201 private final String userAgent; 202 203 @With 204 private final boolean allowLoadingDuplicates; 205 206 @With 207 private final IWorkerContext.ILoggingService loggingService; 208 209 public SimpleWorkerContextBuilder() { 210 cacheTerminologyClientErrors = false; 211 alwaysUseTerminologyServer = false; 212 readOnlyCache = false; 213 terminologyCachePath = null; 214 locale = null; 215 userAgent = null; 216 allowLoadingDuplicates = false; 217 loggingService = new SystemOutLoggingService(); 218 } 219 220 private SimpleWorkerContext getSimpleWorkerContextInstance() throws IOException { 221 if (locale != null) { 222 return new SimpleWorkerContext(locale); 223 } else { 224 return new SimpleWorkerContext(); 225 } 226 } 227 228 public SimpleWorkerContext build() throws IOException { 229 SimpleWorkerContext context = getSimpleWorkerContextInstance(); 230 return build(context); 231 } 232 233 private SimpleWorkerContext build(SimpleWorkerContext context) throws IOException { 234 context.initTS(terminologyCachePath); 235 context.setUserAgent(userAgent); 236 context.setLogger(loggingService); 237 context.cacheResource(new org.hl7.fhir.r5.formats.JsonParser().parse(MagicResources.spdxCodesAsData())); 238 return context; 239 } 240 241 public SimpleWorkerContext fromPackage(NpmPackage pi) throws IOException, FHIRException { 242 SimpleWorkerContext context = getSimpleWorkerContextInstance(); 243 context.setAllowLoadingDuplicates(allowLoadingDuplicates); 244 context.loadFromPackage(pi, null); 245 return build(context); 246 } 247 248 public SimpleWorkerContext fromPackage(NpmPackage pi, IContextResourceLoader loader, boolean genSnapshots) throws IOException, FHIRException { 249 SimpleWorkerContext context = getSimpleWorkerContextInstance(); 250 context.setAllowLoadingDuplicates(allowLoadingDuplicates); 251 context.version = pi.getNpm().asString("version"); 252 context.loadFromPackage(pi, loader); 253 context.finishLoading(genSnapshots); 254 return build(context); 255 } 256 257 /** 258 * Load the working context from the validation pack 259 * 260 * @param path 261 * filename of the validation pack 262 * @return 263 * @throws IOException 264 * @throws FileNotFoundException 265 * @throws FHIRException 266 * @throws Exception 267 */ 268 public SimpleWorkerContext fromPack(String path) throws IOException, FHIRException { 269 SimpleWorkerContext context = getSimpleWorkerContextInstance(); 270 context.setAllowLoadingDuplicates(allowLoadingDuplicates); 271 context.loadFromPack(path, null); 272 return build(context); 273 } 274 275 public SimpleWorkerContext fromPack(String path, IContextResourceLoader loader) throws IOException, FHIRException { 276 SimpleWorkerContext context = getSimpleWorkerContextInstance(); 277 context.loadFromPack(path, loader); 278 return build(context); 279 } 280 281 public SimpleWorkerContext fromClassPath() throws IOException, FHIRException { 282 SimpleWorkerContext context = getSimpleWorkerContextInstance(); 283 context.loadFromStream(SimpleWorkerContext.class.getResourceAsStream("validation.json.zip"), null); 284 return build(context); 285 } 286 287 public SimpleWorkerContext fromClassPath(String name) throws IOException, FHIRException { 288 SimpleWorkerContext context = getSimpleWorkerContextInstance(); 289 InputStream s = SimpleWorkerContext.class.getResourceAsStream("/" + name); 290 context.setAllowLoadingDuplicates(allowLoadingDuplicates); 291 context.loadFromStream(s, null); 292 return build(context); 293 } 294 295 public SimpleWorkerContext fromDefinitions(Map<String, ByteProvider> source, IContextResourceLoader loader, PackageInformation pi) throws IOException, FHIRException { 296 SimpleWorkerContext context = getSimpleWorkerContextInstance(); 297 for (String name : source.keySet()) { 298 try { 299 context.loadDefinitionItem(name, new ByteArrayInputStream(source.get(name).getBytes()), loader, null, pi); 300 } catch (Exception e) { 301 System.out.println("Error loading "+name+": "+e.getMessage()); 302 throw new FHIRException("Error loading "+name+": "+e.getMessage(), e); 303 } 304 } 305 return build(context); 306 } 307 public SimpleWorkerContext fromNothing() throws FHIRException, IOException { 308 return build(); 309 } 310 } 311 312 private void loadDefinitionItem(String name, InputStream stream, IContextResourceLoader loader, ILoadFilter filter, PackageInformation pi) throws IOException, FHIRException { 313 if (name.endsWith(".xml")) 314 loadFromFile(stream, name, loader, filter); 315 else if (name.endsWith(".json")) 316 loadFromFileJson(stream, name, loader, filter, pi); 317 else if (name.equals("version.info")) 318 readVersionInfo(stream); 319 else 320 loadBytes(name, stream); 321 } 322 323 public String connectToTSServer(ITerminologyClient client, String log) { 324 try { 325 txLog("Connect to "+client.getAddress()); 326 tcc.setClient(client); 327 if (log != null && (log.endsWith(".htm") || log.endsWith(".html"))) { 328 txLog = new HTMLClientLogger(log); 329 } else { 330 txLog = new TextClientLogger(log); 331 } 332 tcc.getClient().setLogger(txLog); 333 tcc.getClient().setUserAgent(userAgent); 334 335 final CapabilityStatement capabilitiesStatementQuick = txCache.hasCapabilityStatement() ? txCache.getCapabilityStatement() : tcc.getClient().getCapabilitiesStatementQuick(); 336 txCache.cacheCapabilityStatement(capabilitiesStatementQuick); 337 338 final TerminologyCapabilities capabilityStatement = txCache.hasTerminologyCapabilities() ? txCache.getTerminologyCapabilities() : tcc.getClient().getTerminologyCapabilities(); 339 txCache.cacheTerminologyCapabilities(capabilityStatement); 340 341 setTxCaps(capabilityStatement); 342 return capabilitiesStatementQuick.getSoftware().getVersion(); 343 } catch (Exception e) { 344 throw new FHIRException(formatMessage(canNoTS ? I18nConstants.UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER_USE_PARAMETER_TX_NA_TUN_RUN_WITHOUT_USING_TERMINOLOGY_SERVICES_TO_VALIDATE_LOINC_SNOMED_ICDX_ETC_ERROR__ : I18nConstants.UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER, e.getMessage(), client.getAddress()), e); 345 } 346 } 347 348 public void loadFromFile(InputStream stream, String name, IContextResourceLoader loader) throws FHIRException { 349 loadFromFile(stream, name, loader, null); 350 } 351 352 public void loadFromFile(InputStream stream, String name, IContextResourceLoader loader, ILoadFilter filter) throws FHIRException { 353 Resource f; 354 try { 355 if (loader != null) 356 f = loader.loadBundle(stream, false); 357 else { 358 XmlParser xml = new XmlParser(); 359 f = xml.parse(stream); 360 } 361 } catch (DataFormatException e1) { 362 throw new org.hl7.fhir.exceptions.FHIRFormatError(formatMessage(I18nConstants.ERROR_PARSING_, name, e1.getMessage()), e1); 363 } catch (Exception e1) { 364 throw new org.hl7.fhir.exceptions.FHIRFormatError(formatMessage(I18nConstants.ERROR_PARSING_, name, e1.getMessage()), e1); 365 } 366 if (f instanceof Bundle) { 367 Bundle bnd = (Bundle) f; 368 for (BundleEntryComponent e : bnd.getEntry()) { 369 if (e.getFullUrl() == null) { 370 logger.logDebugMessage(LogCategory.CONTEXT, "unidentified resource in " + name+" (no fullUrl)"); 371 } 372 if (filter == null || filter.isOkToLoad(e.getResource())) { 373 String path = loader != null ? loader.getResourcePath(e.getResource()) : null; 374 if (path != null) { 375 e.getResource().setWebPath(path); 376 } 377 cacheResource(e.getResource()); 378 } 379 } 380 } else if (f instanceof CanonicalResource) { 381 if (filter == null || filter.isOkToLoad(f)) { 382 String path = loader != null ? loader.getResourcePath(f) : null; 383 if (path != null) { 384 f.setWebPath(path); 385 } 386 cacheResource(f); 387 } 388 } 389 } 390 391 private void loadFromFileJson(InputStream stream, String name, IContextResourceLoader loader, ILoadFilter filter, PackageInformation pi) throws IOException, FHIRException { 392 Bundle f = null; 393 try { 394 if (loader != null) 395 f = loader.loadBundle(stream, true); 396 else { 397 JsonParser json = new JsonParser(); 398 Resource r = json.parse(stream); 399 if (r instanceof Bundle) 400 f = (Bundle) r; 401 else if (filter == null || filter.isOkToLoad(f)) { 402 cacheResourceFromPackage(r, pi); 403 } 404 } 405 } catch (FHIRFormatError e1) { 406 throw new org.hl7.fhir.exceptions.FHIRFormatError(e1.getMessage(), e1); 407 } 408 if (f != null) 409 for (BundleEntryComponent e : f.getEntry()) { 410 if (filter == null || filter.isOkToLoad(e.getResource())) { 411 String path = loader != null ? loader.getResourcePath(e.getResource()) : null; 412 if (path != null) { 413 e.getResource().setWebPath(path); 414 } 415 cacheResourceFromPackage(e.getResource(), pi); 416 } 417 } 418 } 419 420 private void loadFromPack(String path, IContextResourceLoader loader) throws IOException, FHIRException { 421 loadFromStream(new CSFileInputStream(path), loader); 422 } 423 424 425 @Override 426 public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws IOException, FHIRException { 427 return loadFromPackageInt(pi, loader, loader == null ? defaultTypesToLoad() : loader.getTypes()); 428 } 429 430 public static List<String> defaultTypesToLoad() { 431 // there's no penalty for listing resources that don't exist, so we just all the relevant possibilities for all versions 432 return Utilities.strings("CodeSystem", "ValueSet", "ConceptMap", "NamingSystem", 433 "StructureDefinition", "StructureMap", 434 "SearchParameter", "OperationDefinition", "CapabilityStatement", "Conformance", 435 "Questionnaire", "ImplementationGuide", "Measure" ); 436 } 437 438 @Override 439 public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, List<String> types) throws IOException, FHIRException { 440 return loadFromPackageInt(pi, loader, types); 441 } 442 443 @Override 444 public int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) throws IOException, FHIRException { 445 return loadFromPackageAndDependenciesInt(pi, loader, pcm, pi.name()+"#"+pi.version()); 446 } 447 public int loadFromPackageAndDependenciesInt(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm, String path) throws IOException, FHIRException { 448 int t = 0; 449 450 for (String e : pi.dependencies()) { 451 if (!loadedPackages.contains(e) && !VersionUtilities.isCorePackage(e)) { 452 NpmPackage npm = pcm.loadPackage(e); 453 if (!VersionUtilities.versionsMatch(version, npm.fhirVersion())) { 454 System.out.println(formatMessage(I18nConstants.PACKAGE_VERSION_MISMATCH, e, version, npm.fhirVersion(), path)); 455 } 456 t = t + loadFromPackageAndDependenciesInt(npm, loader.getNewLoader(npm), pcm, path+" -> "+npm.name()+"#"+npm.version()); 457 } 458 } 459 t = t + loadFromPackageInt(pi, loader, loader.getTypes()); 460 return t; 461 } 462 463 464 public int loadFromPackageInt(NpmPackage pi, IContextResourceLoader loader, List<String> types) throws IOException, FHIRException { 465 int t = 0; 466 if (progress) { 467 System.out.println("Load Package "+pi.name()+"#"+pi.version()); 468 } 469 if (loadedPackages.contains(pi.id()+"#"+pi.version())) { 470 return 0; 471 } 472 473 loadedPackages.add(pi.id()+"#"+pi.version()); 474 if (packageTracker != null) { 475 packageTracker.packageLoaded(pi.id(), pi.version()); 476 } 477 478 if ((types == null || types.size() == 0) && loader != null) { 479 types = loader.getTypes(); 480 } 481 if (VersionUtilities.isR2Ver(pi.fhirVersion()) || !pi.canLazyLoad() || !allowLazyLoading) { 482 // can't lazy load R2 because of valueset/codesystem implementation 483 if (types == null || types.size() == 0) { 484 types = Utilities.strings("StructureDefinition", "ValueSet", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem" ); 485 } 486 for (String s : pi.listResources(types)) { 487 try { 488 loadDefinitionItem(s, pi.load("package", s), loader, null, new PackageInformation(pi)); 489 t++; 490 } catch (Exception e) { 491 throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, s, pi.name(), pi.version(), e.getMessage()), e); 492 } 493 } 494 } else { 495 if (types == null || types.size() == 0) { 496 types = Utilities.strings("StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem", "Measures" ); 497 } 498 for (PackageResourceInformation pri : pi.listIndexedResources(types)) { 499 if (!pri.getFilename().contains("ig-r4") && (loader == null || loader.wantLoad(pi, pri))) { 500 try { 501 if (!pri.hasId()) { 502 loadDefinitionItem(pri.getFilename(), new FileInputStream(pri.getFilename()), loader, null, new PackageInformation(pi)); 503 } else { 504 registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageInformation(pi)); 505 } 506 t++; 507 } catch (FHIRException e) { 508 throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, pri.getFilename(), pi.name(), pi.version(), e.getMessage()), e); 509 } 510 } 511 } 512 } 513 for (String s : pi.list("other")) { 514 binaries.put(s, TextFile.streamToBytes(pi.load("other", s))); 515 } 516 if (version == null) { 517 version = pi.version(); 518 if (version.equals("current")) { 519 version = "5.0.0"; 520 } 521 } 522 return t; 523 } 524 525 public void loadFromFile(String file, IContextResourceLoader loader) throws IOException, FHIRException { 526 loadDefinitionItem(file, new CSFileInputStream(file), loader, null, null); 527 } 528 529 private void loadFromStream(InputStream stream, IContextResourceLoader loader) throws IOException, FHIRException { 530 ZipInputStream zip = new ZipInputStream(stream); 531 ZipEntry zipEntry; 532 while ((zipEntry = zip.getNextEntry()) != null) { 533 String entryName = zipEntry.getName(); 534 if (entryName.contains("..")) { 535 throw new RuntimeException("Entry with an illegal path: " + entryName); 536 } 537 loadDefinitionItem(entryName, zip, loader, null, null); 538 zip.closeEntry(); 539 } 540 zip.close(); 541 } 542 543 private void readVersionInfo(InputStream stream) throws IOException, DefinitionException { 544 byte[] bytes = IOUtils.toByteArray(stream); 545 binaries.put("version.info", bytes); 546 547 String[] vi = new String(bytes).split("\\r?\\n"); 548 for (String s : vi) { 549 if (s.startsWith("version=")) { 550 if (version == null) 551 version = s.substring(8); 552 else if (!version.equals(s.substring(8))) { 553 throw new DefinitionException(formatMessage(I18nConstants.VERSION_MISMATCH_THE_CONTEXT_HAS_VERSION__LOADED_AND_THE_NEW_CONTENT_BEING_LOADED_IS_VERSION_, version, s.substring(8))); 554 } 555 } 556 if (s.startsWith("revision=")) 557 revision = s.substring(9); 558 if (s.startsWith("date=")) 559 date = s.substring(5); 560 } 561 } 562 563 private void loadBytes(String name, InputStream stream) throws IOException { 564 byte[] bytes = IOUtils.toByteArray(stream); 565 binaries.put(name, bytes); 566 } 567 568 @Override 569 public IResourceValidator newValidator() throws FHIRException { 570 if (validatorFactory == null) 571 throw new Error(formatMessage(I18nConstants.NO_VALIDATOR_CONFIGURED)); 572 return validatorFactory.makeValidator(this, xverManager).setJurisdiction(JurisdictionUtilities.getJurisdictionCodingFromLocale(Locale.getDefault().getCountry())); 573 } 574 575 576 577 578 @Override 579 public List<String> getResourceNames() { 580 Set<String> result = new HashSet<String>(); 581 for (StructureDefinition sd : listStructures()) { 582 if (sd.getKind() == StructureDefinitionKind.RESOURCE && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && !sd.hasUserData("old.load.mode")) 583 result.add(sd.getName()); 584 } 585 return Utilities.sorted(result); 586 } 587 588 589 public Questionnaire getQuestionnaire() { 590 return questionnaire; 591 } 592 593 public void setQuestionnaire(Questionnaire questionnaire) { 594 this.questionnaire = questionnaire; 595 } 596 597 598 599 public void loadBinariesFromFolder(String folder) throws IOException { 600 for (String n : new File(folder).list()) { 601 loadBytes(n, new FileInputStream(Utilities.path(folder, n))); 602 } 603 } 604 605 public void loadBinariesFromFolder(NpmPackage pi) throws IOException { 606 for (String n : pi.list("other")) { 607 loadBytes(n, pi.load("other", n)); 608 } 609 } 610 611 public void loadFromFolder(String folder) throws IOException { 612 for (String n : new File(folder).list()) { 613 if (n.endsWith(".json")) 614 loadFromFile(Utilities.path(folder, n), new JsonParser()); 615 else if (n.endsWith(".xml")) 616 loadFromFile(Utilities.path(folder, n), new XmlParser()); 617 } 618 } 619 620 private void loadFromFile(String filename, IParser p) { 621 Resource r; 622 try { 623 r = p.parse(new FileInputStream(filename)); 624 if (r.getResourceType() == ResourceType.Bundle) { 625 for (BundleEntryComponent e : ((Bundle) r).getEntry()) { 626 cacheResource(e.getResource()); 627 } 628 } else { 629 cacheResource(r); 630 } 631 } catch (Exception e) { 632 return; 633 } 634 } 635 636 637 638 @Override 639 public String getVersion() { 640 return version; 641 } 642 643 644 public List<StructureMap> findTransformsforSource(String url) { 645 List<StructureMap> res = new ArrayList<StructureMap>(); 646 for (StructureMap map : fetchResourcesByType(StructureMap.class)) { 647 boolean match = false; 648 boolean ok = true; 649 for (StructureMapStructureComponent t : map.getStructure()) { 650 if (t.getMode() == StructureMapModelMode.SOURCE) { 651 match = match || t.getUrl().equals(url); 652 ok = ok && t.getUrl().equals(url); 653 } 654 } 655 if (match && ok) 656 res.add(map); 657 } 658 return res; 659 } 660 661 public IValidatorFactory getValidatorFactory() { 662 return validatorFactory; 663 } 664 665 public void setValidatorFactory(IValidatorFactory validatorFactory) { 666 this.validatorFactory = validatorFactory; 667 } 668 669 @Override 670 public <T extends Resource> T fetchResource(Class<T> class_, String uri) { 671 T r = super.fetchResource(class_, uri); 672 if (r instanceof StructureDefinition) { 673 StructureDefinition p = (StructureDefinition)r; 674 try { 675 new ContextUtilities(this).generateSnapshot(p); 676 } catch (Exception e) { 677 // not sure what to do in this case? 678 System.out.println("Unable to generate snapshot @3 for "+uri+": "+e.getMessage()); 679 if (logger.isDebugLogging()) { 680 e.printStackTrace(); 681 } 682 } 683 } 684 return r; 685 } 686 687 @Override 688 public <T extends Resource> T fetchResourceRaw(Class<T> class_, String uri) { 689 T r = super.fetchResource(class_, uri); 690 return r; 691 } 692 693 @Override 694 public <T extends Resource> T fetchResource(Class<T> class_, String uri, Resource source) { 695 T r = super.fetchResource(class_, uri, source); 696 if (r instanceof StructureDefinition) { 697 StructureDefinition p = (StructureDefinition)r; 698 if (!p.isGeneratedSnapshot()) { 699 if (p.isGeneratingSnapshot()) { 700 throw new FHIRException("Attempt to fetch the profile "+p.getVersionedUrl()+" while generating the snapshot for it"); 701 } 702 try { 703 if (logger.isDebugLogging()) { 704 System.out.println("Generating snapshot for "+p.getVersionedUrl()); 705 } 706 p.setGeneratingSnapshot(true); 707 try { 708 new ContextUtilities(this).generateSnapshot(p); 709 } finally { 710 p.setGeneratingSnapshot(false); 711 } 712 } catch (Exception e) { 713 // not sure what to do in this case? 714 System.out.println("Unable to generate snapshot @4 for "+p.getVersionedUrl()+": "+e.getMessage()); 715 if (logger.isDebugLogging()) { 716 e.printStackTrace(); 717 } 718 } 719 } 720 } 721 return r; 722 } 723 724 725 726 727 public String listMapUrls() { 728 return Utilities.listCanonicalUrls(transforms.keys()); 729 } 730 731 public boolean isProgress() { 732 return progress; 733 } 734 735 public void setProgress(boolean progress) { 736 this.progress = progress; 737 } 738 739 public void setClock(TimeTracker tt) { 740 clock = tt; 741 } 742 743 public boolean isCanNoTS() { 744 return canNoTS; 745 } 746 747 public void setCanNoTS(boolean canNoTS) { 748 this.canNoTS = canNoTS; 749 } 750 751 public XVerExtensionManager getXVer() { 752 if (xverManager == null) { 753 xverManager = new XVerExtensionManager(this); 754 } 755 return xverManager; 756 } 757 758 public void cachePackage(PackageInformation packageInfo) { 759 // nothing yet 760 } 761 762 @Override 763 public boolean hasPackage(String id, String ver) { 764 return loadedPackages.contains(id+"#"+ver); 765 } 766 767 public boolean hasPackage(String idAndver) { 768 return loadedPackages.contains(idAndver); 769 } 770 771 @Override 772 public boolean hasPackage(PackageInformation pack) { 773 return false; 774 } 775 776 @Override 777 public PackageInformation getPackage(String id, String ver) { 778 return null; 779 } 780 781 public boolean isAllowLazyLoading() { 782 return allowLazyLoading; 783 } 784 785 public void setAllowLazyLoading(boolean allowLazyLoading) { 786 this.allowLazyLoading = allowLazyLoading; 787 } 788 789 public String loadedPackageSummary() { 790 return loadedPackages.toString(); 791 } 792 793 @Override 794 public String getSpecUrl() { 795 return VersionUtilities.getSpecUrl(getVersion())+"/"; 796 } 797 798} 799