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