001package org.hl7.fhir.dstu3.utils; 002 003/* 004Copyright (c) 2011+, HL7, Inc 005All rights reserved. 006 007Redistribution and use in source and binary forms, with or without modification, 008are 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 019THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028POSSIBILITY OF SUCH DAMAGE. 029 030 */ 031 032import java.util.ArrayList; 033import java.util.Iterator; 034import java.util.List; 035 036import org.apache.commons.lang3.StringUtils; 037import org.hl7.fhir.dstu3.model.BooleanType; 038import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent; 039import org.hl7.fhir.dstu3.model.CodeType; 040import org.hl7.fhir.dstu3.model.CodeableConcept; 041import org.hl7.fhir.dstu3.model.Coding; 042import org.hl7.fhir.dstu3.model.DataElement; 043import org.hl7.fhir.dstu3.model.DomainResource; 044import org.hl7.fhir.dstu3.model.Element; 045import org.hl7.fhir.dstu3.model.ElementDefinition; 046import org.hl7.fhir.dstu3.model.Extension; 047import org.hl7.fhir.dstu3.model.ExtensionHelper; 048import org.hl7.fhir.dstu3.model.Factory; 049import org.hl7.fhir.dstu3.model.Identifier; 050import org.hl7.fhir.dstu3.model.IntegerType; 051import org.hl7.fhir.dstu3.model.MarkdownType; 052import org.hl7.fhir.dstu3.model.PrimitiveType; 053import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent; 054import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType; 055import org.hl7.fhir.dstu3.model.StringType; 056import org.hl7.fhir.dstu3.model.Type; 057import org.hl7.fhir.dstu3.model.UriType; 058 059 060public class ToolingExtensions { 061 062 // validated 063 public static final String EXT_SUBSUMES = "http://hl7.org/fhir/StructureDefinition/codesystem-subsumes"; 064// private static final String EXT_OID = "http://hl7.org/fhir/StructureDefinition/valueset-oid"; 065// public static final String EXT_DEPRECATED = "http://hl7.org/fhir/StructureDefinition/codesystem-deprecated"; 066 public static final String EXT_DEFINITION = "http://hl7.org/fhir/StructureDefinition/valueset-definition"; 067 public static final String EXT_COMMENT = "http://hl7.org/fhir/StructureDefinition/valueset-comments"; 068 private static final String EXT_IDENTIFIER = "http://hl7.org/fhir/StructureDefinition/identifier"; 069 public static final String EXT_TRANSLATION = "http://hl7.org/fhir/StructureDefinition/translation"; 070 public static final String EXT_ISSUE_SOURCE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-source"; 071 public static final String EXT_DISPLAY_HINT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-display-hint"; 072 public static final String EXT_REPLACED_BY = "http://hl7.org/fhir/StructureDefinition/valueset-replacedby"; 073 public static final String EXT_JSON_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-json-type"; 074 public static final String EXT_RDF_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-rdf-type"; 075 public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type"; 076 public static final String EXT_REGEX = "http://hl7.org/fhir/StructureDefinition/structuredefinition-regex"; 077 public static final String EXT_CONTROL = "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl"; 078 public static final String EXT_MINOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-minOccurs"; 079 public static final String EXT_MAXOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-maxOccurs"; 080 public static final String EXT_ALLOWEDRESOURCE = "http://hl7.org/fhir/StructureDefinition/questionnaire-allowedResource"; 081 public static final String EXT_REFERENCEFILTER = "http://hl7.org/fhir/StructureDefinition/questionnaire-referenceFilter"; 082 public static final String EXT_CODE_GENERATION_PARENT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-codegen-super"; 083 084 // unregistered? 085 public static final String EXT_MAPPING_PREFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-prefix"; 086 public static final String EXT_MAPPING_SUFFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-suffix"; 087 088// public static final String EXT_FLYOVER = "http://hl7.org/fhir/Profile/questionnaire-extensions#flyover"; 089// private static final String EXT_QTYPE = "http://www.healthintersections.com.au/fhir/Profile/metadata#type"; 090// private static final String EXT_QREF = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference"; 091// private static final String EXTENSION_FILTER_ONLY = "http://www.healthintersections.com.au/fhir/Profile/metadata#expandNeedsFilter"; 092// private static final String EXT_TYPE = "http://www.healthintersections.com.au/fhir/Profile/metadata#type"; 093// private static final String EXT_REFERENCE = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference"; 094 private static final String EXT_FHIRTYPE = "http://hl7.org/fhir/StructureDefinition/questionnaire-fhirType"; 095 private static final String EXT_ALLOWABLE_UNITS = "http://hl7.org/fhir/StructureDefinition/elementdefinition-allowedUnits"; 096 public static final String EXT_CIMI_REFERENCE = "http://hl7.org/fhir/StructureDefinition/cimi-reference"; 097 public static final String EXT_UNCLOSED = "http://hl7.org/fhir/StructureDefinition/valueset-unclosed"; 098 public static final String EXT_FMM_LEVEL = "http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm"; 099 public static final String EXT_RESOURCE_CATEGORY = "http://hl7.org/fhir/StructureDefinition/structuredefinition-category"; 100 public static final String EXT_TABLE_NAME = "http://hl7.org/fhir/StructureDefinition/structuredefinition-table-name"; 101 public static final String EXT_OO_FILE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-file"; 102 103 104 105 // specific extension helpers 106 107// public static Extension makeIssueSource(Source source) { 108// Extension ex = new Extension(); 109// // todo: write this up and get it published with the pack (and handle the redirect?) 110// ex.setUrl(ToolingExtensions.EXT_ISSUE_SOURCE); 111// CodeType c = new CodeType(); 112// c.setValue(source.toString()); 113// ex.setValue(c); 114// return ex; 115// } 116 117 public static boolean hasExtension(DomainResource de, String url) { 118 return getExtension(de, url) != null; 119 } 120 121 public static boolean hasExtension(Element e, String url) { 122 return getExtension(e, url) != null; 123 } 124 125// public static void addStringExtension(DomainResource dr, String url, String content) { 126// if (!StringUtils.isBlank(content)) { 127// Extension ex = getExtension(dr, url); 128// if (ex != null) 129// ex.setValue(new StringType(content)); 130// else 131// dr.getExtension().add(Factory.newExtension(url, new StringType(content), true)); 132// } 133// } 134 135 public static void addMarkdownExtension(DomainResource dr, String url, String content) { 136 if (!StringUtils.isBlank(content)) { 137 Extension ex = getExtension(dr, url); 138 if (ex != null) 139 ex.setValue(new StringType(content)); 140 else 141 dr.getExtension().add(Factory.newExtension(url, new MarkdownType(content), true)); 142 } 143 } 144 145 public static void addStringExtension(Element e, String url, String content) { 146 if (!StringUtils.isBlank(content)) { 147 Extension ex = getExtension(e, url); 148 if (ex != null) 149 ex.setValue(new StringType(content)); 150 else 151 e.getExtension().add(Factory.newExtension(url, new StringType(content), true)); 152 } 153 } 154 155 public static void addStringExtension(DomainResource e, String url, String content) { 156 if (!StringUtils.isBlank(content)) { 157 Extension ex = getExtension(e, url); 158 if (ex != null) 159 ex.setValue(new StringType(content)); 160 else 161 e.getExtension().add(Factory.newExtension(url, new StringType(content), true)); 162 } 163 } 164 165 public static void addIntegerExtension(DomainResource dr, String url, int value) { 166 Extension ex = getExtension(dr, url); 167 if (ex != null) 168 ex.setValue(new IntegerType(value)); 169 else 170 dr.getExtension().add(Factory.newExtension(url, new IntegerType(value), true)); 171 } 172 173 public static void addComment(Element nc, String comment) { 174 if (!StringUtils.isBlank(comment)) 175 nc.getExtension().add(Factory.newExtension(EXT_COMMENT, Factory.newString_(comment), true)); 176 } 177 178// public static void markDeprecated(Element nc) { 179// setDeprecated(nc); 180// } 181// 182 public static void addSubsumes(ConceptDefinitionComponent nc, String code) { 183 nc.getModifierExtension().add(Factory.newExtension(EXT_SUBSUMES, Factory.newCode(code), true)); 184 } 185 186 public static void addDefinition(Element nc, String definition) { 187 if (!StringUtils.isBlank(definition)) 188 nc.getExtension().add(Factory.newExtension(EXT_DEFINITION, Factory.newString_(definition), true)); 189 } 190 191 public static void addDisplayHint(Element def, String hint) { 192 if (!StringUtils.isBlank(hint)) 193 def.getExtension().add(Factory.newExtension(EXT_DISPLAY_HINT, Factory.newString_(hint), true)); 194 } 195 196 public static String getDisplayHint(Element def) { 197 return readStringExtension(def, EXT_DISPLAY_HINT); 198 } 199 200 public static String readStringExtension(Element c, String uri) { 201 Extension ex = ExtensionHelper.getExtension(c, uri); 202 if (ex == null) 203 return null; 204 if (ex.getValue() instanceof UriType) 205 return ((UriType) ex.getValue()).getValue(); 206 if (!(ex.getValue() instanceof StringType)) 207 return null; 208 return ((StringType) ex.getValue()).getValue(); 209 } 210 211 public static String readStringExtension(DomainResource c, String uri) { 212 Extension ex = getExtension(c, uri); 213 if (ex == null) 214 return null; 215 if ((ex.getValue() instanceof StringType)) 216 return ((StringType) ex.getValue()).getValue(); 217 if ((ex.getValue() instanceof UriType)) 218 return ((UriType) ex.getValue()).getValue(); 219 if ((ex.getValue() instanceof MarkdownType)) 220 return ((MarkdownType) ex.getValue()).getValue(); 221 return null; 222 } 223 224 @SuppressWarnings("unchecked") 225 public static PrimitiveType<Type> readPrimitiveExtension(DomainResource c, String uri) { 226 Extension ex = getExtension(c, uri); 227 if (ex == null) 228 return null; 229 return (PrimitiveType<Type>) ex.getValue(); 230 } 231 232 public static boolean findStringExtension(Element c, String uri) { 233 Extension ex = ExtensionHelper.getExtension(c, uri); 234 if (ex == null) 235 return false; 236 if (!(ex.getValue() instanceof StringType)) 237 return false; 238 return !StringUtils.isBlank(((StringType) ex.getValue()).getValue()); 239 } 240 241 public static Boolean readBooleanExtension(Element c, String uri) { 242 Extension ex = ExtensionHelper.getExtension(c, uri); 243 if (ex == null) 244 return null; 245 if (!(ex.getValue() instanceof BooleanType)) 246 return null; 247 return ((BooleanType) ex.getValue()).getValue(); 248 } 249 250 public static boolean findBooleanExtension(Element c, String uri) { 251 Extension ex = ExtensionHelper.getExtension(c, uri); 252 if (ex == null) 253 return false; 254 if (!(ex.getValue() instanceof BooleanType)) 255 return false; 256 return true; 257 } 258 259 public static String getComment(ConceptDefinitionComponent c) { 260 return readStringExtension(c, EXT_COMMENT); 261 } 262// 263// public static Boolean getDeprecated(Element c) { 264// return readBooleanExtension(c, EXT_DEPRECATED); 265// } 266 267 public static boolean hasComment(ConceptDefinitionComponent c) { 268 return findStringExtension(c, EXT_COMMENT); 269 } 270 271// public static boolean hasDeprecated(Element c) { 272// return findBooleanExtension(c, EXT_DEPRECATED); 273// } 274 275 public static List<CodeType> getSubsumes(ConceptDefinitionComponent c) { 276 List<CodeType> res = new ArrayList<CodeType>(); 277 278 for (Extension e : c.getExtension()) { 279 if (EXT_SUBSUMES.equals(e.getUrl())) 280 res.add((CodeType) e.getValue()); 281 } 282 return res; 283 } 284 285 public static void addFlyOver(QuestionnaireItemComponent item, String text){ 286 if (!StringUtils.isBlank(text)) { 287 QuestionnaireItemComponent display = item.addItem(); 288 display.setType(QuestionnaireItemType.DISPLAY); 289 display.setText(text); 290 display.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept("flyover", "http://hl7.org/fhir/questionnaire-item-control", "Fly-over"), true)); 291 } 292 } 293 294 public static void addMin(QuestionnaireItemComponent item, int min) { 295 item.getExtension().add(Factory.newExtension(EXT_MINOCCURS, Factory.newInteger(min), true)); 296 } 297 298 public static void addMax(QuestionnaireItemComponent item, int max) { 299 item.getExtension().add(Factory.newExtension(EXT_MAXOCCURS, Factory.newInteger(max), true)); 300 } 301 302 public static void addFhirType(QuestionnaireItemComponent group, String value) { 303 group.getExtension().add(Factory.newExtension(EXT_FHIRTYPE, Factory.newString_(value), true)); 304 } 305 306 public static void addControl(QuestionnaireItemComponent group, String value) { 307 group.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept(value, "http://hl7.org/fhir/questionnaire-item-control", value), true)); 308 } 309 310 public static void addAllowedResource(QuestionnaireItemComponent group, String value) { 311 group.getExtension().add(Factory.newExtension(EXT_ALLOWEDRESOURCE, Factory.newCode(value), true)); 312 } 313 314 public static void addReferenceFilter(QuestionnaireItemComponent group, String value) { 315 group.getExtension().add(Factory.newExtension(EXT_REFERENCEFILTER, Factory.newString_(value), true)); 316 } 317 318 public static void addIdentifier(Element element, Identifier value) { 319 element.getExtension().add(Factory.newExtension(EXT_IDENTIFIER, value, true)); 320 } 321 322 /** 323 * @param name the identity of the extension of interest 324 * @return The extension, if on this element, else null 325 */ 326 public static Extension getExtension(DomainResource resource, String name) { 327 if (name == null) 328 return null; 329 if (!resource.hasExtension()) 330 return null; 331 for (Extension e : resource.getExtension()) { 332 if (name.equals(e.getUrl())) 333 return e; 334 } 335 return null; 336 } 337 338 public static Extension getExtension(Element el, String name) { 339 if (name == null) 340 return null; 341 if (!el.hasExtension()) 342 return null; 343 for (Extension e : el.getExtension()) { 344 if (name.equals(e.getUrl())) 345 return e; 346 } 347 return null; 348 } 349 350 public static void setStringExtension(DomainResource resource, String uri, String value) { 351 Extension ext = getExtension(resource, uri); 352 if (ext != null) 353 ext.setValue(new StringType(value)); 354 else 355 resource.getExtension().add(new Extension(new UriType(uri)).setValue(new StringType(value))); 356 } 357 358// public static String getOID(CodeSystem define) { 359// return readStringExtension(define, EXT_OID); 360// } 361// 362// public static String getOID(ValueSet vs) { 363// return readStringExtension(vs, EXT_OID); 364// } 365// 366// public static void setOID(CodeSystem define, String oid) throws FHIRFormatError, URISyntaxException { 367// if (!oid.startsWith("urn:oid:")) 368// throw new FHIRFormatError("Error in OID format"); 369// if (oid.startsWith("urn:oid:urn:oid:")) 370// throw new FHIRFormatError("Error in OID format"); 371// if (!hasExtension(define, EXT_OID)) 372// define.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false)); 373// else if (!oid.equals(readStringExtension(define, EXT_OID))) 374// throw new Error("Attempt to assign multiple OIDs to a code system"); 375// } 376// public static void setOID(ValueSet vs, String oid) throws FHIRFormatError, URISyntaxException { 377// if (!oid.startsWith("urn:oid:")) 378// throw new FHIRFormatError("Error in OID format"); 379// if (oid.startsWith("urn:oid:urn:oid:")) 380// throw new FHIRFormatError("Error in OID format"); 381// if (!hasExtension(vs, EXT_OID)) 382// vs.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false)); 383// else if (!oid.equals(readStringExtension(vs, EXT_OID))) 384// throw new Error("Attempt to assign multiple OIDs to value set "+vs.getName()+" ("+vs.getUrl()+"). Has "+readStringExtension(vs, EXT_OID)+", trying to add "+oid); 385// } 386 387 public static boolean hasLanguageTranslation(Element element, String lang) { 388 for (Extension e : element.getExtension()) { 389 if (e.getUrl().equals(EXT_TRANSLATION)) { 390 Extension e1 = ExtensionHelper.getExtension(e, "lang"); 391 392 if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang)) 393 return true; 394 } 395 } 396 return false; 397 } 398 399 public static String getLanguageTranslation(Element element, String lang) { 400 for (Extension e : element.getExtension()) { 401 if (e.getUrl().equals(EXT_TRANSLATION)) { 402 Extension e1 = ExtensionHelper.getExtension(e, "lang"); 403 404 if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang)) { 405 e1 = ExtensionHelper.getExtension(e, "content"); 406 return ((StringType) e.getValue()).getValue(); 407 } 408 } 409 } 410 return null; 411 } 412 413 public static void addLanguageTranslation(Element element, String lang, String value) { 414 Extension extension = new Extension().setUrl(EXT_TRANSLATION); 415 extension.addExtension().setUrl("lang").setValue(new StringType(lang)); 416 extension.addExtension().setUrl("content").setValue(new StringType(value)); 417 element.getExtension().add(extension); 418 } 419 420 public static Type getAllowedUnits(ElementDefinition eld) { 421 for (Extension e : eld.getExtension()) 422 if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) 423 return e.getValue(); 424 return null; 425 } 426 427 public static void setAllowableUnits(ElementDefinition eld, CodeableConcept cc) { 428 for (Extension e : eld.getExtension()) 429 if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) { 430 e.setValue(cc); 431 return; 432 } 433 eld.getExtension().add(new Extension().setUrl(EXT_ALLOWABLE_UNITS).setValue(cc)); 434 } 435 436 public static List<Extension> getExtensions(Element element, String url) { 437 List<Extension> results = new ArrayList<Extension>(); 438 for (Extension ex : element.getExtension()) 439 if (ex.getUrl().equals(url)) 440 results.add(ex); 441 return results; 442 } 443 444 public static List<Extension> getExtensions(DomainResource resource, String url) { 445 List<Extension> results = new ArrayList<Extension>(); 446 for (Extension ex : resource.getExtension()) 447 if (ex.getUrl().equals(url)) 448 results.add(ex); 449 return results; 450 } 451 452 public static void addDEReference(DataElement de, String value) { 453 for (Extension e : de.getExtension()) 454 if (e.getUrl().equals(EXT_CIMI_REFERENCE)) { 455 e.setValue(new UriType(value)); 456 return; 457 } 458 de.getExtension().add(new Extension().setUrl(EXT_CIMI_REFERENCE).setValue(new UriType(value))); 459 } 460 461// public static void setDeprecated(Element nc) { 462// for (Extension e : nc.getExtension()) 463// if (e.getUrl().equals(EXT_DEPRECATED)) { 464// e.setValue(new BooleanType(true)); 465// return; 466// } 467// nc.getExtension().add(new Extension().setUrl(EXT_DEPRECATED).setValue(new BooleanType(true))); 468// } 469 470 public static void setExtension(Element focus, String url, Coding c) { 471 for (Extension e : focus.getExtension()) 472 if (e.getUrl().equals(url)) { 473 e.setValue(c); 474 return; 475 } 476 focus.getExtension().add(new Extension().setUrl(url).setValue(c)); 477 } 478 479 public static void removeExtension(DomainResource focus, String url) { 480 Iterator<Extension> i = focus.getExtension().iterator(); 481 while (i.hasNext()) { 482 Extension e = i.next(); // must be called before you can call i.remove() 483 if (e.getUrl().equals(url)) { 484 i.remove(); 485 } 486 } 487 } 488 489 public static void removeExtension(Element focus, String url) { 490 Iterator<Extension> i = focus.getExtension().iterator(); 491 while (i.hasNext()) { 492 Extension e = i.next(); // must be called before you can call i.remove() 493 if (e.getUrl().equals(url)) { 494 i.remove(); 495 } 496 } 497 } 498 499// public static boolean hasOID(ValueSet vs) { 500// return hasExtension(vs, EXT_OID); 501// } 502// 503// public static boolean hasOID(CodeSystem cs) { 504// return hasExtension(cs, EXT_OID); 505// } 506// 507 508}