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