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