
001package org.hl7.fhir.r5.renderers.utils; 002 003import java.io.IOException; 004import java.text.NumberFormat; 005import java.time.ZoneId; 006import java.time.format.DateTimeFormatter; 007import java.util.ArrayList; 008import java.util.HashMap; 009import java.util.HashSet; 010import java.util.List; 011import java.util.Locale; 012import java.util.Map; 013import java.util.Set; 014 015import org.hl7.fhir.exceptions.FHIRException; 016import org.hl7.fhir.exceptions.FHIRFormatError; 017import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider; 018import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; 019import org.hl7.fhir.r5.context.ContextUtilities; 020import org.hl7.fhir.r5.context.IWorkerContext; 021import org.hl7.fhir.r5.elementmodel.Element; 022import org.hl7.fhir.r5.fhirpath.FHIRPathEngine.IEvaluationContext; 023import org.hl7.fhir.r5.model.Base; 024import org.hl7.fhir.r5.model.DomainResource; 025import org.hl7.fhir.r5.model.Enumeration; 026import org.hl7.fhir.r5.model.PrimitiveType; 027import org.hl7.fhir.r5.model.Resource; 028import org.hl7.fhir.r5.model.StringType; 029import org.hl7.fhir.r5.renderers.utils.RenderingContext.IResourceLinkResolver; 030import org.hl7.fhir.r5.renderers.utils.Resolver.IReferenceResolver; 031import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; 032import org.hl7.fhir.r5.utils.ToolingExtensions; 033import org.hl7.fhir.utilities.FhirPublication; 034import org.hl7.fhir.utilities.MarkDownProcessor; 035import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 036import org.hl7.fhir.utilities.MarkDownProcessor.Dialect; 037import org.hl7.fhir.utilities.StandardsStatus; 038import org.hl7.fhir.utilities.StringPair; 039import org.hl7.fhir.utilities.Utilities; 040import org.hl7.fhir.utilities.i18n.RenderingI18nContext; 041import org.hl7.fhir.utilities.validation.ValidationOptions; 042 043/** 044 * Managing Language when rendering 045 * 046 * You can specify a language to use when rendering resources by setting the setLocale() on 047 * the super class. The locale drives the following: 048 * - choice of java supplied rendering phrase, if translations are provided for the locale 049 * - integer and date formats used (but see below for date formats) 050 * - automatic translation of coded values, if language supplements are available 051 * - choosing text representation considering the FHIR translation extension 052 * 053 * By default, the locale is null, and the default locale for the underlying system is used. 054 * If you set locale to a specific value, then that value will be used instead of the default locale. 055 * 056 * By default, only a single language is rendered, based on the locale. Where resources contain 057 * multiple language content (designations in CodeSystem and ValueSet, or using the translation 058 * extension), you can control what languages are presented using the properties multiLanguagePolicy 059 * and languages 060 * - multiLanguagePolicy: NONE (default), DESIGNATIONS, ALL 061 * - languages: a list of allowed languages. Default is empty which means all languages in scope via multiLanguagePolicy 062 * 063 * Managing Date/Time Formatting 064 * 065 * This class has multiple parameters that influence date/time formatting when rendering resources 066 * 067 * - The default rendering is using the default java locale as above 068 * - If you setLocale() to something, then the defaults for the locale will be used 069 * - Else you can set the values of dateTimeFormat, dateFormat, dateYearFormat and dateYearMonthFormat 070 * 071 * If you set the value of locale, the values of dateTimeFormat, dateFormat, dateYearFormat and dateYearMonthFormat are 072 * reset to the system defaults 073 * 074 * Timezones: by default, date/times are rendered in their source timezone 075 * 076 */ 077@MarkedToMoveToAdjunctPackage 078public class RenderingContext extends RenderingI18nContext { 079 080 public interface IResourceLinkResolver { 081 public <T extends Resource> T findLinkableResource(Class<T> class_, String uri) throws IOException; 082 } 083 084 public static class RenderingContextLangs { 085 086 private RenderingContext defLangRC; 087 private Map<String, RenderingContext> langs = new HashMap<>(); 088 089 public RenderingContextLangs(RenderingContext defLangRC) { 090 this.defLangRC = defLangRC; 091 } 092 093 public void seeLang(String lang, RenderingContext rc) { 094 this.langs.put(lang, rc); 095 } 096 097 public RenderingContext get(String lang) { 098 if (lang == null || !langs.containsKey(lang)) { 099 return defLangRC; 100 } else { 101 return langs.get(lang); 102 } 103 } 104 } 105 106 // provides liquid templates, if they are available for the content 107 public interface ILiquidTemplateProvider { 108 String findTemplate(RenderingContext rcontext, DomainResource r); 109 String findTemplate(RenderingContext rcontext, String resourceName); 110 } 111 112 // parses xml to an XML instance. Whatever codes provides this needs to provide something that parses the right version 113 public interface ITypeParser { 114 Base parseType(String xml, String type) throws FHIRFormatError, IOException, FHIRException ; 115 Base parseType(Element base) throws FHIRFormatError, IOException, FHIRException ; 116 } 117 118 /** 119 * What kind of user the renderer is targeting - end users, or technical users 120 * 121 * This affects the way codes and references are rendered 122 * 123 * @author graha 124 * 125 */ 126 public enum ResourceRendererMode { 127 /** 128 * The user has no interest in the contents of the FHIR resource, and just wants to see the data 129 * 130 */ 131 END_USER, 132 133 /** 134 * The user wants to see the resource, but a technical view so they can see what's going on with the content - this includes content like the meta header 135 */ 136 TECHNICAL 137 } 138 139 public enum GenerationRules { 140 /** 141 * The output must be valid XHTML for a resource: no active content, etc. The only external dependency allowed is fhir.css 142 */ 143 VALID_RESOURCE, 144 145 /** 146 * The output must be valid for an implementation guide according ot the base FHIR template. 147 * This means active content is allowed, though the default presentation must be *show everything* for balloting purposes 148 * Active content is allowed 149 */ 150 IG_PUBLISHER 151 } 152 153 public enum StructureDefinitionRendererMode { 154 SUMMARY, // 5 cells: tree/name | flags | cardinality | type | details 155 BINDINGS, // tree/name + column for each kind of binding found, cells are lists of bindings 156 OBLIGATIONS, // tree/name + column for each actor that has obligations 157 DATA_DICT, // detailed element view 158 } 159 160 public enum ExampleScenarioRendererMode { 161 /** 162 * A visual presentation of the questionnaire, with a set of property panes that can be toggled on and off. 163 * Note that this is not the same as how the questionnaire would like on a form filler, since all dynamic behavior is ignored 164 */ 165 ACTORS, 166 167 /** 168 * A table listing all the instances (and versions there-of) used in a scenario 169 */ 170 INSTANCES, 171 172 /** 173 * Information about the processes (and sub-processes) defined in a scenario 174 */ 175 PROCESSES, 176 177 /** 178 * A diagram showing interactions between the actors as part of the process steps 179 */ 180 DIAGRAM 181 } 182 183 public enum QuestionnaireRendererMode { 184 /** 185 * A visual presentation of the questionnaire, with a set of property panes that can be toggled on and off. 186 * Note that this is not the same as how the questionnaire would like on a form filler, since all dynamic behavior is ignored 187 */ 188 FORM, 189 190 /** 191 * a structured tree that presents the content of the questionnaire in a logical fashion 192 */ 193 TREE, 194 195 /** 196 * A structured tree that presents the enableWhen, terminology and expression bindings for the questionnaire 197 */ 198 LOGIC, 199 200 /** 201 * A presentation that lists all the items, with full details about them 202 */ 203 DEFNS, 204 205 /** 206 * Rendered links to various openly available Form Filler applications that know how to render a questionnaire published in a package 207 */ 208 LINKS 209 } 210 211 212 public enum KnownLinkType { 213 SELF, // absolute link to where the content is to be found (only used in a few circumstances when making external references to tools) 214 SPEC, // version specific link to core specification 215 JSON_NAMES 216 217 } 218 219 public enum FixedValueFormat { 220 JSON, JSON_ALL, XML, XML_ALL; 221 222 public static FixedValueFormat fromCode(String value) { 223 if (value == null) { 224 return JSON; 225 } 226 switch (value.toLowerCase()) { 227 case "json" : return JSON; 228 case "json-all" : return JSON_ALL; 229 case "xml" : return XML; 230 case "xml-all" : return XML_ALL; 231 } 232 return JSON; 233 } 234 235 public boolean notPrimitives() { 236 return this == JSON || this == XML; 237 } 238 239 public boolean isXml() { 240 return this == XML_ALL || this == XML; 241 } 242 } 243 244 public enum MultiLanguagePolicy { 245 NONE, // ONLY render the language in the locale 246 DESIGNATIONS, // in addition to the locale language, render designations from other languages (eg. as found in code systems and value sets 247 ALL // in addition to translations in designations, look for an render translations (WIP) 248 } 249 250 private IWorkerContext worker; 251 private MarkDownProcessor markdown; 252 private ResourceRendererMode mode; 253 private GenerationRules rules; 254 private IReferenceResolver resolver; 255 private ILiquidTemplateProvider templateProvider; 256 private IEvaluationContext services; 257 private ITypeParser parser; 258 259 // i18n related fields 260 private boolean secondaryLang; // true if this is not the primary language for the resource 261 private MultiLanguagePolicy multiLanguagePolicy = MultiLanguagePolicy.NONE; 262 private Set<String> allowedLanguages = new HashSet<>(); 263 private ZoneId timeZoneId; 264 private DateTimeFormatter dateTimeFormat; 265 private DateTimeFormatter dateFormat; 266 private DateTimeFormatter dateYearFormat; 267 private DateTimeFormatter dateYearMonthFormat; 268 269 private String localPrefix; // relative link within local context 270 private int headerLevelContext; 271 private boolean canonicalUrlsAsLinks; 272 private boolean pretty; 273 private boolean showSummaryTable; // for canonical resources 274 private boolean contained; 275 276 private ValidationOptions terminologyServiceOptions = new ValidationOptions(FhirPublication.R5); 277 private boolean noSlowLookup; 278 private List<String> codeSystemPropList = new ArrayList<>(); 279 280 private ProfileUtilities profileUtilitiesR; 281 private ContextUtilities contextUtilities; 282 private String definitionsTarget; 283 private String destDir; 284 private boolean inlineGraphics; 285 private StandardsStatus defaultStandardsStatus; 286 287 private ExampleScenarioRendererMode scenarioMode = null; 288 private QuestionnaireRendererMode questionnaireMode = QuestionnaireRendererMode.FORM; 289 private StructureDefinitionRendererMode structureMode = StructureDefinitionRendererMode.SUMMARY; 290 private FixedValueFormat fixedFormat = FixedValueFormat.JSON; 291 292 private boolean showComments = false; 293 294 private FhirPublication targetVersion; 295 private boolean copyButton; 296 private ProfileKnowledgeProvider pkp; 297 private String changeVersion; 298 private List<String> files = new ArrayList<String>(); // files created as by-products in destDir 299 300 private Map<KnownLinkType, String> links = new HashMap<>(); 301 private Map<String, StringPair> namedLinks = new HashMap<>(); 302 private boolean addName = false; 303 private Map<String, String> typeMap = new HashMap<>(); // type aliases that can be resolved in Markdown type links (mainly for cross-version usage) 304 private int base64Limit = 1024; 305 private boolean shortPatientForm; 306 private String uniqueLocalPrefix; 307 private Set<String> anchors = new HashSet<>(); 308 private boolean unknownLocalReferencesNotLinks; 309 private IResourceLinkResolver resolveLinkResolver; 310 private boolean debug; 311 312 /** 313 * 314 * @param context - access to all related resources that might be needed 315 * @param markdown - appropriate markdown processing engine 316 * @param terminologyServiceOptions - options to use when looking up codes 317 * @param specLink - path to FHIR specification 318 * @param locale - i18n for rendering 319 */ 320 public RenderingContext(IWorkerContext worker, MarkDownProcessor markdown, ValidationOptions terminologyServiceOptions, String specLink, String localPrefix, Locale locale, ResourceRendererMode mode, GenerationRules rules) { 321 super(); 322 this.worker = worker; 323 this.markdown = markdown; 324 this.locale = locale; 325 this.links.put(KnownLinkType.SPEC, specLink); 326 this.localPrefix = localPrefix; 327 this.mode = mode; 328 this.rules = rules; 329 if (terminologyServiceOptions != null) { 330 this.terminologyServiceOptions = terminologyServiceOptions; 331 } 332 } 333 334 public RenderingContext copy(boolean copyAnchors) { 335 RenderingContext res = new RenderingContext(worker, markdown, terminologyServiceOptions, getLink(KnownLinkType.SPEC), localPrefix, locale, mode, rules); 336 337 res.resolver = resolver; 338 res.templateProvider = templateProvider; 339 res.services = services; 340 res.parser = parser; 341 342 res.headerLevelContext = headerLevelContext; 343 res.canonicalUrlsAsLinks = canonicalUrlsAsLinks; 344 res.pretty = pretty; 345 res.contained = contained; 346 347 res.noSlowLookup = noSlowLookup; 348 res.codeSystemPropList.addAll(codeSystemPropList); 349 350 res.profileUtilitiesR = profileUtilitiesR; 351 res.contextUtilities = contextUtilities; 352 res.definitionsTarget = definitionsTarget; 353 res.destDir = destDir; 354 res.scenarioMode = scenarioMode; 355 res.questionnaireMode = questionnaireMode; 356 res.structureMode = structureMode; 357 res.showSummaryTable = showSummaryTable; 358 res.links.putAll(links); 359 res.inlineGraphics = inlineGraphics; 360 res.timeZoneId = timeZoneId; 361 res.dateTimeFormat = dateTimeFormat; 362 res.dateFormat = dateFormat; 363 res.dateYearFormat = dateYearFormat; 364 res.dateYearMonthFormat = dateYearMonthFormat; 365 res.targetVersion = targetVersion; 366 res.showComments = showComments; 367 res.copyButton = copyButton; 368 res.pkp = pkp; 369 res.defaultStandardsStatus = defaultStandardsStatus; 370 res.changeVersion = changeVersion; 371 372 res.terminologyServiceOptions = terminologyServiceOptions.copy(); 373 res.typeMap.putAll(typeMap); 374 res.multiLanguagePolicy = multiLanguagePolicy; 375 res.allowedLanguages.addAll(allowedLanguages); 376 if (copyAnchors) { 377 res.anchors = anchors; 378 } 379 res.unknownLocalReferencesNotLinks = unknownLocalReferencesNotLinks; 380 res.resolveLinkResolver = resolveLinkResolver; 381 res.debug = debug; 382 return res; 383 } 384 385 386 public IWorkerContext getContext() { 387 return worker; 388 } 389 390 391 392 // -- 2. Markdown support ------------------------------------------------------- 393 394 public ProfileUtilities getProfileUtilities() { 395 if (profileUtilitiesR == null) { 396 profileUtilitiesR = new ProfileUtilities(worker, null, pkp); 397 } 398 return profileUtilitiesR; 399 } 400 401 public IWorkerContext getWorker() { 402 return worker; 403 } 404 405 public boolean isCanonicalUrlsAsLinks() { 406 return canonicalUrlsAsLinks; 407 } 408 409 public RenderingContext setCanonicalUrlsAsLinks(boolean canonicalUrlsAsLinks) { 410 this.canonicalUrlsAsLinks = canonicalUrlsAsLinks; 411 return this; 412 } 413 414 public MarkDownProcessor getMarkdown() { 415 if (markdown == null) { 416 markdown = new MarkDownProcessor(Dialect.COMMON_MARK); 417 } 418 return markdown; 419 } 420 421 public MultiLanguagePolicy getMultiLanguagePolicy() { 422 return multiLanguagePolicy; 423 } 424 425 public void setMultiLanguagePolicy(MultiLanguagePolicy multiLanguagePolicy) { 426 this.multiLanguagePolicy = multiLanguagePolicy; 427 } 428 429 public Set<String> getAllowedLanguages() { 430 return allowedLanguages; 431 } 432 433 public String getLocalPrefix() { 434 return localPrefix; 435 } 436 437 public ValidationOptions getTerminologyServiceOptions() { 438 return terminologyServiceOptions; 439 } 440 441 public int getHeaderLevelContext() { 442 return headerLevelContext; 443 } 444 445 public RenderingContext setHeaderLevelContext(int headerLevelContext) { 446 this.headerLevelContext = headerLevelContext; 447 return this; 448 } 449 450 public IReferenceResolver getResolver() { 451 return resolver; 452 } 453 454 public RenderingContext setResolver(IReferenceResolver resolver) { 455 this.resolver = resolver; 456 return this; 457 } 458 459 public RenderingContext setTerminologyServiceOptions(ValidationOptions terminologyServiceOptions) { 460 this.terminologyServiceOptions = terminologyServiceOptions; 461 return this; 462 } 463 464 public boolean isNoSlowLookup() { 465 return noSlowLookup; 466 } 467 468 public RenderingContext setNoSlowLookup(boolean noSlowLookup) { 469 this.noSlowLookup = noSlowLookup; 470 return this; 471 } 472 473 public String getDefinitionsTarget() { 474 return definitionsTarget; 475 } 476 477 public RenderingContext setDefinitionsTarget(String definitionsTarget) { 478 this.definitionsTarget = definitionsTarget; 479 return this; 480 } 481 482 public String getDestDir() { 483 return destDir; 484 } 485 486 public RenderingContext setDestDir(String destDir) { 487 this.destDir = destDir; 488 return this; 489 } 490 491 public RenderingContext setProfileUtilities(ProfileUtilities profileUtilities) { 492 this.profileUtilitiesR = profileUtilities; 493 if (pkp == null && profileUtilities.getPkp() != null) { 494 pkp = profileUtilities.getPkp(); 495 } 496 return this; 497 } 498 499 public ILiquidTemplateProvider getTemplateProvider() { 500 return templateProvider; 501 } 502 503 public RenderingContext setTemplateProvider(ILiquidTemplateProvider templateProvider) { 504 this.templateProvider = templateProvider; 505 return this; 506 } 507 508 public IEvaluationContext getServices() { 509 return services; 510 } 511 512 public RenderingContext setServices(IEvaluationContext services) { 513 this.services = services; 514 return this; 515 } 516 517 public boolean isPretty() { 518 return pretty; 519 } 520 521 public RenderingContext setPretty(boolean pretty) { 522 this.pretty = pretty; 523 return this; 524 } 525 526 public ITypeParser getParser() { 527 return parser; 528 } 529 530 public RenderingContext setParser(ITypeParser parser) { 531 this.parser = parser; 532 return this; 533 } 534 535 536 public List<String> getCodeSystemPropList() { 537 return codeSystemPropList; 538 } 539 540 public RenderingContext setCodeSystemPropList(List<String> codeSystemPropList) { 541 this.codeSystemPropList = codeSystemPropList; 542 return this; 543 } 544 545 546 public boolean isInlineGraphics() { 547 return inlineGraphics; 548 } 549 550 public RenderingContext setInlineGraphics(boolean inlineGraphics) { 551 this.inlineGraphics = inlineGraphics; 552 return this; 553 } 554 555 public boolean isShowSummaryTable() { 556 return showSummaryTable; 557 } 558 559 public RenderingContext setShowSummaryTable(boolean header) { 560 this.showSummaryTable = header; 561 return this; 562 } 563 564 public ExampleScenarioRendererMode getScenarioMode() { 565 return scenarioMode; 566 } 567 568 public RenderingContext setScenarioMode(ExampleScenarioRendererMode scenarioMode) { 569 this.scenarioMode = scenarioMode; 570 return this; 571 } 572 573 public QuestionnaireRendererMode getQuestionnaireMode() { 574 return questionnaireMode; 575 } 576 577 public RenderingContext setQuestionnaireMode(QuestionnaireRendererMode questionnaireMode) { 578 this.questionnaireMode = questionnaireMode; 579 return this; 580 } 581 582 public StructureDefinitionRendererMode getStructureMode() { 583 return structureMode; 584 } 585 586 public RenderingContext setStructureMode(StructureDefinitionRendererMode structureMode) { 587 this.structureMode = structureMode; 588 return this; 589 } 590 591 public String fixReference(String ref) { 592 if (ref == null) { 593 return null; 594 } 595 if (!Utilities.isAbsoluteUrl(ref)) { 596 return (localPrefix == null ? "" : localPrefix)+ref; 597 } 598 if (ref.startsWith("http://hl7.org/fhir") && !ref.substring(20).contains("/")) { 599 return getLink(KnownLinkType.SPEC)+ref.substring(20); 600 } 601 return ref; 602 } 603 604 public RenderingContext setLocalPrefix(String localPrefix) { 605 this.localPrefix = localPrefix; 606 return this; 607 } 608 609 public FhirPublication getTargetVersion() { 610 return targetVersion; 611 } 612 613 public RenderingContext setTargetVersion(FhirPublication targetVersion) { 614 this.targetVersion = targetVersion; 615 return this; 616 } 617 618 public boolean isTechnicalMode() { 619 return mode == ResourceRendererMode.TECHNICAL; 620 } 621 622 /** 623 * if the timezone is null, the rendering will default to the source timezone 624 * in the resource 625 * 626 * Note that if you're working server side, the FHIR project recommends the use 627 * of the Date header so that clients know what timezone the server defaults to, 628 * 629 * There is no standard way for the server to know what the client timezone is. 630 * In the case where the client timezone is unknown, the timezone should be null 631 * 632 * @return the specified timezone to render in 633 */ 634 public ZoneId getTimeZoneId() { 635 return timeZoneId; 636 } 637 638 public RenderingContext setTimeZoneId(ZoneId timeZoneId) { 639 this.timeZoneId = timeZoneId; 640 return this; 641 } 642 643 644 /** 645 * In the absence of a specified format, the renderers will default to 646 * the FormatStyle.MEDIUM for the current locale. 647 * 648 * @return the format to use 649 */ 650 public DateTimeFormatter getDateTimeFormat() { 651 return this.dateTimeFormat; 652 } 653 654 public RenderingContext setDateTimeFormat(DateTimeFormatter dateTimeFormat) { 655 this.dateTimeFormat = dateTimeFormat; 656 return this; 657 } 658 659 public RenderingContext setDateTimeFormatString(String dateTimeFormat) { 660 this.dateTimeFormat = DateTimeFormatter.ofPattern(dateTimeFormat); 661 return this; 662 } 663 664 /** 665 * In the absence of a specified format, the renderers will default to 666 * the FormatStyle.MEDIUM for the current locale. 667 * 668 * @return the format to use 669 */ 670 public DateTimeFormatter getDateFormat() { 671 return this.dateFormat; 672 } 673 674 public RenderingContext setDateFormat(DateTimeFormatter dateFormat) { 675 this.dateFormat = dateFormat; 676 return this; 677 } 678 679 public RenderingContext setDateFormatString(String dateFormat) { 680 this.dateFormat = DateTimeFormatter.ofPattern(dateFormat); 681 return this; 682 } 683 684 public DateTimeFormatter getDateYearFormat() { 685 return dateYearFormat; 686 } 687 688 public RenderingContext setDateYearFormat(DateTimeFormatter dateYearFormat) { 689 this.dateYearFormat = dateYearFormat; 690 return this; 691 } 692 693 public RenderingContext setDateYearFormatString(String dateYearFormat) { 694 this.dateYearFormat = DateTimeFormatter.ofPattern(dateYearFormat); 695 return this; 696 } 697 698 public DateTimeFormatter getDateYearMonthFormat() { 699 return dateYearMonthFormat; 700 } 701 702 public RenderingContext setDateYearMonthFormat(DateTimeFormatter dateYearMonthFormat) { 703 this.dateYearMonthFormat = dateYearMonthFormat; 704 return this; 705 } 706 707 public RenderingContext setDateYearMonthFormatString(String dateYearMonthFormat) { 708 this.dateYearMonthFormat = DateTimeFormatter.ofPattern(dateYearMonthFormat); 709 return this; 710 } 711 712 public ResourceRendererMode getMode() { 713 return mode; 714 } 715 716 public RenderingContext setMode(ResourceRendererMode mode) { 717 this.mode = mode; 718 return this; 719 } 720 721 public boolean isContained() { 722 return contained; 723 } 724 725 public RenderingContext setContained(boolean contained) { 726 this.contained = contained; 727 return this; 728 } 729 public boolean isShowComments() { 730 return showComments; 731 } 732 public RenderingContext setShowComments(boolean showComments) { 733 this.showComments = showComments; 734 return this; 735 } 736 public boolean isCopyButton() { 737 return copyButton; 738 } 739 public RenderingContext setCopyButton(boolean copyButton) { 740 this.copyButton = copyButton; 741 return this; 742 } 743 744 public RenderingContext setPkp(ProfileKnowledgeProvider pkp) { 745 this.pkp = pkp; 746 return this; 747 } 748 public ProfileKnowledgeProvider getPkp() { 749 return pkp; 750 } 751 752 public boolean hasLink(KnownLinkType link) { 753 return links.containsKey(link); 754 } 755 756 public String getLink(KnownLinkType link) { 757 return links.get(link); 758 } 759 public void addLink(KnownLinkType type, String link) { 760 links.put(type, link); 761 762 } 763 public GenerationRules getRules() { 764 return rules; 765 } 766 public RenderingContext setRules(GenerationRules rules) { 767 this.rules = rules; 768 return this; 769 } 770 public StandardsStatus getDefaultStandardsStatus() { 771 return defaultStandardsStatus; 772 } 773 public RenderingContext setDefaultStandardsStatus(StandardsStatus defaultStandardsStatus) { 774 this.defaultStandardsStatus = defaultStandardsStatus; 775 return this; 776 } 777 778 public String getChangeVersion() { 779 return changeVersion; 780 } 781 782 public RenderingContext setChangeVersion(String changeVersion) { 783 this.changeVersion = changeVersion; 784 return this; 785 } 786 787 public Map<String, StringPair> getNamedLinks() { 788 return namedLinks; 789 } 790 791 public void registerFile(String n) { 792 try { 793 files.add(Utilities.path(destDir, n)); 794 } catch (IOException e) { 795 } 796 } 797 798 public List<String> getFiles() { 799 return files; 800 } 801 802 public FixedValueFormat getFixedFormat() { 803 return fixedFormat; 804 } 805 806 public void setFixedFormat(FixedValueFormat fixedFormat) { 807 this.fixedFormat = fixedFormat; 808 } 809 810 public boolean isAddName() { 811 return addName; 812 } 813 814 public RenderingContext setAddName(boolean addName) { 815 this.addName = addName; 816 return this; 817 } 818 819 public Map<String, String> getTypeMap() { 820 return typeMap; 821 } 822 823 824 public String toStr(int v) { 825 NumberFormat nf = NumberFormat.getInstance(locale); 826 return nf.format(v); 827 } 828 829 830 public String getTranslated(PrimitiveType<?> t) { 831 if (locale != null) { 832 String v = ToolingExtensions.getLanguageTranslation(t, locale.toLanguageTag()); 833 if (v != null) { 834 return v; 835 } 836 } 837 return t.asStringValue(); 838 } 839 840 public String getTranslated(ResourceWrapper t) { 841 if (t == null) { 842 return null; 843 } 844 if (locale != null) { 845 for (ResourceWrapper e : t.extensions(ToolingExtensions.EXT_TRANSLATION)) { 846 String l = e.extensionString("lang"); 847 if (l != null && l.equals(locale.toLanguageTag())) { 848 String v = e.extensionString("content"); 849 if (v != null) { 850 return v; 851 } 852 } 853 } 854 } 855 return t.primitiveValue(); 856 } 857 858 public StringType getTranslatedElement(PrimitiveType<?> t) { 859 if (locale != null) { 860 StringType v = ToolingExtensions.getLanguageTranslationElement(t, locale.toLanguageTag()); 861 if (v != null) { 862 return v; 863 } 864 } 865 if (t instanceof StringType) { 866 return (StringType) t; 867 } else { 868 return new StringType(t.asStringValue()); 869 } 870 } 871 872 public String getTranslatedCode(Base b, String codeSystem) { 873 874 if (b instanceof org.hl7.fhir.r5.model.Element) { 875 org.hl7.fhir.r5.model.Element e = (org.hl7.fhir.r5.model.Element) b; 876 if (locale != null) { 877 String v = ToolingExtensions.getLanguageTranslation(e, locale.toLanguageTag()); 878 if (v != null) { 879 return v; 880 } 881 // no? then see if the tx service can translate it for us 882 try { 883 ValidationResult t = getContext().validateCode(getTerminologyServiceOptions().withLanguage(locale.toLanguageTag()).withVersionFlexible(true), 884 codeSystem, null, e.primitiveValue(), null); 885 if (t.isOk() && t.getDisplay() != null) { 886 return t.getDisplay(); 887 } 888 } catch (Exception ex) { 889 // nothing 890 } 891 } 892 if (e instanceof Enumeration<?>) { 893 return ((Enumeration<?>) e).getDisplay(); 894 } else { 895 return e.primitiveValue(); 896 } 897 } else if (b instanceof Element) { 898 return getTranslatedCode((Element) b, codeSystem); 899 } else { 900 return "??"; 901 } 902 } 903 904 public String getTranslatedCode(String code, String codeSystem) { 905 906 if (locale != null) { 907 try { 908 ValidationResult t = getContext().validateCode(getTerminologyServiceOptions().withLanguage(locale.toLanguageTag()).withVersionFlexible(true), codeSystem, null, code, null); 909 if (t.isOk() && t.getDisplay() != null) { 910 return t.getDisplay(); 911 } 912 } catch (Exception ex) { 913 // nothing 914 } 915 } 916 return code; 917 } 918 919 public String getTranslatedCode(Enumeration<?> e, String codeSystem) { 920 if (locale != null) { 921 String v = ToolingExtensions.getLanguageTranslation(e, locale.toLanguageTag()); 922 if (v != null) { 923 return v; 924 } 925 // no? then see if the tx service can translate it for us 926 try { 927 ValidationResult t = getContext().validateCode(getTerminologyServiceOptions().withLanguage(locale.toLanguageTag()).withVersionFlexible(true), 928 codeSystem, null, e.getCode(), null); 929 if (t.isOk() && t.getDisplay() != null) { 930 return t.getDisplay(); 931 } 932 } catch (Exception ex) { 933 // nothing 934 } 935 } 936 try { 937 ValidationResult t = getContext().validateCode(getTerminologyServiceOptions().withVersionFlexible(true), 938 codeSystem, null, e.getCode(), null); 939 if (t.isOk() && t.getDisplay() != null) { 940 return t.getDisplay(); 941 } 942 } catch (Exception ex) { 943 // nothing 944 } 945 946 return e.getCode(); 947 } 948 949 public String getTranslatedCode(Element e, String codeSystem) { 950 if (locale != null) { 951 // first we look through the translation extensions 952 for (Element ext : e.getChildrenByName("extension")) { 953 String url = ext.getNamedChildValue("url"); 954 if (url.equals(ToolingExtensions.EXT_TRANSLATION)) { 955 Base e1 = ext.getExtensionValue("lang"); 956 957 if (e1 != null && e1.primitiveValue() != null && e1.primitiveValue().equals(locale.toLanguageTag())) { 958 e1 = ext.getExtensionValue("content"); 959 if (e1 != null && e1.isPrimitive()) { 960 return e1.primitiveValue(); 961 } 962 } 963 } 964 } 965 // no? then see if the tx service can translate it for us 966 try { 967 ValidationResult t = getContext().validateCode(getTerminologyServiceOptions().withLanguage(locale.toLanguageTag()).withVersionFlexible(true), 968 codeSystem, null, e.primitiveValue(), null); 969 if (t.isOk() && t.getDisplay() != null) { 970 return t.getDisplay(); 971 } 972 } catch (Exception ex) { 973 // nothing 974 } 975 } 976 return e.primitiveValue(); 977 } 978 979 public RenderingContext withLocale(Locale locale) { 980 setLocale(locale); 981 return this; 982 } 983 984 public RenderingContext withLocaleCode(String locale) { 985 setLocale(new Locale(locale)); 986 return this; 987 } 988 989 public RenderingContext withMode(ResourceRendererMode mode) { 990 setMode(mode); 991 return this; 992 } 993 994 public ContextUtilities getContextUtilities() { 995 if (contextUtilities == null) { 996 contextUtilities = new ContextUtilities(worker); 997 } 998 return contextUtilities; 999 } 1000 1001 public int getBase64Limit() { 1002 return base64Limit; 1003 } 1004 1005 public void setBase64Limit(int base64Limit) { 1006 this.base64Limit = base64Limit; 1007 } 1008 1009 public boolean isShortPatientForm() { 1010 return shortPatientForm; 1011 } 1012 1013 public void setShortPatientForm(boolean shortPatientForm) { 1014 this.shortPatientForm = shortPatientForm; 1015 } 1016 1017 public boolean isSecondaryLang() { 1018 return secondaryLang; 1019 } 1020 1021 public void setSecondaryLang(boolean secondaryLang) { 1022 this.secondaryLang = secondaryLang; 1023 } 1024 1025 public String prefixAnchor(String anchor) { 1026 return uniqueLocalPrefix == null ? anchor : uniqueLocalPrefix+"-" + anchor; 1027 } 1028 1029 public String prefixLocalHref(String url) { 1030 if (url == null || uniqueLocalPrefix == null || !url.startsWith("#")) { 1031 return url; 1032 } 1033 return "#"+uniqueLocalPrefix+"-"+url.substring(1); 1034 } 1035 1036 public String getUniqueLocalPrefix() { 1037 return uniqueLocalPrefix; 1038 } 1039 1040 public void setUniqueLocalPrefix(String uniqueLocalPrefix) { 1041 this.uniqueLocalPrefix = uniqueLocalPrefix; 1042 } 1043 1044 public RenderingContext withUniqueLocalPrefix(String uniqueLocalPrefix) { 1045 RenderingContext self = this.copy(true); 1046 self.uniqueLocalPrefix = uniqueLocalPrefix; 1047 return self; 1048 } 1049 1050 public RenderingContext forContained() { 1051 RenderingContext self = this.copy(true); 1052 self.contained = true; 1053 return self; 1054 } 1055 1056 public boolean hasAnchor(String anchor) { 1057 return anchors.contains(anchor); 1058 } 1059 1060 public void addAnchor(String anchor) { 1061 anchors.add(anchor); 1062 } 1063 1064 public Set<String> getAnchors() { 1065 return anchors; 1066 } 1067 1068 public void clearAnchors() { 1069 anchors.clear(); 1070 } 1071 1072 public boolean isUnknownLocalReferencesNotLinks() { 1073 return unknownLocalReferencesNotLinks; 1074 } 1075 1076 public void setUnknownLocalReferencesNotLinks(boolean unknownLocalReferencesNotLinks) { 1077 this.unknownLocalReferencesNotLinks = unknownLocalReferencesNotLinks; 1078 } 1079 1080 public <T extends Resource> T findLinkableResource(Class<T> class_, String uri) throws IOException { 1081 if (resolveLinkResolver == null) { 1082 return null; 1083 } else { 1084 return resolveLinkResolver.findLinkableResource(class_, uri); 1085 } 1086 } 1087 1088 public IResourceLinkResolver getResolveLinkResolver() { 1089 return resolveLinkResolver; 1090 } 1091 1092 public void setResolveLinkResolver(IResourceLinkResolver resolveLinkResolver) { 1093 this.resolveLinkResolver = resolveLinkResolver; 1094 } 1095 1096 public boolean isDebug() { 1097 return debug; 1098 } 1099 1100 public void setDebug(boolean debug) { 1101 this.debug = debug; 1102 } 1103 1104}