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