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