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