001package org.hl7.fhir.dstu3.terminologies; 002 003/*- 004 * #%L 005 * org.hl7.fhir.dstu3 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 024import java.util.List; 025 026import org.hl7.fhir.dstu3.model.BooleanType; 027import org.hl7.fhir.dstu3.model.CodeSystem; 028import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent; 029import org.hl7.fhir.dstu3.model.CodeSystem.ConceptPropertyComponent; 030import org.hl7.fhir.dstu3.model.CodeSystem.PropertyComponent; 031import org.hl7.fhir.dstu3.model.CodeSystem.PropertyType; 032import org.hl7.fhir.dstu3.model.DateTimeType; 033import org.hl7.fhir.dstu3.model.Identifier; 034import org.hl7.fhir.dstu3.model.Meta; 035import org.hl7.fhir.dstu3.model.UriType; 036import org.hl7.fhir.dstu3.utils.ToolingExtensions; 037import org.hl7.fhir.exceptions.FHIRException; 038import org.hl7.fhir.exceptions.FHIRFormatError; 039import org.hl7.fhir.utilities.Utilities; 040 041public class CodeSystemUtilities { 042 043 public static boolean isDeprecated(CodeSystem cs, ConceptDefinitionComponent def) { 044 for (ConceptPropertyComponent p : def.getProperty()) { 045 if (p.getCode().equals("deprecated") && p.hasValue() && p.getValue() instanceof BooleanType) 046 return ((BooleanType) p.getValue()).getValue(); 047 if (p.getCode().equals("deprecationDate") && p.hasValue() && p.getValue() instanceof DateTimeType) 048 return ((DateTimeType) p.getValue()).before(new DateTimeType()); 049 } 050 return false; 051 } 052 053 public static boolean isNotSelectable(CodeSystem cs, ConceptDefinitionComponent def) { 054 for (ConceptPropertyComponent p : def.getProperty()) { 055 if (p.getCode().equals("notSelectable") && p.hasValue() && p.getValue() instanceof BooleanType) 056 return ((BooleanType) p.getValue()).getValue(); 057 } 058 return false; 059 } 060 061 public static void setNotSelectable(CodeSystem cs, ConceptDefinitionComponent concept) throws FHIRFormatError { 062 defineNotSelectableProperty(cs); 063 concept.addProperty().setCode("notSelectable").setValue(new BooleanType(true)); 064 } 065 066 public static void setInactive(CodeSystem cs, ConceptDefinitionComponent concept) throws FHIRFormatError { 067 defineInactiveProperty(cs); 068 concept.addProperty().setCode("inactive").setValue(new BooleanType(true)); 069 } 070 071 public static void setDeprecated(CodeSystem cs, ConceptDefinitionComponent concept, DateTimeType date) throws FHIRFormatError { 072 defineDeprecatedProperty(cs); 073 concept.addProperty().setCode("deprecationDate").setValue(date); 074 } 075 076 public static void defineNotSelectableProperty(CodeSystem cs) { 077 defineCodeSystemProperty(cs, "notSelectable", "Indicates that the code is abstract - only intended to be used as a selector for other concepts", PropertyType.BOOLEAN); 078 } 079 080 public static void defineInactiveProperty(CodeSystem cs) { 081 defineCodeSystemProperty(cs, "inactive", "True if the concept is not considered active - e.g. not a valid concept any more", PropertyType.BOOLEAN); 082 } 083 084 public static void defineDeprecatedProperty(CodeSystem cs) { 085 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); 086 } 087 088 public static void defineCodeSystemProperty(CodeSystem cs, String code, String description, PropertyType type) { 089 for (PropertyComponent p : cs.getProperty()) { 090 if (p.getCode().equals(code)) 091 return; 092 } 093 cs.addProperty().setCode(code).setDescription(description).setType(type).setUri("http://hl7.org/fhir/concept-properties#"+code); 094 } 095 096 public static String getCodeDefinition(CodeSystem cs, String code) { 097 return getCodeDefinition(cs.getConcept(), code); 098 } 099 100 private static String getCodeDefinition(List<ConceptDefinitionComponent> list, String code) { 101 for (ConceptDefinitionComponent c : list) { 102 if (c.getCode().equals(code)) 103 return c.getDefinition(); 104 String s = getCodeDefinition(c.getConcept(), code); 105 if (s != null) 106 return s; 107 } 108 return null; 109 } 110 111 public static CodeSystem makeShareable(CodeSystem cs) { 112 if (!cs.hasMeta()) 113 cs.setMeta(new Meta()); 114 for (UriType t : cs.getMeta().getProfile()) 115 if (t.getValue().equals("http://hl7.org/fhir/StructureDefinition/shareablecodesystem")) 116 return cs; 117 cs.getMeta().getProfile().add(new UriType("http://hl7.org/fhir/StructureDefinition/shareablecodesystem")); 118 return cs; 119 } 120 121 public static void setOID(CodeSystem cs, String oid) { 122 if (!oid.startsWith("urn:oid:")) 123 oid = "urn:oid:" + oid; 124 if (!cs.hasIdentifier()) 125 cs.setIdentifier(new Identifier().setSystem("urn:ietf:rfc:3986").setValue(oid)); 126 else if ("urn:ietf:rfc:3986".equals(cs.getIdentifier().getSystem()) && cs.getIdentifier().hasValue() && cs.getIdentifier().getValue().startsWith("urn:oid:")) 127 cs.getIdentifier().setValue(oid); 128 else 129 throw new Error("unable to set OID on code system"); 130 131 } 132 133 public static boolean hasOID(CodeSystem cs) { 134 return getOID(cs) != null; 135 } 136 137 public static String getOID(CodeSystem cs) { 138 if (cs.hasIdentifier() && "urn:ietf:rfc:3986".equals(cs.getIdentifier().getSystem()) && cs.getIdentifier().hasValue() && cs.getIdentifier().getValue().startsWith("urn:oid:")) 139 return cs.getIdentifier().getValue().substring(8); 140 return null; 141 } 142 143 public static boolean isInactive(CodeSystem cs, ConceptDefinitionComponent def) throws FHIRException { 144 for (ConceptPropertyComponent p : def.getProperty()) { 145 if (p.getCode().equals("status") && p.hasValueStringType()) 146 return "inactive".equals(p.getValueStringType()); 147 } 148 return false; 149 } 150 151 public static boolean isInactive(CodeSystem cs, String code) throws FHIRException { 152 ConceptDefinitionComponent def = findCode(cs.getConcept(), code); 153 if (def == null) 154 return true; 155 return isInactive(cs, def); 156 } 157 158 private static ConceptDefinitionComponent findCode(List<ConceptDefinitionComponent> list, String code) { 159 for (ConceptDefinitionComponent c : list) { 160 if (c.getCode().equals(code)) 161 return c; 162 ConceptDefinitionComponent s = findCode(c.getConcept(), code); 163 if (s != null) 164 return s; 165 } 166 return null; 167 } 168 169 public static void markStatus(CodeSystem cs, String wg, String status, String fmm) { 170 if (wg != null) { 171 if (!ToolingExtensions.hasExtension(cs, ToolingExtensions.EXT_WORKGROUP) || 172 (Utilities.existsInList(ToolingExtensions.readStringExtension(cs, ToolingExtensions.EXT_WORKGROUP), "fhir", "vocab") && !Utilities.existsInList(wg, "fhir", "vocab"))) { 173 ToolingExtensions.setCodeExtension(cs, ToolingExtensions.EXT_WORKGROUP, wg); 174 } 175 } 176 if (status != null) { 177 String ss = ToolingExtensions.readStringExtension(cs, ToolingExtensions.EXT_BALLOT_STATUS); 178 if (Utilities.noString(ss) || ssval(ss) < ssval(status)) 179 ToolingExtensions.setStringExtension(cs, ToolingExtensions.EXT_BALLOT_STATUS, status); 180 } 181 if (fmm != null) { 182 String sfmm = ToolingExtensions.readStringExtension(cs, ToolingExtensions.EXT_FMM_LEVEL); 183 if (Utilities.noString(sfmm) || Integer.parseInt(sfmm) < Integer.parseInt(fmm)) 184 ToolingExtensions.setIntegerExtension(cs, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(fmm)); 185 } 186 } 187 188 private static int ssval(String status) { 189 if ("Draft".equals("status")) 190 return 1; 191 if ("Informative".equals("status")) 192 return 2; 193 if ("External".equals("status")) 194 return 3; 195 if ("Trial Use".equals("status")) 196 return 3; 197 if ("Normative".equals("status")) 198 return 4; 199 return -1; 200 } 201 202}