001package org.hl7.fhir.r4.utils; 002 003import java.util.ArrayList; 004import java.util.List; 005 006import org.hl7.fhir.r4.context.IWorkerContext; 007import org.hl7.fhir.r4.model.Base; 008import org.hl7.fhir.r4.model.Bundle; 009import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; 010import org.hl7.fhir.r4.model.Bundle.BundleLinkComponent; 011import org.hl7.fhir.r4.model.CodeableConcept; 012import org.hl7.fhir.r4.model.Coding; 013import org.hl7.fhir.r4.model.ContactDetail; 014import org.hl7.fhir.r4.model.ContactPoint; 015import org.hl7.fhir.r4.model.ContactPoint.ContactPointSystem; 016import org.hl7.fhir.r4.model.ElementDefinition; 017import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent; 018import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent; 019import org.hl7.fhir.r4.model.Meta; 020import org.hl7.fhir.r4.model.OperationOutcome; 021import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity; 022import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; 023import org.hl7.fhir.r4.model.Reference; 024import org.hl7.fhir.r4.model.Resource; 025import org.hl7.fhir.r4.model.ResourceType; 026import org.hl7.fhir.r4.model.Type; 027import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; 028import org.hl7.fhir.utilities.Utilities; 029import org.hl7.fhir.utilities.xhtml.XhtmlComposer; 030 031/** 032 * Decoration utilities for various resource types 033 * @author Grahame 034 * 035 */ 036public class ResourceUtilities { 037 038 public final static String FHIR_LANGUAGE = "urn:ietf:bcp:47"; 039 040 public static boolean isAnError(OperationOutcome error) { 041 for (OperationOutcomeIssueComponent t : error.getIssue()) 042 if (t.getSeverity() == IssueSeverity.ERROR) 043 return true; 044 else if (t.getSeverity() == IssueSeverity.FATAL) 045 return true; 046 return false; 047 } 048 049 public static String getErrorDescription(OperationOutcome error) { 050 if (error.hasText() && error.getText().hasDiv()) 051 return new XhtmlComposer(XhtmlComposer.XML).composePlainText(error.getText().getDiv()); 052 053 StringBuilder b = new StringBuilder(); 054 for (OperationOutcomeIssueComponent t : error.getIssue()) 055 if (t.getSeverity() == IssueSeverity.ERROR) 056 b.append("Error:" +t.getDetails()+"\r\n"); 057 else if (t.getSeverity() == IssueSeverity.FATAL) 058 b.append("Fatal:" +t.getDetails()+"\r\n"); 059 else if (t.getSeverity() == IssueSeverity.WARNING) 060 b.append("Warning:" +t.getDetails()+"\r\n"); 061 else if (t.getSeverity() == IssueSeverity.INFORMATION) 062 b.append("Information:" +t.getDetails()+"\r\n"); 063 return b.toString(); 064 } 065 066 public static Resource getById(Bundle feed, ResourceType type, String reference) { 067 for (BundleEntryComponent item : feed.getEntry()) { 068 if (item.getResource().getId().equals(reference) && item.getResource().getResourceType() == type) 069 return item.getResource(); 070 } 071 return null; 072 } 073 074 public static BundleEntryComponent getEntryById(Bundle feed, ResourceType type, String reference) { 075 for (BundleEntryComponent item : feed.getEntry()) { 076 if (item.getResource().getId().equals(reference) && item.getResource().getResourceType() == type) 077 return item; 078 } 079 return null; 080 } 081 082 public static String getLink(Bundle feed, String rel) { 083 for (BundleLinkComponent link : feed.getLink()) { 084 if (link.getRelation().equals(rel)) 085 return link.getUrl(); 086 } 087 return null; 088 } 089 090 public static Meta meta(Resource resource) { 091 if (!resource.hasMeta()) 092 resource.setMeta(new Meta()); 093 return resource.getMeta(); 094 } 095 096// public static String representDataElementCollection(IWorkerContext context, Bundle bundle, boolean profileLink, String linkBase) { 097// StringBuilder b = new StringBuilder(); 098// DataElement common = showDECHeader(b, bundle); 099// b.append("<table class=\"grid\">\r\n"); 100// List<String> cols = chooseColumns(bundle, common, b, profileLink); 101// for (BundleEntryComponent e : bundle.getEntry()) { 102// DataElement de = (DataElement) e.getResource(); 103// renderDE(de, cols, b, profileLink, linkBase); 104// } 105// b.append("</table>\r\n"); 106// return b.toString(); 107// } 108// 109// 110// private static void renderDE(DataElement de, List<String> cols, StringBuilder b, boolean profileLink, String linkBase) { 111// b.append("<tr>"); 112// for (String col : cols) { 113// String v; 114// ElementDefinition dee = de.getElement().get(0); 115// if (col.equals("DataElement.name")) { 116// v = de.hasName() ? Utilities.escapeXml(de.getName()) : ""; 117// } else if (col.equals("DataElement.status")) { 118// v = de.hasStatusElement() ? de.getStatusElement().asStringValue() : ""; 119// } else if (col.equals("DataElement.code")) { 120// v = renderCoding(dee.getCode()); 121// } else if (col.equals("DataElement.type")) { 122// v = dee.hasType() ? Utilities.escapeXml(dee.getType().get(0).getCode()) : ""; 123// } else if (col.equals("DataElement.units")) { 124// v = renderDEUnits(ToolingExtensions.getAllowedUnits(dee)); 125// } else if (col.equals("DataElement.binding")) { 126// v = renderBinding(dee.getBinding()); 127// } else if (col.equals("DataElement.minValue")) { 128// v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/minValue") ? Utilities.escapeXml(ToolingExtensions.readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/minValue").asStringValue()) : ""; 129// } else if (col.equals("DataElement.maxValue")) { 130// v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/maxValue") ? Utilities.escapeXml(ToolingExtensions.readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/maxValue").asStringValue()) : ""; 131// } else if (col.equals("DataElement.maxLength")) { 132// v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/maxLength") ? Utilities.escapeXml(ToolingExtensions.readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/maxLength").asStringValue()) : ""; 133// } else if (col.equals("DataElement.mask")) { 134// v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/mask") ? Utilities.escapeXml(ToolingExtensions.readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/mask").asStringValue()) : ""; 135// } else 136// throw new Error("Unknown column name: "+col); 137// 138// b.append("<td>"+v+"</td>"); 139// } 140// if (profileLink) { 141// b.append("<td><a href=\""+linkBase+"-"+de.getId()+".html\">Profile</a>, <a href=\"http://www.opencem.org/#/20140917/Intermountain/"+de.getId()+"\">CEM</a>"); 142// if (ToolingExtensions.hasExtension(de, ToolingExtensions.EXT_CIMI_REFERENCE)) 143// b.append(", <a href=\""+ToolingExtensions.readStringExtension(de, ToolingExtensions.EXT_CIMI_REFERENCE)+"\">CIMI</a>"); 144// b.append("</td>"); 145// } 146// b.append("</tr>\r\n"); 147// } 148 149 150 151 private static String renderBinding(ElementDefinitionBindingComponent binding) { 152 // TODO Auto-generated method stub 153 return null; 154 } 155 156 private static String renderDEUnits(Type units) { 157 if (units == null || units.isEmpty()) 158 return ""; 159 if (units instanceof CodeableConcept) 160 return renderCodeable((CodeableConcept) units); 161 else 162 return "<a href=\""+Utilities.escapeXml(((Reference) units).getReference())+"\">"+Utilities.escapeXml(((Reference) units).getReference())+"</a>"; 163 164 } 165 166 private static String renderCodeable(CodeableConcept units) { 167 if (units == null || units.isEmpty()) 168 return ""; 169 String v = renderCoding(units.getCoding()); 170 if (units.hasText()) 171 v = v + " " +Utilities.escapeXml(units.getText()); 172 return v; 173 } 174 175 private static String renderCoding(List<Coding> codes) { 176 CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); 177 for (Coding c : codes) 178 b.append(renderCoding(c)); 179 return b.toString(); 180 } 181 182 private static String renderCoding(Coding code) { 183 if (code == null || code.isEmpty()) 184 return ""; 185 else 186 return "<span title=\""+Utilities.escapeXml(code.getSystem())+"\">"+Utilities.escapeXml(code.getCode())+"</span>"; 187 } 188 189// private static List<String> chooseColumns(Bundle bundle, DataElement common, StringBuilder b, boolean profileLink) { 190// b.append("<tr>"); 191// List<String> results = new ArrayList<String>(); 192// results.add("DataElement.name"); 193// b.append("<td width=\"250\"><b>Name</b></td>"); 194// if (!common.hasStatus()) { 195// results.add("DataElement.status"); 196// b.append("<td><b>Status</b></td>"); 197// } 198// if (hasCode(bundle)) { 199// results.add("DataElement.code"); 200// b.append("<td><b>Code</b></td>"); 201// } 202// if (!common.getElement().get(0).hasType() && hasType(bundle)) { 203// results.add("DataElement.type"); 204// b.append("<td><b>Type</b></td>"); 205// } 206// if (hasUnits(bundle)) { 207// results.add("DataElement.units"); 208// b.append("<td><b>Units</b></td>"); 209// } 210// if (hasBinding(bundle)) { 211// results.add("DataElement.binding"); 212// b.append("<td><b>Binding</b></td>"); 213// } 214// if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/minValue")) { 215// results.add("DataElement.minValue"); 216// b.append("<td><b>Min Value</b></td>"); 217// } 218// if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/maxValue")) { 219// results.add("DataElement.maxValue"); 220// b.append("<td><b>Max Value</b></td>"); 221// } 222// if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/maxLength")) { 223// results.add("DataElement.maxLength"); 224// b.append("<td><b>Max Length</b></td>"); 225// } 226// if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/mask")) { 227// results.add("DataElement.mask"); 228// b.append("<td><b>Mask</b></td>"); 229// } 230// if (profileLink) 231// b.append("<td><b>Links</b></td>"); 232// b.append("</tr>\r\n"); 233// return results; 234// } 235// 236// private static boolean hasExtension(Bundle bundle, String url) { 237// for (BundleEntryComponent e : bundle.getEntry()) { 238// DataElement de = (DataElement) e.getResource(); 239// if (ToolingExtensions.hasExtension(de, url)) 240// return true; 241// } 242// return false; 243// } 244// 245// private static boolean hasBinding(Bundle bundle) { 246// for (BundleEntryComponent e : bundle.getEntry()) { 247// DataElement de = (DataElement) e.getResource(); 248// if (de.getElement().get(0).hasBinding()) 249// return true; 250// } 251// return false; 252// } 253// 254// private static boolean hasCode(Bundle bundle) { 255// for (BundleEntryComponent e : bundle.getEntry()) { 256// DataElement de = (DataElement) e.getResource(); 257// if (de.getElement().get(0).hasCode()) 258// return true; 259// } 260// return false; 261// } 262// 263// private static boolean hasType(Bundle bundle) { 264// for (BundleEntryComponent e : bundle.getEntry()) { 265// DataElement de = (DataElement) e.getResource(); 266// if (de.getElement().get(0).hasType()) 267// return true; 268// } 269// return false; 270// } 271// 272// private static boolean hasUnits(Bundle bundle) { 273// for (BundleEntryComponent e : bundle.getEntry()) { 274// DataElement de = (DataElement) e.getResource(); 275// if (ToolingExtensions.getAllowedUnits(de.getElement().get(0)) != null) 276// return true; 277// } 278// return false; 279// } 280// 281// private static DataElement showDECHeader(StringBuilder b, Bundle bundle) { 282// DataElement meta = new DataElement(); 283// DataElement prototype = (DataElement) bundle.getEntry().get(0).getResource(); 284// meta.setPublisher(prototype.getPublisher()); 285// meta.getContact().addAll(prototype.getContact()); 286// meta.setStatus(prototype.getStatus()); 287// meta.setDate(prototype.getDate()); 288// meta.addElement().getType().addAll(prototype.getElement().get(0).getType()); 289// 290// for (BundleEntryComponent e : bundle.getEntry()) { 291// DataElement de = (DataElement) e.getResource(); 292// if (!Base.compareDeep(de.getPublisherElement(), meta.getPublisherElement(), false)) 293// meta.setPublisherElement(null); 294// if (!Base.compareDeep(de.getContact(), meta.getContact(), false)) 295// meta.getContact().clear(); 296// if (!Base.compareDeep(de.getStatusElement(), meta.getStatusElement(), false)) 297// meta.setStatusElement(null); 298// if (!Base.compareDeep(de.getDateElement(), meta.getDateElement(), false)) 299// meta.setDateElement(null); 300// if (!Base.compareDeep(de.getElement().get(0).getType(), meta.getElement().get(0).getType(), false)) 301// meta.getElement().get(0).getType().clear(); 302// } 303// if (meta.hasPublisher() || meta.hasContact() || meta.hasStatus() || meta.hasDate() /* || meta.hasType() */) { 304// b.append("<table class=\"grid\">\r\n"); 305// if (meta.hasPublisher()) 306// b.append("<tr><td>Publisher:</td><td>"+meta.getPublisher()+"</td></tr>\r\n"); 307// if (meta.hasContact()) { 308// b.append("<tr><td>Contacts:</td><td>"); 309// boolean firsti = true; 310// for (ContactDetail c : meta.getContact()) { 311// if (firsti) 312// firsti = false; 313// else 314// b.append("<br/>"); 315// if (c.hasName()) 316// b.append(Utilities.escapeXml(c.getName())+": "); 317// boolean first = true; 318// for (ContactPoint cp : c.getTelecom()) { 319// if (first) 320// first = false; 321// else 322// b.append(", "); 323// renderContactPoint(b, cp); 324// } 325// } 326// b.append("</td></tr>\r\n"); 327// } 328// if (meta.hasStatus()) 329// b.append("<tr><td>Status:</td><td>"+meta.getStatus().toString()+"</td></tr>\r\n"); 330// if (meta.hasDate()) 331// b.append("<tr><td>Date:</td><td>"+meta.getDateElement().asStringValue()+"</td></tr>\r\n"); 332// if (meta.getElement().get(0).hasType()) 333// b.append("<tr><td>Type:</td><td>"+renderType(meta.getElement().get(0).getType())+"</td></tr>\r\n"); 334// b.append("</table>\r\n"); 335// } 336// return meta; 337// } 338 339 private static String renderType(List<TypeRefComponent> type) { 340 if (type == null || type.isEmpty()) 341 return ""; 342 CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); 343 for (TypeRefComponent c : type) 344 b.append(renderType(c)); 345 return b.toString(); 346 } 347 348 private static String renderType(TypeRefComponent type) { 349 if (type == null || type.isEmpty()) 350 return ""; 351 return type.getCode(); 352 } 353 354 public static void renderContactPoint(StringBuilder b, ContactPoint cp) { 355 if (cp != null && !cp.isEmpty()) { 356 if (cp.getSystem() == ContactPointSystem.EMAIL) 357 b.append("<a href=\"mailto:"+cp.getValue()+"\">"+cp.getValue()+"</a>"); 358 else if (cp.getSystem() == ContactPointSystem.FAX) 359 b.append("Fax: "+cp.getValue()); 360 else if (cp.getSystem() == ContactPointSystem.OTHER) 361 b.append("<a href=\""+cp.getValue()+"\">"+cp.getValue()+"</a>"); 362 else 363 b.append(cp.getValue()); 364 } 365 } 366}