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