001package org.hl7.fhir.r4.utils;
002
003/*-
004 * #%L
005 * org.hl7.fhir.r4
006 * %%
007 * Copyright (C) 2014 - 2019 Health Level 7
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023
024/*
025Copyright (c) 2011+, HL7, Inc
026All rights reserved.
027
028Redistribution and use in source and binary forms, with or without modification, 
029are permitted provided that the following conditions are met:
030
031 * Redistributions of source code must retain the above copyright notice, this 
032   list of conditions and the following disclaimer.
033 * Redistributions in binary form must reproduce the above copyright notice, 
034   this list of conditions and the following disclaimer in the documentation 
035   and/or other materials provided with the distribution.
036 * Neither the name of HL7 nor the names of its contributors may be used to 
037   endorse or promote products derived from this software without specific 
038   prior written permission.
039
040THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
041ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
042WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
043IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
044INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
045NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
046PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
047WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
048ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
049POSSIBILITY OF SUCH DAMAGE.
050
051 */
052
053import java.util.ArrayList;
054import java.util.HashMap;
055import java.util.Iterator;
056import java.util.List;
057import java.util.Map;
058
059import org.apache.commons.lang3.StringUtils;
060import org.fhir.ucum.Utilities;
061import org.hl7.fhir.exceptions.FHIRException;
062import org.hl7.fhir.r4.model.BooleanType;
063import org.hl7.fhir.r4.model.CanonicalType;
064import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
065import org.hl7.fhir.r4.model.CodeType;
066import org.hl7.fhir.r4.model.CodeableConcept;
067import org.hl7.fhir.r4.model.Coding;
068import org.hl7.fhir.r4.model.DomainResource;
069import org.hl7.fhir.r4.model.Element;
070import org.hl7.fhir.r4.model.ElementDefinition;
071import org.hl7.fhir.r4.model.Extension;
072import org.hl7.fhir.r4.model.ExtensionHelper;
073import org.hl7.fhir.r4.model.Factory;
074import org.hl7.fhir.r4.model.Identifier;
075import org.hl7.fhir.r4.model.IntegerType;
076import org.hl7.fhir.r4.model.MarkdownType;
077import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent;
078import org.hl7.fhir.r4.model.PrimitiveType;
079import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent;
080import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemType;
081import org.hl7.fhir.r4.model.StringType;
082import org.hl7.fhir.r4.model.Type;
083import org.hl7.fhir.r4.model.UriType;
084import org.hl7.fhir.r4.model.ValueSet.ConceptReferenceComponent;
085import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
086import org.hl7.fhir.utilities.StandardsStatus;
087import org.hl7.fhir.utilities.validation.ValidationMessage;
088import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
089import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
090import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
091
092
093public class ToolingExtensions {
094
095  // validated
096//  private static final String EXT_OID = "http://hl7.org/fhir/StructureDefinition/valueset-oid";
097//  public static final String EXT_DEPRECATED = "http://hl7.org/fhir/StructureDefinition/codesystem-deprecated";
098  public static final String EXT_DEFINITION = "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition";
099  public static final String EXT_CS_COMMENT = "http://hl7.org/fhir/StructureDefinition/codesystem-concept-comments";
100  public static final String EXT_VS_COMMENT = "http://hl7.org/fhir/StructureDefinition/valueset-concept-comments";
101  private static final String EXT_IDENTIFIER = "http://hl7.org/fhir/StructureDefinition/identifier";
102  public static final String EXT_TRANSLATION = "http://hl7.org/fhir/StructureDefinition/translation";
103  public static final String EXT_ISSUE_SOURCE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-source";
104  public static final String EXT_ISSUE_LINE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-line";
105  public static final String EXT_ISSUE_COL = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-col";
106  public static final String EXT_DISPLAY_HINT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-display-hint"; 
107  public static final String EXT_REPLACED_BY = "http://hl7.org/fhir/StructureDefinition/valueset-replacedby";
108  public static final String EXT_REGEX = "http://hl7.org/fhir/StructureDefinition/regex"; 
109  public static final String EXT_CONTROL = "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl"; 
110  public static final String EXT_MINOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-minOccurs"; 
111  public static final String EXT_MAXOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-maxOccurs";
112  public static final String EXT_ALLOWEDRESOURCE = "http://hl7.org/fhir/StructureDefinition/questionnaire-allowedResource";
113  public static final String EXT_REFERENCEFILTER = "http://hl7.org/fhir/StructureDefinition/questionnaire-referenceFilter";
114  public static final String EXT_CODE_GENERATION_PARENT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-codegen-super";
115  public static final String EXT_HIERARCHY = "http://hl7.org/fhir/StructureDefinition/structuredefinition-hierarchy";
116  public static final String EXT_BEST_PRACTICE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice";
117  public static final String EXT_BEST_PRACTICE_EXPLANATION = "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice-explanation";
118  // unregistered?
119  public static final String EXT_MAPPING_PREFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-prefix";
120  public static final String EXT_MAPPING_SUFFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-suffix";
121
122//  public static final String EXT_FLYOVER = "http://hl7.org/fhir/Profile/questionnaire-extensions#flyover";
123  public static final String EXT_QTYPE = "http://hl7.org/fhir/StructureDefinition/questionnnaire-baseType";
124//  private static final String EXT_QREF = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference";
125//  private static final String EXTENSION_FILTER_ONLY = "http://www.healthintersections.com.au/fhir/Profile/metadata#expandNeedsFilter";
126//  private static final String EXT_TYPE = "http://www.healthintersections.com.au/fhir/Profile/metadata#type";
127//  private static final String EXT_REFERENCE = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference";
128  private static final String EXT_FHIRTYPE = "http://hl7.org/fhir/StructureDefinition/questionnaire-fhirType";
129  private static final String EXT_ALLOWABLE_UNITS = "http://hl7.org/fhir/StructureDefinition/elementdefinition-allowedUnits";
130  public static final String EXT_CIMI_REFERENCE = "http://hl7.org/fhir/StructureDefinition/cimi-reference";
131  public static final String EXT_UNCLOSED = "http://hl7.org/fhir/StructureDefinition/valueset-unclosed";
132  public static final String EXT_FMM_LEVEL = "http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm";
133  public static final String EXT_SEC_CAT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-security-category";
134  public static final String EXT_RESOURCE_CATEGORY = "http://hl7.org/fhir/StructureDefinition/structuredefinition-category";
135  public static final String EXT_TABLE_NAME = "http://hl7.org/fhir/StructureDefinition/structuredefinition-table-name";
136  public static final String EXT_OO_FILE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-file";
137  public static final String EXT_WORKGROUP = "http://hl7.org/fhir/StructureDefinition/structuredefinition-wg";
138  public static final String EXT_STANDARDS_STATUS = "http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status";
139  public static final String EXT_NORMATIVE_VERSION = "http://hl7.org/fhir/StructureDefinition/structuredefinition-normative-version";
140  public static final String EXT_IGP_BASE = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-base";
141  public static final String EXT_IGP_DEFNS = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-defns";
142  public static final String EXT_IGP_FORMAT = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-format";
143  public static final String EXT_IGP_SOURCE = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-source";
144  public static final String EXT_IGP_VERSION = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-version";
145  public static final String EXT_IGP_RESOURCES = "http://hl7.org/fhir/StructureDefinition/igpublisher-folder-resource";
146  public static final String EXT_IGP_PAGES = "http://hl7.org/fhir/StructureDefinition/igpublisher-folder-pages";
147  public static final String EXT_IGP_SPREADSHEET = "http://hl7.org/fhir/StructureDefinition/igpublisher-spreadsheet";
148  public static final String EXT_IGP_MAPPING_CSV = "http://hl7.org/fhir/StructureDefinition/igpublisher-mapping-csv";
149  public static final String EXT_IGP_BUNDLE = "http://hl7.org/fhir/StructureDefinition/igpublisher-bundle";
150  public static final String EXT_IGP_RESOURCE_INFO = "http://hl7.org/fhir/tools/StructureDefinition/resource-information";
151  public static final String EXT_IGP_LOADVERSION = "http://hl7.org/fhir/StructureDefinition/igpublisher-loadversion";
152  public static final String EXT_MAX_VALUESET = "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet";
153  public static final String EXT_MIN_VALUESET = "http://hl7.org/fhir/StructureDefinition/elementdefinition-minValueSet";
154  public static final String EXT_PROFILE_ELEMENT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-profile-element";
155  public static final String EXT_LIST_PACKAGE = "http://hl7.org/fhir/StructureDefinition/list-packageId";
156  public static final String EXT_MAPPING_NAME = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-source-name";
157  public static final String EXT_MAPPING_TYPE = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-source-type";
158  public static final String EXT_MAPPING_CARD = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-source-cardinality";
159  public static final String EXT_MAPPING_TGTTYPE = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-target-type";
160  public static final String EXT_MAPPING_TGTCARD = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-target-cardinality";
161  public static final String EXT_PRIVATE_BASE = "http://hl7.org/fhir/tools/";
162  public static final String EXT_ALLOWED_TYPE =  "http://hl7.org/fhir/StructureDefinition/operationdefinition-allowed-type";
163  public static final String EXT_FHIR_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type";
164  public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type";
165  public static final String EXT_JSON_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-json-type";
166
167  // specific extension helpers
168
169  public static Extension makeIssueSource(Source source) {
170    Extension ex = new Extension();
171    // todo: write this up and get it published with the pack (and handle the redirect?)
172    ex.setUrl(ToolingExtensions.EXT_ISSUE_SOURCE);
173    CodeType c = new CodeType();
174    c.setValue(source.toString());
175    ex.setValue(c);
176    return ex;
177  }
178
179  public static boolean hasExtension(DomainResource de, String url) {
180    return getExtension(de, url) != null;
181  }
182
183  public static boolean hasExtension(Element e, String url) {
184    return getExtension(e, url) != null;
185  }
186
187//  public static void addStringExtension(DomainResource dr, String url, String content) {
188//    if (!StringUtils.isBlank(content)) {
189//      Extension ex = getExtension(dr, url);
190//      if (ex != null)
191//        ex.setValue(new StringType(content));
192//      else
193//        dr.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
194//    }
195//  }
196
197  public static void addMarkdownExtension(DomainResource dr, String url, String content) {
198    if (!StringUtils.isBlank(content)) {
199      Extension ex = getExtension(dr, url);
200      if (ex != null)
201        ex.setValue(new StringType(content));
202      else
203        dr.getExtension().add(Factory.newExtension(url, new MarkdownType(content), true));   
204    }
205  }
206
207  public static void addStringExtension(Element e, String url, String content) {
208    if (!StringUtils.isBlank(content)) {
209      Extension ex = getExtension(e, url);
210      if (ex != null)
211        ex.setValue(new StringType(content));
212      else
213        e.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
214    }
215  }
216
217  public static void addCodeExtension(Element e, String url, String content) {
218    if (!StringUtils.isBlank(content)) {
219      Extension ex = getExtension(e, url);
220      if (ex != null)
221        ex.setValue(new CodeType(content));
222      else
223        e.getExtension().add(Factory.newExtension(url, new CodeType(content), true));   
224    }
225  }
226
227  public static void addStringExtension(DomainResource e, String url, String content) {
228    if (!StringUtils.isBlank(content)) {
229      Extension ex = getExtension(e, url);
230      if (ex != null)
231        ex.setValue(new StringType(content));
232      else
233        e.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
234    }
235  }
236
237  public static void addBooleanExtension(Element e, String url, boolean content) {
238    Extension ex = getExtension(e, url);
239    if (ex != null)
240      ex.setValue(new BooleanType(content));
241    else
242      e.getExtension().add(Factory.newExtension(url, new BooleanType(content), true));   
243  }
244
245  public static void addBooleanExtension(DomainResource e, String url, boolean content) {
246    Extension ex = getExtension(e, url);
247    if (ex != null)
248      ex.setValue(new BooleanType(content));
249    else
250      e.getExtension().add(Factory.newExtension(url, new BooleanType(content), true));   
251  }
252
253  public static void addIntegerExtension(DomainResource dr, String url, int value) {
254    Extension ex = getExtension(dr, url);
255    if (ex != null)
256      ex.setValue(new IntegerType(value));
257    else
258      dr.getExtension().add(Factory.newExtension(url, new IntegerType(value), true));   
259  }
260
261  public static void addCodeExtension(DomainResource dr, String url, String value) {
262    Extension ex = getExtension(dr, url);
263    if (ex != null)
264      ex.setValue(new CodeType(value));
265    else
266      dr.getExtension().add(Factory.newExtension(url, new CodeType(value), true));   
267  }
268
269  public static void addVSComment(ConceptSetComponent nc, String comment) {
270    if (!StringUtils.isBlank(comment))
271      nc.getExtension().add(Factory.newExtension(EXT_VS_COMMENT, Factory.newString_(comment), true));   
272  }
273  public static void addVSComment(ConceptReferenceComponent nc, String comment) {
274    if (!StringUtils.isBlank(comment))
275      nc.getExtension().add(Factory.newExtension(EXT_VS_COMMENT, Factory.newString_(comment), true));   
276  }
277
278  public static void addCSComment(ConceptDefinitionComponent nc, String comment) {
279    if (!StringUtils.isBlank(comment))
280      nc.getExtension().add(Factory.newExtension(EXT_CS_COMMENT, Factory.newString_(comment), true));   
281  }
282
283//  public static void markDeprecated(Element nc) {
284//    setDeprecated(nc);   
285//  }
286//
287
288  public static void addDefinition(Element nc, String definition) {
289    if (!StringUtils.isBlank(definition))
290      nc.getExtension().add(Factory.newExtension(EXT_DEFINITION, Factory.newString_(definition), true));   
291  }
292
293  public static void addDisplayHint(Element def, String hint) {
294    if (!StringUtils.isBlank(hint))
295      def.getExtension().add(Factory.newExtension(EXT_DISPLAY_HINT, Factory.newString_(hint), true));   
296  }
297
298  public static String getDisplayHint(Element def) {
299    return readStringExtension(def, EXT_DISPLAY_HINT);    
300  }
301
302  public static String readStringExtension(Element c, String uri) {
303    Extension ex = ExtensionHelper.getExtension(c, uri);
304    if (ex == null)
305      return null;
306    if (ex.getValue() instanceof UriType)
307      return ((UriType) ex.getValue()).getValue();
308    if (ex.getValue() instanceof CanonicalType)
309      return ((CanonicalType) ex.getValue()).getValue();
310    if (ex.getValue() instanceof CodeType)
311      return ((CodeType) ex.getValue()).getValue();
312    if (ex.getValue() instanceof IntegerType)
313      return ((IntegerType) ex.getValue()).asStringValue();
314    if ((ex.getValue() instanceof MarkdownType))
315      return ((MarkdownType) ex.getValue()).getValue();
316    if (!(ex.getValue() instanceof StringType))
317      return null;
318    return ((StringType) ex.getValue()).getValue();
319  }
320
321  public static String readStringExtension(DomainResource c, String uri) {
322    Extension ex = getExtension(c, uri);
323    if (ex == null)
324      return null;
325    if ((ex.getValue() instanceof StringType))
326      return ((StringType) ex.getValue()).getValue();
327    if ((ex.getValue() instanceof UriType))
328      return ((UriType) ex.getValue()).getValue();
329    if (ex.getValue() instanceof CodeType)
330      return ((CodeType) ex.getValue()).getValue();
331    if (ex.getValue() instanceof IntegerType)
332      return ((IntegerType) ex.getValue()).asStringValue();
333    if ((ex.getValue() instanceof MarkdownType))
334      return ((MarkdownType) ex.getValue()).getValue();
335    return null;
336  }
337
338  @SuppressWarnings("unchecked")
339  public static PrimitiveType<Type> readPrimitiveExtension(DomainResource c, String uri) {
340    Extension ex = getExtension(c, uri);
341    if (ex == null)
342      return null;
343    return (PrimitiveType<Type>) ex.getValue();
344  }
345
346  public static boolean findStringExtension(Element c, String uri) {
347    Extension ex = ExtensionHelper.getExtension(c, uri);
348    if (ex == null)
349      return false;
350    if (!(ex.getValue() instanceof StringType))
351      return false;
352    return !StringUtils.isBlank(((StringType) ex.getValue()).getValue());
353  }
354
355  public static Boolean readBooleanExtension(Element c, String uri) {
356    Extension ex = ExtensionHelper.getExtension(c, uri);
357    if (ex == null)
358      return null;
359    if (!(ex.getValue() instanceof BooleanType))
360      return null;
361    return ((BooleanType) ex.getValue()).getValue();
362  }
363
364  public static boolean findBooleanExtension(Element c, String uri) {
365    Extension ex = ExtensionHelper.getExtension(c, uri);
366    if (ex == null)
367      return false;
368    if (!(ex.getValue() instanceof BooleanType))
369      return false;
370    return true;
371  }
372
373  public static Boolean readBooleanExtension(DomainResource c, String uri) {
374    Extension ex = ExtensionHelper.getExtension(c, uri);
375    if (ex == null)
376      return null;
377    if (!(ex.getValue() instanceof BooleanType))
378      return null;
379    return ((BooleanType) ex.getValue()).getValue();
380  }
381
382  public static boolean readBoolExtension(DomainResource c, String uri) {
383    Extension ex = ExtensionHelper.getExtension(c, uri);
384    if (ex == null)
385      return false;
386    if (!(ex.getValue() instanceof BooleanType))
387      return false;
388    return ((BooleanType) ex.getValue()).getValue();
389  }
390
391  public static boolean findBooleanExtension(DomainResource c, String uri) {
392    Extension ex = ExtensionHelper.getExtension(c, uri);
393    if (ex == null)
394      return false;
395    if (!(ex.getValue() instanceof BooleanType))
396      return false;
397    return true;
398  }
399
400  public static String getCSComment(ConceptDefinitionComponent c) {
401    return readStringExtension(c, EXT_CS_COMMENT);    
402  }
403//
404//  public static Boolean getDeprecated(Element c) {
405//    return readBooleanExtension(c, EXT_DEPRECATED);    
406//  }
407
408  public static boolean hasCSComment(ConceptDefinitionComponent c) {
409    return findStringExtension(c, EXT_CS_COMMENT);    
410  }
411
412//  public static boolean hasDeprecated(Element c) {
413//    return findBooleanExtension(c, EXT_DEPRECATED);    
414//  }
415
416  public static void addFlyOver(QuestionnaireItemComponent item, String text){
417    if (!StringUtils.isBlank(text)) {
418        QuestionnaireItemComponent display = item.addItem();
419        display.setType(QuestionnaireItemType.DISPLAY);
420        display.setText(text);
421        display.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept("flyover", "http://hl7.org/fhir/questionnaire-item-control", "Fly-over"), true));
422    }
423  }
424
425  public static void addMin(QuestionnaireItemComponent item, int min) {
426    item.getExtension().add(Factory.newExtension(EXT_MINOCCURS, Factory.newInteger(min), true));
427  }
428  
429  public static void addMax(QuestionnaireItemComponent item, int max) {
430    item.getExtension().add(Factory.newExtension(EXT_MAXOCCURS, Factory.newInteger(max), true));
431  }
432  
433  public static void addFhirType(QuestionnaireItemComponent group, String value) {
434    group.getExtension().add(Factory.newExtension(EXT_FHIRTYPE, Factory.newString_(value), true));       
435  }
436
437  public static void addControl(QuestionnaireItemComponent group, String value) {
438    group.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept(value, "http://hl7.org/fhir/questionnaire-item-control", value), true));
439  }
440
441  public static void addAllowedResource(QuestionnaireItemComponent group, String value) {
442    group.getExtension().add(Factory.newExtension(EXT_ALLOWEDRESOURCE, Factory.newCode(value), true));       
443  }
444
445  public static void addReferenceFilter(QuestionnaireItemComponent group, String value) {
446    group.getExtension().add(Factory.newExtension(EXT_REFERENCEFILTER, Factory.newString_(value), true));       
447  }
448
449  public static void addIdentifier(Element element, Identifier value) {
450    element.getExtension().add(Factory.newExtension(EXT_IDENTIFIER, value, true));       
451  }
452
453  /**
454   * @param name the identity of the extension of interest
455   * @return The extension, if on this element, else null
456   */
457  public static Extension getExtension(DomainResource resource, String name) {
458    if (name == null)
459      return null;
460    if (!resource.hasExtension())
461      return null;
462    for (Extension e : resource.getExtension()) {
463      if (name.equals(e.getUrl()))
464        return e;
465    }
466    return null;
467  }
468
469  public static Extension getExtension(Element el, String name) {
470    if (name == null)
471      return null;
472    if (!el.hasExtension())
473      return null;
474    for (Extension e : el.getExtension()) {
475      if (name.equals(e.getUrl()))
476        return e;
477    }
478    return null;
479  }
480
481  public static void setStringExtension(DomainResource resource, String uri, String value) {
482    if (Utilities.noString(value))
483      return;
484        Extension ext = getExtension(resource, uri);
485    if (ext != null)
486      ext.setValue(new StringType(value));
487    else
488      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new StringType(value)));
489  }
490
491  public static void setStringExtension(Element resource, String uri, String value) {
492    if (Utilities.noString(value))
493      return;
494        Extension ext = getExtension(resource, uri);
495    if (ext != null)
496      ext.setValue(new StringType(value));
497    else
498      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new StringType(value)));
499  }
500
501  public static void setCodeExtension(DomainResource resource, String uri, String value) {
502    if (Utilities.noString(value))
503      return;
504    
505    Extension ext = getExtension(resource, uri);
506    if (ext != null)
507      ext.setValue(new CodeType(value));
508    else
509      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new CodeType(value)));
510  }
511
512  public static void setCodeExtension(Element element, String uri, String value) {
513    if (Utilities.noString(value))
514      return;
515    
516    Extension ext = getExtension(element, uri);
517    if (ext != null)
518      ext.setValue(new CodeType(value));
519    else
520      element.getExtension().add(new Extension(new UriType(uri)).setValue(new CodeType(value)));
521  }
522
523  public static void setIntegerExtension(DomainResource resource, String uri, int value) {
524    Extension ext = getExtension(resource, uri);
525    if (ext != null)
526      ext.setValue(new IntegerType(value));
527    else
528      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new IntegerType(value)));
529  }
530
531//  public static String getOID(CodeSystem define) {
532//    return readStringExtension(define, EXT_OID);    
533//  }
534//
535//  public static String getOID(ValueSet vs) {
536//    return readStringExtension(vs, EXT_OID);    
537//  }
538//
539//  public static void setOID(CodeSystem define, String oid) throws FHIRFormatError, URISyntaxException {
540//    if (!oid.startsWith("urn:oid:"))
541//      throw new FHIRFormatError("Error in OID format");
542//    if (oid.startsWith("urn:oid:urn:oid:"))
543//      throw new FHIRFormatError("Error in OID format");
544//    if (!hasExtension(define, EXT_OID))
545//    define.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false));       
546//    else if (!oid.equals(readStringExtension(define, EXT_OID)))
547//      throw new Error("Attempt to assign multiple OIDs to a code system");
548//  }
549//  public static void setOID(ValueSet vs, String oid) throws FHIRFormatError, URISyntaxException {
550//    if (!oid.startsWith("urn:oid:"))
551//      throw new FHIRFormatError("Error in OID format");
552//    if (oid.startsWith("urn:oid:urn:oid:"))
553//      throw new FHIRFormatError("Error in OID format");
554//    if (!hasExtension(vs, EXT_OID))
555//    vs.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false));       
556//    else if (!oid.equals(readStringExtension(vs, EXT_OID)))
557//      throw new Error("Attempt to assign multiple OIDs to value set "+vs.getName()+" ("+vs.getUrl()+"). Has "+readStringExtension(vs, EXT_OID)+", trying to add "+oid);
558//  }
559
560  public static boolean hasLanguageTranslation(Element element, String lang) {
561    for (Extension e : element.getExtension()) {
562      if (e.getUrl().equals(EXT_TRANSLATION)) {
563        Extension e1 = ExtensionHelper.getExtension(e, "lang");
564
565        if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang))
566          return true;
567      }
568    }
569    return false;
570  }
571
572  public static String getLanguageTranslation(Element element, String lang) {
573    for (Extension e : element.getExtension()) {
574      if (e.getUrl().equals(EXT_TRANSLATION)) {
575        Extension e1 = ExtensionHelper.getExtension(e, "lang");
576
577        if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang)) {
578          e1 = ExtensionHelper.getExtension(e, "content");
579          return ((StringType) e.getValue()).getValue();
580        }
581      }
582    }
583    return null;
584  }
585
586  public static void addLanguageTranslation(Element element, String lang, String value) {
587    if (Utilities.noString(lang) || Utilities.noString(value))
588      return;
589    
590    Extension extension = new Extension().setUrl(EXT_TRANSLATION);
591    extension.addExtension().setUrl("lang").setValue(new CodeType(lang));
592    extension.addExtension().setUrl("content").setValue(new StringType(value));
593    element.getExtension().add(extension);
594  }
595
596  public static Type getAllowedUnits(ElementDefinition eld) {
597    for (Extension e : eld.getExtension()) 
598      if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) 
599        return e.getValue();
600    return null;
601  }
602
603  public static void setAllowableUnits(ElementDefinition eld, CodeableConcept cc) {
604    for (Extension e : eld.getExtension()) 
605      if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) {
606        e.setValue(cc);
607        return;
608      }
609    eld.getExtension().add(new Extension().setUrl(EXT_ALLOWABLE_UNITS).setValue(cc));
610  }
611
612  public static List<Extension> getExtensions(Element element, String url) {
613    List<Extension> results = new ArrayList<Extension>();
614    for (Extension ex : element.getExtension())
615      if (ex.getUrl().equals(url))
616        results.add(ex);
617    return results;
618  }
619
620  public static List<Extension> getExtensions(DomainResource resource, String url) {
621    List<Extension> results = new ArrayList<Extension>();
622    for (Extension ex : resource.getExtension())
623      if (ex.getUrl().equals(url))
624        results.add(ex);
625    return results;
626  }
627
628//  public static void addDEReference(DataElement de, String value) {
629//    for (Extension e : de.getExtension()) 
630//      if (e.getUrl().equals(EXT_CIMI_REFERENCE)) {
631//        e.setValue(new UriType(value));
632//        return;
633//      }
634//    de.getExtension().add(new Extension().setUrl(EXT_CIMI_REFERENCE).setValue(new UriType(value)));
635//  }
636
637//  public static void setDeprecated(Element nc) {
638//    for (Extension e : nc.getExtension()) 
639//      if (e.getUrl().equals(EXT_DEPRECATED)) {
640//        e.setValue(new BooleanType(true));
641//        return;
642//      }
643//    nc.getExtension().add(new Extension().setUrl(EXT_DEPRECATED).setValue(new BooleanType(true)));    
644//  }
645
646  public static void setExtension(Element focus, String url, Coding c) {
647    for (Extension e : focus.getExtension()) 
648      if (e.getUrl().equals(url)) {
649        e.setValue(c);
650        return;
651      }
652    focus.getExtension().add(new Extension().setUrl(url).setValue(c));    
653  }
654
655  public static void removeExtension(DomainResource focus, String url) {
656    Iterator<Extension> i = focus.getExtension().iterator();
657    while (i.hasNext()) {
658      Extension e = i.next(); // must be called before you can call i.remove()
659      if (e.getUrl().equals(url)) {
660        i.remove();
661      }
662    }
663  }
664  
665  public static void removeExtension(Element focus, String url) {
666    Iterator<Extension> i = focus.getExtension().iterator();
667    while (i.hasNext()) {
668      Extension e = i.next(); // must be called before you can call i.remove()
669      if (e.getUrl().equals(url)) {
670        i.remove();
671      }
672    }
673  }
674
675  public static int readIntegerExtension(DomainResource dr, String uri, int defaultValue) {
676    Extension ex = ExtensionHelper.getExtension(dr, uri);
677    if (ex == null)
678      return defaultValue;
679    if (ex.getValue() instanceof IntegerType)
680      return ((IntegerType) ex.getValue()).getValue();
681    throw new Error("Unable to read extension "+uri+" as an integer");
682  }
683
684  public static int readIntegerExtension(Element e, String uri, int defaultValue) {
685    Extension ex = ExtensionHelper.getExtension(e, uri);
686    if (ex == null)
687      return defaultValue;
688    if (ex.getValue() instanceof IntegerType)
689      return ((IntegerType) ex.getValue()).getValue();
690    throw new Error("Unable to read extension "+uri+" as an integer");
691  }
692
693  public static Map<String, String> getLanguageTranslations(Element e) {
694    Map<String, String> res = new HashMap<String, String>();
695    for (Extension ext : e.getExtension()) {
696      if (ext.getUrl().equals(EXT_TRANSLATION)) {
697        String lang = readStringExtension(ext, "lang");
698        String value = readStringExtension(ext, "content");
699        res.put(lang,  value);
700      }
701    }
702    return res;
703  }
704
705  public static StandardsStatus getStandardsStatus(DomainResource dr) throws FHIRException {
706    return StandardsStatus.fromCode(ToolingExtensions.readStringExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS));
707  }
708
709  public static void setStandardsStatus(DomainResource dr, StandardsStatus status, String normativeVersion) {
710    if (status == null)
711      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS);
712    else
713      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS, status.toCode());
714    if (normativeVersion == null)
715      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION);
716    else
717      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION, normativeVersion);
718  }
719
720  public static void setStandardsStatus(Element dr, StandardsStatus status, String normativeVersion) {
721    if (status == null)
722      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS);
723    else
724      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS, status.toCode());
725    if (normativeVersion == null)
726      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION);
727    else
728      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION, normativeVersion);
729  }
730
731  public static ValidationMessage readValidationMessage(OperationOutcomeIssueComponent issue, Source source) {
732    ValidationMessage vm = new ValidationMessage();
733    vm.setSource(source);
734    vm.setLevel(mapSeverity(issue.getSeverity()));
735    vm.setType(mapType(issue.getCode()));
736    if (issue.hasExtension(ToolingExtensions.EXT_ISSUE_LINE))
737      vm.setLine(ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_LINE, 0));
738    if (issue.hasExtension(ToolingExtensions.EXT_ISSUE_COL))
739      vm.setCol(ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_COL, 0));
740    if (issue.hasExpression())
741      vm.setLocation(issue.getExpression().get(0).asStringValue());
742    vm.setMessage(issue.getDetails().getText());
743    if (issue.hasExtension("http://hl7.org/fhir/StructureDefinition/rendering-xhtml"))
744      vm.setHtml(ToolingExtensions.readStringExtension(issue, "http://hl7.org/fhir/StructureDefinition/rendering-xhtml"));
745    return vm;
746  }
747
748  private static IssueType mapType(org.hl7.fhir.r4.model.OperationOutcome.IssueType code) {
749    switch (code) {
750    case BUSINESSRULE: return IssueType.BUSINESSRULE;
751    case CODEINVALID: return IssueType.CODEINVALID;
752    case CONFLICT: return IssueType.CONFLICT;
753    case DELETED: return IssueType.DELETED;
754    case DUPLICATE: return IssueType.DUPLICATE;
755    case EXCEPTION: return IssueType.EXCEPTION;
756    case EXPIRED: return IssueType.EXPIRED;
757    case EXTENSION: return IssueType.EXTENSION;
758    case FORBIDDEN: return IssueType.FORBIDDEN;
759    case INCOMPLETE: return IssueType.INCOMPLETE;
760    case INFORMATIONAL: return IssueType.INFORMATIONAL;
761    case INVALID: return IssueType.INVALID;
762    case INVARIANT: return IssueType.INVARIANT;
763    case LOCKERROR: return IssueType.LOCKERROR;
764    case LOGIN: return IssueType.LOGIN;
765    case MULTIPLEMATCHES: return IssueType.MULTIPLEMATCHES;
766    case NOSTORE: return IssueType.NOSTORE;
767    case NOTFOUND: return IssueType.NOTFOUND;
768    case NOTSUPPORTED: return IssueType.NOTSUPPORTED;
769    case NULL: return IssueType.NULL;
770    case PROCESSING: return IssueType.PROCESSING;
771    case REQUIRED: return IssueType.REQUIRED;
772    case SECURITY: return IssueType.SECURITY;
773    case STRUCTURE: return IssueType.STRUCTURE;
774    case SUPPRESSED: return IssueType.SUPPRESSED;
775    case THROTTLED: return IssueType.THROTTLED;
776    case TIMEOUT: return IssueType.TIMEOUT;
777    case TOOCOSTLY: return IssueType.TOOCOSTLY;
778    case TOOLONG: return IssueType.TOOLONG;
779    case TRANSIENT: return IssueType.TRANSIENT;
780    case UNKNOWN: return IssueType.UNKNOWN;
781    case VALUE: return IssueType.VALUE;
782    default: return null;
783    }
784  }
785
786  private static IssueSeverity mapSeverity(org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity severity) {
787    switch (severity) {
788    case ERROR: return IssueSeverity.ERROR;
789    case FATAL: return IssueSeverity.FATAL;
790    case INFORMATION: return IssueSeverity.INFORMATION;
791    case WARNING: return IssueSeverity.WARNING;
792    default: return null;
793    }
794  }
795
796//  public static boolean hasOID(ValueSet vs) {
797//    return hasExtension(vs, EXT_OID);
798//  }
799//  
800//  public static boolean hasOID(CodeSystem cs) {
801//    return hasExtension(cs, EXT_OID);
802//  }
803//  
804  
805}