001/*-
002 * #%L
003 * HAPI FHIR JPA Server
004 * %%
005 * Copyright (C) 2014 - 2025 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.jpa.packages;
021
022import ca.uhn.fhir.context.FhirContext;
023import ca.uhn.fhir.parser.IParser;
024import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
025import ca.uhn.fhir.util.BundleBuilder;
026import jakarta.annotation.Nonnull;
027import org.hl7.fhir.instance.model.api.IBaseBundle;
028import org.hl7.fhir.instance.model.api.IBaseResource;
029import org.hl7.fhir.utilities.npm.NpmPackage;
030
031import java.io.ByteArrayInputStream;
032import java.io.IOException;
033import java.util.Collection;
034import java.util.LinkedList;
035import java.util.List;
036import java.util.Objects;
037import java.util.Set;
038import java.util.stream.Collectors;
039
040public class AdditionalResourcesParser {
041
042        public static IBaseBundle bundleAdditionalResources(
043                        Set<String> additionalResources, PackageInstallationSpec packageInstallationSpec, FhirContext fhirContext) {
044                NpmPackage npmPackage;
045                try {
046                        npmPackage = NpmPackage.fromPackage(new ByteArrayInputStream(packageInstallationSpec.getPackageContents()));
047                } catch (IOException e) {
048                        throw new InternalErrorException(e);
049                }
050                List<IBaseResource> resources = getAdditionalResources(additionalResources, npmPackage, fhirContext);
051
052                BundleBuilder bundleBuilder = new BundleBuilder(fhirContext);
053                resources.forEach(bundleBuilder::addTransactionUpdateEntry);
054                return bundleBuilder.getBundle();
055        }
056
057        @Nonnull
058        public static List<IBaseResource> getAdditionalResources(
059                        Set<String> folderNames, NpmPackage npmPackage, FhirContext fhirContext) {
060
061                List<NpmPackage.NpmPackageFolder> npmFolders = folderNames.stream()
062                                .map(name -> npmPackage.getFolders().get(name))
063                                .filter(Objects::nonNull)
064                                .collect(Collectors.toList());
065
066                List<IBaseResource> resources = new LinkedList<>();
067                IParser parser = fhirContext.newJsonParser().setSuppressNarratives(true);
068
069                for (NpmPackage.NpmPackageFolder folder : npmFolders) {
070                        List<String> fileNames;
071                        try {
072                                fileNames = folder.getTypes().values().stream()
073                                                .flatMap(Collection::stream)
074                                                .collect(Collectors.toList());
075                        } catch (IOException e) {
076                                throw new InternalErrorException(e.getMessage(), e);
077                        }
078
079                        resources.addAll(fileNames.stream()
080                                        .map(fileName -> {
081                                                try {
082                                                        return new String(folder.fetchFile(fileName));
083                                                } catch (IOException e) {
084                                                        throw new InternalErrorException(e.getMessage(), e);
085                                                }
086                                        })
087                                        .map(parser::parseResource)
088                                        .collect(Collectors.toList()));
089                }
090                return resources;
091        }
092}