
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 046 public BaseLoaderR5(Set<String> types, ILoaderKnowledgeProviderR5 lkp) { 047 super(); 048 this.types.addAll(types); 049 this.lkp = lkp; 050 } 051 052 public String getResourcePath(Resource resource) { 053 return lkp.getResourcePath(resource); 054 } 055 056 public void setPath(Resource r) { 057 String path = lkp.getResourcePath(r); 058 if (lkp.getWebRoot() != null) { 059 r.setUserData(UserDataNames.render_webroot, lkp.getWebRoot()); 060 } else { 061 r.setUserData(UserDataNames.render_webroot, ""); 062 } 063 if (path != null) { 064 r.setWebPath(path); 065 } 066 } 067 068 public IContextResourceLoader getNewLoader(NpmPackage npm) throws JsonSyntaxException, IOException { 069 BaseLoaderR5 ret = loaderFactory(npm); 070 ret.patchUrls = patchUrls; 071 ret.killPrimitives = killPrimitives; 072 return ret; 073 } 074 075 protected BaseLoaderR5 loaderFactory(NpmPackage npm) throws JsonSyntaxException, IOException { 076 if (VersionUtilities.isR5Plus(npm.fhirVersion())) { 077 return new R5ToR5Loader(types, lkp.forNewPackage(npm)); 078 } else if (VersionUtilities.isR4BVer(npm.fhirVersion())) { 079 return new R4BToR5Loader(types, lkp.forNewPackage(npm), npm.version()); 080 } else if (VersionUtilities.isR4Ver(npm.fhirVersion())) { 081 return new R4ToR5Loader(types, lkp.forNewPackage(npm), npm.version()); 082 } else if (VersionUtilities.isR3Ver(npm.fhirVersion())) { 083 return new R3ToR5Loader(types, lkp.forNewPackage(npm)); 084 } else if (VersionUtilities.isR2Ver(npm.fhirVersion())) { 085 return new R2ToR5Loader(types, lkp.forNewPackage(npm)); 086 } else if (VersionUtilities.isR2BVer(npm.fhirVersion())) { 087 return new R2016MayToR5Loader(types, lkp.forNewPackage(npm)); 088 } else { 089 throw new FHIRException("Unsupported FHIR Version " + npm.fhirVersion()); 090 } 091 } 092 093 public boolean isPatchUrls() { 094 return patchUrls; 095 } 096 097 public void setPatchUrls(boolean patchUrls) { 098 this.patchUrls = patchUrls; 099 } 100 101 protected abstract String versionString(); 102 103 104 @Override 105 public String patchUrl(String url, String type) { 106 if (!patchUrls || url == null) { 107 return url; 108 } else if (url.startsWith("http://hl7.org/fhir/"+type+"/")) { 109 return "http://hl7.org/fhir/"+versionString()+"/"+url.substring(20); 110 } else if ("CodeSystem".equals(type) && url.startsWith("http://hl7.org/fhir/")) { 111 return "http://hl7.org/fhir/"+versionString()+"/"+url.substring(20); 112 } else { 113 return url; 114 } 115 } 116 117 // we don't patch everything. It's quite hard work to do that, 118 // and we only patch URLs to support version transforms 119 // so we just patch sd/od -> vs -> cs 120 protected void doPatchUrls(Resource resource) { 121 resource.setUserData(UserDataNames.loader_urls_patched, true); 122 if (resource instanceof CanonicalResource) { 123 CanonicalResource cr = (CanonicalResource) resource; 124 cr.setUrl(patchUrl(cr.getUrl(), cr.fhirType())); 125 if (cr instanceof StructureDefinition) { 126 StructureDefinition sd = (StructureDefinition) cr; 127 sd.setBaseDefinition(patchUrl(sd.getBaseDefinition(), sd.fhirType())); 128 new ProfileUtilities(null, null, null, null).setIds(sd, false); 129 sd.addExtension().setUrl(ExtensionDefinitions.EXT_XML_NAMESPACE).setValue(new UriType(URL_BASE)); 130 for (ElementDefinition ed : sd.getSnapshot().getElement()) 131 patchUrl(ed); 132 for (ElementDefinition ed : sd.getDifferential().getElement()) 133 patchUrl(ed); 134 } 135 136 if (cr instanceof ValueSet) { 137 ValueSet vs = (ValueSet) cr; 138 for (ConceptSetComponent inc : vs.getCompose().getInclude()) { 139 inc.setSystem(patchUrl(inc.getSystem(), "CodeSystem")); 140 } 141 for (ConceptSetComponent inc : vs.getCompose().getExclude()) { 142 inc.setSystem(patchUrl(inc.getSystem(), "CodeSystem")); 143 } 144 } 145 if (cr instanceof OperationDefinition) { 146 OperationDefinition od = (OperationDefinition) cr; 147 for (OperationDefinitionParameterComponent param : od.getParameter()) { 148 patchUrls(param); 149 } 150 } 151 } 152 } 153 154 private void patchUrls(OperationDefinitionParameterComponent param) { 155 if (param.hasBinding()) { 156 param.getBinding().setValueSet(patchUrl(param.getBinding().getValueSet(), "ValueSet")); 157 } 158 for (OperationDefinitionParameterComponent p : param.getPart()) { 159 patchUrls(p); 160 } 161 } 162 163 private void patchUrl(ElementDefinition ed) { 164 for (TypeRefComponent tr : ed.getType()) { 165 if (!Utilities.isAbsoluteUrl(tr.getCode())) { 166 tr.setCode(URL_BASE+versionString()+"/StructureDefinition/"+tr.getCode()); 167 } 168 for (CanonicalType s : tr.getTargetProfile()) { 169 s.setValue(patchUrl(s.getValue(), "StructureDefinition")); 170 } 171 if (tr.hasExtension(ExtensionDefinitions.EXT_FHIR_TYPE)) { 172 String code = ExtensionUtilities.readStringExtension(tr, ExtensionDefinitions.EXT_FHIR_TYPE); 173 String url = URL_BASE+versionString()+"/StructureDefinition/"+code; 174 ExtensionUtilities.setUrlExtension(tr, ExtensionDefinitions.EXT_FHIR_TYPE, url); 175 } 176 for (CanonicalType c : tr.getProfile()) { 177 c.setValue(patchUrl(c.getValue(), "StructureDefinition")); 178 } 179 for (CanonicalType c : tr.getTargetProfile()) { 180 c.setValue(patchUrl(c.getValue(), "StructureDefinition")); 181 } 182 } 183 if (ed.hasBinding()) { 184 ed.getBinding().setValueSet(patchUrl(ed.getBinding().getValueSet(), "ValueSet")); 185 } 186 if (ed.hasContentReference()) { 187 ed.setContentReference(patchUrl(ed.getContentReference(), "StructureDefinition")); 188 } 189 } 190 191 public IContextResourceLoader setLoadProfiles(boolean value) { 192 loadProfiles = value; 193 return this; 194 } 195 196 public boolean wantLoad(NpmPackage pi, PackageResourceInformation pri) { 197 if (pri.getResourceType().equals("StructureDefinition")) { 198 if (loadProfiles) { 199 return true; 200 } else { 201 return pi.isCore() && Utilities.tail(pri.getUrl()).equals(pri.getStatedType()); 202 } 203 } else if (pi.isCore() && "CodeSystem".equals(pri.getResourceType()) && "spdx-license".equals(pri.getId())) { 204 return false; 205 } else { 206 return true; 207 } 208 } 209}