001package org.hl7.fhir.common.hapi.validation.support; 002 003import ca.uhn.fhir.context.FhirContext; 004import ca.uhn.fhir.parser.IParser; 005import ca.uhn.fhir.parser.LenientErrorHandler; 006import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 007import ca.uhn.fhir.util.ClasspathUtil; 008import jakarta.annotation.Nonnull; 009import org.hl7.fhir.instance.model.api.IBaseResource; 010import org.hl7.fhir.utilities.TextFile; 011import org.hl7.fhir.utilities.npm.NpmPackage; 012 013import java.io.IOException; 014import java.io.InputStream; 015import java.nio.charset.StandardCharsets; 016import java.util.List; 017import java.util.Locale; 018 019/** 020 * This interceptor loads and parses FHIR NPM Conformance Packages, and makes the 021 * artifacts found within them available to the FHIR validator. 022 * 023 * @since 5.5.0 024 */ 025public class NpmPackageValidationSupport extends PrePopulatedValidationSupport { 026 027 /** 028 * Constructor 029 */ 030 public NpmPackageValidationSupport(@Nonnull FhirContext theFhirContext) { 031 super(theFhirContext); 032 } 033 034 /** 035 * Load an NPM package using a classpath specification, e.g. <code>/path/to/resource/my_package.tgz</code>. The 036 * classpath spec can optionally be prefixed with the string <code>classpath:</code> 037 * 038 * @throws InternalErrorException If the classpath file can't be found 039 */ 040 public void loadPackageFromClasspath(String theClasspath) throws IOException { 041 try (InputStream is = ClasspathUtil.loadResourceAsStream(theClasspath)) { 042 NpmPackage pkg = NpmPackage.fromPackage(is); 043 if (pkg.getFolders().containsKey("package")) { 044 loadResourcesFromPackage(pkg); 045 loadBinariesFromPackage(pkg); 046 } 047 } 048 } 049 050 private void loadResourcesFromPackage(NpmPackage thePackage) { 051 NpmPackage.NpmPackageFolder packageFolder = thePackage.getFolders().get("package"); 052 053 for (String nextFile : packageFolder.listFiles()) { 054 if (nextFile.toLowerCase(Locale.US).endsWith(".json")) { 055 String input = new String(packageFolder.getContent().get(nextFile), StandardCharsets.UTF_8); 056 IParser parser = getFhirContext().newJsonParser(); 057 parser.setParserErrorHandler(new LenientErrorHandler(false)); 058 IBaseResource resource = parser.parseResource(input); 059 super.addResource(resource); 060 } 061 } 062 } 063 064 private void loadBinariesFromPackage(NpmPackage thePackage) throws IOException { 065 List<String> binaries = thePackage.list("other"); 066 for (String binaryName : binaries) { 067 addBinary(TextFile.streamToBytes(thePackage.load("other", binaryName)), binaryName); 068 } 069 } 070}