
001package org.hl7.fhir.convertors.loaders.loaderR5; 002 003import java.io.IOException; 004import java.util.HashSet; 005import java.util.Set; 006 007import org.hl7.fhir.exceptions.FHIRException; 008import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; 009import org.hl7.fhir.r5.context.IContextResourceLoader; 010import org.hl7.fhir.r5.extensions.ExtensionDefinitions; 011import org.hl7.fhir.r5.extensions.ExtensionUtilities; 012import org.hl7.fhir.r5.model.CanonicalResource; 013import org.hl7.fhir.r5.model.CanonicalType; 014import org.hl7.fhir.r5.model.ElementDefinition; 015import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; 016import org.hl7.fhir.r5.model.OperationDefinition; 017import org.hl7.fhir.r5.model.OperationDefinition.OperationDefinitionParameterComponent; 018import org.hl7.fhir.r5.model.Resource; 019import org.hl7.fhir.r5.model.StructureDefinition; 020import org.hl7.fhir.r5.model.UriType; 021import org.hl7.fhir.r5.model.ValueSet; 022import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; 023import org.hl7.fhir.r5.utils.UserDataNames; 024import org.hl7.fhir.utilities.Utilities; 025import org.hl7.fhir.utilities.VersionUtilities; 026import org.hl7.fhir.utilities.npm.NpmPackage; 027import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation; 028 029import com.google.gson.JsonSyntaxException; 030 031import lombok.Getter; 032import lombok.Setter; 033import lombok.experimental.Accessors; 034 035@Accessors(chain = true) 036public abstract class BaseLoaderR5 implements IContextResourceLoader { 037 038 protected final String URL_BASE = "http://hl7.org/fhir/"; 039 040 protected boolean patchUrls; 041 @Getter @Setter protected boolean killPrimitives; 042 @Getter protected Set<String> types = new HashSet<>(); 043 protected ILoaderKnowledgeProviderR5 lkp; 044 private boolean loadProfiles = true; 045 protected Set<String> tags = new HashSet<>(); 046 047 public BaseLoaderR5(Set<String> types, ILoaderKnowledgeProviderR5 lkp) { 048 super(); 049 this.types.addAll(types); 050 this.lkp = lkp; 051 } 052 053 public String getResourcePath(Resource resource) { 054 return lkp.getResourcePath(resource); 055 } 056 057 public void setPath(Resource r) { 058 String path = lkp.getResourcePath(r); 059 if (lkp.getWebRoot() != null) { 060 r.setUserData(UserDataNames.render_webroot, lkp.getWebRoot()); 061 } else { 062 r.setUserData(UserDataNames.render_webroot, ""); 063 } 064 if (path != null) { 065 r.setWebPath(path); 066 } 067 } 068 069 public IContextResourceLoader getNewLoader(NpmPackage npm) throws JsonSyntaxException, IOException { 070 BaseLoaderR5 ret = loaderFactory(npm); 071 ret.patchUrls = patchUrls; 072 ret.killPrimitives = killPrimitives; 073 return ret; 074 } 075 076 protected BaseLoaderR5 loaderFactory(NpmPackage npm) throws JsonSyntaxException, IOException { 077 if (VersionUtilities.isR5Plus(npm.fhirVersion())) { 078 return new R5ToR5Loader(types, lkp.forNewPackage(npm)); 079 } else if (VersionUtilities.isR4BVer(npm.fhirVersion())) { 080 return new R4BToR5Loader(types, lkp.forNewPackage(npm), npm.fhirVersion()); 081 } else if (VersionUtilities.isR4Ver(npm.fhirVersion())) { 082 return new R4ToR5Loader(types, lkp.forNewPackage(npm), npm.fhirVersion()); 083 } else if (VersionUtilities.isR3Ver(npm.fhirVersion())) { 084 return new R3ToR5Loader(types, lkp.forNewPackage(npm)); 085 } else if (VersionUtilities.isR2Ver(npm.fhirVersion())) { 086 return new R2ToR5Loader(types, lkp.forNewPackage(npm)); 087 } else if (VersionUtilities.isR2BVer(npm.fhirVersion())) { 088 return new R2016MayToR5Loader(types, lkp.forNewPackage(npm)); 089 } else { 090 throw new FHIRException("Unsupported FHIR Version " + npm.fhirVersion()); 091 } 092 } 093 094 public boolean isPatchUrls() { 095 return patchUrls; 096 } 097 098 public void setPatchUrls(boolean patchUrls) { 099 this.patchUrls = patchUrls; 100 } 101 102 protected abstract String versionString(); 103 104 105 @Override 106 public String patchUrl(String url, String type) { 107 if (!patchUrls || url == null) { 108 return url; 109 } else if (url.startsWith("http://hl7.org/fhir/"+type+"/")) { 110 return "http://hl7.org/fhir/"+versionString()+"/"+url.substring(20); 111 } else if ("CodeSystem".equals(type) && url.startsWith("http://hl7.org/fhir/")) { 112 return "http://hl7.org/fhir/"+versionString()+"/"+url.substring(20); 113 } else { 114 return url; 115 } 116 } 117 118 // we don't patch everything. It's quite hard work to do that, 119 // and we only patch URLs to support version transforms 120 // so we just patch sd/od -> vs -> cs 121 protected void doPatchUrls(Resource resource) { 122 resource.setUserData(UserDataNames.loader_urls_patched, true); 123 if (resource instanceof CanonicalResource) { 124 CanonicalResource cr = (CanonicalResource) resource; 125 cr.setUrl(patchUrl(cr.getUrl(), cr.fhirType())); 126 if (cr instanceof StructureDefinition) { 127 StructureDefinition sd = (StructureDefinition) cr; 128 sd.setBaseDefinition(patchUrl(sd.getBaseDefinition(), sd.fhirType())); 129 new ProfileUtilities(null, null, null, null).setIds(sd, false); 130 sd.addExtension().setUrl(ExtensionDefinitions.EXT_XML_NAMESPACE).setValue(new UriType(URL_BASE)); 131 for (ElementDefinition ed : sd.getSnapshot().getElement()) 132 patchUrl(ed); 133 for (ElementDefinition ed : sd.getDifferential().getElement()) 134 patchUrl(ed); 135 } 136 137 if (cr instanceof ValueSet) { 138 ValueSet vs = (ValueSet) cr; 139 for (ConceptSetComponent inc : vs.getCompose().getInclude()) { 140 inc.setSystem(patchUrl(inc.getSystem(), "CodeSystem")); 141 } 142 for (ConceptSetComponent inc : vs.getCompose().getExclude()) { 143 inc.setSystem(patchUrl(inc.getSystem(), "CodeSystem")); 144 } 145 } 146 if (cr instanceof OperationDefinition) { 147 OperationDefinition od = (OperationDefinition) cr; 148 for (OperationDefinitionParameterComponent param : od.getParameter()) { 149 patchUrls(param); 150 } 151 } 152 } 153 } 154 155 private void patchUrls(OperationDefinitionParameterComponent param) { 156 if (param.hasBinding()) { 157 param.getBinding().setValueSet(patchUrl(param.getBinding().getValueSet(), "ValueSet")); 158 } 159 for (OperationDefinitionParameterComponent p : param.getPart()) { 160 patchUrls(p); 161 } 162 } 163 164 private void patchUrl(ElementDefinition ed) { 165 for (TypeRefComponent tr : ed.getType()) { 166 if (!Utilities.isAbsoluteUrl(tr.getCode())) { 167 tr.setCode(URL_BASE+versionString()+"/StructureDefinition/"+tr.getCode()); 168 } 169 for (CanonicalType s : tr.getTargetProfile()) { 170 s.setValue(patchUrl(s.getValue(), "StructureDefinition")); 171 } 172 if (tr.hasExtension(ExtensionDefinitions.EXT_FHIR_TYPE)) { 173 String code = ExtensionUtilities.readStringExtension(tr, ExtensionDefinitions.EXT_FHIR_TYPE); 174 String url = URL_BASE+versionString()+"/StructureDefinition/"+code; 175 ExtensionUtilities.setUrlExtension(tr, ExtensionDefinitions.EXT_FHIR_TYPE, url); 176 } 177 for (CanonicalType c : tr.getProfile()) { 178 c.setValue(patchUrl(c.getValue(), "StructureDefinition")); 179 } 180 for (CanonicalType c : tr.getTargetProfile()) { 181 c.setValue(patchUrl(c.getValue(), "StructureDefinition")); 182 } 183 } 184 if (ed.hasBinding()) { 185 ed.getBinding().setValueSet(patchUrl(ed.getBinding().getValueSet(), "ValueSet")); 186 } 187 if (ed.hasContentReference()) { 188 ed.setContentReference(patchUrl(ed.getContentReference(), "StructureDefinition")); 189 } 190 } 191 192 public IContextResourceLoader setLoadProfiles(boolean value) { 193 loadProfiles = value; 194 return this; 195 } 196 197 public boolean wantLoad(NpmPackage pi, PackageResourceInformation pri) { 198 if (pri.getResourceType().equals("StructureDefinition")) { 199 if (loadProfiles) { 200 return true; 201 } else { 202 return pi.isCore() && Utilities.tail(pri.getUrl()).equals(pri.getStatedType()); 203 } 204 } else if (pi.isCore() && "CodeSystem".equals(pri.getResourceType()) && "spdx-license".equals(pri.getId())) { 205 return false; 206 } else { 207 return true; 208 } 209 } 210 211 public BaseLoaderR5 addTag(String tag) { 212 if (tag != null) { 213 tags.add(tag); 214 } 215 return this; 216 } 217 218 protected void inspectResource(Resource res) { 219 for (String t : tags) { 220 res.setUserData(t, true); 221 } 222 } 223}