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