
001package org.hl7.fhir.dstu2.utils; 002 003/* 004 Copyright (c) 2011+, HL7, Inc. 005 All rights reserved. 006 007 Redistribution and use in source and binary forms, with or without modification, 008 are permitted provided that the following conditions are met: 009 010 * Redistributions of source code must retain the above copyright notice, this 011 list of conditions and the following disclaimer. 012 * Redistributions in binary form must reproduce the above copyright notice, 013 this list of conditions and the following disclaimer in the documentation 014 and/or other materials provided with the distribution. 015 * Neither the name of HL7 nor the names of its contributors may be used to 016 endorse or promote products derived from this software without specific 017 prior written permission. 018 019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 POSSIBILITY OF SUCH DAMAGE. 029 030 */ 031 032import java.util.ArrayList; 033import java.util.List; 034 035import org.hl7.fhir.dstu2.model.Base; 036import org.hl7.fhir.dstu2.model.Bundle; 037import org.hl7.fhir.dstu2.model.Bundle.BundleEntryComponent; 038import org.hl7.fhir.dstu2.model.Bundle.BundleLinkComponent; 039import org.hl7.fhir.dstu2.model.CodeableConcept; 040import org.hl7.fhir.dstu2.model.Coding; 041import org.hl7.fhir.dstu2.model.ContactPoint; 042import org.hl7.fhir.dstu2.model.ContactPoint.ContactPointSystem; 043import org.hl7.fhir.dstu2.model.DataElement; 044import org.hl7.fhir.dstu2.model.DataElement.DataElementContactComponent; 045import org.hl7.fhir.dstu2.model.ElementDefinition; 046import org.hl7.fhir.dstu2.model.ElementDefinition.ElementDefinitionBindingComponent; 047import org.hl7.fhir.dstu2.model.ElementDefinition.TypeRefComponent; 048import org.hl7.fhir.dstu2.model.Meta; 049import org.hl7.fhir.dstu2.model.OperationOutcome; 050import org.hl7.fhir.dstu2.model.OperationOutcome.IssueSeverity; 051import org.hl7.fhir.dstu2.model.OperationOutcome.OperationOutcomeIssueComponent; 052import org.hl7.fhir.dstu2.model.Reference; 053import org.hl7.fhir.dstu2.model.Resource; 054import org.hl7.fhir.dstu2.model.ResourceType; 055import org.hl7.fhir.dstu2.model.Type; 056import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; 057import org.hl7.fhir.utilities.Utilities; 058import org.hl7.fhir.utilities.xhtml.XhtmlComposer; 059 060/** 061 * Decoration utilities for various resource types 062 * 063 * @author Grahame 064 * 065 */ 066@Deprecated 067public class ResourceUtilities { 068 069 public final static String FHIR_LANGUAGE = "urn:ietf:bcp:47"; 070 071 public static boolean isAnError(OperationOutcome error) { 072 for (OperationOutcomeIssueComponent t : error.getIssue()) 073 if (t.getSeverity() == IssueSeverity.ERROR) 074 return true; 075 else if (t.getSeverity() == IssueSeverity.FATAL) 076 return true; 077 return false; 078 } 079 080 public static String getErrorDescription(OperationOutcome error) { 081 if (error.hasText() && error.getText().hasDiv()) 082 return new XhtmlComposer(true, false).composePlainText(error.getText().getDiv()); 083 084 StringBuilder b = new StringBuilder(); 085 for (OperationOutcomeIssueComponent t : error.getIssue()) 086 if (t.getSeverity() == IssueSeverity.ERROR) 087 b.append("Error:" + t.getDetails() + "\r\n"); 088 else if (t.getSeverity() == IssueSeverity.FATAL) 089 b.append("Fatal:" + t.getDetails() + "\r\n"); 090 else if (t.getSeverity() == IssueSeverity.WARNING) 091 b.append("Warning:" + t.getDetails() + "\r\n"); 092 else if (t.getSeverity() == IssueSeverity.INFORMATION) 093 b.append("Information:" + t.getDetails() + "\r\n"); 094 return b.toString(); 095 } 096 097 public static Resource getById(Bundle feed, ResourceType type, String reference) { 098 for (BundleEntryComponent item : feed.getEntry()) { 099 if (item.getResource().getId().equals(reference) && item.getResource().getResourceType() == type) 100 return item.getResource(); 101 } 102 return null; 103 } 104 105 public static BundleEntryComponent getEntryById(Bundle feed, ResourceType type, String reference) { 106 for (BundleEntryComponent item : feed.getEntry()) { 107 if (item.getResource().getId().equals(reference) && item.getResource().getResourceType() == type) 108 return item; 109 } 110 return null; 111 } 112 113 public static String getLink(Bundle feed, String rel) { 114 for (BundleLinkComponent link : feed.getLink()) { 115 if (link.getRelation().equals(rel)) 116 return link.getUrl(); 117 } 118 return null; 119 } 120 121 public static Meta meta(Resource resource) { 122 if (!resource.hasMeta()) 123 resource.setMeta(new Meta()); 124 return resource.getMeta(); 125 } 126 127 public static String representDataElementCollection(IWorkerContext context, Bundle bundle, boolean profileLink, 128 String linkBase) { 129 StringBuilder b = new StringBuilder(); 130 DataElement common = showDECHeader(b, bundle); 131 b.append("<table class=\"grid\">\r\n"); 132 List<String> cols = chooseColumns(bundle, common, b, profileLink); 133 for (BundleEntryComponent e : bundle.getEntry()) { 134 DataElement de = (DataElement) e.getResource(); 135 renderDE(de, cols, b, profileLink, linkBase); 136 } 137 b.append("</table>\r\n"); 138 return b.toString(); 139 } 140 141 private static void renderDE(DataElement de, List<String> cols, StringBuilder b, boolean profileLink, 142 String linkBase) { 143 b.append("<tr>"); 144 for (String col : cols) { 145 String v; 146 ElementDefinition dee = de.getElement().get(0); 147 if (col.equals("DataElement.name")) { 148 v = de.hasName() ? Utilities.escapeXml(de.getName()) : ""; 149 } else if (col.equals("DataElement.status")) { 150 v = de.hasStatusElement() ? de.getStatusElement().asStringValue() : ""; 151 } else if (col.equals("DataElement.code")) { 152 v = renderCoding(dee.getCode()); 153 } else if (col.equals("DataElement.type")) { 154 v = dee.hasType() ? Utilities.escapeXml(dee.getType().get(0).getCode()) : ""; 155 } else if (col.equals("DataElement.units")) { 156 v = renderDEUnits(ToolingExtensions.getAllowedUnits(dee)); 157 } else if (col.equals("DataElement.binding")) { 158 v = renderBinding(dee.getBinding()); 159 } else if (col.equals("DataElement.minValue")) { 160 v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/minValue") 161 ? Utilities.escapeXml(ToolingExtensions 162 .readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/minValue").asStringValue()) 163 : ""; 164 } else if (col.equals("DataElement.maxValue")) { 165 v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/maxValue") 166 ? Utilities.escapeXml(ToolingExtensions 167 .readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/maxValue").asStringValue()) 168 : ""; 169 } else if (col.equals("DataElement.maxLength")) { 170 v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/maxLength") 171 ? Utilities.escapeXml(ToolingExtensions 172 .readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/maxLength").asStringValue()) 173 : ""; 174 } else if (col.equals("DataElement.mask")) { 175 v = ToolingExtensions.hasExtension(de, "http://hl7.org/fhir/StructureDefinition/mask") 176 ? Utilities.escapeXml(ToolingExtensions 177 .readPrimitiveExtension(de, "http://hl7.org/fhir/StructureDefinition/mask").asStringValue()) 178 : ""; 179 } else 180 throw new Error("Unknown column name: " + col); 181 182 b.append("<td>" + v + "</td>"); 183 } 184 if (profileLink) { 185 b.append("<td><a href=\"" + linkBase + "-" + de.getId() 186 + ".html\">Profile</a>, <a href=\"http://www.opencem.org/#/20140917/Intermountain/" + de.getId() 187 + "\">CEM</a>"); 188 if (ToolingExtensions.hasExtension(de, ToolingExtensions.EXT_CIMI_REFERENCE)) 189 b.append(", <a href=\"" + ToolingExtensions.readStringExtension(de, ToolingExtensions.EXT_CIMI_REFERENCE) 190 + "\">CIMI</a>"); 191 b.append("</td>"); 192 } 193 b.append("</tr>\r\n"); 194 } 195 196 private static String renderBinding(ElementDefinitionBindingComponent binding) { 197 // TODO Auto-generated method stub 198 return null; 199 } 200 201 private static String renderDEUnits(Type units) { 202 if (units == null || units.isEmpty()) 203 return ""; 204 if (units instanceof CodeableConcept) 205 return renderCodeable((CodeableConcept) units); 206 else 207 return "<a href=\"" + Utilities.escapeXml(((Reference) units).getReference()) + "\">" 208 + Utilities.escapeXml(((Reference) units).getReference()) + "</a>"; 209 210 } 211 212 private static String renderCodeable(CodeableConcept units) { 213 if (units == null || units.isEmpty()) 214 return ""; 215 String v = renderCoding(units.getCoding()); 216 if (units.hasText()) 217 v = v + " " + Utilities.escapeXml(units.getText()); 218 return v; 219 } 220 221 private static String renderCoding(List<Coding> codes) { 222 CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); 223 for (Coding c : codes) 224 b.append(renderCoding(c)); 225 return b.toString(); 226 } 227 228 private static String renderCoding(Coding code) { 229 if (code == null || code.isEmpty()) 230 return ""; 231 else 232 return "<span title=\"" + Utilities.escapeXml(code.getSystem()) + "\">" + Utilities.escapeXml(code.getCode()) 233 + "</span>"; 234 } 235 236 private static List<String> chooseColumns(Bundle bundle, DataElement common, StringBuilder b, boolean profileLink) { 237 b.append("<tr>"); 238 List<String> results = new ArrayList<String>(); 239 results.add("DataElement.name"); 240 b.append("<td width=\"250\"><b>Name</b></td>"); 241 if (!common.hasStatus()) { 242 results.add("DataElement.status"); 243 b.append("<td><b>Status</b></td>"); 244 } 245 if (hasCode(bundle)) { 246 results.add("DataElement.code"); 247 b.append("<td><b>Code</b></td>"); 248 } 249 if (!common.getElement().get(0).hasType() && hasType(bundle)) { 250 results.add("DataElement.type"); 251 b.append("<td><b>Type</b></td>"); 252 } 253 if (hasUnits(bundle)) { 254 results.add("DataElement.units"); 255 b.append("<td><b>Units</b></td>"); 256 } 257 if (hasBinding(bundle)) { 258 results.add("DataElement.binding"); 259 b.append("<td><b>Binding</b></td>"); 260 } 261 if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/minValue")) { 262 results.add("DataElement.minValue"); 263 b.append("<td><b>Min Value</b></td>"); 264 } 265 if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/maxValue")) { 266 results.add("DataElement.maxValue"); 267 b.append("<td><b>Max Value</b></td>"); 268 } 269 if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/maxLength")) { 270 results.add("DataElement.maxLength"); 271 b.append("<td><b>Max Length</b></td>"); 272 } 273 if (hasExtension(bundle, "http://hl7.org/fhir/StructureDefinition/mask")) { 274 results.add("DataElement.mask"); 275 b.append("<td><b>Mask</b></td>"); 276 } 277 if (profileLink) 278 b.append("<td><b>Links</b></td>"); 279 b.append("</tr>\r\n"); 280 return results; 281 } 282 283 private static boolean hasExtension(Bundle bundle, String url) { 284 for (BundleEntryComponent e : bundle.getEntry()) { 285 DataElement de = (DataElement) e.getResource(); 286 if (ToolingExtensions.hasExtension(de, url)) 287 return true; 288 } 289 return false; 290 } 291 292 private static boolean hasBinding(Bundle bundle) { 293 for (BundleEntryComponent e : bundle.getEntry()) { 294 DataElement de = (DataElement) e.getResource(); 295 if (de.getElement().get(0).hasBinding()) 296 return true; 297 } 298 return false; 299 } 300 301 private static boolean hasCode(Bundle bundle) { 302 for (BundleEntryComponent e : bundle.getEntry()) { 303 DataElement de = (DataElement) e.getResource(); 304 if (de.getElement().get(0).hasCode()) 305 return true; 306 } 307 return false; 308 } 309 310 private static boolean hasType(Bundle bundle) { 311 for (BundleEntryComponent e : bundle.getEntry()) { 312 DataElement de = (DataElement) e.getResource(); 313 if (de.getElement().get(0).hasType()) 314 return true; 315 } 316 return false; 317 } 318 319 private static boolean hasUnits(Bundle bundle) { 320 for (BundleEntryComponent e : bundle.getEntry()) { 321 DataElement de = (DataElement) e.getResource(); 322 if (ToolingExtensions.getAllowedUnits(de.getElement().get(0)) != null) 323 return true; 324 } 325 return false; 326 } 327 328 private static DataElement showDECHeader(StringBuilder b, Bundle bundle) { 329 DataElement meta = new DataElement(); 330 DataElement prototype = (DataElement) bundle.getEntry().get(0).getResource(); 331 meta.setPublisher(prototype.getPublisher()); 332 meta.getContact().addAll(prototype.getContact()); 333 meta.setStatus(prototype.getStatus()); 334 meta.setDate(prototype.getDate()); 335 meta.addElement().getType().addAll(prototype.getElement().get(0).getType()); 336 337 for (BundleEntryComponent e : bundle.getEntry()) { 338 DataElement de = (DataElement) e.getResource(); 339 if (!Base.compareDeep(de.getPublisherElement(), meta.getPublisherElement(), false)) 340 meta.setPublisherElement(null); 341 if (!Base.compareDeep(de.getContact(), meta.getContact(), false)) 342 meta.getContact().clear(); 343 if (!Base.compareDeep(de.getStatusElement(), meta.getStatusElement(), false)) 344 meta.setStatusElement(null); 345 if (!Base.compareDeep(de.getDateElement(), meta.getDateElement(), false)) 346 meta.setDateElement(null); 347 if (!Base.compareDeep(de.getElement().get(0).getType(), meta.getElement().get(0).getType(), false)) 348 meta.getElement().get(0).getType().clear(); 349 } 350 if (meta.hasPublisher() || meta.hasContact() || meta.hasStatus() || meta.hasDate() /* || meta.hasType() */) { 351 b.append("<table class=\"grid\">\r\n"); 352 if (meta.hasPublisher()) 353 b.append("<tr><td>Publisher:</td><td>" + meta.getPublisher() + "</td></tr>\r\n"); 354 if (meta.hasContact()) { 355 b.append("<tr><td>Contacts:</td><td>"); 356 boolean firsti = true; 357 for (DataElementContactComponent c : meta.getContact()) { 358 if (firsti) 359 firsti = false; 360 else 361 b.append("<br/>"); 362 if (c.hasName()) 363 b.append(Utilities.escapeXml(c.getName()) + ": "); 364 boolean first = true; 365 for (ContactPoint cp : c.getTelecom()) { 366 if (first) 367 first = false; 368 else 369 b.append(", "); 370 renderContactPoint(b, cp); 371 } 372 } 373 b.append("</td></tr>\r\n"); 374 } 375 if (meta.hasStatus()) 376 b.append("<tr><td>Status:</td><td>" + meta.getStatus().toString() + "</td></tr>\r\n"); 377 if (meta.hasDate()) 378 b.append("<tr><td>Date:</td><td>" + meta.getDateElement().asStringValue() + "</td></tr>\r\n"); 379 if (meta.getElement().get(0).hasType()) 380 b.append("<tr><td>Type:</td><td>" + renderType(meta.getElement().get(0).getType()) + "</td></tr>\r\n"); 381 b.append("</table>\r\n"); 382 } 383 return meta; 384 } 385 386 private static String renderType(List<TypeRefComponent> type) { 387 if (type == null || type.isEmpty()) 388 return ""; 389 CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); 390 for (TypeRefComponent c : type) 391 b.append(renderType(c)); 392 return b.toString(); 393 } 394 395 private static String renderType(TypeRefComponent type) { 396 if (type == null || type.isEmpty()) 397 return ""; 398 return type.getCode(); 399 } 400 401 public static void renderContactPoint(StringBuilder b, ContactPoint cp) { 402 if (cp != null && !cp.isEmpty()) { 403 if (cp.getSystem() == ContactPointSystem.EMAIL) 404 b.append("<a href=\"mailto:" + cp.getValue() + "\">" + cp.getValue() + "</a>"); 405 else if (cp.getSystem() == ContactPointSystem.FAX) 406 b.append("Fax: " + cp.getValue()); 407 else if (cp.getSystem() == ContactPointSystem.OTHER) 408 b.append("<a href=\"" + cp.getValue() + "\">" + cp.getValue() + "</a>"); 409 else 410 b.append(cp.getValue()); 411 } 412 } 413}