
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.FHIRException; 008import org.hl7.fhir.exceptions.FHIRFormatError; 009import org.hl7.fhir.r5.model.CanonicalType; 010import org.hl7.fhir.r5.model.Enumeration; 011import org.hl7.fhir.r5.model.Enumerations.FHIRTypes; 012import org.hl7.fhir.r5.model.Enumerations.VersionIndependentResourceTypesAll; 013import org.hl7.fhir.r5.model.Extension; 014import org.hl7.fhir.r5.model.OperationDefinition; 015import org.hl7.fhir.r5.model.OperationDefinition.OperationDefinitionParameterComponent; 016import org.hl7.fhir.r5.model.OperationDefinition.OperationKind; 017import org.hl7.fhir.r5.model.OperationDefinition.OperationParameterScope; 018import org.hl7.fhir.r5.model.Resource; 019import org.hl7.fhir.r5.model.StructureDefinition; 020import org.hl7.fhir.r5.renderers.utils.RenderingContext; 021import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; 022import org.hl7.fhir.r5.renderers.utils.ResourceWrapper; 023import org.hl7.fhir.r5.utils.EOperationOutcome; 024import org.hl7.fhir.r5.utils.ToolingExtensions; 025import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; 026import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 027import org.hl7.fhir.utilities.StandardsStatus; 028import org.hl7.fhir.utilities.Utilities; 029import org.hl7.fhir.utilities.xhtml.XhtmlNode; 030 031@MarkedToMoveToAdjunctPackage 032public class OperationDefinitionRenderer extends TerminologyRenderer { 033 034 035 public OperationDefinitionRenderer(RenderingContext context) { 036 super(context); 037 } 038 039 @Override 040 public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome { 041 if (r.isDirect()) { 042 renderResourceTechDetails(r, x); 043 genSummaryTable(status, x, (OperationDefinition) r.getBase()); 044 render(status, x, (OperationDefinition) r.getBase()); 045 } else { 046 // the intention is to change this in the future 047 x.para().tx("OperationDefinitionRenderer only renders native resources directly"); 048 } 049 } 050 051 @Override 052 public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException { 053 return canonicalTitle(r); 054 } 055 056 public void render(RenderingStatus status, XhtmlNode x, OperationDefinition opd) throws IOException, FHIRException, EOperationOutcome { 057 if (context.isShowSummaryTable()) { 058 x.h2().addText(opd.getName()); 059 x.para().addText(Utilities.capitalize(opd.getKind().toString())+": "+opd.getName()); 060 x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_OFFIC)+" "); 061 x.pre().tx(opd.getUrl()); 062 addMarkdown(x, opd.getDescription());} 063 064 if (opd.getKind() == OperationKind.QUERY) { 065 if (opd.getSystem()) { 066 x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URLS, "?_query="+opd.getCode()+"&...")); 067 } 068 for (Enumeration<VersionIndependentResourceTypesAll> c : opd.getResource()) { 069 if (opd.getType()) 070 x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"?_query="+opd.getCode()+"&...")); 071 if (opd.getInstance()) 072 x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"/[id]?_query="+opd.getCode()+"&...")); 073 } 074 } else { 075 if (opd.getSystem()) { 076 x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URLS, "$"+opd.getCode())); 077 } 078 for (Enumeration<VersionIndependentResourceTypesAll> c : opd.getResource()) { 079 if (opd.getType()) 080 x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"/$"+opd.getCode())); 081 if (opd.getInstance()) 082 x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"/[id]/$"+opd.getCode())); 083 } 084 } 085 086 if (opd.hasInputProfile()) { 087 XhtmlNode p = x.para(); 088 p.tx(context.formatPhrase(RenderingContext.OP_DEF_INPAR)); 089 StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getInputProfile(), opd); 090 if (sd == null) { 091 p.pre().tx(opd.getInputProfile()); 092 } else { 093 p.ah(context.prefixLocalHref(sd.getWebPath())).tx(sd.present()); 094 } 095 } 096 if (opd.hasOutputProfile()) { 097 XhtmlNode p = x.para(); 098 p.tx(context.formatPhrase(RenderingContext.OP_DEF_OUTPAR)); 099 StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getOutputProfile(), opd); 100 if (sd == null) { 101 p.pre().tx(opd.getOutputProfile()); 102 } else { 103 p.ah(context.prefixLocalHref(sd.getWebPath())).tx(sd.present()); 104 } 105 } 106 107 x.h3().tx(context.formatPhrase(RenderingContext.GENERAL_PARS)); 108 //x.para().tx(context.formatPhrase(RenderingContext.GENERAL_PARS)); 109 XhtmlNode tbl = x.table( "grid", false); 110 XhtmlNode tr = tbl.tr(); 111 tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_USE)); 112 tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_NAME)); 113 tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_SCO)); 114 tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CARDINALITY)); 115 tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_TYPE)); 116 tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_BINDING)); 117 tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_DOCUMENTATION)); 118 for (OperationDefinitionParameterComponent p : opd.getParameter()) { 119 genOpParam(tbl, "", p, opd); 120 } 121 addMarkdown(x, opd.getComment()); 122 } 123 124 public void describe(XhtmlNode x, OperationDefinition opd) { 125 x.tx(display(opd)); 126 } 127 128 public String display(OperationDefinition opd) { 129 return opd.present(); 130 } 131 132 @Override 133 public String display(Resource r) throws UnsupportedEncodingException, IOException { 134 return ((OperationDefinition) r).present(); 135 } 136 137 private void genOpParam(XhtmlNode tbl, String path, OperationDefinitionParameterComponent p, Resource opd) throws EOperationOutcome, FHIRException, IOException { 138 XhtmlNode tr; 139 tr = tbl.tr(); 140 tr.td().addText(p.getUse().toString()); 141 XhtmlNode td = tr.td(); 142 td.addText(path+p.getName()); 143 StandardsStatus ss = ToolingExtensions.getStandardsStatus(p); 144 genStandardsStatus(td, ss); 145 td = tr.td(); 146 if (p.hasScope()) { 147 CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); 148 for (Enumeration<OperationParameterScope> s : p.getScope()) { 149 b.append(s.getCode()); 150 } 151 td.tx(b.toString()); 152 } 153 tr.td().addText(Integer.toString(p.getMin())+".."+p.getMax()); 154 td = tr.td(); 155 String actualType = translateTypeToVersion(p.getTypeElement()); 156 StructureDefinition sd = actualType != null ? context.getWorker().fetchTypeDefinition(actualType) : null; 157 if (sd == null) { 158 td.tx(p.hasType() ? actualType : ""); 159 } else if (sd.getAbstract() && p.hasExtension(ToolingExtensions.EXT_ALLOWED_TYPE)) { 160 boolean first = true; 161 for (Extension ex : p.getExtensionsByUrl(ToolingExtensions.EXT_ALLOWED_TYPE)) { 162 if (first) first = false; else td.tx(" | "); 163 String s = ex.getValue().primitiveValue(); 164 StructureDefinition sdt = context.getWorker().fetchTypeDefinition(s); 165 if (sdt == null) 166 td.tx(p.hasType() ? actualType : ""); 167 else 168 td.ah(context.prefixLocalHref(sdt.getWebPath())).tx(s); 169 } 170 } else if (sd.getAbstract() && (p.hasAllowedType())) { 171 boolean first = true; 172 for (Enumeration<FHIRTypes> ex : p.getAllowedType()) { 173 if (first) first = false; else td.tx(" | "); 174 String s = ex.primitiveValue(); 175 StructureDefinition sdt = context.getWorker().fetchTypeDefinition(s); 176 if (sdt == null) 177 td.tx(p.hasType() ? actualType : ""); 178 else 179 td.ah(context.prefixLocalHref(sdt.getWebPath())).tx(s); 180 } 181 } else 182 td.ah(context.prefixLocalHref(sd.getWebPath())).tx(actualType); 183 if (p.hasTargetProfile()) { 184 td.tx(" ("); 185 boolean first = true; 186 for (CanonicalType tp : p.getTargetProfile()) { 187 if (first) { first = false;} else {td.tx(", ");}; 188 StructureDefinition sdt = context.getWorker().fetchTypeDefinition(tp.asStringValue()); 189 if (sdt == null || !sdt.hasWebPath()) { 190 td.code().tx(tp.asStringValue()); 191 } else { 192 td.ah(context.prefixLocalHref(sdt.getWebPath()), tp.asStringValue()).tx(sdt.present()); 193 } 194 } 195 td.tx(")"); 196 } 197 if (p.hasSearchType()) { 198 td.br(); 199 td.tx("("); 200 td.ah(context.prefixLocalHref(context.getLink(KnownLinkType.SPEC, true) == null ? "search.html#"+p.getSearchType().toCode() : Utilities.pathURL(context.getLink(KnownLinkType.SPEC, true), "search.html#"+p.getSearchType().toCode()))).tx(p.getSearchType().toCode()); 201 td.tx(")"); 202 } 203 td = tr.td(); 204 if (p.hasBinding() && p.getBinding().hasValueSet()) { 205 AddVsRef(p.getBinding().getValueSet(), td, opd); 206 td.tx(" ("+p.getBinding().getStrength().getDisplay()+")"); 207 } 208 addMarkdown(tr.td(), p.getDocumentation()); 209 if (!p.hasType()) { 210 for (OperationDefinitionParameterComponent pp : p.getPart()) { 211 genOpParam(tbl, path+p.getName()+".", pp, opd); 212 } 213 } 214 } 215 216 public static final String EXT_OPDEF_ORIGINAL_TYPE = "http://hl7.org/fhir/4.0/StructureDefinition/extension-OperationDefinition.parameter.type"; 217 218 private String translateTypeToVersion(Enumeration<FHIRTypes> src) { 219 if (src.hasExtension(EXT_OPDEF_ORIGINAL_TYPE)) { 220 return src.getExtensionString(EXT_OPDEF_ORIGINAL_TYPE); 221 } else { 222 return src.asStringValue(); 223 } 224 } 225 226 227}