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