
001package org.hl7.fhir.r5.utils.xver; 002 003import org.hl7.fhir.exceptions.FHIRException; 004import org.hl7.fhir.r5.context.IWorkerContext; 005import org.hl7.fhir.r5.model.ElementDefinition; 006import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; 007import org.hl7.fhir.r5.model.Enumerations.FHIRVersion; 008import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; 009import org.hl7.fhir.r5.model.StructureDefinition; 010import org.hl7.fhir.r5.model.StructureDefinition.ExtensionContextType; 011import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; 012import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; 013import org.hl7.fhir.r5.model.UriType; 014import org.hl7.fhir.utilities.Utilities; 015import org.hl7.fhir.utilities.VersionUtilities; 016import org.hl7.fhir.utilities.json.model.JsonElement; 017import org.hl7.fhir.utilities.json.model.JsonObject; 018import org.hl7.fhir.utilities.json.parser.JsonParser; 019import org.hl7.fhir.utilities.npm.PackageHacker; 020 021import java.io.IOException; 022import java.util.Date; 023import java.util.HashMap; 024import java.util.Map; 025 026public class XVerExtensionManagerOld extends XVerExtensionManager { 027 028 private Map<String, JsonObject> lists = new HashMap<>(); 029 030 public XVerExtensionManagerOld(IWorkerContext context) { 031 super(context); 032 } 033 034 @Override 035 public XVerExtensionStatus status(String url) throws FHIRException { 036 if (url.length() < 54) { 037 return XVerExtensionStatus.Invalid; 038 } 039 url = url.replace("%5Bx%5D", "[x]"); 040 String v = url.substring(20, 23); 041 String e = url.substring(54); 042 if (!lists.containsKey(v)) { 043 if (context.hasBinaryKey("xver-paths-"+v+".json")) { 044 try { 045 lists.put(v, JsonParser.parseObject(context.getBinaryForKey("xver-paths-"+v+".json"))); 046 } catch (IOException e1) { 047 throw new FHIRException(e); 048 } 049 } else { 050 return XVerExtensionStatus.BadVersion; 051 } 052 } 053 JsonObject root = lists.get(v); 054 JsonObject path = root.getJsonObject(e); 055 if (path == null) { 056 path = root.getJsonObject(e+"[x]"); 057 } 058 if (path == null) { 059 return XVerExtensionStatus.Unknown; 060 } 061 if (path.has("elements") || path.has("types")) { 062 return XVerExtensionStatus.Valid; 063 } else { 064 return XVerExtensionStatus.Invalid; 065 } 066 } 067 068 @Override 069 public StructureDefinition getDefinition(String url) { 070 url = url.replace("%5Bx%5D", "[x]"); 071 String verSource = url.substring(20, 23); 072 String verTarget = VersionUtilities.getMajMin(context.getVersion()); 073 String e = url.substring(54); 074 String r = e.contains(".") ? e.substring(0, e.indexOf(".")) : e; 075 JsonObject root = lists.get(verSource); 076 JsonObject path = root.getJsonObject(e); 077 if (path == null) { 078 path = root.getJsonObject(e+"[x]"); 079 } 080 081 StructureDefinition sd = new StructureDefinition(); 082 sd.setUserData(XVER_EXT_MARKER, "true"); 083 sd.setUserData(XVER_VER_MARKER, verSource); 084 if (context.getResourceNamesAsSet().contains(r)) { 085 sd.setWebPath(Utilities.pathURL(context.getSpecUrl(), r.toLowerCase()+"-definitions.html#"+e)); 086 } else { 087 sd.setWebPath(PackageHacker.fixPackageUrl("https://hl7.org/fhir/versions.html#extensions")); 088 } 089 sd.setUrl(url); 090 sd.setVersion(context.getVersion()); 091 sd.setFhirVersion(FHIRVersion.fromCode(context.getVersion())); 092 sd.setKind(StructureDefinitionKind.COMPLEXTYPE); 093 sd.setType("Extension"); 094 sd.setDerivation(TypeDerivationRule.CONSTRAINT); 095 sd.setName("Extension-"+verSource+"-"+e); 096 sd.setTitle("Extension Definition for "+e+" for Version "+verSource); 097 sd.setStatus(PublicationStatus.ACTIVE); 098 sd.setExperimental(false); 099 sd.setDate(new Date()); 100 sd.setPublisher("FHIR Project"); 101 sd.setPurpose("Defined so the validator can validate cross version extensions (see http://hl7.org/fhir/versions.html#extensions)"); 102 sd.setAbstract(false); 103 sd.addContext().setType(ExtensionContextType.ELEMENT).setExpression(head(e)); 104 sd.setBaseDefinition("http://hl7.org/fhir/StructureDefinition/Extension"); 105 if (path.has("types")) { 106 sd.getDifferential().addElement().setPath("Extension.extension").setMax("0"); 107 sd.getDifferential().addElement().setPath("Extension.url").setFixed(new UriType(url)); 108 ElementDefinition val = sd.getDifferential().addElement().setPath("Extension.value[x]").setMin(1); 109 populateTypes(path, val, verSource, verTarget); 110 } else if (path.has("elements")) { 111 for (JsonElement i : path.forceArray("elements").getItems()) { 112 String apath = e+"."+i.asString(); 113 JsonObject elt = root.getJsonObject(apath); 114 if (elt != null) { 115 genExtensionContents(root, apath, verSource, verTarget, sd, i, elt, "Extension.extension"); 116 } 117 } 118 sd.getDifferential().addElement().setPath("Extension.url").setFixed(new UriType(url)); 119 sd.getDifferential().addElement().setPath("Extension.value[x]").setMax("0"); 120 } else { 121 throw new FHIRException("Internal error - attempt to define extension for "+url+" when it is invalid"); 122 } 123 if (path.has("modifier") && path.asBoolean("modifier")) { 124 ElementDefinition baseDef = new ElementDefinition("Extension"); 125 sd.getDifferential().getElement().add(0, baseDef); 126 baseDef.setIsModifier(true); 127 } 128 return sd; 129 } 130 131 private void genExtensionContents(JsonObject root, String apath, String verSource, String verTarget, StructureDefinition sd, JsonElement i, JsonObject elt, String epath) { 132 String s = i.asString().replace("[x]", ""); 133 sd.getDifferential().addElement().setPath(epath).setSliceName(s); 134 if (elt.has("types")) { 135 sd.getDifferential().addElement().setPath(epath+".extension").setMax("0"); 136 sd.getDifferential().addElement().setPath(epath+".url").setFixed(new UriType(s)); 137 ElementDefinition val = sd.getDifferential().addElement().setPath(epath+".value[x]").setMin(1); 138 populateTypes(elt, val, verSource, verTarget); 139 } else if (elt.has("elements")) { 140 for (JsonElement ic : elt.forceArray("elements").getItems()) { 141 String apathC = apath+"."+ic.asString(); 142 JsonObject eltC = root.getJsonObject(apathC); 143 if (eltC != null) { 144 genExtensionContents(root, apathC, verSource, verTarget, sd, ic, eltC, epath+".extension"); 145 } 146 } 147 sd.getDifferential().addElement().setPath(epath+".url").setFixed(new UriType(s)); 148 sd.getDifferential().addElement().setPath(epath+".value[x]").setMax("0"); 149 } else { 150 throw new FHIRException("Internal error - unknown element "+apath); 151 } 152 } 153 154 private void populateTypes(JsonObject path, ElementDefinition val, String verSource, String verTarget) { 155 for (JsonElement i : path.forceArray("types").getItems()) { 156 String s = i.asString(); 157 if (!s.startsWith("!")) { 158 if (s.contains("(")) { 159 String t = s.substring(0, s.indexOf("(")); 160 TypeRefComponent tr = val.addType().setCode(translateDataType(verTarget, t)); 161 if (hasTargets(tr.getCode()) ) { 162 s = s.substring(t.length()+1); 163 for (String p : s.substring(0, s.length()-1).split("\\|")) { 164 if ("Any".equals(p)) { 165 tr.addTargetProfile("http://hl7.org/fhir/StructureDefinition/Resource"); 166 } else if (p.contains(",")) { 167 for (String pp : p.split("\\,")) { 168 if (isResource(pp)) { 169 tr.addTargetProfile("http://hl7.org/fhir/StructureDefinition/"+pp); 170 } 171 } 172 } else if (isResource(p)) { 173 tr.addTargetProfile("http://hl7.org/fhir/StructureDefinition/"+p); 174 } 175 } 176 } 177 } else { 178 val.addType().setCode(translateDataType(verTarget, s)); 179 } 180 } 181 } 182 } 183 private boolean isResource(String p) { 184 return context.getResourceNames().contains(p); 185 } 186 187 private boolean hasTargets(String dt) { 188 return Utilities.existsInList(dt, "canonical", "Reference", "CodeableReference"); 189 } 190 191 private String translateDataType(String v, String dt) { 192 if (VersionUtilities.versionMatches("1.0.x", v) || VersionUtilities.versionMatches("1.4.x", v)) { 193 return translateToR2(dt); 194 } else if (VersionUtilities.versionMatches("3.0.x", v)) { 195 return translateToR3(dt); 196 } else { 197 return dt; 198 } 199 } 200 201 private String translateToR3(String dt) { 202 if ("canonical".equals(dt)) { 203 return "uri"; 204 } else if ("url".equals(dt)) { 205 return "uri"; 206 } else { 207 return dt; 208 } 209 } 210 211 private String translateToR2(String dt) { 212 if ("canonical".equals(dt)) { 213 return "uri"; 214 } else if ("url".equals(dt)) { 215 return "uri"; 216 } else if ("uuid".equals(dt)) { 217 return "id"; 218 } else { 219 return dt; 220 } 221 } 222 223 private String head(String id) { 224 if (id.contains(".")) { 225 return id.substring(0, id.lastIndexOf(".")); 226 } else { 227 return id; 228 } 229 } 230 231}