All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hl7.fhir.validation.IgLoader Maven / Gradle / Ivy

The newest version!
package org.hl7.fhir.validation;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_43_50;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.IContextResourceLoader;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
import org.hl7.fhir.utilities.ByteProvider;
import org.hl7.fhir.utilities.IniFile;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
import org.hl7.fhir.utilities.http.HTTPResult;
import org.hl7.fhir.utilities.http.ManagedWebAccess;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.turtle.Turtle;
import org.hl7.fhir.validation.IgLoader.IDirectPackageProvider;
import org.hl7.fhir.validation.ValidationEngine.IValidationEngineLoader;
import org.hl7.fhir.validation.ValidatorUtils.SourceFile;
import org.hl7.fhir.validation.cli.utils.Common;
import org.hl7.fhir.validation.cli.utils.VersionSourceInformation;

import lombok.Getter;
import lombok.Setter;

public class IgLoader implements IValidationEngineLoader {

  /**
   * This is used in testing to allow tests to deal with unreleased packages 
   */
  public interface IDirectPackageProvider {

    InputStream fetchByPackage(String src) throws IOException;

  }

  private static final String[] IGNORED_EXTENSIONS = {"md", "css", "js", "png", "gif", "jpg", "html", "tgz", "pack", "zip"};
  private static final String[] EXEMPT_FILES = {"spec.internals", "version.info", "schematron.zip", "package.json"};
  private static final int SCAN_HEADER_SIZE = 2048;

  @Getter private final FilesystemPackageCacheManager packageCacheManager;
  @Getter private final SimpleWorkerContext context;
  @Getter private final String version;
  @Getter private final boolean isDebug;
  @Getter @Setter private IDirectPackageProvider directProvider;

  public IgLoader(FilesystemPackageCacheManager packageCacheManager,
                  SimpleWorkerContext context,
                  String theVersion) {
      this(packageCacheManager, context, theVersion, false);
  }

  public IgLoader(FilesystemPackageCacheManager packageCacheManager,
                  SimpleWorkerContext context,
                  String theVersion,
                  boolean isDebug) {
      this.packageCacheManager = packageCacheManager;
      this.context = context;
      this.version = theVersion;
      this.isDebug = isDebug;
  }

  /**
   *
   * @param igs
   * @param binaries
   * @param src Source of the IG
   *
   * @param recursive
   * @throws IOException
   * @throws FHIRException
   *
   * @see IgLoader#loadIgSource(String, boolean, boolean) loadIgSource for detailed description of the src parameter
   */
  public void loadIg(List igs,
                     Map binaries,
                     String src,
                     boolean recursive) throws IOException, FHIRException {

    final String explicitFhirVersion;
    final String srcPackage;
    if (src.startsWith("[") && src.indexOf(']', 1) > 1) {
      explicitFhirVersion = src.substring(1,src.indexOf(']', 1));
      srcPackage = src.substring(src.indexOf(']',1) + 1);
      if (!VersionUtilities.isSupportedVersion(explicitFhirVersion)) {
        throw new FHIRException("Unsupported FHIR Version: " + explicitFhirVersion + " valid versions are " + VersionUtilities.listSupportedVersions());
      }
    } else {
      explicitFhirVersion = null;
      srcPackage = src;
    }

    NpmPackage npm = srcPackage.matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX_OPT) && !ManagedFileAccess.file(srcPackage).exists() ? getPackageCacheManager().loadPackage(srcPackage, null) : null;
    if (npm == null && ManagedFileAccess.file(srcPackage).exists()) {
      // try treating the file as an npm
      try {
        npm = NpmPackage.fromPackage(ManagedFileAccess.inStream(srcPackage));
      } catch (Exception e) {
        // nothing - any errors will be properly handled later in the process
      }
    }
    if (npm != null) {
      for (String s : npm.dependencies()) {
        if (!getContext().getLoadedPackages().contains(s)) {
          if (!VersionUtilities.isCorePackage(s)) {
            loadIg(igs, binaries, s, false);
          }
        }
      }
      System.out.print("  Load " + srcPackage);
      if (!srcPackage.contains("#")) {
        System.out.print("#" + npm.version());
      }
      IContextResourceLoader loader = ValidatorUtils.loaderForVersion(npm.fhirVersion());
      loader.setPatchUrls(VersionUtilities.isCorePackage(npm.id()));
      int count = getContext().loadFromPackage(npm, loader);
      System.out.println(" - " + count + " resources (" + getContext().clock().milestone() + ")");
    } else {
      System.out.print("  Load " + srcPackage);
      String canonical = null;
      int count = 0;
      Map source = loadIgSource(srcPackage, recursive, true);
      String version = Constants.VERSION;
      if (getVersion() != null) {
        version = getVersion();
      }
      if (source.containsKey("version.info")) {
        version = readInfoVersion(source.get("version.info"));
      }
      if (explicitFhirVersion != null) {
        version = explicitFhirVersion;
      }

      for (Map.Entry t : source.entrySet()) {
        String fn = t.getKey();
        if (!exemptFile(fn)) {
          Resource r = loadFileWithErrorChecking(version, t, fn);
          if (r != null) {
            count++;
            getContext().cacheResource(r);
            if (r instanceof ImplementationGuide) {
              canonical = ((ImplementationGuide) r).getUrl();
              igs.add((ImplementationGuide) r);
              if (canonical.contains("/ImplementationGuide/")) {
                Resource r2 = r.copy();
                ((ImplementationGuide) r2).setUrl(canonical.substring(0, canonical.indexOf("/ImplementationGuide/")));
                getContext().cacheResource(r2);
              }
            }
          }
        }
      }
      if (canonical != null) {
        ValidatorUtils.grabNatives(binaries, source, canonical);
      }
      System.out.println(" - " + count + " resources (" + getContext().clock().milestone() + ")");
    }
  }

  /**
   *
   * @param source
   * @param opName
   * @param asIg
   * @return
   * @throws FHIRException
   * @throws IOException
   *
   *    * @see IgLoader#loadIgSource(String, boolean, boolean) loadIgSource for detailed description of the src parameter
   */

  public Content loadContent(String source, String opName, boolean asIg, boolean mustLoad) throws FHIRException, IOException {
    Map s = loadIgSource(source, false, asIg);
    Content res = new Content();
    if (!mustLoad && s.size() == 0) {
      return null;
    }
    if (s.size() != 1)
      throw new FHIRException("Unable to find resource " + source + " to " + opName);
    for (Map.Entry t : s.entrySet()) {
      res.setFocus(t.getValue());
      if (t.getKey().endsWith(".json"))
        res.setCntType(Manager.FhirFormat.JSON);
      else if (t.getKey().endsWith(".ndjson"))
        res.setCntType(Manager.FhirFormat.NDJSON);
      else if (t.getKey().endsWith(".xml"))
        res.setCntType(Manager.FhirFormat.XML);
      else if (t.getKey().endsWith(".ttl"))
        res.setCntType(Manager.FhirFormat.TURTLE);
      else if (t.getKey().endsWith(".shc"))
        res.setCntType(Manager.FhirFormat.SHC);
      else if (t.getKey().endsWith(".txt"))
        res.setCntType(Manager.FhirFormat.TEXT);
      else if (t.getKey().endsWith(".fml") || t.getKey().endsWith(".map"))
        res.setCntType(Manager.FhirFormat.FML);
      else
        throw new FHIRException("Todo: Determining resource type is not yet done");
    }
    return res;
  }

  /**
   *
   * @param src can be one of the following:
   *      
- a canonical url for an ig - this will be converted to a package id and loaded into the cache *
- a package id for an ig - this will be loaded into the cache *
- a direct reference to a package ("package.tgz") - this will be extracted by the cache manager, but not put in the cache *
- a folder containing resources - these will be loaded directly * @param recursive if true and src resolves to a folder, recursively find and load IgSources from that directory * @param explore should be true if we're trying to load an -ig parameter, and false if we're loading source * * @return * @throws FHIRException * @throws IOException */ public Map loadIgSource(String src, boolean recursive, boolean explore) throws FHIRException, IOException { // if (Common.isNetworkPath(src)) { String v = null; if (src.contains("|")) { v = src.substring(src.indexOf("|") + 1); src = src.substring(0, src.indexOf("|")); } String pid = explore ? getPackageCacheManager().getPackageId(src) : null; if (!Utilities.noString(pid)) return fetchByPackage(pid + (v == null ? "" : "#" + v), false); else return fetchFromUrl(src + (v == null ? "" : "|" + v), explore); } File f = ManagedFileAccess.file(Utilities.path(src)); if (f.exists()) { if (f.isDirectory() && ManagedFileAccess.file(Utilities.path(src, "package.tgz")).exists()) { FileInputStream stream = ManagedFileAccess.inStream(Utilities.path(src, "package.tgz")); try { return loadPackage(stream, Utilities.path(src, "package.tgz"), false); } finally { stream.close(); } } if (f.isDirectory() && ManagedFileAccess.file(Utilities.path(src, "igpack.zip")).exists()) { FileInputStream stream = ManagedFileAccess.inStream(Utilities.path(src, "igpack.zip")); try { return readZip(stream); } finally { stream.close(); } } if (f.isDirectory() && ManagedFileAccess.file(Utilities.path(src, "validator.pack")).exists()) { FileInputStream stream = ManagedFileAccess.inStream(Utilities.path(src, "validator.pack")); try { return readZip(stream); } finally { stream.close(); } } if (f.isDirectory()) { return scanDirectory(f, recursive); } FileInputStream stream = ManagedFileAccess.inStream(src); try { if (src.endsWith(".tgz")) { Map res = loadPackage(stream, src, false); return res; } if (src.endsWith(".pack")) { return readZip(stream); } if (src.endsWith("igpack.zip")) { return readZip(stream); } } finally { stream.close(); } Manager.FhirFormat fmt = ResourceChecker.checkIsResource(getContext(), isDebug(), TextFile.fileToBytes(f), src, true); if (fmt != null) { Map res = new HashMap(); res.put(Utilities.changeFileExt(src, "." + fmt.getExtension()), ByteProvider.forFile(src)); return res; } } else if ((src.matches(FilesystemPackageCacheManager.PACKAGE_REGEX) || src.matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX)) && !src.endsWith(".zip") && !src.endsWith(".tgz")) { return fetchByPackage(src, false); } throw new FHIRException("Unable to find/resolve/read " + (explore ? "-ig " : "") + src); } public void scanForIgVersion(String src, boolean recursive, VersionSourceInformation versions) throws IOException { Map source = loadIgSourceForVersion(src, recursive, true, versions); if (source != null) { if (source.containsKey("version.info")) { versions.see(readInfoVersion(source.get("version.info")), "version.info in " + src); } else if (source.size() == 1) { for (ByteProvider v : source.values()) { scanForFhirVersion(versions, src, v); } } } } public void scanForVersions(List sources, VersionSourceInformation versions) throws FHIRException, IOException { List refs = new ArrayList<>(); ValidatorUtils.parseSources(sources, refs, context); for (SourceFile ref : refs) { Content cnt = loadContent(ref.getRef(), "validate", false, true); scanForFhirVersion(versions, ref.getRef(), cnt.getFocus()); } } private void scanForFhirVersion(VersionSourceInformation versions, String ref, ByteProvider bp) throws IOException { byte[] cnt = bp.getBytes(); String s = TextFile.bytesToString(cnt.length > SCAN_HEADER_SIZE ? Arrays.copyOfRange(cnt, 0, SCAN_HEADER_SIZE) : cnt).trim(); try { int i = s.indexOf("fhirVersion"); if (i > 1) { boolean xml = s.charAt(i) == '<'; i = find(s, i, '"'); if (!xml) { i = find(s, i+1, '"'); } if (i > 0) { int j = find(s, i+1, '"'); if (j > 0) { String v = s.substring(i+1, j); if (VersionUtilities.isSemVer(v)) { versions.see(VersionUtilities.getMajMin(v), "fhirVersion in " + ref); return; } } } i = find(s, i, '\''); if (!xml) { i = find(s, i+1, '\''); } if (i > 0) { int j = find(s, i+1, '\''); if (j > 0) { String v = s.substring(i, j); if (VersionUtilities.isSemVer(v)) { versions.see(VersionUtilities.getMajMin(v), "fhirVersion in " + ref); return; } } } } } catch (Exception e) { // nothing } if (s.contains("http://hl7.org/fhir/3.0")) { versions.see("3.0", "Profile in " + ref); return; } if (s.contains("http://hl7.org/fhir/1.0")) { versions.see("1.0", "Profile in " + ref); return; } if (s.contains("http://hl7.org/fhir/4.0")) { versions.see("4.0", "Profile in " + ref); return; } if (s.contains("http://hl7.org/fhir/1.4")) { versions.see("1.4", "Profile in " + ref); return; } } private int find(String s, int i, char c) { while (i < s.length() && s.charAt(i) != c) { i++; } return i == s.length() ? -1 : i; } protected Map readZip(InputStream stream) throws IOException { Map res = new HashMap<>(); ZipInputStream zip = new ZipInputStream(stream); ZipEntry zipEntry; while ((zipEntry = zip.getNextEntry()) != null) { String entryName = zipEntry.getName(); if (entryName.contains("..") || Path.of(entryName).isAbsolute()) { throw new RuntimeException("Entry with an illegal path: " + entryName); } ByteArrayOutputStream b = new ByteArrayOutputStream(); int n; byte[] buf = new byte[1024]; while ((n = ((InputStream) zip).read(buf, 0, 1024)) > -1) { b.write(buf, 0, n); } res.put(entryName, ByteProvider.forBytes(b.toByteArray())); zip.closeEntry(); } zip.close(); return res; } private String loadPackageForVersion(InputStream stream) throws FHIRException, IOException { return NpmPackage.fromPackage(stream).fhirVersion(); } private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException, IOException { try { HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source + "?nocache=" + System.currentTimeMillis()); res.checkThrowException(); return new ByteArrayInputStream(res.getContent()); } catch (IOException e) { if (optional) return null; else throw e; } } private Map loadIgSourceForVersion(String src, boolean recursive, boolean explore, VersionSourceInformation versions) throws FHIRException, IOException { if (Common.isNetworkPath(src)) { String v = null; if (src.contains("|")) { v = src.substring(src.indexOf("|") + 1); src = src.substring(0, src.indexOf("|")); } String pid = getPackageCacheManager().getPackageId(src); if (!Utilities.noString(pid)) { versions.see(fetchVersionByPackage(pid + (v == null ? "" : "#" + v)), "Package " + src); return null; } else { return fetchVersionFromUrl(src + (v == null ? "" : "|" + v), explore, versions); } } File f = ManagedFileAccess.file(Utilities.path(src)); if (f.exists()) { if (f.isDirectory() && ManagedFileAccess.file(Utilities.path(src, "package.tgz")).exists()) { versions.see(loadPackageForVersion(ManagedFileAccess.inStream(Utilities.path(src, "package.tgz"))), "Package " + src); return null; } if (f.isDirectory() && ManagedFileAccess.file(Utilities.path(src, "igpack.zip")).exists()) return readZip(ManagedFileAccess.inStream(Utilities.path(src, "igpack.zip"))); if (f.isDirectory() && ManagedFileAccess.file(Utilities.path(src, "validator.pack")).exists()) return readZip(ManagedFileAccess.inStream(Utilities.path(src, "validator.pack"))); if (f.isDirectory()) return scanDirectory(f, recursive); if (src.endsWith(".tgz")) { versions.see(loadPackageForVersion(ManagedFileAccess.inStream(src)), "Package " + src); return null; } if (src.endsWith(".pack")) return readZip(ManagedFileAccess.inStream(src)); if (src.endsWith("igpack.zip")) return readZip(ManagedFileAccess.inStream(src)); Manager.FhirFormat fmt = ResourceChecker.checkIsResource(getContext(), isDebug(), TextFile.fileToBytes(f), src, true); if (fmt != null) { Map res = new HashMap(); res.put(Utilities.changeFileExt(src, "." + fmt.getExtension()), ByteProvider.forFile(src)); return res; } } else if ((src.matches(FilesystemPackageCacheManager.PACKAGE_REGEX) || src.matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX)) && !src.endsWith(".zip") && !src.endsWith(".tgz")) { versions.see(fetchVersionByPackage(src), "Package " + src); return null; } throw new FHIRException("Unable to find/resolve/read -ig " + src); } private Map fetchByPackage(String src, boolean loadInContext) throws FHIRException, IOException { NpmPackage pi; if (directProvider != null) { InputStream stream = directProvider.fetchByPackage(src); if (stream != null) { pi = NpmPackage.fromPackage(stream); return loadPackage(pi, loadInContext); } } String id = src; String version = null; if (src.contains("#")) { id = src.substring(0, src.indexOf("#")); version = src.substring(src.indexOf("#") + 1); } if (version == null) { version = getPackageCacheManager().getLatestVersion(id); } if (version == null) { pi = getPackageCacheManager().loadPackageFromCacheOnly(id); if (pi != null) System.out.println(" ... Using version " + pi.version()); } else pi = getPackageCacheManager().loadPackage(id, version); if (pi == null) { throw new FHIRException("Unable to find package "+src); } else return loadPackage(pi, loadInContext); } private Map loadPackage(InputStream stream, String name, boolean loadInContext) throws FHIRException, IOException { return loadPackage(NpmPackage.fromPackage(stream), loadInContext); } public Map loadPackage(NpmPackage pi, boolean loadInContext) throws FHIRException, IOException { Map res = new HashMap(); for (String s : pi.dependencies()) { if (s.endsWith(".x") && s.length() > 2) { String packageMajorMinor = s.substring(0, s.length() - 2); boolean found = false; for (int i = 0; i < getContext().getLoadedPackages().size() && !found; ++i) { String loadedPackage = getContext().getLoadedPackages().get(i); if (loadedPackage.startsWith(packageMajorMinor)) { found = true; } } if (found) continue; } if (!getContext().getLoadedPackages().contains(s)) { if (!VersionUtilities.isCorePackage(s)) { System.out.println("+ .. load IG from " + s); res.putAll(fetchByPackage(s, loadInContext)); } } } if (!pi.isCoreExamples()) { if (loadInContext) { // getContext().getLoadedPackages().add(pi.name() + "#" + pi.version()); getContext().loadFromPackage(pi, ValidatorUtils.loaderForVersion(pi.fhirVersion())); } for (String s : pi.listResources("CodeSystem", "ConceptMap", "ImplementationGuide", "CapabilityStatement", "SearchParameter", "Conformance", "StructureMap", "ValueSet", "StructureDefinition")) { res.put(s, pi.getProvider("package", s)); } } String ini = "[FHIR]\r\nversion=" + pi.fhirVersion() + "\r\n"; res.put("version.info", ByteProvider.forBytes(ini.getBytes())); return res; } private Map resolvePackage(String id, String v, boolean loadInContext) throws FHIRException, IOException { NpmPackage pi = getPackageCacheManager().loadPackage(id, v); if (pi != null && v == null) System.out.println(" ... Using version " + pi.version()); return loadPackage(pi, loadInContext); } private String readInfoVersion(ByteProvider bs) throws IOException { String is = TextFile.bytesToString(bs.getBytes()); is = is.trim(); IniFile ini = new IniFile(new ByteArrayInputStream(TextFile.stringToBytes(is))); return ini.getStringProperty("FHIR", "version"); } private byte[] fetchFromUrlSpecific(String source, String contentType, boolean optional, List errors) throws FHIRException, IOException { try { try { // try with cache-busting option and then try without in case the server doesn't support that HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"),source + "?nocache=" + System.currentTimeMillis(), contentType); res.checkThrowException(); return res.getContent(); } catch (Exception e) { HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source, contentType); res.checkThrowException(); return res.getContent(); } } catch (IOException e) { if (errors != null) { errors.add("Error accessing " + source + ": " + e.getMessage()); } if (optional) return null; else throw e; } } private Map fetchVersionFromUrl(String src, boolean explore, VersionSourceInformation versions) throws FHIRException, IOException { if (src.endsWith(".tgz")) { versions.see(loadPackageForVersion(fetchFromUrlSpecific(src, false)), "From Package " + src); return null; } if (src.endsWith(".pack")) return readZip(fetchFromUrlSpecific(src, false)); if (src.endsWith("igpack.zip")) return readZip(fetchFromUrlSpecific(src, false)); InputStream stream = null; if (explore) { stream = fetchFromUrlSpecific(Utilities.pathURL(src, "package.tgz"), true); if (stream != null) { versions.see(loadPackageForVersion(stream), "From Package at " + src); return null; } // todo: these options are deprecated - remove once all IGs have been rebuilt post R4 technical correction stream = fetchFromUrlSpecific(Utilities.pathURL(src, "igpack.zip"), true); if (stream != null) return readZip(stream); stream = fetchFromUrlSpecific(Utilities.pathURL(src, "validator.pack"), true); if (stream != null) return readZip(stream); stream = fetchFromUrlSpecific(Utilities.pathURL(src, "validator.pack"), true); //// ----- } // ok, having tried all that... now we'll just try to access it directly byte[] cnt; if (stream == null) cnt = fetchFromUrlSpecific(src, "application/json", true, null); else cnt = TextFile.streamToBytes(stream); Manager.FhirFormat fmt = ResourceChecker.checkIsResource(getContext(), isDebug(), cnt, src, true); if (fmt != null) { Map res = new HashMap(); res.put(Utilities.changeFileExt(src, "." + fmt.getExtension()), ByteProvider.forBytes(cnt)); return res; } String fn = Utilities.path("[tmp]", "fetch-resource-error-content.bin"); TextFile.bytesToFile(cnt, fn); System.out.println("Error Fetching " + src); System.out.println("Some content was found, saved to " + fn); System.out.println("1st 100 bytes = " + presentForDebugging(cnt)); throw new FHIRException("Unable to find/resolve/read " + (explore ? "-ig " : "") + src); } private String fetchVersionByPackage(String src) throws FHIRException, IOException { String id = src; String version = null; if (src.contains("#")) { id = src.substring(0, src.indexOf("#")); version = src.substring(src.indexOf("#") + 1); } if (version == null) { version = getPackageCacheManager().getLatestVersion(id); } NpmPackage pi = null; if (version == null) { pi = getPackageCacheManager().loadPackageFromCacheOnly(id); if (pi != null) System.out.println(" ... Using version " + pi.version()); } else pi = getPackageCacheManager().loadPackage(id, version); if (pi == null) { throw new FHIRException("Unable to resolve package "+src); } else { return pi.fhirVersion(); } } private Map fetchFromUrl(String src, boolean explore) throws FHIRException, IOException { if (src.endsWith(".tgz")) return loadPackage(fetchFromUrlSpecific(src, false), src, false); if (src.endsWith(".pack")) return readZip(fetchFromUrlSpecific(src, false)); if (src.endsWith("igpack.zip")) return readZip(fetchFromUrlSpecific(src, false)); InputStream stream = null; if (explore) { stream = fetchFromUrlSpecific(Utilities.pathURL(src, "package.tgz"), true); if (stream != null) { try { return loadPackage(stream, Utilities.pathURL(src, "package.tgz"), false); } catch (Exception e) { // nothing } } } // ok, having tried all that... now we'll just try to access it directly byte[] cnt; List errors = new ArrayList<>(); cnt = fetchFromUrlSpecific(src, "application/json", true, errors); if (cnt == null) { cnt = fetchFromUrlSpecific(src, "application/xml", true, errors); } if (cnt == null) { throw new FHIRException("Unable to fetch content from " + src + " (" + errors.toString() + ")"); } Manager.FhirFormat fmt = checkFormat(cnt, src); if (fmt != null) { Map res = new HashMap<>(); res.put(Utilities.changeFileExt(src, "." + fmt.getExtension()), ByteProvider.forBytes(cnt)); return res; } throw new FHIRException("Unable to read content from " + src + ": cannot determine format"); } private boolean isIgnoreFile(File ff) { if (ff.getName().startsWith(".") || ff.getAbsolutePath().contains(".git")) { return true; } return Utilities.existsInList(Utilities.getFileExtension(ff.getName()).toLowerCase(), IGNORED_EXTENSIONS); } private Map scanDirectory(File f, boolean recursive) throws IOException { Map res = new HashMap<>(); for (File ff : f.listFiles()) { if (ff.isDirectory() && recursive) { res.putAll(scanDirectory(ff, true)); } else if (!ff.isDirectory() && !isIgnoreFile(ff)) { Manager.FhirFormat fmt = ResourceChecker.checkIsResource(getContext(), isDebug(), TextFile.fileToBytes(ff), ff.getAbsolutePath(), true); if (fmt != null) { res.put(Utilities.changeFileExt(ff.getName(), "." + fmt.getExtension()), ByteProvider.forFile(ff)); } } } return res; } private String resolvePackageForVersion(String id, String v) throws FHIRException, IOException { NpmPackage pi = getPackageCacheManager().loadPackage(id, v); return pi.fhirVersion(); } private String presentForDebugging(byte[] cnt) { StringBuilder b = new StringBuilder(); for (int i = 0; i < Integer.min(cnt.length, 50); i++) { b.append(Integer.toHexString(cnt[i])); } return b.toString(); } private Manager.FhirFormat checkFormat(byte[] cnt, String filename) throws IOException { String text = TextFile.bytesToString(cnt); System.out.println(" ..Detect format for " + filename); try { org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(cnt); return Manager.FhirFormat.JSON; } catch (Exception e) { log("Not JSON: " + e.getMessage()); } try { ValidatorUtils.parseXml(cnt); return Manager.FhirFormat.XML; } catch (Exception e) { log("Not XML: " + e.getMessage()); } try { new Turtle().parse(TextFile.bytesToString(cnt)); return Manager.FhirFormat.TURTLE; } catch (Exception e) { log("Not Turtle: " + e.getMessage()); } try { new StructureMapUtilities(getContext(), null, null).parse(TextFile.bytesToString(cnt), null); return Manager.FhirFormat.TEXT; } catch (Exception e) { log("Not Text: " + e.getMessage()); } log(" .. not a resource: " + filename); return null; } private boolean exemptFile(String fn) { return Utilities.existsInList(fn, EXEMPT_FILES); } protected Resource loadFileWithErrorChecking(String version, Map.Entry t, String fn) { log("* load file: " + fn); Resource r = null; try { r = loadResourceByVersion(version, t.getValue().getBytes(), fn); log(" .. success"); } catch (Exception e) { if (!isDebug()) { System.out.print("* load file: " + fn); } System.out.println(" - ignored due to error: " + (e.getMessage() == null ? " (null - NPE)" : e.getMessage())); if (isDebug() || ((e.getMessage() != null && e.getMessage().contains("cannot be cast")))) { e.printStackTrace(); } e.printStackTrace(); } return r; } public Resource loadResourceByVersion(String fhirVersion, byte[] content, String fn) throws IOException, FHIRException { Resource r; if (fhirVersion.startsWith("3.0")) { org.hl7.fhir.dstu3.model.Resource res; if (fn.endsWith(".xml") && !fn.endsWith("template.xml")) res = new org.hl7.fhir.dstu3.formats.XmlParser().parse(new ByteArrayInputStream(content)); else if (fn.endsWith(".json") && !fn.endsWith("template.json")) res = new org.hl7.fhir.dstu3.formats.JsonParser().parse(new ByteArrayInputStream(content)); else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml")) res = new org.hl7.fhir.dstu3.utils.StructureMapUtilities(org.hl7.fhir.dstu3.context.SimpleWorkerContext.fromNothing()).parse(new String(content)); else throw new FHIRException("Unsupported format for " + fn); r = VersionConvertorFactory_30_50.convertResource(res); } else if (fhirVersion.startsWith("4.0")) { org.hl7.fhir.r4.model.Resource res; if (fn.endsWith(".xml") && !fn.endsWith("template.xml")) res = new org.hl7.fhir.r4.formats.XmlParser().parse(new ByteArrayInputStream(content)); else if (fn.endsWith(".json") && !fn.endsWith("template.json")) res = new org.hl7.fhir.r4.formats.JsonParser().parse(new ByteArrayInputStream(content)); else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml")) res = new org.hl7.fhir.r4.utils.StructureMapUtilities(org.hl7.fhir.r4.context.SimpleWorkerContext.fromNothing()).parse(new String(content), fn); else throw new FHIRException("Unsupported format for " + fn); r = VersionConvertorFactory_40_50.convertResource(res); } else if (fhirVersion.startsWith("4.3")) { org.hl7.fhir.r4b.model.Resource res; if (fn.endsWith(".xml") && !fn.endsWith("template.xml")) res = new org.hl7.fhir.r4b.formats.XmlParser().parse(new ByteArrayInputStream(content)); else if (fn.endsWith(".json") && !fn.endsWith("template.json")) res = new org.hl7.fhir.r4b.formats.JsonParser().parse(new ByteArrayInputStream(content)); else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml")) res = new org.hl7.fhir.r4b.utils.structuremap.StructureMapUtilities(org.hl7.fhir.r4b.context.SimpleWorkerContext.fromNothing()).parse(new String(content), fn); else throw new FHIRException("Unsupported format for " + fn); r = VersionConvertorFactory_43_50.convertResource(res); } else if (fhirVersion.startsWith("1.4")) { org.hl7.fhir.dstu2016may.model.Resource res; if (fn.endsWith(".xml") && !fn.endsWith("template.xml")) res = new org.hl7.fhir.dstu2016may.formats.XmlParser().parse(new ByteArrayInputStream(content)); else if (fn.endsWith(".json") && !fn.endsWith("template.json")) res = new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(new ByteArrayInputStream(content)); else throw new FHIRException("Unsupported format for " + fn); r = VersionConvertorFactory_14_50.convertResource(res); } else if (fhirVersion.startsWith("1.0")) { org.hl7.fhir.dstu2.model.Resource res; if (fn.endsWith(".xml") && !fn.endsWith("template.xml")) res = new org.hl7.fhir.dstu2.formats.JsonParser().parse(new ByteArrayInputStream(content)); else if (fn.endsWith(".json") && !fn.endsWith("template.json")) res = new org.hl7.fhir.dstu2.formats.JsonParser().parse(new ByteArrayInputStream(content)); else throw new FHIRException("Unsupported format for " + fn); r = VersionConvertorFactory_10_50.convertResource(res, new org.hl7.fhir.convertors.misc.IGR2ConvertorAdvisor5()); } else if (fhirVersion.startsWith("5.0")) { if (fn.endsWith(".xml") && !fn.endsWith("template.xml")) r = new XmlParser().parse(new ByteArrayInputStream(content)); else if (fn.endsWith(".json") && !fn.endsWith("template.json")) r = new JsonParser().parse(new ByteArrayInputStream(content)); else if (fn.endsWith(".txt")) r = new StructureMapUtilities(getContext(), null, null).parse(TextFile.bytesToString(content), fn); else if (fn.endsWith(".map") || fn.endsWith(".fml")) r = new StructureMapUtilities(context).parse(new String(content), fn); else throw new FHIRException("Unsupported format for " + fn); } else throw new FHIRException("Unsupported version " + fhirVersion); return r; } private void log(String s) { if (isDebug()) { System.out.println(s); } } @Override public void load(Content cnt) throws FHIRException, IOException { Resource res = loadResourceByVersion(version, cnt.getFocus().getBytes(), cnt.getExampleFileName()); context.cacheResource(res); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy