001package org.hl7.fhir.r5.renderers; 002 003import java.io.IOException; 004import java.io.UnsupportedEncodingException; 005import java.util.ArrayList; 006import java.util.HashMap; 007import java.util.List; 008import java.util.Map; 009 010import javax.annotation.Nullable; 011 012import org.hl7.fhir.exceptions.DefinitionException; 013import org.hl7.fhir.exceptions.FHIRException; 014import org.hl7.fhir.exceptions.FHIRFormatError; 015import org.hl7.fhir.r5.model.CanonicalType; 016import org.hl7.fhir.r5.model.CapabilityStatement; 017import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestComponent; 018import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestResourceComponent; 019import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestResourceOperationComponent; 020import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent; 021import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementDocumentComponent; 022import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementMessagingComponent; 023import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementMessagingSupportedMessageComponent; 024import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementMessagingEndpointComponent; 025import org.hl7.fhir.r5.model.CapabilityStatement.ReferenceHandlingPolicy; 026import org.hl7.fhir.r5.model.CapabilityStatement.ResourceInteractionComponent; 027import org.hl7.fhir.r5.model.CapabilityStatement.SystemInteractionComponent; 028import org.hl7.fhir.r5.model.CapabilityStatement.SystemRestfulInteraction; 029import org.hl7.fhir.r5.model.CapabilityStatement.TypeRestfulInteraction; 030import org.hl7.fhir.r5.model.CodeType; 031import org.hl7.fhir.r5.model.CodeableConcept; 032import org.hl7.fhir.r5.model.Element; 033import org.hl7.fhir.r5.model.Enumeration; 034import org.hl7.fhir.r5.model.Enumerations.FHIRVersion; 035import org.hl7.fhir.r5.model.Extension; 036import org.hl7.fhir.r5.model.Resource; 037import org.hl7.fhir.r5.model.StringType; 038import org.hl7.fhir.r5.model.StructureDefinition; 039import org.hl7.fhir.r5.renderers.utils.RenderingContext; 040import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; 041import org.hl7.fhir.r5.renderers.utils.ResourceWrapper; 042import org.hl7.fhir.r5.utils.EOperationOutcome; 043import org.hl7.fhir.r5.utils.ToolingExtensions; 044import org.hl7.fhir.utilities.Utilities; 045import org.hl7.fhir.utilities.xhtml.XhtmlNode; 046 047 048public class CapabilityStatementRenderer extends ResourceRenderer { 049 050 public CapabilityStatementRenderer(RenderingContext context) { 051 super(context); 052 } 053 054 @Override 055 public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome { 056 if (r.isDirect()) { 057 renderResourceTechDetails(r, x); 058 render(status, x, (CapabilityStatement) r.getBase(), r); 059 } else { 060 // the intention is to change this in the future 061 x.para().tx("CapabilityStatementRenderer only renders native resources directly"); 062 } 063 } 064 065 @Override 066 public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException { 067 return canonicalTitle(r); 068 } 069 070 private static final String EXPECTATION = "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation"; 071 private static final String COMBINED = "http://hl7.org/fhir/StructureDefinition/capabilitystatement-search-parameter-combination"; 072 private static final String SP_BASE = "http://hl7.org/fhir/searchparameter/"; 073 private static final String FHIR_BASE = "http://hl7.org/fhir/"; 074 private static final String VERS_DEF_PREFIX = "FHIR Release "; 075 076 private String currentFhirBase = ""; 077 private String collapseClass = "panel-collapse in"; 078 079 private boolean multExpectationsPresent = false; 080 081 //Private classes for driving the rendering 082 083 private class CombinedSearchParamSet { 084 private Map<Boolean, List<SingleParam>> params; 085 String expectation = ""; 086 087 CombinedSearchParamSet(String expectation) { 088 params = new HashMap<Boolean, List<SingleParam>>(); 089 params.put(true, new ArrayList<SingleParam>()); 090 params.put(false, new ArrayList<SingleParam>()); 091 if (!Utilities.noString(expectation)) this.expectation = expectation; 092 } 093 094 public Map<Boolean, List<SingleParam>> getParams() { 095 return params; 096 } 097 098 public String getExpectation() { 099 return expectation; 100 } 101 102 public void addParam(boolean required, SingleParam param) { 103 params.get(required).add(param); 104 } 105 } 106 private class SingleParam { 107 private String name = ""; 108 private String definition = ""; 109 private String type = ""; 110 private String documentation = ""; 111 private String expectation = ""; 112 private String hostResource = ""; 113 114 public SingleParam(String name) { 115 if (!Utilities.noString(name)) this.name=name; 116 } 117 118 public SingleParam(String name, String definition) { 119 if (!Utilities.noString(name)) this.name=name; 120 if (!Utilities.noString(definition)) this.definition=definition; 121 } 122 123 public SingleParam(String name, String definition, String type) { 124 if (!Utilities.noString(name)) this.name=name; 125 if (!Utilities.noString(definition)) this.definition=definition; 126 if (!Utilities.noString(type)) this.type=type; 127 } 128 129 public SingleParam(String name, String definition, String type, String documentation) { 130 if (!Utilities.noString(name)) this.name=name; 131 if (!Utilities.noString(definition)) this.definition=definition; 132 if (!Utilities.noString(type)) this.type=type; 133 if (!Utilities.noString(documentation)) this.documentation=documentation; 134 } 135 136 public SingleParam(String name, String definition, String type, String documentation, String expectation, String hostResource) { 137 if (!Utilities.noString(name)) this.name=name; 138 if (!Utilities.noString(definition)) this.definition=definition; 139 if (!Utilities.noString(type)) this.type=type; 140 if (!Utilities.noString(documentation)) this.documentation=documentation; 141 if (!Utilities.noString(expectation)) this.expectation=expectation; 142 if (!Utilities.noString(hostResource)) this.hostResource = hostResource; 143 } 144 145 public String getName() { 146 return name; 147 } 148 149 public String getDefinition() { 150 return definition; 151 } 152 153 public String getDocumentation() { 154 return documentation; 155 } 156 157 public String getType() { 158 return type; 159 } 160 161 public String getExpectation() { 162 return expectation; 163 } 164 165 public String getHostResource() { 166 return hostResource; 167 } 168 } 169 private class ResourceSearchParams { 170 private Map<String, List<CombinedSearchParamSet>> combinedParams; 171 private Map<String, SingleParam> individualParamsByName; 172 private Map<String, List<SingleParam>> individualParamsByExp; 173 174 public ResourceSearchParams() { 175 combinedParams = new HashMap<String, List<CombinedSearchParamSet>>(); 176 combinedParams.put("SHALL", new ArrayList<CombinedSearchParamSet>()); 177 combinedParams.put("SHOULD", new ArrayList<CombinedSearchParamSet>()); 178 combinedParams.put("SHOULD-NOT", new ArrayList<CombinedSearchParamSet>()); 179 combinedParams.put("MAY", new ArrayList<CombinedSearchParamSet>()); 180 combinedParams.put("supported", new ArrayList<CombinedSearchParamSet>()); 181 individualParamsByName = new HashMap<String, SingleParam>(); 182 individualParamsByExp = new HashMap<String, List<SingleParam>>(); 183 individualParamsByExp.put("SHALL", new ArrayList<SingleParam>()); 184 individualParamsByExp.put("SHOULD", new ArrayList<SingleParam>()); 185 individualParamsByExp.put("MAY", new ArrayList<SingleParam>()); 186 individualParamsByExp.put("SHOULD-NOT", new ArrayList<SingleParam>()); 187 individualParamsByExp.put("supported", new ArrayList<SingleParam>()); 188 } 189 190 public Map<String, List<CombinedSearchParamSet>> getCombined() { 191 return combinedParams; 192 } 193 194 public Map<String, SingleParam> getInd() { 195 return individualParamsByName; 196 } 197 198 public Map<String, SingleParam> getIndbyName() { 199 return individualParamsByName; 200 } 201 202 public Map<String, List<SingleParam>> getIndbyExp() { 203 return individualParamsByExp; 204 } 205 206 public void addCombinedParamSet(String exp, CombinedSearchParamSet params) { 207 combinedParams.get(exp).add(params); 208 } 209 210 public void addIndividualbyName(String name, SingleParam param) { 211 individualParamsByName.put(name, param); 212 } 213 214 public void addIndividualbyExp(String exp, SingleParam param) { 215 individualParamsByExp.get(exp).add(param); 216 } 217 218 } 219 220 private class SingleOperation { 221 private String name = ""; 222 private String definition = ""; 223 private String documentation = ""; 224 private String expectation = ""; 225 226 public SingleOperation(String name) { 227 if (!Utilities.noString(name)) this.name=name; 228 } 229 230 public SingleOperation(String name, String definition) { 231 if (!Utilities.noString(name)) this.name=name; 232 if (!Utilities.noString(definition)) this.definition=definition; 233 } 234 235 public SingleOperation(String name, String definition, String documentation) { 236 if (!Utilities.noString(name)) this.name=name; 237 if (!Utilities.noString(definition)) this.definition=definition; 238 239 if (!Utilities.noString(documentation)) this.documentation=documentation; 240 } 241 242 public SingleOperation(String name, String definition, String documentation, String expectation) { 243 if (!Utilities.noString(name)) this.name=name; 244 if (!Utilities.noString(definition)) this.definition=definition; 245 if (!Utilities.noString(documentation)) this.documentation=documentation; 246 if (!Utilities.noString(expectation)) this.expectation=expectation; 247 } 248 249 public String getName() { 250 return name; 251 } 252 253 public String getDefinition() { 254 return definition; 255 } 256 257 public String getDocumentation() { 258 return documentation; 259 } 260 261 public String getExpectation() { 262 return expectation; 263 } 264 } 265 266 private class ResourceOperations { 267 private Map<String, List<SingleOperation>> operationsByExp; 268 269 public ResourceOperations() { 270 271 operationsByExp = new HashMap<String, List<SingleOperation>>(); 272 operationsByExp.put("SHALL", new ArrayList<SingleOperation>()); 273 operationsByExp.put("SHOULD", new ArrayList<SingleOperation>()); 274 operationsByExp.put("MAY", new ArrayList<SingleOperation>()); 275 operationsByExp.put("SHOULD-NOT", new ArrayList<SingleOperation>()); 276 operationsByExp.put("supported", new ArrayList<SingleOperation>()); 277 } 278 279 public Map<String, List<SingleOperation>> getOperations() { 280 return operationsByExp; 281 } 282 public void addOperation(String exp, SingleOperation op) { 283 operationsByExp.get(exp).add(op); 284 } 285 286 } 287 288 private class ResourceInteraction { 289 private String codeString; 290 private String documentation; 291 public ResourceInteraction(String code, String markdown) { 292 codeString = code; 293 if (!Utilities.noString(markdown)) { 294 documentation = markdown; 295 } 296 else { 297 documentation = null; 298 } 299 } 300 301 public String getDocumentation() { 302 return documentation; 303 } 304 305 public String getInteraction() { 306 return codeString; 307 } 308 } 309 310 311 312 public void render(RenderingStatus status, XhtmlNode x, CapabilityStatement conf, ResourceWrapper res) throws FHIRFormatError, DefinitionException, IOException { 313 status.setExtensions(true); 314 boolean igRenderingMode = (context.getRules() == GenerationRules.IG_PUBLISHER); 315 FHIRVersion currentVersion = conf.getFhirVersion(); 316 String versionPathComponent = getVersionPathComponent(currentVersion.getDefinition()); 317 if (!Utilities.noString(versionPathComponent)) { 318 currentFhirBase = FHIR_BASE + versionPathComponent + "/"; 319 } 320 else { 321 currentFhirBase = FHIR_BASE; 322 } 323 324 String igVersion = conf.getVersion(); 325 326 x.h(2,"title").addText(conf.getTitle()); 327 XhtmlNode uList = x.ul(); 328 uList.li().addText(context.formatPhrase(RenderingContext.CAPABILITY_IMP_VER, igVersion) + " "); 329 uList.li().addText(context.formatPhrase(RenderingContext.CAPABILITY_FHIR_VER, currentVersion.toCode()) + " "); 330 addSupportedFormats(uList, conf); 331 332 uList.li().addText(context.formatPhrase(RenderingContext.CAPABILITY_PUB_ON, displayDateTime(wrapWC(res, conf.getDateElement())) + " ")); 333 uList.li().addText(context.formatPhrase(RenderingContext.CAPABILITY_PUB_BY, conf.getPublisherElement().asStringValue()) + " "); 334 335 336 XhtmlNode block = x.addTag("blockquote").attribute("class","impl-note"); 337 block.addTag("p").addTag("strong").addText(context.formatPhrase(RenderingContext.CAPABILITY_NOTE_CAP)); 338 block.addTag("p").addText(context.formatPhrase(RenderingContext.CAPABILTY_ALLOW_CAP)); 339 340 341 addSupportedCSs(status, x, conf, res); 342 addSupportedIGs(x, conf); 343 344 int restNum = conf.getRest().size(); 345 int nextLevel = 3; 346 if (restNum > 0) { 347 x.h(2,"rest").addText((context.formatPhrase(RenderingContext.CAPABILITY_REST_CAPS))); 348 int count=1; 349 for (CapabilityStatementRestComponent rest : conf.getRest()) { 350 if (restNum > 1) { 351 x.h(3,"rest"+Integer.toString(count)).addText(context.formatPhrase(RenderingContext.CAPABILITY_REST_CONFIG, Integer.toString(count)) + " "); 352 nextLevel = 4; 353 } 354 addRestConfigPanel(x, rest, nextLevel, count); 355 356 boolean hasVRead = false; 357 boolean hasPatch = false; 358 boolean hasDelete = false; 359 boolean hasHistory = false; 360 boolean hasUpdates = false; 361 for (CapabilityStatementRestResourceComponent r : rest.getResource()) { 362 hasVRead = hasVRead || hasOp(r, TypeRestfulInteraction.VREAD); 363 hasPatch = hasPatch || hasOp(r, TypeRestfulInteraction.PATCH); 364 hasDelete = hasDelete || hasOp(r, TypeRestfulInteraction.DELETE); 365 hasHistory = hasHistory || hasOp(r, TypeRestfulInteraction.HISTORYTYPE); 366 hasUpdates = hasUpdates || hasOp(r, TypeRestfulInteraction.HISTORYINSTANCE); 367 } 368 if (rest.getResource().size() >0) { 369 x.h(nextLevel,"resourcesCap" + Integer.toString(count)).addText(context.formatPhrase(RenderingContext.CAPABILITY_RES_PRO)); 370 x.h(nextLevel+1,"resourcesSummary" + Integer.toString(count)).addText(context.formatPhrase(RenderingContext.GENERAL_SUMM)); 371 addSummaryIntro(x); 372 addSummaryTable(status, res, x, rest, hasVRead, hasPatch, hasDelete, hasHistory, hasUpdates, count); 373 x.addTag("hr"); 374 //Third time for individual resources 375 int resCount = 1; 376 for (CapabilityStatementRestResourceComponent r : rest.getResource()) { 377 addResourceConfigPanel(status, res, x, r, nextLevel+1, count, resCount, igRenderingMode); 378 resCount++; 379 } 380 } 381 if (rest.getOperation().size() > 0) { 382 //TODO Figure out what should come out of this 383 x.h(nextLevel,"operationsCap" + Integer.toString(count)).addText(context.formatPhrase(RenderingContext.CAPABILITY_OP)); 384 x.h(nextLevel+1,"operationsSummary" + Integer.toString(count)).addText(context.formatPhrase(RenderingContext.OP_DEF_USE)); 385 } 386 count++; 387 } 388 } 389 390 int messagingNum = conf.getMessaging().size(); 391 nextLevel = 3; 392 if (messagingNum > 0) { 393 x.h(2,"messaging").addText((context.formatPhrase(RenderingContext.CAPABILITY_MESSAGING_CAPS))); 394 int count=1; 395 for (CapabilityStatementMessagingComponent msg : conf.getMessaging()) 396 { 397 addMessagingPanel(status, res, x, msg, nextLevel, count, messagingNum); 398 count++; 399 } 400 401 } 402 403 int documentNum = conf.getDocument().size(); 404 nextLevel = 3; 405 if (documentNum > 0) { 406 x.h(2,"document").addText((context.formatPhrase(RenderingContext.CAPABILITY_DOCUMENT_CAPS))); 407 addDocumentTable(status, res, x, conf, nextLevel); 408 } 409 410 411 if (multExpectationsPresent) { 412 addWarningPanel(x,"?? - " + context.formatPhrase(RenderingContext.CAPABILITY_MULT_EXT)); 413 } 414 415 } 416 417 private String getVersionPathComponent(String definition) { 418 if (Utilities.noString(definition)) return ""; 419 if (!definition.startsWith(VERS_DEF_PREFIX)) return ""; 420 String restOfDef[] = definition.substring(VERS_DEF_PREFIX.length()).split(" "); 421 if (restOfDef[1].startsWith("(")) return "R"+restOfDef[0]; 422 return ""; 423 } 424 425 public void describe(XhtmlNode x, CapabilityStatement cs) { 426 x.tx(display(cs)); 427 } 428 429 public String display(CapabilityStatement cs) { 430 return cs.present(); 431 } 432 433 private boolean hasOp(CapabilityStatementRestResourceComponent r, TypeRestfulInteraction on) { 434 for (ResourceInteractionComponent op : r.getInteraction()) { 435 if (op.getCode() == on) 436 return true; 437 } 438 return false; 439 } 440 441 private String showOp(CapabilityStatementRestResourceComponent r, TypeRestfulInteraction on) { 442 for (ResourceInteractionComponent op : r.getInteraction()) { 443 if (op.getCode() == on) 444 return "y"; 445 } 446 return ""; 447 } 448 449 private String showOp(CapabilityStatementRestComponent r, SystemRestfulInteraction on) { 450 for (SystemInteractionComponent op : r.getInteraction()) { 451 if (op.getCode() == on) 452 return "y"; 453 } 454 return ""; 455 } 456 457 private XhtmlNode addTableRow(XhtmlNode t, String name) { 458 XhtmlNode tr = t.tr(); 459 tr.td().addText(name); 460 return tr.td(); 461 } 462 463 private void addTableRow(XhtmlNode t, String name, String value) { 464 XhtmlNode tr = t.tr(); 465 tr.td().addText(name); 466 tr.td().addText(value); 467 } 468 469 @Nullable 470 private String getExtValueCode(Extension ext) { 471 if (ext != null) { 472 return ext.getValueCodeType().getCode(); 473 } 474 return null; 475 } 476 477 private void addSupportedCSs(RenderingStatus status, XhtmlNode x, CapabilityStatement cap, ResourceWrapper res) throws UnsupportedEncodingException, IOException { 478 if (cap.hasInstantiates()) { 479 XhtmlNode p = x.para(); 480 p.tx(cap.getInstantiates().size() > 1 ? "This CapabilityStatement instantiates these CapabilityStatements " : "This CapabilityStatement instantiates the CapabilityStatement "); 481 boolean first = true; 482 for (CanonicalType ct : cap.getInstantiates()) { 483 if (first) {first = false;} else {p.tx(", ");}; 484 renderCanonical(status, res, p, CapabilityStatement.class, ct); 485 } 486 } 487 if (cap.hasImports()) { 488 XhtmlNode p = x.para(); 489 p.tx(cap.getImports().size() > 1 ? "This CapabilityStatement imports these CapabilityStatements " : "This CapabilityStatement imports the CapabilityStatement "); 490 boolean first = true; 491 for (CanonicalType ct : cap.getImports()) { 492 if (first) {first = false;} else {p.tx(", ");}; 493 renderCanonical(status, res, p, CapabilityStatement.class, ct); 494 } 495 } 496 } 497 498 private void addSupportedIGs(XhtmlNode x, CapabilityStatement cap) { 499 String capExpectation=null; 500 if (cap.hasImplementationGuide()) { 501 ArrayList<String> igShoulds = new ArrayList<String>(); 502 ArrayList<String> igShalls = new ArrayList<String>(); 503 ArrayList<String> igMays = new ArrayList<String>(); 504 int i=0; 505 for (CanonicalType c : cap.getImplementationGuide()) 506 { 507 capExpectation=getExtValueCode(c.getExtensionByUrl(EXPECTATION)); 508 if (!Utilities.noString(capExpectation)) { 509 if (capExpectation.equals("SHALL")) { 510 igShalls.add(c.asStringValue()); 511 } 512 else if (capExpectation.equals("SHOULD")) { 513 igShoulds.add(c.asStringValue()); 514 } 515 else if (capExpectation.equals("MAY")) { 516 igMays.add(c.asStringValue()); 517 } 518 } 519 else { 520 igShalls.add(c.asStringValue()); //default to SHALL 521 } 522 } 523 XhtmlNode ul = null; 524 if (igShalls.size() > 0) { 525 x.h(3,"shallIGs").addText(context.formatPhrase(RenderingContext.CAPABILTY_SHALL_SUPP)); 526 ul = x.ul(); 527 for (String url : igShalls) { 528 addResourceLink(ul.li(), url, url); 529 //ul.li().ah(url).addText(url); 530 } 531 } 532 if (igShoulds.size() > 0) { 533 x.h(3,"shouldIGs").addText(context.formatPhrase(RenderingContext.CAPABILITY_SHOULD_SUPP)); 534 ul = x.ul(); 535 for (String url : igShoulds) { 536 addResourceLink(ul.li(), url, url); 537 //ul.li().ah(url).addText(url); 538 } 539 } 540 if (igMays.size() > 0) { 541 x.h(3,"mayIGs").addText(context.formatPhrase(RenderingContext.CAPABILITY_MAY_SUPP)); 542 ul = x.ul(); 543 for (String url : igMays) { 544 addResourceLink(ul.li(), url, url); 545 //ul.li().ah(url).addText(url); 546 } 547 } 548 549 } 550 } 551 552 private void addSupportedFormats(XhtmlNode uList, CapabilityStatement conf) { 553 XhtmlNode lItem = uList.li(); 554 lItem.addText(context.formatPhrase(RenderingContext.CAPABILITY_SUPP_FORM) + " "); 555 Boolean first = true; 556 String capExpectation = null; 557 for (CodeType c : conf.getFormat()) { 558 if (!first) { 559 lItem.addText(", "); 560 } 561 capExpectation = getExtValueCode(c.getExtensionByUrl(EXPECTATION)); 562 if (!Utilities.noString(capExpectation)) { 563 lItem.addTag("strong").addText(capExpectation); 564 lItem.addText(" "+ (context.formatPhrase(RenderingContext.CAPABILITY_SUPP) + " ")); 565 } 566 lItem.code().addText(c.getCode()); 567 first = false; 568 } 569 lItem = uList.li(); 570 lItem.addText(context.formatPhrase(RenderingContext.CAPABILITY_SUPP_PATCH_FORM) + " "); 571 first=true; 572 for (CodeType c : conf.getPatchFormat()) { 573 if (!first) { 574 lItem.addText(", "); 575 } 576 capExpectation = getExtValueCode(c.getExtensionByUrl(EXPECTATION)); 577 if (!Utilities.noString(capExpectation)) { 578 lItem.addTag("strong").addText(capExpectation); 579 lItem.addText(" " + context.formatPhrase(RenderingContext.CAPABILITY_SUPP) + " "); 580 } 581 lItem.code().addText(c.getCode()); 582 first = false; 583 } 584 } 585 586 private void addRestConfigPanel(XhtmlNode x, CapabilityStatementRestComponent rest, int nextLevel, int count) throws FHIRFormatError, DefinitionException, IOException { 587 XhtmlNode panel= null; 588 XhtmlNode body = null; 589 XhtmlNode row = null; 590 XhtmlNode cell = null; 591 XhtmlNode heading = null; 592 panel = x.div().attribute("class", "panel panel-default"); 593 heading = panel.div().attribute("class", "panel-heading").h(nextLevel,"mode" + Integer.toString(count)).attribute("class", "panel-title"); 594 heading.addText("Mode: "); 595 heading.code().addText(rest.getMode().toCode()); 596 body = panel.div().attribute("class", "panel-body"); 597 addMarkdown(body, rest.getDocumentation()); 598 //Security info 599 if (rest.hasSecurity()) { 600 body.div().attribute("class","lead").addTag("em").addText("Security"); 601 String mdText = rest.getSecurity().getDescription(); 602 boolean cors = rest.getSecurity().getCors(); 603 List<CodeableConcept> services = rest.getSecurity().getService(); 604 if (cors || services.size() >0) { 605 row = body.div().attribute("class","row"); 606 row.div().attribute("class","col-lg-6").addText(getCorsText(cors)); 607 cell = row.div().attribute("class","col-lg-6"); 608 cell.addText("Security services supported: "); 609 addSeparatedListOfCodes(cell, getSecServices(services), ","); 610 } 611 612 if (!Utilities.noString(mdText)) { 613 addMarkdown(body.blockquote(),mdText); 614 } 615 } 616 body.div().attribute("class","lead").addTag("em").addText(context.formatPhrase(RenderingContext.CAPABILITY_SUMM_SYS_INT)); 617 addSystemInteractions(body, rest.getInteraction()); 618 619 } 620 621 private void addMessagingPanel(RenderingStatus status, ResourceWrapper res, XhtmlNode x, CapabilityStatementMessagingComponent msg, int nextLevel, int index, int total) throws FHIRFormatError, DefinitionException, IOException { 622 XhtmlNode panel= null; 623 XhtmlNode body = null; 624 XhtmlNode row = null; 625 XhtmlNode heading = null; 626 627 XhtmlNode table; 628 XhtmlNode tbody; 629 XhtmlNode tr; 630 631 panel = x.div().attribute("class", "panel panel-default"); 632 heading = panel.div().attribute("class", "panel-heading").h(nextLevel,"messaging_" + Integer.toString(index)).attribute("class", "panel-title"); 633 if(total == 1) 634 { 635 heading.addText(context.formatPhrase(RenderingContext.CAPABILITY_MESSAGING_CAP)); 636 } 637 else 638 { 639 heading.addText(context.formatPhrase(RenderingContext.CAPABILITY_MESSAGING_CAP) + " " + String.valueOf(index)); 640 } 641 642 body = panel.div().attribute("class", "panel-body"); 643 644 if(msg.hasReliableCache()) 645 { 646 addLead(body, "Reliable Cache Length"); 647 body.br(); 648 body.addText(String.valueOf(msg.getReliableCache()) + " Minute(s)"); 649 body.br(); 650 } 651 652 if(msg.hasEndpoint()) 653 { 654 body.h(nextLevel+1,"msg_end_"+Integer.toString(index)).addText(context.formatPhrase(RenderingContext.CAPABILITY_ENDPOINTS)); 655 table = body.table("table table-condensed table-hover"); 656 tr = table.addTag("thead").tr(); 657 tr.th().addText("Protocol"); 658 tr.th().addText("Address"); 659 660 tbody = table.addTag("tbody"); 661 for (CapabilityStatementMessagingEndpointComponent end : msg.getEndpoint()) 662 { 663 tr = tbody.tr(); 664 renderDataType(status, tr.td(), wrapNC(end.getProtocol())); 665 renderUri(status, tr.td(), wrapNC(end.getAddressElement())); 666 } 667 body.br(); 668 } 669 670 if(msg.hasSupportedMessage()) 671 { 672 body.h(nextLevel+1,"msg_end_"+Integer.toString(index)).addText(context.formatPhrase(RenderingContext.CAPABILITY_SUPP_MSGS)); 673 table = body.table("table table-condensed table-hover"); 674 tr = table.addTag("thead").tr(); 675 tr.th().addText("Mode"); 676 tr.th().addText(context.formatPhrase(RenderingContext.GENERAL_DEFINITION)); 677 678 tbody = table.addTag("tbody"); 679 for (CapabilityStatementMessagingSupportedMessageComponent sup : msg.getSupportedMessage()) 680 { 681 tr = tbody.tr(); 682 tr.td().addText(sup.getMode().toCode()); 683 renderCanonical(status, res, tr.td(), StructureDefinition.class, sup.getDefinitionElement()); 684 } 685 if(msg.hasDocumentation()) 686 { 687 addLead(body, context.formatPhrase(RenderingContext.GENERAL_DOCUMENTATION)); 688 addMarkdown(body.blockquote(), msg.getDocumentation()); 689 } 690 body.br(); 691 } 692 } 693 694 695 private void addDocumentTable(RenderingStatus status, ResourceWrapper res, XhtmlNode x, CapabilityStatement conf, int nextLevel) throws FHIRFormatError, DefinitionException, IOException { 696 XhtmlNode table; 697 XhtmlNode tbody; 698 XhtmlNode tr; 699 700 table = x.table("table table-condensed table-hover"); 701 tr = table.addTag("thead").tr(); 702 tr.th().addText("Mode"); 703 tr.th().addText(context.formatPhrase(RenderingContext.CAPABILITY_PROF_RES_DOC)); 704 tr.th().addText(context.formatPhrase(RenderingContext.GENERAL_DOCUMENTATION)); 705 706 tbody = table.addTag("tbody"); 707 for (CapabilityStatementDocumentComponent document : conf.getDocument()) { 708 tr = tbody.tr(); 709 tr.td().addText(document.getMode().toCode()); 710 renderCanonical(status, res, tr.td(), StructureDefinition.class, document.getProfileElement()); 711 if(document.hasDocumentation()) 712 { 713 addMarkdown(tr.td(), document.getDocumentation()); 714 } 715 else 716 { 717 tr.td().nbsp(); 718 } 719 } 720 } 721 722 private String getCorsText(boolean on) { 723 if (on) { 724 return context.formatPhrase(RenderingContext.CAPABILITY_CORS_YES); 725 } 726 return context.formatPhrase(RenderingContext.CAPABILITY_CORS_NO); 727 } 728 729 private List<String> getSecServices(List<CodeableConcept> services) 730 { 731 List<String> serviceStrings = new ArrayList<String>(); 732 for (CodeableConcept c: services) { 733 if (c.hasCoding()){ 734 serviceStrings.add(c.getCodingFirstRep().getCode()); 735 } 736 else { 737 serviceStrings.add(c.getText()); 738 } 739 } 740 return serviceStrings; 741 } 742 743 744 private void addSystemInteractions(XhtmlNode body, List<SystemInteractionComponent> interactions) { 745 if (interactions.size()==0) return; 746 XhtmlNode uList = body.ul(); 747 String capExpectation = null; 748 String expName = null; 749 String documentation = null; 750 Map<String,String> expression = null; 751 ArrayList<Map<String,String>> shalls = new ArrayList<Map<String,String>>(); 752 ArrayList<Map<String,String>> shoulds = new ArrayList<Map<String,String>>(); 753 ArrayList<Map<String,String>> mays = new ArrayList<Map<String,String>>(); 754 ArrayList<Map<String,String>> shouldnots = new ArrayList<Map<String,String>>(); 755 ArrayList<Map<String,String>> supports = new ArrayList<Map<String,String>>(); 756 for (SystemInteractionComponent comp : interactions) { 757 capExpectation=getExtValueCode(comp.getExtensionByUrl(EXPECTATION)); 758 expName = comp.getCode().toCode(); 759 documentation = comp.getDocumentation(); 760 if (Utilities.noString(documentation)) { 761 documentation=""; 762 } 763 expression = new HashMap<String,String>(); 764 expression.put(expName,documentation); 765 if (!Utilities.noString(capExpectation)) { 766 if (capExpectation.equals("SHALL")) { 767 shalls.add(expression); 768 } 769 else if (capExpectation.equals("SHOULD")) { 770 shoulds.add(expression); 771 } 772 else if (capExpectation.equals("MAY")) { 773 mays.add(expression); 774 } 775 else if (capExpectation.equals("SHOULD-NOT")) { 776 shouldnots.add(expression); 777 } 778 } 779 else { 780 supports.add(expression); 781 } 782 } 783 addInteractionListItems(uList, "SHALL", shalls); 784 addInteractionListItems(uList, "SHOULD", shoulds); 785 addInteractionListItems(uList, "MAY", mays); 786 addInteractionListItems(uList, "SHOULD NOT", shouldnots); 787 addInteractionListItems(uList, null, supports); 788 } 789 790 private void addInteractionListItems(XhtmlNode uList, String verb, List<Map<String,String>> interactions) { 791 XhtmlNode item = null; 792 String interaction = null; 793 String documentation = null; 794 for (Map<String,String> interactionMap : interactions) { 795 item = uList.li(); 796 if (Utilities.noString(verb)) { 797 item.addText(context.formatPhrase(RenderingContext.CAPABILITY_SUPPS_THE) + " "); 798 } 799 else { 800 item.addTag("strong").addText(verb + " "); 801 item.addText(context.formatPhrase(RenderingContext.CAPABILITY_SUPP_THE) + " "); 802 } 803 interaction = interactionMap.keySet().toArray()[0].toString(); 804 item.code(interaction); 805 documentation = interactionMap.get(interaction); 806 if (Utilities.noString(documentation)) { 807 item.addText(context.formatPhrase(RenderingContext.CAPABILITY_INT)); 808 } 809 else { 810 item.addText(context.formatPhrase(RenderingContext.CAPABILITY_INT_DESC)); 811 try { 812 addMarkdown(item, documentation); 813 } catch (FHIRFormatError e) { 814 // TODO Auto-generated catch block 815 e.printStackTrace(); 816 } catch (DefinitionException e) { 817 // TODO Auto-generated catch block 818 e.printStackTrace(); 819 } catch (IOException e) { 820 // TODO Auto-generated catch block 821 e.printStackTrace(); 822 } 823 } 824 } 825 } 826 827 private void addInteractionSummaryList(XhtmlNode uList, String verb, List<ResourceInteraction> interactions) { 828 if (interactions.size() == 0) return; 829 XhtmlNode item = uList.li(); 830 if (Utilities.noString(verb)) { 831 item.addText(context.formatPhrase(RenderingContext.CAPABILITY_SUPPS) + " "); 832 } 833 else { 834 item.addTag("strong").addText(verb); 835 item.addText(" " + context.formatPhrase(RenderingContext.CAPABILITY_SUPP) + " "); 836 } 837 838 applyInteractionsList(item, interactions); 839 } 840 841 private void addSummaryIntro(XhtmlNode x) { 842 XhtmlNode uList = null; 843 XhtmlNode lItem = null; 844 x.para().addText(context.formatPhrase(RenderingContext.CAPABILITY_SUMM_RES)); 845 uList=x.ul(); 846 uList.li().addText(context.formatPhrase(RenderingContext.CAPABILITY_REV_PROF)); 847 lItem = uList.li(); 848 lItem.addText(context.formatPhrase(RenderingContext.CAPABILITY_INTER_SUPP)); 849 lItem.b().addTag("span").attribute("class","bg-info").addText("R"); 850 lItem.addText("ead, "); 851 lItem.b().addTag("span").attribute("class","bg-info").addText("S"); 852 lItem.addText("earch, "); 853 lItem.b().addTag("span").attribute("class","bg-info").addText("U"); 854 lItem.addText("pdate, and "); 855 lItem.b().addTag("span").attribute("class","bg-info").addText("C"); 856 lItem.addText("reate, are always shown, while "); 857 lItem.b().addTag("span").attribute("class","bg-info").addText("VR"); 858 lItem.addText("ead, "); 859 lItem.b().addTag("span").attribute("class","bg-info").addText("P"); 860 lItem.addText("atch, "); 861 lItem.b().addTag("span").attribute("class","bg-info").addText("D"); 862 lItem.addText("elete, "); 863 lItem.b().addTag("span").attribute("class","bg-info").addText("H"); 864 lItem.addText("istory on "); 865 lItem.b().addTag("span").attribute("class","bg-info").addText("I"); 866 lItem.addText("nstance, or "); 867 lItem.b().addTag("span").attribute("class","bg-info").addText("H"); 868 lItem.addText("istory on "); 869 lItem.b().addTag("span").attribute("class","bg-info").addText("T"); 870 lItem.addText(context.formatPhrase(RenderingContext.CAPABILITY_TYP_PRES)); 871 uList.li().addTag("span").addText(context.formatPhrase(RenderingContext.CAPABILITY_SEARCH_PAR) + " "); 872 lItem = uList.li(); 873 lItem.addText(context.formatPhrase(RenderingContext.CAPABILITY_RES_ENB) + " "); 874 lItem.code().addText("_include"); 875 lItem = uList.li(); 876 lItem.addText(context.formatPhrase(RenderingContext.CAPABILITY_OTH_RES_ENB) + " "); 877 lItem.code().addText("_revinclude"); 878 uList.li().addText(context.formatPhrase(RenderingContext.CAPABILITY_RES_OPER)); 879 } 880 881 private void addSummaryTable(RenderingStatus status, ResourceWrapper res, XhtmlNode x, CapabilityStatement.CapabilityStatementRestComponent rest, boolean hasVRead, boolean hasPatch, boolean hasDelete, boolean hasHistory, boolean hasUpdates, int count) throws IOException { 882 XhtmlNode t = x.div().attribute("class","table-responsive").table("table table-condensed table-hover"); 883 XhtmlNode tr = t.addTag("thead").tr(); 884 tr.th().b().tx(context.formatPhrase(RenderingContext.CAPABILITY_RES_TYP)); 885 tr.th().b().tx(context.formatPhrase(RenderingContext.GENERAL_PROF)); 886 tr.th().attribute("class", "text-center").b().attribute("title", context.formatPhrase(RenderingContext.CAPABILITY_READ_INT)).tx("R"); 887 if (hasVRead) 888 tr.th().attribute("class", "text-center").b().attribute("title", context.formatPhrase(RenderingContext.CAPABILITY_VREAD_INT)).tx("V-R"); 889 tr.th().attribute("class", "text-center").b().attribute("title", context.formatPhrase(RenderingContext.CAPABILITY_SEARCH_INT)).tx("S"); 890 tr.th().attribute("class", "text-center").b().attribute("title", context.formatPhrase(RenderingContext.CAPABILITY_UPDATE_INT)).tx("U"); 891 if (hasPatch) 892 tr.th().attribute("class", "text-center").b().attribute("title", context.formatPhrase(RenderingContext.CAPABILITY_PATCH_INT)).tx("P"); 893 tr.th().attribute("class", "text-center").b().attribute("title", context.formatPhrase(RenderingContext.CAPABILITY_CREATE_INT)).tx("C"); 894 if (hasDelete) 895 tr.th().attribute("class", "text-center").b().attribute("title", context.formatPhrase(RenderingContext.CAPABILITY_DELETE_INT)).tx("D"); 896 if (hasUpdates) 897 tr.th().attribute("class", "text-center").b().attribute("title", context.formatPhrase(RenderingContext.CAPABILITY_HISTORY_INT)).tx("H-I"); 898 if (hasHistory) 899 tr.th().attribute("class", "text-center").b().attribute("title", context.formatPhrase(RenderingContext.CAPABILITY_HISTORY_TYPE)).tx("H-T"); 900 tr.th().b().attribute("title", context.formatPhrase(RenderingContext.CAPABILITY_REQ_RECOM)).tx(context.formatPhrase(RenderingContext.CAPABILITY_SEARCHES)); 901 tr.th().code().b().tx("_include"); 902 tr.th().code().b().tx("_revinclude"); 903 tr.th().b().tx(context.formatPhrase(RenderingContext.CAPABILITY_OP)); 904 905 XhtmlNode tbody = t.addTag("tbody"); 906 XhtmlNode profCell = null; 907 boolean hasProf = false; 908 boolean hasSupProf = false; 909 int resCount = 1; 910 String countString = ""; 911 for (CapabilityStatementRestResourceComponent r : rest.getResource()) { 912 tr = tbody.tr(); 913 countString = Integer.toString(count) + "-" + Integer.toString(resCount); 914 tr.td().ah("#" + r.getType() + countString).addText(r.getType()); 915 resCount++; 916 //Show profiles 917 profCell = tr.td(); 918 hasProf = r.hasProfile(); 919 hasSupProf = r.hasSupportedProfile(); 920 if ((!hasProf) && (!hasSupProf)) { 921 profCell.nbsp(); 922 } 923 else if (hasProf) { 924 addResourceLink(profCell, r.getProfile(), r.getProfile()); 925 //profCell.ah(r.getProfile()).addText(r.getProfile()); 926 if (hasSupProf) { 927 profCell.br(); 928 profCell.addTag("em").addText(context.formatPhrase(RenderingContext.CAPABILITY_ADD_SUPP_PROF)); 929 renderSupportedProfiles(status, res, profCell, r); 930 } 931 } 932 else { //Case of only supported profiles 933 profCell.addText(context.formatPhrase(RenderingContext.CAPABILITY_SUPP_PROFS)); 934 renderSupportedProfiles(status, res, profCell, r); 935 } 936 //Show capabilities 937 tr.td().attribute("class", "text-center").addText(showOp(r, TypeRestfulInteraction.READ)); 938 if (hasVRead) 939 tr.td().attribute("class", "text-center").addText(showOp(r, TypeRestfulInteraction.VREAD)); 940 tr.td().attribute("class", "text-center").addText(showOp(r, TypeRestfulInteraction.SEARCHTYPE)); 941 tr.td().attribute("class", "text-center").addText(showOp(r, TypeRestfulInteraction.UPDATE)); 942 if (hasPatch) 943 tr.td().attribute("class", "text-center").addText(showOp(r, TypeRestfulInteraction.PATCH)); 944 tr.td().attribute("class", "text-center").addText(showOp(r, TypeRestfulInteraction.CREATE)); 945 if (hasDelete) 946 tr.td().attribute("class", "text-center").addText(showOp(r, TypeRestfulInteraction.DELETE)); 947 if (hasUpdates) 948 tr.td().attribute("class", "text-center").addText(showOp(r, TypeRestfulInteraction.HISTORYINSTANCE)); 949 if (hasHistory) 950 tr.td().attribute("class", "text-center").addText(showOp(r, TypeRestfulInteraction.HISTORYTYPE)); 951 //Show search parameters 952 List<String> stringList = new ArrayList<String>(); 953 getParams(stringList,r.getSearchParam()); 954 getCombinedParams(stringList,r.getExtensionsByUrl(COMBINED)); 955 tr.td().addText(getSeparatedList(stringList,",")); 956 //Show supported includes 957 stringList = getStringListFromStringTypeList(r.getSearchInclude()); 958 addSeparatedListOfCodes(tr.td(), stringList, ","); 959 //Show supported revIncludes 960 stringList = getStringListFromStringTypeList(r.getSearchRevInclude()); 961 addSeparatedListOfCodes(tr.td(), stringList, ","); 962 //Show supported operations 963 stringList = getStringListFromOperations(r.getOperation()); 964 addSeparatedListOfCodes(tr.td(), stringList, ","); 965 } 966 } 967 968 private List<String> getCombinedParams(List<String> paramNames, List<Extension> paramExtensions) { 969 for (Extension e : paramExtensions) { 970 String capExpectation = expectationForDisplay(e,EXPECTATION); 971 if (!Utilities.noString(capExpectation)) { 972 if (capExpectation.equals("SHALL") || capExpectation.equals("SHOULD") || capExpectation.equals("MAY")) { 973 paramNames.add(printCombinedParams(e)); 974 } 975 } 976 } 977 return paramNames; 978 } 979 980 private void renderSupportedProfiles(RenderingStatus status, ResourceWrapper res, XhtmlNode profCell, CapabilityStatementRestResourceComponent r) throws IOException { 981 for (CanonicalType sp: r.getSupportedProfile()) { 982 profCell.br(); 983 profCell.nbsp().nbsp(); 984 renderCanonical(status, res, profCell, StructureDefinition.class, sp); 985 } 986 if (r.hasExtension(ToolingExtensions.EXT_PROFILE_MAPPING)) { 987 profCell.br(); 988 profCell.b().tx(context.formatPhrase(RenderingContext.CAPABILITY_PROF_MAP)); 989 XhtmlNode tbl = profCell.table("grid"); 990 boolean doco = false; 991 for (Extension ext : r.getExtensionsByUrl(ToolingExtensions.EXT_PROFILE_MAPPING)) { 992 doco = doco || ext.hasExtension("documentation"); 993 } 994 XhtmlNode tr = tbl.tr(); 995 tr.th().tx(context.formatPhrase(RenderingContext.GENERAL_CRIT)); 996 tr.th().tx(context.formatPhrase(RenderingContext.GENERAL_PROF)); 997 if (doco) { 998 tr.th().tx(context.formatPhrase(RenderingContext.GENERAL_CRIT)); 999 } 1000 for (Extension ext : r.getExtensionsByUrl(ToolingExtensions.EXT_PROFILE_MAPPING)) { 1001 tr = tbl.tr(); 1002 tr.td().code().tx(ToolingExtensions.readStringExtension(ext, "search")); 1003 String url = ToolingExtensions.readStringExtension(ext, "profile"); 1004 StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, url); 1005 if (sd != null) { 1006 tr.td().code().ah(sd.getWebPath()).tx(sd.present()); 1007 } else { 1008 tr.td().code().tx(url); 1009 } 1010 if (doco) { 1011 tr.td().code().markdown(ToolingExtensions.readStringExtension(ext, "documentation"), "documentation"); 1012 } 1013 } 1014 } 1015 } 1016 1017 private String printCombinedParams(Extension e) { 1018 StringBuilder params = new StringBuilder(); 1019 List<Extension> requiredParams = e.getExtensionsByUrl("required"); 1020 List<Extension> optionalParams = e.getExtensionsByUrl("optional"); 1021 boolean first = true; 1022 for (Extension param : requiredParams) { 1023 if (!first) { 1024 params.append("+"); 1025 } 1026 first = false; 1027 params.append(param.getValueStringType()); 1028 } 1029 for (Extension param : optionalParams) { 1030 params.append("+"); 1031 params.append(param.getValueStringType()); 1032 } 1033 return params.toString(); 1034 } 1035 1036 private List<String> getParams(List<String> paramNames, List<CapabilityStatementRestResourceSearchParamComponent> params) { 1037 for (CapabilityStatementRestResourceSearchParamComponent p : params) { 1038 String capExpectation = expectationForDisplay(p,EXPECTATION); 1039 if (!Utilities.noString(capExpectation)) { 1040 if (capExpectation.equals("SHALL") || capExpectation.equals("SHOULD") || capExpectation.equals("MAY")) { 1041 paramNames.add(p.getName()); 1042 } 1043 } 1044 else { //When there is not extension, assume parameters are required 1045 paramNames.add(p.getName()); 1046 } 1047 } 1048 return paramNames; 1049 } 1050 1051 private String getSeparatedList(List<String> list, String separator) { 1052 StringBuilder result = new StringBuilder(); 1053 boolean first = true; 1054 for (String s : list) { 1055 if (!first) { 1056 result.append(separator + " "); 1057 } 1058 first = false; 1059 result.append(s); 1060 } 1061 return result.toString(); 1062 } 1063 1064 private List<String> getStringListFromStringTypeList(List<StringType> list) { 1065 List<String> stringList = new ArrayList<String>(); 1066 for (StringType st : list) { 1067 stringList.add(st.asStringValue()); 1068 } 1069 return stringList; 1070 } 1071 1072 private void addSeparatedListOfCodes(XhtmlNode parent, List<String> list, String separator) { 1073 boolean first = true; 1074 for (String s : list) { 1075 if (!first) { 1076 parent.addText(separator + " "); 1077 } 1078 first = false; 1079 parent.code().addText(s); 1080 } 1081 } 1082 1083 private List<String> getStringListFromOperations(List<CapabilityStatementRestResourceOperationComponent> list) { 1084 List<String> result = new ArrayList<String>(); 1085 for (CapabilityStatementRestResourceOperationComponent op : list) { 1086 String capExpectation = expectationForDisplay(op,EXPECTATION); 1087 if (!Utilities.noString(capExpectation)) { 1088 if (capExpectation.equals("SHALL") || capExpectation.equals("SHOULD") || capExpectation.equals("MAY")) { 1089 result.add("$"+op.getName()); 1090 } 1091 } 1092 else { 1093 result.add("$"+op.getName()); 1094 } 1095 } 1096 return result; 1097 } 1098 1099 private void applyInteractionsList(XhtmlNode item, List<ResourceInteraction> list) { 1100 List<String> noDocList = new ArrayList<String>(); 1101 List<ResourceInteraction> docList = new ArrayList<ResourceInteraction>(); 1102 for (ResourceInteraction inter : list) { 1103 if (Utilities.noString(inter.getDocumentation())) { 1104 noDocList.add(inter.getInteraction()); 1105 } 1106 else { 1107 docList.add(inter); 1108 } 1109 } 1110 if (noDocList.size() > 0) { 1111 addSeparatedListOfCodes(item,noDocList, ","); 1112 } 1113 if (docList.size() > 0) { 1114 item.br(); 1115 for (ResourceInteraction inter : docList) { 1116 item.code().addText(inter.getInteraction()); 1117 try { 1118 addMarkdown(item, inter.getDocumentation()); 1119 } 1120 catch(IOException e) { 1121 e.printStackTrace(); 1122 } 1123 } 1124 } 1125 else { 1126 item.addText("."); 1127 } 1128 } 1129 1130 private void addResourceConfigPanel(RenderingStatus status, ResourceWrapper res, XhtmlNode x, CapabilityStatementRestResourceComponent r, int nextLevel, int count, int resCount, boolean igRenderingMode) throws FHIRFormatError, DefinitionException, IOException { 1131 XhtmlNode panel= null; 1132 XhtmlNode body = null; 1133 XhtmlNode panelHead = null; 1134 XhtmlNode panelRef = null; 1135 1136 String countString = Integer.toString(count) + "-" + Integer.toString(resCount); 1137 panel = x.div().attribute("class", "panel panel-default"); 1138 if (igRenderingMode) { 1139 panelHead = panel.div().attribute("class", "panel-heading").attribute("role", "tab").attribute("id","heading" + countString).h(nextLevel,r.getType() + countString).attribute("class", "panel-title"); 1140 panelRef = panelHead.ah("#collapse" + countString).attribute("role","button").attribute("data-toggle", "collapse").attribute("aria-expanded","true").attribute("aria-controls","collapse" + countString); 1141 //panelRef = panelHead.addTag("button").attribute("href","#collapse" + countString).attribute("role","button").attribute("data-toggle", "collapse").attribute("aria-expanded","false").attribute("aria-controls","collapse" + countString); 1142 //panelRef.span("float: right;","").attribute("class", "lead").addText("Resource Conformance: " + getResourceExpectation(r)); 1143 panelRef.span("float: right;","").addText("Resource Conformance: " + getResourceExpectation(r)); 1144 panelRef.addText(r.getType()); 1145 body = panel.div().attribute("class", collapseClass).attribute("id","collapse" + countString).attribute("role","tabpanel").attribute("aria-labelledby","heading" + countString).div().attribute("class", "panel-body").div().attribute("class", "container"); 1146 } 1147 else { 1148 panelHead = panel.div().attribute("class", "panel-heading").h(nextLevel,r.getType() + countString).attribute("class", "panel-title"); 1149 panelHead.span("float: right;","").addText(context.formatPhrase(RenderingContext.CAPABILITY_RES_CONF, getResourceExpectation(r)) + " "); 1150 panelHead.addText(r.getType()); 1151 body = panel.div().attribute("class", "panel-body").div().attribute("class", "container"); 1152 } 1153 1154 1155 //Top part of panel 1156 XhtmlNode cell = null; 1157 XhtmlNode row = body.div().attribute("class", "row"); 1158 String text = r.getProfile(); 1159 boolean pullInteraction = false; 1160 String refPolicyWidth = "col-lg-3"; 1161 if (!Utilities.noString(text)) { 1162 cell = row.div().attribute("class", "col-lg-6"); 1163 addLead(cell,context.formatPhrase(RenderingContext.CAPABILITY_BASE_SYS)); 1164 cell.br(); 1165 renderCanonical(status, res, cell, StructureDefinition.class, r.getProfileElement()); 1166 cell=row.div().attribute("class", "col-lg-3"); 1167 addLead(cell, context.formatPhrase(RenderingContext.CAPABILITY_PROF_CONF)); 1168 cell.br(); 1169 cell.b().addText(getProfileExpectation(r.getProfileElement())); 1170 } 1171 else { //No profile, use FHIR Core Resource 1172 cell = row.div().attribute("class", "col-lg-4"); 1173 addLead(cell, context.formatPhrase(RenderingContext.CAPABILITY_FHIR)); 1174 cell.br(); 1175 cell.ah(currentFhirBase + r.getType().toLowerCase() + ".html").addText(r.getType()); 1176 pullInteraction = true; 1177 refPolicyWidth = "col-lg-4"; 1178 } 1179 1180 cell = row.div().attribute("class", refPolicyWidth); 1181 addLead(cell,context.formatPhrase(RenderingContext.CAPABILITY_REF_PROF)); 1182 cell.br(); 1183 addSeparatedListOfCodes(cell, getReferencePolicyStrings(r.getReferencePolicy()) , ","); 1184 if (pullInteraction) { 1185 addInteractions(row, r, 4); 1186 } 1187 body.para(); 1188 List<CanonicalType> supportedProfiles = r.getSupportedProfile(); 1189 if (supportedProfiles.size() > 0) { 1190 row = body.div().attribute("class", "row"); 1191 cell = row.div().attribute("class", "col-6"); 1192 addLead(cell, context.formatPhrase(RenderingContext.CAPABILITY_SUPP_PROFS)); 1193 XhtmlNode para = cell.para(); 1194 boolean first = true; 1195 for (CanonicalType c : supportedProfiles) { 1196 if (!first) { 1197 para.br(); 1198 } 1199 first=false; 1200 renderCanonical(status, res, para, StructureDefinition.class, c); 1201 //para.ah(c.asStringValue()).addText(c.asStringValue()); 1202 } 1203 } 1204 if (!pullInteraction) { 1205 if (supportedProfiles.size() < 1) { 1206 row = body.div().attribute("class", "row"); 1207 } 1208 addInteractions(row, r, 6); 1209 } 1210 1211 //Resource Documentation 1212 body.para(); 1213 String mdText = r.getDocumentation(); 1214 if (!Utilities.noString(mdText)) { 1215 row = body.div().attribute("class", "row"); 1216 cell = row.div().attribute("class", "col-12"); 1217 addLead(cell, context.formatPhrase(RenderingContext.GENERAL_DOCUMENTATION)); 1218 addMarkdown(cell.blockquote(), mdText); 1219 } 1220 1221 //Resource search parameters 1222 ResourceSearchParams sParams = collectParams(r); 1223 addSearchParams(body, sParams); 1224 //addSearchParamsDocumentation(body, sParams); 1225 //Resource operations 1226 ResourceOperations ops = collectOperations(r); 1227 addExtendedOperations(body, ops); 1228 } 1229 1230 private void addExtendedOperations(XhtmlNode body, ResourceOperations ops) { 1231 if (ops == null) return; 1232 Map<String, List<SingleOperation>> map = ops.getOperations(); 1233 if (!hasOperations(map)) return; 1234 XhtmlNode row; 1235 XhtmlNode cell; 1236 XhtmlNode table; 1237 XhtmlNode tbody; 1238 XhtmlNode tr; 1239 row = body.div().attribute("class", "row"); 1240 cell = row.div().attribute("class", "col-12"); 1241 addLead(cell, context.formatPhrase(RenderingContext.CAPABILITY_EXT_OP)); 1242 table = cell.table("table table-condensed table-hover"); 1243 tr = table.addTag("thead").tr(); 1244 tr.th().addText(context.formatPhrase(RenderingContext.GENERAL_CONFORMANCE)); 1245 tr.th().addText(context.formatPhrase(RenderingContext.CAPABILITY_OPER)); 1246 tr.th().addText(context.formatPhrase(RenderingContext.GENERAL_DOCUMENTATION)); 1247 tbody = table.addTag("tbody"); 1248 addOps(tbody, map, "supported"); 1249 addOps(tbody, map, "SHALL"); 1250 addOps(tbody, map, "SHOULD"); 1251 addOps(tbody, map, "MAY"); 1252 addOps(tbody, map, "SHOULD-NOT"); 1253 return; 1254 } 1255 1256 private ResourceOperations collectOperations(CapabilityStatementRestResourceComponent r) { 1257 List <CapabilityStatementRestResourceOperationComponent> opList = r.getOperation(); 1258 if (opList.size()==0) return null; 1259 String capExpectation; 1260 SingleOperation operation; 1261 ResourceOperations ops = new ResourceOperations(); 1262 1263 for ( CapabilityStatementRestResourceOperationComponent op : opList) { 1264 capExpectation = expectationForDisplay(op,EXPECTATION); 1265 if (Utilities.noString(capExpectation)) { 1266 capExpectation = "supported"; 1267 } 1268 operation = new SingleOperation(op.getName(),op.getDefinition(),op.getDocumentation(),capExpectation); 1269 ops.addOperation(capExpectation, operation); 1270 } 1271 return ops; 1272 } 1273 1274 private void addInteractions(XhtmlNode row, CapabilityStatementRestResourceComponent r, int width) { 1275 String capExpectation; 1276 String widthString = "col-lg-" + Integer.toString(width); 1277 //Need to build a different structure 1278 List<ResourceInteraction> shalls = new ArrayList<ResourceInteraction>(); 1279 List<ResourceInteraction> shoulds = new ArrayList<ResourceInteraction>(); 1280 List<ResourceInteraction> mays = new ArrayList<ResourceInteraction>(); 1281 List<ResourceInteraction> shouldnots = new ArrayList<ResourceInteraction>(); 1282 List<ResourceInteraction> supporteds = new ArrayList<ResourceInteraction>(); 1283 1284 ResourceInteraction tempInteraction = null; 1285 1286 for (ResourceInteractionComponent op : r.getInteraction()) { 1287 capExpectation = expectationForDisplay(op,EXPECTATION); 1288 tempInteraction = new ResourceInteraction(op.getCode().toCode(), op.getDocumentation()); 1289 if (!Utilities.noString(capExpectation)) { 1290 switch(capExpectation) { 1291 case "SHALL" : shalls.add(tempInteraction); 1292 break; 1293 case "SHOULD" : shoulds.add(tempInteraction); 1294 break; 1295 case "MAY" : mays.add(tempInteraction); 1296 break; 1297 case "SHOULD-NOT" : shouldnots.add(tempInteraction); 1298 break; 1299 } 1300 } 1301 else { 1302 supporteds.add(tempInteraction); 1303 } 1304 } 1305 XhtmlNode cell = row.div().attribute("class", widthString); 1306 addLead(cell, context.formatPhrase(RenderingContext.CAPABILITY_INT_SUMM)); 1307 cell.br(); 1308 XhtmlNode ul = cell.ul(); 1309 addInteractionSummaryList(ul, "SHALL", shalls); 1310 addInteractionSummaryList(ul, "SHOULD", shoulds); 1311 addInteractionSummaryList(ul, "MAY", mays); 1312 addInteractionSummaryList(ul, "SHOULD-NOT", shouldnots); 1313 addInteractionSummaryList(ul, "", supporteds); 1314 } 1315 1316 private ResourceSearchParams collectParams(CapabilityStatementRestResourceComponent r) { 1317 ResourceSearchParams sParams = new ResourceSearchParams(); 1318 String capExpectation; 1319 SingleParam param; 1320 for ( CapabilityStatementRestResourceSearchParamComponent sp : r.getSearchParam()) { 1321 capExpectation = expectationForDisplay(sp,EXPECTATION); 1322 if (Utilities.noString(capExpectation)) { 1323 capExpectation = "supported"; 1324 } 1325 param = new SingleParam(sp.getName(),sp.getDefinition(),sp.getType().toCode(),sp.getDocumentation(),capExpectation, r.getType().toLowerCase()); 1326 sParams.addIndividualbyName(param.getName(), param); 1327 sParams.addIndividualbyExp(capExpectation,param); 1328 } 1329 //CombinedSearchParam component; 1330 CombinedSearchParamSet combinedParams; 1331 String paramName; 1332 for (Extension e : r.getExtensionsByUrl(COMBINED)) { 1333 capExpectation = expectationForDisplay(e,EXPECTATION); 1334 if (Utilities.noString(capExpectation)) { 1335 capExpectation = "supported"; 1336 } 1337 combinedParams = new CombinedSearchParamSet(capExpectation); 1338 for (Extension cmpnt : e.getExtensionsByUrl("required")) { 1339 paramName = cmpnt.getValueStringType().asStringValue(); 1340 param = sParams.getIndbyName().get(paramName); 1341 if (param == null) { 1342 param = new SingleParam(paramName,"","<unknown>"); 1343 } 1344 //component = new CombinedSearchParam(param, true); 1345 combinedParams.addParam(true, param); 1346 } 1347 for (Extension cmpnt : e.getExtensionsByUrl("optional")) { 1348 paramName = cmpnt.getValueStringType().asStringValue(); 1349 param = sParams.getIndbyName().get(paramName); 1350 if (param == null) { 1351 param = new SingleParam(paramName); 1352 } 1353 //component = new CombinedSearchParam(param); 1354 combinedParams.addParam(false, param); 1355 } 1356 sParams.addCombinedParamSet(capExpectation, combinedParams); 1357 } 1358 return sParams; 1359 } 1360 1361 private void addSearchParams(XhtmlNode body, ResourceSearchParams sParams) { 1362 Map<String, List<CombinedSearchParamSet>> comboMap = sParams.getCombined(); 1363 if (isCombinedEmpty(comboMap) && sParams.getIndbyName().size()==0) return; 1364 XhtmlNode row; 1365 XhtmlNode cell; 1366 XhtmlNode table; 1367 XhtmlNode tbody; 1368 XhtmlNode tr; 1369 row = body.div().attribute("class", "row"); 1370 cell = row.div().attribute("class", "col-lg-7"); 1371 addLead(cell, context.formatPhrase(RenderingContext.CAPABILITY_SEARCH_PARS)); 1372 table = cell.table("table table-condensed table-hover"); 1373 tr = table.addTag("thead").tr(); 1374 tr.th().addText(context.formatPhrase(RenderingContext.GENERAL_CONFORMANCE)); 1375 tr.th().addText(context.formatPhrase(RenderingContext.GENERAL_PAR)); 1376 tr.th().addText(context.formatPhrase(RenderingContext.GENERAL_TYPE)); 1377 tr.th().addText(context.formatPhrase(RenderingContext.GENERAL_DOCUMENTATION)); 1378 tbody = table.addTag("tbody"); 1379 Map<String,List<SingleParam>> map = sParams.getIndbyExp(); 1380 addIndRows(tbody, map, "supported"); 1381 addIndRows(tbody, map, "SHALL"); 1382 addIndRows(tbody, map, "SHOULD"); 1383 addIndRows(tbody, map, "MAY"); 1384 addIndRows(tbody, map, "SHOULD-NOT"); 1385 cell = row.div().attribute("class", "col-lg-5"); 1386 if (!isCombinedEmpty(comboMap)) { 1387 addLead(cell, context.formatPhrase(RenderingContext.CAPABILITY_COMB_SEARCH_PAR)); 1388 table = cell.table("table table-condensed table-hover"); 1389 tr = table.addTag("thead").tr(); 1390 tr.th().addText(context.formatPhrase(RenderingContext.GENERAL_CONFORMANCE)); 1391 tr.th().addText(context.formatPhrase(RenderingContext.GENERAL_PARS)); 1392 tr.th().addText(context.formatPhrase(RenderingContext.CAPABILITY_TYPS)); 1393 tbody = table.addTag("tbody"); 1394 addComboRows(tbody, comboMap, "supported"); 1395 addComboRows(tbody, comboMap, "SHALL"); 1396 addComboRows(tbody, comboMap, "SHOULD"); 1397 addComboRows(tbody, comboMap, "MAY"); 1398 addComboRows(tbody, comboMap, "SHOULD-NOT"); 1399 } 1400 else { 1401 cell.nbsp(); 1402 } 1403 } 1404 1405 private void addIndRows(XhtmlNode tbody, Map<String, List<SingleParam>> map, String exp) { 1406 XhtmlNode tr; 1407 for (SingleParam param: map.get(exp)) { 1408 tr=tbody.tr(); 1409 if (!exp.equals("supported")) { 1410 tr.td().b().addText(exp); 1411 } 1412 else { 1413 tr.td().b().addText("SHALL"); 1414 } 1415 addResourceLink(tr.td(), param.getName(), param.getDefinition(),true, param.getHostResource()); 1416 /*if (Utilities.noString(param.getDefinition())) { 1417 tr.td().addText(param.getName()); 1418 } 1419 else { 1420 tr.td().ah(param.getDefinition()).addText(param.getName()); 1421 }*/ 1422 tr.td().code().addText(param.getType()); 1423 try { 1424 addMarkdown(tr.td(), param.getDocumentation()); 1425 } catch (FHIRFormatError e) { 1426 // TODO Auto-generated catch block 1427 e.printStackTrace(); 1428 } catch (DefinitionException e) { 1429 // TODO Auto-generated catch block 1430 e.printStackTrace(); 1431 } catch (IOException e) { 1432 // TODO Auto-generated catch block 1433 e.printStackTrace(); 1434 } 1435 } 1436 } 1437 1438 private void addOps(XhtmlNode tbody, Map<String, List<SingleOperation>> map, String exp) { 1439 XhtmlNode tr; 1440 String name; 1441 String canonicalUri; 1442 for (SingleOperation operation: map.get(exp)) { 1443 tr = tbody.tr(); 1444 name = "$" + operation.getName(); 1445 if (!exp.equals("supported")) { 1446 tr.td().b().addText(exp); 1447 } 1448 else { 1449 tr.td().b().addText("SHALL"); 1450 } 1451 canonicalUri = operation.getDefinition(); 1452 addResourceLink(tr.td(), name, canonicalUri); 1453 /* 1454 if (Utilities.noString(operation.getDefinition())) { 1455 tr.td().addText(name); 1456 } 1457 else { 1458 tr.td().ah(operation.getDefinition()).addText(name); 1459 Resource cr = context.getContext().fetchResource(Resource.class, operation.getDefinition()); 1460 } */ 1461 try { 1462 addMarkdown(tr.td(), operation.getDocumentation()); 1463 } catch (FHIRFormatError e) { 1464 // TODO Auto-generated catch block 1465 e.printStackTrace(); 1466 } catch (DefinitionException e) { 1467 // TODO Auto-generated catch block 1468 e.printStackTrace(); 1469 } catch (IOException e) { 1470 // TODO Auto-generated catch block 1471 e.printStackTrace(); 1472 } 1473 } 1474 } 1475 1476 private void addComboRows(XhtmlNode tbody, Map<String, List<CombinedSearchParamSet>> map, String exp) { 1477 XhtmlNode tr,td; 1478 boolean first; 1479 for (CombinedSearchParamSet paramSet: map.get(exp)) { 1480 tr=tbody.tr(); 1481 if (!exp.equals("supported")) { 1482 tr.td().b().addText(exp); 1483 } 1484 else { 1485 tr.td().nbsp(); 1486 } 1487 //Parameter combination 1488 td = tr.td(); 1489 first = true; 1490 for (SingleParam p : paramSet.getParams().get(true)) { 1491 if (!first) { 1492 td.addText("+"); 1493 } 1494 first=false; 1495 if (Utilities.noString(p.getDefinition())) { 1496 td.addText(p.getName()); 1497 } 1498 else { 1499 addResourceLink(td, p.getName(), p.getDefinition(), true, p.getHostResource()); 1500 //td.ah(p.param.getDefinition()).addText(p.param.getName()); 1501 } 1502 } 1503 if (paramSet.getParams().get(false).size() > 0) { 1504 td.addText("("); 1505 for (SingleParam p : paramSet.getParams().get(false)) { 1506 td.addText("+"); 1507 if (Utilities.noString(p.getDefinition())) { 1508 td.addText(p.getName()); 1509 } 1510 else { 1511 addResourceLink(td, p.getName(), p.getDefinition(), true, p.getHostResource()); 1512 //td.ah(p.param.getDefinition()).addText(p.param.getName()); 1513 } 1514 } 1515 td.addText(")"); 1516 } 1517 //types combination 1518 td = tr.td(); 1519 first = true; 1520 for (SingleParam p : paramSet.getParams().get(true)) { 1521 if (!first) { 1522 td.addText("+"); 1523 } 1524 first=false; 1525 td.code().addText(p.getType()); 1526 } 1527 if (paramSet.getParams().get(false).size() > 0) { 1528 td.addText("("); 1529 for (SingleParam p : paramSet.getParams().get(false)) { 1530 td.addText("+"); 1531 if (!p.getType().equals("<unknown>")) { 1532 td.code().addText(p.getType()); 1533 } 1534 else { 1535 td.addText(p.getType()); 1536 } 1537 } 1538 td.addText(")"); 1539 } 1540 } 1541 } 1542 1543 boolean isCombinedEmpty(Map<String, List<CombinedSearchParamSet>> combinedMap) { 1544 boolean result = true; 1545 for (String s : combinedMap.keySet()) { 1546 if (combinedMap.get(s).size() > 0) { 1547 result=false; 1548 break; 1549 } 1550 } 1551 return result; 1552 } 1553 1554 boolean hasOperations(Map<String, List<SingleOperation>> operationsMap) { 1555 boolean result = false; 1556 for (String s : operationsMap.keySet()) { 1557 if (operationsMap.get(s).size() > 0) { 1558 result=true; 1559 break; 1560 } 1561 } 1562 return result; 1563 } 1564 1565 private List<String> getReferencePolicyStrings(List<Enumeration<ReferenceHandlingPolicy>> list) { 1566 List<String> stringList = new ArrayList<String>(); 1567 for (Enumeration<ReferenceHandlingPolicy> p : list) { 1568 stringList.add(p.getCode()); 1569 } 1570 return stringList; 1571 } 1572 private String getResourceExpectation(CapabilityStatementRestResourceComponent r) { 1573 String capExpectation = expectationForDisplay(r,EXPECTATION); 1574 if (!Utilities.noString(capExpectation)) return capExpectation; 1575 boolean shalls = false; 1576 boolean shoulds = false; 1577 boolean mays = false; 1578 boolean shouldnots = false; 1579 for (ResourceInteractionComponent ric : r.getInteraction()) { 1580 capExpectation = expectationForDisplay(ric,EXPECTATION); 1581 if (!Utilities.noString(capExpectation)) { 1582 switch(capExpectation) { 1583 case "SHALL" : shalls = true; 1584 break; 1585 case "SHOULD" : shoulds = true; 1586 break; 1587 case "MAY" : mays = true; 1588 break; 1589 case "SHOULD-NOT" : shouldnots = true; 1590 break; 1591 } 1592 } 1593 } 1594 if (shalls) return "SHALL"; 1595 //Check search parameters requirements 1596 for ( CapabilityStatementRestResourceSearchParamComponent sp : r.getSearchParam()) { 1597 capExpectation = expectationForDisplay(sp,EXPECTATION); 1598 if (!Utilities.noString(capExpectation)) { 1599 switch(capExpectation) { 1600 case "SHALL" : shalls = true; 1601 break; 1602 case "SHOULD" : shoulds = true; 1603 break; 1604 case "MAY" : mays = true; 1605 break; 1606 case "SHOULD-NOT" : shouldnots = true; 1607 break; 1608 } 1609 } 1610 } 1611 if (shalls) return "SHALL"; 1612 if (shoulds) return "SHOULD"; 1613 if (mays) return "MAY"; 1614 if (shouldnots) return "SHOULD NOT"; 1615 return "supported"; 1616 } 1617 1618 private String getProfileExpectation(CanonicalType r) { 1619 String capExpectation = expectationForDisplay(r,EXPECTATION); 1620 if (!Utilities.noString(capExpectation)) return capExpectation; 1621 return "SHALL"; 1622 } 1623 1624 private void addLead(XhtmlNode node, String text) { 1625 node.addTag("span").attribute("class", "lead").addText(text); 1626 } 1627 1628 private void addResourceLink(XhtmlNode node, String name, String canonicalUri) { 1629 addResourceLink(node, name, canonicalUri, false, ""); 1630 } 1631 1632 private void addResourceLink(XhtmlNode node, String name, String canonicalUri, boolean isParam, String hostResource) { 1633 if (Utilities.noString(canonicalUri)) { 1634 node.addText(name); 1635 return; 1636 } 1637 1638 Resource cr = context.getContext().fetchResource(Resource.class, canonicalUri); 1639 if (cr == null) { 1640 node.addText(name); 1641 } 1642 else { 1643 //String path = cr.getUserString("path"); 1644 String path = cr.getWebPath(); 1645 if (Utilities.noString(path)) { 1646 if (isParam && (canonicalUri.toLowerCase().startsWith(SP_BASE)) && (!Utilities.noString(currentFhirBase)) && (!Utilities.noString(hostResource))) { 1647 String resourceName = ""; 1648 if (canonicalUri.substring(SP_BASE.length()).split("-")[0].toLowerCase().equals("resource")) { 1649 resourceName = "resource"; 1650 } 1651 else if (canonicalUri.substring(SP_BASE.length()).split("-")[0].toLowerCase().equals("domainresource")) { 1652 resourceName = "domainresource"; 1653 } 1654 else { 1655 resourceName = hostResource; 1656 } 1657 1658 node.ah(currentFhirBase + resourceName + ".html#search").addText(name); 1659 } 1660 else { 1661 node.addText(name); 1662 } 1663 } 1664 else { 1665 node.ah(path).addText(name); 1666 } 1667 } 1668 } 1669 1670 private String expectationForDisplay(Element e, String url) { 1671 String result; 1672 try { 1673 result = e.getExtensionString(url); 1674 return result; 1675 } 1676 catch (FHIRException fex) { 1677 List<Extension> ext = e.getExtensionsByUrl(url); 1678 if (ext.isEmpty()) 1679 return null; 1680 if (!ext.get(0).hasValue()) 1681 return null; 1682 multExpectationsPresent = true; 1683 return ext.get(0).getValue().primitiveValue() + "-??"; 1684 } 1685 1686 } 1687 1688 private void addWarningPanel(XhtmlNode node, String text) { 1689 XhtmlNode panel = node.addTag("div").attribute("class","panel panel-danger").addTag("div").attribute("class","panel-body"); 1690 panel.addTag("span").attribute("class","label label-danger").addText(context.formatPhrase(RenderingContext.CAPABILITY_ERR_DET)); 1691 panel.addText(" " + text); 1692 } 1693}