
001package org.hl7.fhir.r5.renderers; 002 003import java.io.IOException; 004import java.io.UnsupportedEncodingException; 005import java.util.List; 006 007import org.apache.commons.codec.binary.Base64; 008import org.hl7.fhir.exceptions.DefinitionException; 009import org.hl7.fhir.exceptions.FHIRException; 010import org.hl7.fhir.exceptions.FHIRFormatError; 011import org.hl7.fhir.r5.model.CanonicalResource; 012import org.hl7.fhir.r5.model.Resource; 013import org.hl7.fhir.r5.model.ValueSet; 014import org.hl7.fhir.r5.renderers.utils.RenderingContext; 015import org.hl7.fhir.r5.renderers.utils.ResourceWrapper; 016import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; 017import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; 018import org.hl7.fhir.r5.utils.EOperationOutcome; 019import org.hl7.fhir.r5.utils.ToolingExtensions; 020import org.hl7.fhir.r5.utils.UserDataNames; 021import org.hl7.fhir.r5.utils.sql.Column; 022import org.hl7.fhir.r5.utils.sql.ColumnKind; 023import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; 024import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 025import org.hl7.fhir.utilities.Utilities; 026import org.hl7.fhir.utilities.VersionUtilities; 027import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; 028import org.hl7.fhir.utilities.xhtml.NodeType; 029import org.hl7.fhir.utilities.xhtml.XhtmlNode; 030import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell; 031import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; 032import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row; 033import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel; 034import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Title; 035 036@MarkedToMoveToAdjunctPackage 037public class ViewDefinitionRenderer extends ResourceRenderer { 038 039 public ViewDefinitionRenderer(RenderingContext context) { 040 super(context); 041 } 042 043 @Override 044 public boolean renderingUsesValidation() { 045 return true; 046 } 047 048 @Override 049 public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException { 050 return canonicalTitle(r); 051 } 052 053 @Override 054 public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper vd) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome { 055 renderResourceTechDetails(vd, x); 056 genSummaryTable(status, x, vd); 057 058 XhtmlNode p = x.para(); 059 p.tx("This view acts on the "+vd.primitiveValue("resource")+" resource"); 060 var vers = vd.children("fhirVersion"); 061 for (int i = 0; i < vers.size(); i++) { 062 if (i == 0) { 063 p.tx(" for version"+(vers.size() == 1 ? "" : "s")+" "); 064 } else if (i == vers.size() - 1) { 065 p.tx(" and "); 066 } else { 067 p.tx(", "); 068 } 069 String ver = vers.get(i).primitiveValue(); 070 p.ah(VersionUtilities.getSpecUrl(ver)).tx(VersionUtilities.getNameForVersion(ver)); 071 } 072 if (vd.has("resourceProfile")) { 073 p.tx(" using profile ?"); 074 } 075 if (vd.has("name")) { 076 p.tx(" to produce a table named \""); 077 p.code().tx(vd.primitiveValue("name")); 078 p.tx("\""); 079 } else { 080 p.tx(" to produce a unnamed table"); 081 } 082 if (vd.has("where")) { 083 List<ResourceWrapper> wheres = vd.children("where"); 084 if (wheres.size() == 1) { 085 p.tx(" where "); 086 p.code().tx(wheres.get(0).primitiveValue("path")); 087 if (wheres.get(0).has("description")) { 088 p.tx(" ("+wheres.get(0).primitiveValue("description")+")"); 089 } 090 p.tx("."); 091 } else { 092 p.tx(" where:"); 093 XhtmlNode ul = x.ul(); 094 for (ResourceWrapper w : wheres) { 095 XhtmlNode li = ul.li(); 096 li.code().tx(wheres.get(0).primitiveValue("path")); 097 if (wheres.get(0).has("description")) { 098 li.tx(" ("+wheres.get(0).primitiveValue("description")+")"); 099 } 100 } 101 } 102 } else { 103 p.tx("."); 104 } 105 106 if (vd.hasUserData(UserDataNames.db_columns)) { 107 x.para().tx("The table contains the following columns:"); 108 List<Column> cols = (List<Column>) vd.getUserData(UserDataNames.db_columns); 109 boolean hasNotes = false; 110 for (Column col : cols) { 111 hasNotes = hasNotes || !Utilities.noString(col.getNotes()); 112 } 113 114 XhtmlNode t2 = x.table("grid", false); 115 XhtmlNode tr = t2.tr(); 116 tr.th().tx("Name"); 117 tr.th().tx("Fhir Type"); 118 tr.th().tx("SQL Type"); 119 tr.th().tx("Collection"); 120 if (hasNotes) { 121 tr.th().tx("Notes"); 122 } 123 124 for (Column col : cols) { 125 tr = t2.tr(); 126 tr.td().tx(col.getName()); 127 tr.td().tx(col.getType()); 128 tr.td().tx(col.getKind().name()); 129 tr.td().tx(col.isColl() == null ? "" : col.isColl() ? "Y" : "N"); 130 if (hasNotes) { 131 tr.td().tx(col.getNotes()); 132 } 133 } 134 } 135 if (vd.has("constant")) { 136 x.para().tx("Constants:"); 137 138 XhtmlNode t2 = x.table("grid", false); 139 XhtmlNode tr = t2.tr(); 140 tr.th().tx("Name"); 141 tr.th().tx("Value"); 142 143 for (ResourceWrapper cnst : vd.children("constant")) { 144 tr = t2.tr(); 145 tr.td().tx(cnst.primitiveValue("name")); 146 tr.td().tx(cnst.primitiveValue("value")); 147 } 148 } 149 // row 4: select tree 150 x.para().tx("Selection Rules:"); 151 152 HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true, ""); 153 TableModel model = gen.new TableModel("vd="+vd.getId(), context.getRules() == GenerationRules.IG_PUBLISHER); 154 model.setAlternating(true); 155 if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { 156 model.setDocoImg(HierarchicalTableGenerator.help16AsData()); 157 } else { 158 model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); 159 } 160 model.getTitles().add(gen.new Title(null, model.getDocoRef(), ("Item"), (context.formatPhrase(RenderingContext.QUEST_LINK)), null, 0)); 161 model.getTitles().add(gen.new Title(null, model.getDocoRef(), ("Coll"), (context.formatPhrase(RenderingContext.QUEST_TEXTFOR)), null, 0)); 162 model.getTitles().add(gen.new Title(null, model.getDocoRef(), ("Type"), (context.formatPhrase(RenderingContext.QUEST_TIMES)), null, 0)); 163 model.getTitles().add(gen.new Title(null, model.getDocoRef(), ("Description"), (context.formatPhrase(RenderingContext.QUEST_TYPE_ITEM)), null, 0)); 164 165 // first we add a root for the questionaire itself 166 Row row = addViewRoot(gen, model.getRows(), vd); 167 for (ResourceWrapper select : vd.children("select")) { 168 renderSelect(status, gen, row.getSubRows(), vd, select); 169 } 170 XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); 171 x.addChildNode(xn); 172 } 173 174 private void renderSelect(RenderingStatus status, HierarchicalTableGenerator gen, List<Row> rows, ResourceWrapper vd, ResourceWrapper select) { 175 Row r = gen.new Row(); 176 rows.add(r); 177 178 r.setIcon("icon_vd_select.png", "Select"); 179 Cell c1 = gen.new Cell(null, null, "Select", null, null); 180 r.getCells().add(c1); 181 r.getCells().add(gen.new Cell(null, null, null, null, null)); 182 r.getCells().add(gen.new Cell(null, null, null, null, null)); 183 Cell cell = gen.new Cell(null, null, null, null, null); 184 if (select.has("forEach")) { 185 addFHIRPath(cell.getPieces().get(0), "for each ", select.primitiveValue("forEach"), null); 186 } else if (select.has("forEachOrNull")) { 187 addFHIRPath(cell.getPieces().get(0), "for each ", select.primitiveValue("forEachOrNull"), ", or null"); 188 } else { 189 } 190 r.getCells().add(cell); 191 192 for (ResourceWrapper column : select.children("column")) { 193 renderColumn(status, gen, r.getSubRows(), vd, select, column); 194 } 195 196 for (ResourceWrapper child : select.children("select")) { 197 renderSelect(status, gen, r.getSubRows(), vd, child); 198 } 199 200 } 201 202 private void renderColumn(RenderingStatus status, HierarchicalTableGenerator gen, List<Row> rows, ResourceWrapper vd, ResourceWrapper select, ResourceWrapper column) { 203 Row r = gen.new Row(); 204 rows.add(r); 205 206 r.setIcon("icon_vd_col.png", "Column"); 207 Cell c1 = gen.new Cell(null, null, column.primitiveValue("name"), null, null); 208 r.getCells().add(c1); 209 String coll = column.has("collection") ? "true".equals(column.primitiveValue("collection")) ? "Y" : "N" : ""; 210 r.getCells().add(gen.new Cell(null, null, coll, null, null)); 211 r.getCells().add(gen.new Cell(null, null, column.primitiveValue("type"), null, null)); 212 Cell cell = gen.new Cell(null, null, null, null, null); 213 addFHIRPath(cell.getPieces().get(0), null, column.primitiveValue("path"), null); 214 if (column.has("description")) { 215 cell.addPiece(gen.new Piece("br")); 216 cell.addPiece(gen.new Piece(null, column.primitiveValue("description"), null)); 217 } 218 for (ResourceWrapper tag : column.children("tag")) { 219 cell.addPiece(gen.new Piece("br")); 220 cell.addPiece(gen.new Piece(null, tag.primitiveValue("name")+"="+tag.primitiveValue("value"), null)); 221 } 222 r.getCells().add(cell); 223 } 224 225 private void addFHIRPath(Piece p, String pfx, String expr, String sfx) { 226 XhtmlNode x = new XhtmlNode(NodeType.Element, "span").style("font-size: 11px"); 227 p.addHtml(x); 228 if (pfx != null) { 229 x.tx(pfx); 230 } 231 x.code(expr); 232 if (sfx != null) { 233 x.tx(sfx); 234 } 235 } 236 237 private Row addViewRoot(HierarchicalTableGenerator gen, List<Row> rows, ResourceWrapper vd) throws IOException { 238 Row r = gen.new Row(); 239 rows.add(r); 240 241 r.setIcon("icon_vd_view.png", context.formatPhrase(RenderingContext.QUEST_ROOT)); 242 r.getCells().add(gen.new Cell(null, null, vd.primitiveValue("name"), null, null)); 243 r.getCells().add(gen.new Cell(null, null, "", null, null)); 244 r.getCells().add(gen.new Cell(null, null, vd.primitiveValue("resource"), null, null)); 245 r.getCells().add(gen.new Cell(null, null, vd.primitiveValue("description"), null, null)); 246 return r; 247 } 248 249}