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