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