001package org.hl7.fhir.dstu3.terminologies; 002 003/* 004 Copyright (c) 2011+, HL7, Inc. 005 All rights reserved. 006 007 Redistribution and use in source and binary forms, with or without modification, 008 are permitted provided that the following conditions are met: 009 010 * Redistributions of source code must retain the above copyright notice, this 011 list of conditions and the following disclaimer. 012 * Redistributions in binary form must reproduce the above copyright notice, 013 this list of conditions and the following disclaimer in the documentation 014 and/or other materials provided with the distribution. 015 * Neither the name of HL7 nor the names of its contributors may be used to 016 endorse or promote products derived from this software without specific 017 prior written permission. 018 019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 POSSIBILITY OF SUCH DAMAGE. 029 030 */ 031 032 033 034import java.util.List; 035 036import org.hl7.fhir.dstu3.model.BooleanType; 037import org.hl7.fhir.dstu3.model.CodeSystem; 038import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent; 039import org.hl7.fhir.dstu3.model.CodeSystem.ConceptPropertyComponent; 040import org.hl7.fhir.dstu3.model.CodeSystem.PropertyComponent; 041import org.hl7.fhir.dstu3.model.CodeSystem.PropertyType; 042import org.hl7.fhir.dstu3.model.DateTimeType; 043import org.hl7.fhir.dstu3.model.Identifier; 044import org.hl7.fhir.dstu3.model.Meta; 045import org.hl7.fhir.dstu3.model.UriType; 046import org.hl7.fhir.dstu3.utils.ToolingExtensions; 047import org.hl7.fhir.exceptions.FHIRException; 048import org.hl7.fhir.exceptions.FHIRFormatError; 049import org.hl7.fhir.utilities.Utilities; 050 051public class CodeSystemUtilities { 052 053 public static boolean isDeprecated(CodeSystem cs, ConceptDefinitionComponent def) { 054 for (ConceptPropertyComponent p : def.getProperty()) { 055 if (p.getCode().equals("deprecated") && p.hasValue() && p.getValue() instanceof BooleanType) 056 return ((BooleanType) p.getValue()).getValue(); 057 if (p.getCode().equals("deprecationDate") && p.hasValue() && p.getValue() instanceof DateTimeType) 058 return ((DateTimeType) p.getValue()).before(new DateTimeType()); 059 } 060 return false; 061 } 062 063 public static boolean isNotSelectable(CodeSystem cs, ConceptDefinitionComponent def) { 064 for (ConceptPropertyComponent p : def.getProperty()) { 065 if (p.getCode().equals("notSelectable") && p.hasValue() && p.getValue() instanceof BooleanType) 066 return ((BooleanType) p.getValue()).getValue(); 067 } 068 return false; 069 } 070 071 public static void setNotSelectable(CodeSystem cs, ConceptDefinitionComponent concept) throws FHIRFormatError { 072 defineNotSelectableProperty(cs); 073 concept.addProperty().setCode("notSelectable").setValue(new BooleanType(true)); 074 } 075 076 public static void setInactive(CodeSystem cs, ConceptDefinitionComponent concept) throws FHIRFormatError { 077 defineInactiveProperty(cs); 078 concept.addProperty().setCode("inactive").setValue(new BooleanType(true)); 079 } 080 081 public static void setDeprecated(CodeSystem cs, ConceptDefinitionComponent concept, DateTimeType date) throws FHIRFormatError { 082 defineDeprecatedProperty(cs); 083 concept.addProperty().setCode("deprecationDate").setValue(date); 084 } 085 086 public static void defineNotSelectableProperty(CodeSystem cs) { 087 defineCodeSystemProperty(cs, "notSelectable", "Indicates that the code is abstract - only intended to be used as a selector for other concepts", PropertyType.BOOLEAN); 088 } 089 090 public static void defineInactiveProperty(CodeSystem cs) { 091 defineCodeSystemProperty(cs, "inactive", "True if the concept is not considered active - e.g. not a valid concept any more", PropertyType.BOOLEAN); 092 } 093 094 public static void defineDeprecatedProperty(CodeSystem cs) { 095 defineCodeSystemProperty(cs, "deprecationDate", "The date at which a concept was deprecated. Concepts that are deprecated but not inactive can still be used, but their use is discouraged", PropertyType.DATETIME); 096 } 097 098 public static void defineCodeSystemProperty(CodeSystem cs, String code, String description, PropertyType type) { 099 for (PropertyComponent p : cs.getProperty()) { 100 if (p.getCode().equals(code)) 101 return; 102 } 103 cs.addProperty().setCode(code).setDescription(description).setType(type).setUri("http://hl7.org/fhir/concept-properties#"+code); 104 } 105 106 public static String getCodeDefinition(CodeSystem cs, String code) { 107 return getCodeDefinition(cs.getConcept(), code); 108 } 109 110 private static String getCodeDefinition(List<ConceptDefinitionComponent> list, String code) { 111 for (ConceptDefinitionComponent c : list) { 112 if (c.getCode().equals(code)) 113 return c.getDefinition(); 114 String s = getCodeDefinition(c.getConcept(), code); 115 if (s != null) 116 return s; 117 } 118 return null; 119 } 120 121 public static CodeSystem makeShareable(CodeSystem cs) { 122 if (!cs.hasMeta()) 123 cs.setMeta(new Meta()); 124 for (UriType t : cs.getMeta().getProfile()) 125 if (t.getValue().equals("http://hl7.org/fhir/StructureDefinition/shareablecodesystem")) 126 return cs; 127 cs.getMeta().getProfile().add(new UriType("http://hl7.org/fhir/StructureDefinition/shareablecodesystem")); 128 return cs; 129 } 130 131 public static void setOID(CodeSystem cs, String oid) { 132 if (!oid.startsWith("urn:oid:")) 133 oid = "urn:oid:" + oid; 134 if (!cs.hasIdentifier()) 135 cs.setIdentifier(new Identifier().setSystem("urn:ietf:rfc:3986").setValue(oid)); 136 else if ("urn:ietf:rfc:3986".equals(cs.getIdentifier().getSystem()) && cs.getIdentifier().hasValue() && cs.getIdentifier().getValue().startsWith("urn:oid:")) 137 cs.getIdentifier().setValue(oid); 138 else 139 throw new Error("unable to set OID on code system"); 140 141 } 142 143 public static boolean hasOID(CodeSystem cs) { 144 return getOID(cs) != null; 145 } 146 147 public static String getOID(CodeSystem cs) { 148 if (cs.hasIdentifier() && "urn:ietf:rfc:3986".equals(cs.getIdentifier().getSystem()) && cs.getIdentifier().hasValue() && cs.getIdentifier().getValue().startsWith("urn:oid:")) 149 return cs.getIdentifier().getValue().substring(8); 150 return null; 151 } 152 153 public static boolean isInactive(CodeSystem cs, ConceptDefinitionComponent def) throws FHIRException { 154 for (ConceptPropertyComponent p : def.getProperty()) { 155 if (p.getCode().equals("status") && p.hasValueStringType()) 156 return "inactive".equals(p.getValueStringType()); 157 } 158 return false; 159 } 160 161 public static boolean isInactive(CodeSystem cs, String code) throws FHIRException { 162 ConceptDefinitionComponent def = findCode(cs.getConcept(), code); 163 if (def == null) 164 return true; 165 return isInactive(cs, def); 166 } 167 168 private static ConceptDefinitionComponent findCode(List<ConceptDefinitionComponent> list, String code) { 169 for (ConceptDefinitionComponent c : list) { 170 if (c.getCode().equals(code)) 171 return c; 172 ConceptDefinitionComponent s = findCode(c.getConcept(), code); 173 if (s != null) 174 return s; 175 } 176 return null; 177 } 178 179 public static void markStatus(CodeSystem cs, String wg, String status, String fmm) { 180 if (wg != null) { 181 if (!ToolingExtensions.hasExtension(cs, ToolingExtensions.EXT_WORKGROUP) || 182 (Utilities.existsInList(ToolingExtensions.readStringExtension(cs, ToolingExtensions.EXT_WORKGROUP), "fhir", "vocab") && !Utilities.existsInList(wg, "fhir", "vocab"))) { 183 ToolingExtensions.setCodeExtension(cs, ToolingExtensions.EXT_WORKGROUP, wg); 184 } 185 } 186 if (status != null) { 187 String ss = ToolingExtensions.readStringExtension(cs, ToolingExtensions.EXT_BALLOT_STATUS); 188 if (Utilities.noString(ss) || ssval(ss) < ssval(status)) 189 ToolingExtensions.setStringExtension(cs, ToolingExtensions.EXT_BALLOT_STATUS, status); 190 } 191 if (fmm != null) { 192 String sfmm = ToolingExtensions.readStringExtension(cs, ToolingExtensions.EXT_FMM_LEVEL); 193 if (Utilities.noString(sfmm) || Integer.parseInt(sfmm) < Integer.parseInt(fmm)) 194 ToolingExtensions.setIntegerExtension(cs, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(fmm)); 195 } 196 } 197 198 private static int ssval(String status) { 199 if ("Draft".equals("status")) 200 return 1; 201 if ("Informative".equals("status")) 202 return 2; 203 if ("External".equals("status")) 204 return 3; 205 if ("Trial Use".equals("status")) 206 return 3; 207 if ("Normative".equals("status")) 208 return 4; 209 return -1; 210 } 211 212}