001package org.hl7.fhir.r5.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 033import org.hl7.fhir.exceptions.FHIRException; 034import org.hl7.fhir.r5.context.IWorkerContext; 035import org.hl7.fhir.r5.model.CanonicalType; 036import org.hl7.fhir.r5.model.CodeSystem; 037import org.hl7.fhir.r5.model.Enumerations.FilterOperator; 038import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; 039import org.hl7.fhir.r5.model.Identifier; 040import org.hl7.fhir.r5.model.Meta; 041import org.hl7.fhir.r5.model.UriType; 042import org.hl7.fhir.r5.model.ValueSet; 043import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; 044import org.hl7.fhir.r5.utils.ToolingExtensions; 045import org.hl7.fhir.utilities.StandardsStatus; 046import org.hl7.fhir.utilities.Utilities; 047 048public class ValueSetUtilities { 049 050 public static ValueSet makeShareable(ValueSet vs) { 051 if (!vs.hasExperimental()) { 052 vs.setExperimental(false); 053 } 054 if (!vs.hasMeta()) 055 vs.setMeta(new Meta()); 056 for (UriType t : vs.getMeta().getProfile()) 057 if (t.getValue().equals("http://hl7.org/fhir/StructureDefinition/shareablevalueset")) 058 return vs; 059 vs.getMeta().getProfile().add(new CanonicalType("http://hl7.org/fhir/StructureDefinition/shareablevalueset")); 060 return vs; 061 } 062 063 public static boolean makeVSShareable(ValueSet vs) { 064 if (!vs.hasMeta()) 065 vs.setMeta(new Meta()); 066 for (UriType t : vs.getMeta().getProfile()) 067 if (t.getValue().equals("http://hl7.org/fhir/StructureDefinition/shareablevalueset")) 068 return false; 069 vs.getMeta().getProfile().add(new CanonicalType("http://hl7.org/fhir/StructureDefinition/shareablevalueset")); 070 return true; 071 } 072 073 public static void checkShareable(ValueSet vs) { 074 if (!vs.hasMeta()) 075 throw new Error("ValueSet "+vs.getUrl()+" is not shareable"); 076 for (UriType t : vs.getMeta().getProfile()) { 077 if (t.getValue().equals("http://hl7.org/fhir/StructureDefinition/shareablevalueset")) 078 return; 079 } 080 throw new Error("ValueSet "+vs.getUrl()+" is not shareable"); 081 } 082 083 public static boolean hasOID(ValueSet vs) { 084 return getOID(vs) != null; 085 } 086 087 public static String getOID(ValueSet vs) { 088 for (Identifier id : vs.getIdentifier()) { 089 if ("urn:ietf:rfc:3986".equals(id.getSystem()) && id.hasValue() && id.getValue().startsWith("urn:oid:")) 090 return id.getValue().substring(8); 091 } 092 return null; 093 } 094 095 public static void setOID(ValueSet vs, String oid) { 096 if (!oid.startsWith("urn:oid:")) 097 oid = "urn:oid:" + oid; 098 for (Identifier id : vs.getIdentifier()) { 099 if ("urn:ietf:rfc:3986".equals(id.getSystem()) && id.hasValue() && id.getValue().startsWith("urn:oid:")) { 100 id.setValue(oid); 101 return; 102 } 103 } 104 vs.addIdentifier().setSystem("urn:ietf:rfc:3986").setValue(oid); 105 } 106 107 public static void markStatus(ValueSet vs, String wg, StandardsStatus status, String pckage, String fmm, IWorkerContext context, String normativeVersion) throws FHIRException { 108 if (vs.hasUserData("external.url")) 109 return; 110 111 if (wg != null) { 112 if (!ToolingExtensions.hasExtension(vs, ToolingExtensions.EXT_WORKGROUP) || 113 (!Utilities.existsInList(ToolingExtensions.readStringExtension(vs, ToolingExtensions.EXT_WORKGROUP), "fhir", "vocab") && Utilities.existsInList(wg, "fhir", "vocab"))) { 114 ToolingExtensions.setCodeExtension(vs, ToolingExtensions.EXT_WORKGROUP, wg); 115 } 116 } 117 if (status != null) { 118 StandardsStatus ss = ToolingExtensions.getStandardsStatus(vs); 119 if (ss == null || ss.isLowerThan(status)) 120 ToolingExtensions.setStandardsStatus(vs, status, normativeVersion); 121 if (pckage != null) { 122 if (!vs.hasUserData("ballot.package")) 123 vs.setUserData("ballot.package", pckage); 124 else if (!pckage.equals(vs.getUserString("ballot.package"))) 125 if (!"infrastructure".equals(vs.getUserString("ballot.package"))) 126 System.out.println("Value Set "+vs.getUrl()+": ownership clash "+pckage+" vs "+vs.getUserString("ballot.package")); 127 } 128 if (status == StandardsStatus.NORMATIVE) { 129 vs.setExperimental(false); 130 vs.setStatus(PublicationStatus.ACTIVE); 131 } 132 } 133 if (fmm != null) { 134 String sfmm = ToolingExtensions.readStringExtension(vs, ToolingExtensions.EXT_FMM_LEVEL); 135 if (Utilities.noString(sfmm) || Integer.parseInt(sfmm) < Integer.parseInt(fmm)) { 136 ToolingExtensions.setIntegerExtension(vs, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(fmm)); 137 } 138 if (Integer.parseInt(fmm) <= 1) { 139 vs.setExperimental(true); 140 } 141 } 142 if (vs.hasUserData("cs")) 143 CodeSystemUtilities.markStatus((CodeSystem) vs.getUserData("cs"), wg, status, pckage, fmm, normativeVersion); 144 else if (status == StandardsStatus.NORMATIVE && context != null) { 145 for (ConceptSetComponent csc : vs.getCompose().getInclude()) { 146 if (csc.hasSystem()) { 147 CodeSystem cs = context.fetchCodeSystem(csc.getSystem()); 148 if (cs != null) { 149 CodeSystemUtilities.markStatus(cs, wg, status, pckage, fmm, normativeVersion); 150 } 151 } 152 } 153 } 154 } 155 156 private static int ssval(String status) { 157 if ("Draft".equals("status")) 158 return 1; 159 if ("Informative".equals("status")) 160 return 2; 161 if ("External".equals("status")) 162 return 3; 163 if ("Trial Use".equals("status")) 164 return 3; 165 if ("Normative".equals("status")) 166 return 4; 167 return -1; 168 } 169 170 public static ValueSet generateImplicitValueSet(String uri) { 171 if (uri.startsWith("http://snomed.info/sct")) 172 return generateImplicitSnomedValueSet(uri); 173 if (uri.startsWith("http://loinc.org/vs")) 174 return generateImplicitLoincValueSet(uri); 175 if (uri.equals("http://hl7.org/fhir/ValueSet/mimetypes")) { 176 return generateImplicitMimetypesValueSet(uri); 177 } 178 return null; 179 } 180 181 private static ValueSet generateImplicitMimetypesValueSet(String theUri) { 182 ValueSet valueSet = new ValueSet(); 183 valueSet.setStatus(PublicationStatus.ACTIVE); 184 valueSet.setUrl(theUri); 185 valueSet.setDescription("This value set includes all possible codes from BCP-13 (http://tools.ietf.org/html/bcp13)"); 186 valueSet.getCompose() 187 .addInclude().setSystem("urn:ietf:bcp:13"); 188 return valueSet; 189 } 190 191 private static ValueSet generateImplicitLoincValueSet(String uri) { 192 if ("http://loinc.org/vs".equals(uri)) 193 return makeLoincValueSet(); 194 if (uri.startsWith("http://loinc.org/vs/LL")) 195 return makeAnswerList(makeLoincValueSet(), uri); 196 return null; 197 } 198 199 private static ValueSet makeAnswerList(ValueSet vs, String uri) { 200 vs.setUrl(uri); 201 String c = uri.substring(20); 202 vs.setName("LOINCAnswers"+c); 203 vs.setTitle("LOINC Answer Codes for "+c); 204 vs.getCompose().getIncludeFirstRep().addFilter().setProperty("LIST").setOp(FilterOperator.EQUAL).setValue(c); 205 return vs; 206 } 207 208 private static ValueSet makeLoincValueSet() { 209 ValueSet vs = new ValueSet(); 210 vs.setUrl("http://loinc.org/vs"); 211 vs.setName("LOINCCodes"); 212 vs.setTitle("All LOINC codes"); 213 vs.setCopyright("This content LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at http://loinc.org/terms-of-use"); 214 vs.setStatus(PublicationStatus.ACTIVE); 215 vs.getCompose().addInclude().setSystem("http://loinc.org"); 216 return vs; 217 } 218 219 private static ValueSet generateImplicitSnomedValueSet(String uri) { 220 if ("http://snomed.info/sct?fhir_vs".equals(uri)) 221 return makeImplicitSnomedValueSet(uri); 222 return null; 223 } 224 225 private static ValueSet makeImplicitSnomedValueSet(String uri) { 226 ValueSet vs = new ValueSet(); 227 vs.setUrl(uri); 228 vs.setName("SCTValueSet"); 229 vs.setTitle("SCT ValueSet"); 230 vs.setDescription("All SNOMED CT Concepts"); 231 vs.setCopyright("This value set includes content from SNOMED CT, which is copyright © 2002+ International Health Terminology Standards Development Organisation (SNOMED International), and distributed by agreement between SNOMED International and HL7. Implementer use of SNOMED CT is not covered by this agreement"); 232 vs.setStatus(PublicationStatus.ACTIVE); 233 vs.getCompose().addInclude().setSystem("http://snomed.info/sct"); 234 return vs; 235 } 236 237}