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