001package org.hl7.fhir.r5.renderers; 002 003import java.io.IOException; 004import java.io.UnsupportedEncodingException; 005 006import org.hl7.fhir.exceptions.DefinitionException; 007import org.hl7.fhir.exceptions.FHIRFormatError; 008import org.hl7.fhir.r5.model.CanonicalType; 009import org.hl7.fhir.r5.model.CapabilityStatement; 010import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestComponent; 011import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestResourceComponent; 012import org.hl7.fhir.r5.model.CapabilityStatement.ResourceInteractionComponent; 013import org.hl7.fhir.r5.model.CapabilityStatement.SystemInteractionComponent; 014import org.hl7.fhir.r5.model.CapabilityStatement.SystemRestfulInteraction; 015import org.hl7.fhir.r5.model.CapabilityStatement.TypeRestfulInteraction; 016import org.hl7.fhir.r5.model.Extension; 017import org.hl7.fhir.r5.model.Resource; 018import org.hl7.fhir.r5.model.StructureDefinition; 019import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; 020import org.hl7.fhir.r5.renderers.utils.RenderingContext; 021import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; 022import org.hl7.fhir.r5.utils.ToolingExtensions; 023import org.hl7.fhir.utilities.xhtml.XhtmlNode; 024 025public class CapabilityStatementRenderer extends ResourceRenderer { 026 027 public CapabilityStatementRenderer(RenderingContext context) { 028 super(context); 029 } 030 031 public CapabilityStatementRenderer(RenderingContext context, ResourceContext rcontext) { 032 super(context, rcontext); 033 } 034 035 public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException { 036 return render(x, (CapabilityStatement) dr); 037 } 038 039 public boolean render(XhtmlNode x, CapabilityStatement conf) throws FHIRFormatError, DefinitionException, IOException { 040 x.h2().addText(conf.getName()); 041 addMarkdown(x, conf.getDescription()); 042 if (conf.getRest().size() > 0) { 043 CapabilityStatementRestComponent rest = conf.getRest().get(0); 044 XhtmlNode t = x.table(null); 045 if (rest.hasMode()) { 046 addTableRow(t, "Mode", rest.getMode().toString()); 047 } 048 addMarkdown(addTableRow(t, "Description"), rest.getDocumentation()); 049 050 addTableRow(t, "Transaction", showOp(rest, SystemRestfulInteraction.TRANSACTION)); 051 addTableRow(t, "System History", showOp(rest, SystemRestfulInteraction.HISTORYSYSTEM)); 052 addTableRow(t, "System Search", showOp(rest, SystemRestfulInteraction.SEARCHSYSTEM)); 053 054 boolean hasVRead = false; 055 boolean hasPatch = false; 056 boolean hasDelete = false; 057 boolean hasHistory = false; 058 boolean hasUpdates = false; 059 for (CapabilityStatementRestResourceComponent r : rest.getResource()) { 060 hasVRead = hasVRead || hasOp(r, TypeRestfulInteraction.VREAD); 061 hasPatch = hasPatch || hasOp(r, TypeRestfulInteraction.PATCH); 062 hasDelete = hasDelete || hasOp(r, TypeRestfulInteraction.DELETE); 063 hasHistory = hasHistory || hasOp(r, TypeRestfulInteraction.HISTORYTYPE); 064 hasUpdates = hasUpdates || hasOp(r, TypeRestfulInteraction.HISTORYINSTANCE); 065 } 066 067 t = x.table(null); 068 XhtmlNode tr = t.tr(); 069 tr.th().b().tx("Resource Type"); 070 tr.th().b().tx("Profile"); 071 tr.th().b().attribute("title", "GET a resource (read interaction)").tx("Read"); 072 if (hasVRead) 073 tr.th().b().attribute("title", "GET past versions of resources (vread interaction)").tx("V-Read"); 074 tr.th().b().attribute("title", "GET all set of resources of the type (search interaction)").tx("Search"); 075 tr.th().b().attribute("title", "PUT a new resource version (update interaction)").tx("Update"); 076 if (hasPatch) 077 tr.th().b().attribute("title", "PATCH a new resource version (patch interaction)").tx("Patch"); 078 tr.th().b().attribute("title", "POST a new resource (create interaction)").tx("Create"); 079 if (hasDelete) 080 tr.th().b().attribute("title", "DELETE a resource (delete interaction)").tx("Delete"); 081 if (hasUpdates) 082 tr.th().b().attribute("title", "GET changes to a resource (history interaction on instance)").tx("Updates"); 083 if (hasHistory) 084 tr.th().b().attribute("title", "GET changes for all resources of the type (history interaction on type)").tx("History"); 085 086 XhtmlNode profCell = null; 087 boolean hasProf = false; 088 boolean hasSupProf = false; 089 for (CapabilityStatementRestResourceComponent r : rest.getResource()) { 090 tr = t.tr(); 091 tr.td().addText(r.getType()); 092 093 //Show profiles 094 profCell = tr.td(); 095 hasProf = r.hasProfile(); 096 hasSupProf = r.hasSupportedProfile(); 097 if ((!hasProf) && (!hasSupProf)) { 098 profCell.nbsp(); 099 } 100 else if (hasProf) { 101 profCell.ah(r.getProfile()).addText(r.getProfile()); 102 if (hasSupProf) { 103 profCell.br(); 104 profCell.addText("Additional supported profiles:"); 105 renderSupportedProfiles(profCell, r); 106 } 107 } 108 else { //Case of only supported profiles 109 profCell.addText("Supported profiles:"); 110 renderSupportedProfiles(profCell, r); 111 } 112 //Show capabilities 113 tr.td().addText(showOp(r, TypeRestfulInteraction.READ)); 114 if (hasVRead) 115 tr.td().addText(showOp(r, TypeRestfulInteraction.VREAD)); 116 tr.td().addText(showOp(r, TypeRestfulInteraction.SEARCHTYPE)); 117 tr.td().addText(showOp(r, TypeRestfulInteraction.UPDATE)); 118 if (hasPatch) 119 tr.td().addText(showOp(r, TypeRestfulInteraction.PATCH)); 120 tr.td().addText(showOp(r, TypeRestfulInteraction.CREATE)); 121 if (hasDelete) 122 tr.td().addText(showOp(r, TypeRestfulInteraction.DELETE)); 123 if (hasUpdates) 124 tr.td().addText(showOp(r, TypeRestfulInteraction.HISTORYINSTANCE)); 125 if (hasHistory) 126 tr.td().addText(showOp(r, TypeRestfulInteraction.HISTORYTYPE)); 127 } 128 } 129 130 return true; 131 } 132 133 private void renderSupportedProfiles(XhtmlNode profCell, CapabilityStatementRestResourceComponent r) throws IOException { 134 for (CanonicalType sp: r.getSupportedProfile()) { 135 profCell.br(); 136 profCell.nbsp().nbsp(); 137 StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, sp.getValue()); 138 if (sd != null) { 139 profCell.ah(sd.getWebPath()).addText(sd.present()); 140 } else { 141 profCell.ah(sp.getValue()).addText(sp.getValue()); 142 } 143 } 144 if (r.hasExtension(ToolingExtensions.EXT_PROFILE_MAPPING)) { 145 profCell.br(); 146 profCell.b().tx("Profile Mapping"); 147 XhtmlNode tbl = profCell.table("grid"); 148 boolean doco = false; 149 for (Extension ext : r.getExtensionsByUrl(ToolingExtensions.EXT_PROFILE_MAPPING)) { 150 doco = doco || ext.hasExtension("documentation"); 151 } 152 XhtmlNode tr = tbl.tr(); 153 tr.th().tx("Criteria"); 154 tr.th().tx("Profile"); 155 if (doco) { 156 tr.th().tx("Criteria"); 157 } 158 for (Extension ext : r.getExtensionsByUrl(ToolingExtensions.EXT_PROFILE_MAPPING)) { 159 tr = tbl.tr(); 160 tr.td().code().tx(ToolingExtensions.readStringExtension(ext, "search")); 161 String url = ToolingExtensions.readStringExtension(ext, "profile"); 162 StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, url); 163 if (sd != null) { 164 tr.td().code().ah(sd.getWebPath()).tx(sd.present()); 165 } else { 166 tr.td().code().tx(url); 167 } 168 if (doco) { 169 tr.td().code().markdown(ToolingExtensions.readStringExtension(ext, "documentation"), "documentation"); 170 } 171 } 172 } 173 } 174 175 public void describe(XhtmlNode x, CapabilityStatement cs) { 176 x.tx(display(cs)); 177 } 178 179 public String display(CapabilityStatement cs) { 180 return cs.present(); 181 } 182 183 @Override 184 public String display(Resource r) throws UnsupportedEncodingException, IOException { 185 return ((CapabilityStatement) r).present(); 186 } 187 188 189 private boolean hasOp(CapabilityStatementRestResourceComponent r, TypeRestfulInteraction on) { 190 for (ResourceInteractionComponent op : r.getInteraction()) { 191 if (op.getCode() == on) 192 return true; 193 } 194 return false; 195 } 196 197 private String showOp(CapabilityStatementRestResourceComponent r, TypeRestfulInteraction on) { 198 for (ResourceInteractionComponent op : r.getInteraction()) { 199 if (op.getCode() == on) 200 return "y"; 201 } 202 return ""; 203 } 204 205 private String showOp(CapabilityStatementRestComponent r, SystemRestfulInteraction on) { 206 for (SystemInteractionComponent op : r.getInteraction()) { 207 if (op.getCode() == on) 208 return "y"; 209 } 210 return ""; 211 } 212 213 private XhtmlNode addTableRow(XhtmlNode t, String name) { 214 XhtmlNode tr = t.tr(); 215 tr.td().addText(name); 216 return tr.td(); 217 } 218 219 private void addTableRow(XhtmlNode t, String name, String value) { 220 XhtmlNode tr = t.tr(); 221 tr.td().addText(name); 222 tr.td().addText(value); 223 } 224 225 public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { 226 if (r.has("title")) { 227 return r.children("title").get(0).getBase().primitiveValue(); 228 } 229 if (r.has("name")) { 230 return r.children("name").get(0).getBase().primitiveValue(); 231 } 232 return "??"; 233 } 234 235}