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