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