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