
001package org.hl7.fhir.r4.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.net.URISyntaxException; 039import java.util.ArrayList; 040import java.util.Arrays; 041import java.util.Collections; 042import java.util.HashMap; 043import java.util.HashSet; 044import java.util.List; 045import java.util.Map; 046import java.util.Set; 047import java.util.zip.ZipEntry; 048import java.util.zip.ZipInputStream; 049 050import lombok.extern.slf4j.Slf4j; 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.r4.conformance.ProfileUtilities; 056import org.hl7.fhir.r4.conformance.ProfileUtilities.ProfileKnowledgeProvider; 057import org.hl7.fhir.r4.context.IWorkerContext.ILoggingService.LogCategory; 058import org.hl7.fhir.r4.formats.IParser; 059import org.hl7.fhir.r4.formats.JsonParser; 060import org.hl7.fhir.r4.formats.ParserType; 061import org.hl7.fhir.r4.formats.XmlParser; 062import org.hl7.fhir.r4.model.Bundle; 063import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; 064import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent; 065import org.hl7.fhir.r4.model.MetadataResource; 066import org.hl7.fhir.r4.model.Questionnaire; 067import org.hl7.fhir.r4.model.Resource; 068import org.hl7.fhir.r4.model.ResourceType; 069import org.hl7.fhir.r4.model.StructureDefinition; 070import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind; 071import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule; 072import org.hl7.fhir.r4.model.StructureMap; 073import org.hl7.fhir.r4.model.StructureMap.StructureMapModelMode; 074import org.hl7.fhir.r4.model.StructureMap.StructureMapStructureComponent; 075import org.hl7.fhir.r4.terminologies.TerminologyClient; 076import org.hl7.fhir.r4.utils.INarrativeGenerator; 077import org.hl7.fhir.r4.utils.NarrativeGenerator; 078import org.hl7.fhir.r4.utils.validation.IResourceValidator; 079import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 080import org.hl7.fhir.utilities.Utilities; 081import org.hl7.fhir.utilities.filesystem.CSFileInputStream; 082import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; 083import org.hl7.fhir.utilities.npm.NpmPackage; 084import org.hl7.fhir.utilities.validation.ValidationMessage; 085import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; 086import org.hl7.fhir.utilities.validation.ValidationMessage.Source; 087 088import ca.uhn.fhir.parser.DataFormatException; 089import org.slf4j.MarkerFactory; 090import org.slf4j.event.Level; 091 092/* 093 * This is a stand alone implementation of worker context for use inside a tool. 094 * It loads from the validation package (validation-min.xml.zip), and has a 095 * very light client to connect to an open unauthenticated terminology service 096 */ 097 098@MarkedToMoveToAdjunctPackage 099@Slf4j 100public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerContext, ProfileKnowledgeProvider { 101 102 public interface IContextResourceLoader { 103 Bundle loadBundle(InputStream stream, boolean isJson) throws FHIRException, IOException; 104 } 105 106 public interface IValidatorFactory { 107 IResourceValidator makeValidator(IWorkerContext ctxts) throws FHIRException; 108 } 109 110 private Questionnaire questionnaire; 111 private Map<String, byte[]> binaries = new HashMap<String, byte[]>(); 112 private String version; 113 private String revision; 114 private String date; 115 private IValidatorFactory validatorFactory; 116 private boolean ignoreProfileErrors; 117 118 public SimpleWorkerContext() throws FileNotFoundException, IOException, FHIRException { 119 super(); 120 } 121 122 public SimpleWorkerContext(SimpleWorkerContext other) throws FileNotFoundException, IOException, FHIRException { 123 super(); 124 copy(other); 125 } 126 127 protected void copy(SimpleWorkerContext other) { 128 super.copy(other); 129 questionnaire = other.questionnaire; 130 binaries.putAll(other.binaries); 131 version = other.version; 132 revision = other.revision; 133 date = other.date; 134 validatorFactory = other.validatorFactory; 135 } 136 137 // -- Initializations 138 /** 139 * Load the working context from the validation pack 140 * 141 * @param path filename of the validation pack 142 * @return 143 * @throws IOException 144 * @throws FileNotFoundException 145 * @throws FHIRException 146 * @throws Exception 147 */ 148 public static SimpleWorkerContext fromPack(String path) throws FileNotFoundException, IOException, FHIRException { 149 SimpleWorkerContext res = new SimpleWorkerContext(); 150 res.loadFromPack(path, null); 151 return res; 152 } 153 154 public static SimpleWorkerContext fromNothing() throws FileNotFoundException, IOException, FHIRException { 155 SimpleWorkerContext res = new SimpleWorkerContext(); 156 return res; 157 } 158 159 public static SimpleWorkerContext fromPackage(NpmPackage pi, boolean allowDuplicates) 160 throws FileNotFoundException, IOException, FHIRException { 161 SimpleWorkerContext res = new SimpleWorkerContext(); 162 res.setAllowLoadingDuplicates(allowDuplicates); 163 res.loadFromPackage(pi, null); 164 return res; 165 } 166 167 public static SimpleWorkerContext fromPackage(NpmPackage pi) 168 throws FileNotFoundException, IOException, FHIRException { 169 SimpleWorkerContext res = new SimpleWorkerContext(); 170 res.loadFromPackage(pi, null); 171 return res; 172 } 173 174 public static SimpleWorkerContext fromPackage(NpmPackage pi, IContextResourceLoader loader) 175 throws FileNotFoundException, IOException, FHIRException { 176 SimpleWorkerContext res = new SimpleWorkerContext(); 177 res.setAllowLoadingDuplicates(true); 178 res.version = pi.getNpm().asString("version"); 179 res.loadFromPackage(pi, loader); 180 return res; 181 } 182 183 public static SimpleWorkerContext fromPack(String path, boolean allowDuplicates) 184 throws FileNotFoundException, IOException, FHIRException { 185 SimpleWorkerContext res = new SimpleWorkerContext(); 186 res.setAllowLoadingDuplicates(allowDuplicates); 187 res.loadFromPack(path, null); 188 return res; 189 } 190 191 public static SimpleWorkerContext fromPack(String path, IContextResourceLoader loader) 192 throws FileNotFoundException, IOException, FHIRException { 193 SimpleWorkerContext res = new SimpleWorkerContext(); 194 res.loadFromPack(path, loader); 195 return res; 196 } 197 198 public static SimpleWorkerContext fromClassPath() throws IOException, FHIRException { 199 SimpleWorkerContext res = new SimpleWorkerContext(); 200 res.loadFromStream(SimpleWorkerContext.class.getResourceAsStream("validation.json.zip"), null); 201 return res; 202 } 203 204 public static SimpleWorkerContext fromClassPath(String name) throws IOException, FHIRException { 205 InputStream s = SimpleWorkerContext.class.getResourceAsStream("/" + name); 206 SimpleWorkerContext res = new SimpleWorkerContext(); 207 res.loadFromStream(s, null); 208 return res; 209 } 210 211 public static SimpleWorkerContext fromDefinitions(Map<String, byte[]> source) throws IOException, FHIRException { 212 SimpleWorkerContext res = new SimpleWorkerContext(); 213 for (String name : source.keySet()) { 214 res.loadDefinitionItem(name, new ByteArrayInputStream(source.get(name)), null); 215 } 216 return res; 217 } 218 219 public static SimpleWorkerContext fromDefinitions(Map<String, byte[]> source, IContextResourceLoader loader) 220 throws FileNotFoundException, IOException, FHIRException { 221 SimpleWorkerContext res = new SimpleWorkerContext(); 222 for (String name : source.keySet()) { 223 try { 224 res.loadDefinitionItem(name, new ByteArrayInputStream(source.get(name)), loader); 225 } catch (Exception e) { 226 log.error("Error loading " + name + ": " + e.getMessage()); 227 throw new FHIRException("Error loading " + name + ": " + e.getMessage(), e); 228 } 229 } 230 return res; 231 } 232 233 private void loadDefinitionItem(String name, InputStream stream, IContextResourceLoader loader) 234 throws IOException, FHIRException { 235 if (name.endsWith(".xml")) 236 loadFromFile(stream, name, loader); 237 else if (name.endsWith(".json")) 238 loadFromFileJson(stream, name, loader); 239 else if (name.equals("version.info")) 240 readVersionInfo(stream); 241 else 242 loadBytes(name, stream); 243 } 244 245 public String connectToTSServer(TerminologyClient client, String log) throws URISyntaxException, FHIRException, IOException { 246 tlog("Connect to " + client.getAddress()); 247 txClient = client; 248 txLog = new HTMLClientLogger(log); 249 txClient.setLogger(txLog); 250 return txClient.getCapabilitiesStatementQuick().getSoftware().getVersion(); 251 } 252 253 public void loadFromFile(InputStream stream, String name, IContextResourceLoader loader) 254 throws IOException, FHIRException { 255 Resource f; 256 try { 257 if (loader != null) 258 f = loader.loadBundle(stream, false); 259 else { 260 XmlParser xml = new XmlParser(); 261 f = xml.parse(stream); 262 } 263 } catch (DataFormatException e1) { 264 throw new org.hl7.fhir.exceptions.FHIRFormatError("Error parsing " + name + ":" + e1.getMessage(), e1); 265 } catch (Exception e1) { 266 throw new org.hl7.fhir.exceptions.FHIRFormatError("Error parsing " + name + ":" + e1.getMessage(), e1); 267 } 268 if (f instanceof Bundle) { 269 Bundle bnd = (Bundle) f; 270 for (BundleEntryComponent e : bnd.getEntry()) { 271 if (e.getFullUrl() == null) { 272 logContextDebugMessage("unidentified resource in " + name + " (no fullUrl)"); 273 } 274 cacheResource(e.getResource()); 275 } 276 } else if (f instanceof MetadataResource) { 277 MetadataResource m = (MetadataResource) f; 278 cacheResource(m); 279 } 280 } 281 282 private void logContextDebugMessage(String message) { 283 log.makeLoggingEventBuilder(Level.DEBUG) 284 .addMarker(MarkerFactory.getMarker(LogCategory.CONTEXT.name().toLowerCase())) 285 .setMessage(message) 286 .log(); 287 } 288 289 private void loadFromFileJson(InputStream stream, String name, IContextResourceLoader loader) 290 throws IOException, FHIRException { 291 Bundle f = null; 292 try { 293 if (loader != null) 294 f = loader.loadBundle(stream, true); 295 else { 296 JsonParser json = new JsonParser(); 297 Resource r = json.parse(stream); 298 if (r instanceof Bundle) 299 f = (Bundle) r; 300 else 301 cacheResource(r); 302 } 303 } catch (FHIRFormatError e1) { 304 throw new org.hl7.fhir.exceptions.FHIRFormatError(e1.getMessage(), e1); 305 } 306 if (f != null) 307 for (BundleEntryComponent e : f.getEntry()) { 308 cacheResource(e.getResource()); 309 } 310 } 311 312 private void loadFromPack(String path, IContextResourceLoader loader) 313 throws FileNotFoundException, IOException, FHIRException { 314 loadFromStream(new CSFileInputStream(path), loader); 315 } 316 317 public void loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String... types) 318 throws FileNotFoundException, IOException, FHIRException { 319 if (types.length == 0) 320 types = new String[] { "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", 321 "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem" }; 322 for (String s : pi.listResources(types)) { 323 loadDefinitionItem(s, pi.load("package", s), loader); 324 } 325 version = pi.version(); 326 } 327 328 public void loadFromFile(String file, IContextResourceLoader loader) throws IOException, FHIRException { 329 loadDefinitionItem(file, new CSFileInputStream(file), loader); 330 } 331 332 private void loadFromStream(InputStream stream, IContextResourceLoader loader) throws IOException, FHIRException { 333 ZipInputStream zip = new ZipInputStream(stream); 334 ZipEntry ze; 335 while ((ze = zip.getNextEntry()) != null) { 336 loadDefinitionItem(ze.getName(), zip, loader); 337 zip.closeEntry(); 338 } 339 zip.close(); 340 } 341 342 private void readVersionInfo(InputStream stream) throws IOException, DefinitionException { 343 byte[] bytes = IOUtils.toByteArray(stream); 344 binaries.put("version.info", bytes); 345 346 String[] vi = new String(bytes).split("\\r?\\n"); 347 for (String s : vi) { 348 if (s.startsWith("version=")) { 349 if (version == null) 350 version = s.substring(8); 351 else if (!version.equals(s.substring(8))) 352 throw new DefinitionException("Version mismatch. The context has version " + version 353 + " loaded, and the new content being loaded is version " + s.substring(8)); 354 } 355 if (s.startsWith("revision=")) 356 revision = s.substring(9); 357 if (s.startsWith("date=")) 358 date = s.substring(5); 359 } 360 } 361 362 private void loadBytes(String name, InputStream stream) throws IOException { 363 byte[] bytes = IOUtils.toByteArray(stream); 364 binaries.put(name, bytes); 365 } 366 367 @Override 368 public IParser getParser(ParserType type) { 369 switch (type) { 370 case JSON: 371 return newJsonParser(); 372 case XML: 373 return newXmlParser(); 374 default: 375 throw new Error("Parser Type " + type.toString() + " not supported"); 376 } 377 } 378 379 @Override 380 public IParser getParser(String type) { 381 if (type.equalsIgnoreCase("JSON")) 382 return new JsonParser(); 383 if (type.equalsIgnoreCase("XML")) 384 return new XmlParser(); 385 throw new Error("Parser Type " + type.toString() + " not supported"); 386 } 387 388 @Override 389 public IParser newJsonParser() { 390 return new JsonParser(); 391 } 392 393 @Override 394 public IParser newXmlParser() { 395 return new XmlParser(); 396 } 397 398 @Override 399 public INarrativeGenerator getNarrativeGenerator(String prefix, String basePath) { 400 return new NarrativeGenerator(prefix, basePath, this); 401 } 402 403 @Override 404 public IResourceValidator newValidator() throws FHIRException { 405 if (validatorFactory == null) 406 throw new Error("No validator configured"); 407 return validatorFactory.makeValidator(this); 408 } 409 410 @Override 411 public List<String> getResourceNames() { 412 List<String> result = new ArrayList<String>(); 413 for (StructureDefinition sd : listStructures()) { 414 if (sd.getKind() == StructureDefinitionKind.RESOURCE && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) 415 result.add(sd.getName()); 416 } 417 Collections.sort(result); 418 return result; 419 } 420 421 @Override 422 public List<String> getTypeNames() { 423 List<String> result = new ArrayList<String>(); 424 for (StructureDefinition sd : listStructures()) { 425 if (sd.getKind() != StructureDefinitionKind.LOGICAL && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) 426 result.add(sd.getName()); 427 } 428 Collections.sort(result); 429 return result; 430 } 431 432 @Override 433 public String getAbbreviation(String name) { 434 return "xxx"; 435 } 436 437 @Override 438 public boolean isDatatype(String typeSimple) { 439 // TODO Auto-generated method stub 440 return false; 441 } 442 443 @Override 444 public boolean isResource(String t) { 445 StructureDefinition sd; 446 try { 447 sd = fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + t); 448 } catch (Exception e) { 449 return false; 450 } 451 if (sd == null) 452 return false; 453 if (sd.getDerivation() == TypeDerivationRule.CONSTRAINT) 454 return false; 455 return sd.getKind() == StructureDefinitionKind.RESOURCE; 456 } 457 458 @Override 459 public boolean hasLinkFor(String typeSimple) { 460 return false; 461 } 462 463 @Override 464 public String getLinkFor(String corePath, String typeSimple) { 465 return null; 466 } 467 468 @Override 469 public BindingResolution resolveBinding(StructureDefinition profile, ElementDefinitionBindingComponent binding, 470 String path) { 471 return null; 472 } 473 474 @Override 475 public BindingResolution resolveBinding(StructureDefinition profile, String url, String path) { 476 return null; 477 } 478 479 @Override 480 public String getLinkForProfile(StructureDefinition profile, String url) { 481 return null; 482 } 483 484 public Questionnaire getQuestionnaire() { 485 return questionnaire; 486 } 487 488 public void setQuestionnaire(Questionnaire questionnaire) { 489 this.questionnaire = questionnaire; 490 } 491 492 @Override 493 public Set<String> typeTails() { 494 return new HashSet<String>( 495 Arrays.asList("Integer", "UnsignedInt", "PositiveInt", "Decimal", "DateTime", "Date", "Time", "Instant", 496 "String", "Uri", "Url", "Canonical", "Oid", "Uuid", "Id", "Boolean", "Code", "Markdown", "Base64Binary", 497 "Coding", "CodeableConcept", "Attachment", "Identifier", "Quantity", "SampledData", "Range", "Period", 498 "Ratio", "HumanName", "Address", "ContactPoint", "Timing", "Reference", "Annotation", "Signature", "Meta")); 499 } 500 501 @Override 502 public List<StructureDefinition> allStructures() { 503 List<StructureDefinition> result = new ArrayList<StructureDefinition>(); 504 Set<StructureDefinition> set = new HashSet<StructureDefinition>(); 505 for (StructureDefinition sd : listStructures()) { 506 if (!set.contains(sd)) { 507 try { 508 generateSnapshot(sd); 509 } catch (Exception e) { 510 log.warn("Unable to generate snapshot for " + sd.getUrl() + " because " + e.getMessage()); 511 } 512 result.add(sd); 513 set.add(sd); 514 } 515 } 516 return result; 517 } 518 519 public void loadBinariesFromFolder(String folder) throws FileNotFoundException, Exception { 520 for (String n : ManagedFileAccess.file(folder).list()) { 521 loadBytes(n, ManagedFileAccess.inStream(Utilities.path(folder, n))); 522 } 523 } 524 525 public void loadBinariesFromFolder(NpmPackage pi) throws FileNotFoundException, Exception { 526 for (String n : pi.list("other")) { 527 loadBytes(n, pi.load("other", n)); 528 } 529 } 530 531 public void loadFromFolder(String folder) throws FileNotFoundException, Exception { 532 for (String n : ManagedFileAccess.file(folder).list()) { 533 if (n.endsWith(".json")) 534 loadFromFile(Utilities.path(folder, n), new JsonParser()); 535 else if (n.endsWith(".xml")) 536 loadFromFile(Utilities.path(folder, n), new XmlParser()); 537 } 538 } 539 540 private void loadFromFile(String filename, IParser p) throws FileNotFoundException, Exception { 541 Resource r; 542 try { 543 r = p.parse(ManagedFileAccess.inStream(filename)); 544 if (r.getResourceType() == ResourceType.Bundle) { 545 for (BundleEntryComponent e : ((Bundle) r).getEntry()) { 546 cacheResource(e.getResource()); 547 } 548 } else { 549 cacheResource(r); 550 } 551 } catch (Exception e) { 552 return; 553 } 554 } 555 556 public Map<String, byte[]> getBinaries() { 557 return binaries; 558 } 559 560 @Override 561 public boolean prependLinks() { 562 return false; 563 } 564 565 @Override 566 public boolean hasCache() { 567 return false; 568 } 569 570 @Override 571 public String getVersion() { 572 return version; 573 } 574 575 public List<StructureMap> findTransformsforSource(String url) { 576 List<StructureMap> res = new ArrayList<StructureMap>(); 577 for (StructureMap map : listTransforms()) { 578 boolean match = false; 579 boolean ok = true; 580 for (StructureMapStructureComponent t : map.getStructure()) { 581 if (t.getMode() == StructureMapModelMode.SOURCE) { 582 match = match || t.getUrl().equals(url); 583 ok = ok && t.getUrl().equals(url); 584 } 585 } 586 if (match && ok) 587 res.add(map); 588 } 589 return res; 590 } 591 592 public IValidatorFactory getValidatorFactory() { 593 return validatorFactory; 594 } 595 596 public void setValidatorFactory(IValidatorFactory validatorFactory) { 597 this.validatorFactory = validatorFactory; 598 } 599 600 @Override 601 public <T extends Resource> T fetchResource(Class<T> class_, String uri) { 602 T r = super.fetchResource(class_, uri); 603 if (r instanceof StructureDefinition) { 604 StructureDefinition p = (StructureDefinition) r; 605 try { 606 generateSnapshot(p); 607 } catch (Exception e) { 608 // not sure what to do in this case? 609 log.warn("Unable to generate snapshot for " + uri + ": " + e.getMessage()); 610 } 611 } 612 return r; 613 } 614 615 public void generateSnapshot(StructureDefinition p) throws DefinitionException, FHIRException { 616 if (!p.hasSnapshot() && p.getKind() != StructureDefinitionKind.LOGICAL) { 617 if (!p.hasBaseDefinition()) 618 throw new DefinitionException("Profile " + p.getName() + " (" + p.getUrl() + ") has no base and no snapshot"); 619 StructureDefinition sd = fetchResource(StructureDefinition.class, p.getBaseDefinition()); 620 if (sd == null) 621 throw new DefinitionException("Profile " + p.getName() + " (" + p.getUrl() + ") base " + p.getBaseDefinition() 622 + " could not be resolved"); 623 List<ValidationMessage> msgs = new ArrayList<ValidationMessage>(); 624 List<String> errors = new ArrayList<String>(); 625 ProfileUtilities pu = new ProfileUtilities(this, msgs, this); 626 pu.setThrowException(false); 627 pu.sortDifferential(sd, p, p.getUrl(), errors); 628 for (String err : errors) 629 msgs.add(new ValidationMessage(Source.ProfileValidator, IssueType.EXCEPTION, p.getUserString("path"), 630 "Error sorting Differential: " + err, ValidationMessage.IssueSeverity.ERROR)); 631 pu.generateSnapshot(sd, p, p.getUrl(), Utilities.extractBaseUrl(sd.getUserString("path")), p.getName()); 632 for (ValidationMessage msg : msgs) { 633 if ((!ignoreProfileErrors && msg.getLevel() == ValidationMessage.IssueSeverity.ERROR) 634 || msg.getLevel() == ValidationMessage.IssueSeverity.FATAL) 635 throw new DefinitionException( 636 "Profile " + p.getName() + " (" + p.getUrl() + "). Error generating snapshot: " + msg.getMessage()); 637 } 638 if (!p.hasSnapshot()) 639 throw new FHIRException("Profile " + p.getName() + " (" + p.getUrl() + "). Error generating snapshot"); 640 pu = null; 641 } 642 } 643 644 public boolean isIgnoreProfileErrors() { 645 return ignoreProfileErrors; 646 } 647 648 public void setIgnoreProfileErrors(boolean ignoreProfileErrors) { 649 this.ignoreProfileErrors = ignoreProfileErrors; 650 } 651 652 public String listMapUrls() { 653 return Utilities.listCanonicalUrls(transforms.keySet()); 654 } 655 656}