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