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