001package ca.uhn.fhir.util;
002
003/*-
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.context.FhirContext;
024import ca.uhn.fhir.rest.api.EncodingEnum;
025import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
026import com.google.common.base.Charsets;
027import org.apache.commons.io.IOUtils;
028import org.apache.commons.io.input.BOMInputStream;
029import org.hl7.fhir.instance.model.api.IBaseResource;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033import javax.annotation.Nonnull;
034import java.io.IOException;
035import java.io.InputStream;
036import java.util.function.Function;
037import java.util.zip.GZIPInputStream;
038
039/**
040 * Use this API with caution, it may change!
041 */
042public class ClasspathUtil {
043
044        private static final Logger ourLog = LoggerFactory.getLogger(ClasspathUtil.class);
045
046        /**
047         * Non instantiable
048         */
049        private ClasspathUtil() {
050                // nothing
051        }
052
053        public static String loadResource(String theClasspath) {
054                return loadResource(theClasspath, Function.identity());
055        }
056
057        /**
058         * Load a classpath resource, throw an {@link InternalErrorException} if not found
059         *
060         * @throws InternalErrorException If the resource can't be found
061         */
062        @Nonnull
063        public static InputStream loadResourceAsStream(String theClasspath) {
064                String classpath = theClasspath;
065                if (classpath.startsWith("classpath:")) {
066                        classpath = classpath.substring("classpath:".length());
067                }
068
069                InputStream retVal = ClasspathUtil.class.getResourceAsStream(classpath);
070                if (retVal == null) {
071                        if (classpath.startsWith("/")) {
072                                retVal = ClasspathUtil.class.getResourceAsStream(classpath.substring(1));
073                        } else {
074                                retVal = ClasspathUtil.class.getResourceAsStream("/" + classpath);
075                        }
076                        if (retVal == null) {
077                                throw new InternalErrorException("Unable to find classpath resource: " + classpath);
078                        }
079                }
080                return retVal;
081        }
082
083        /**
084         * Load a classpath resource, throw an {@link InternalErrorException} if not found
085         */
086        @Nonnull
087        public static String loadResource(String theClasspath, Function<InputStream, InputStream> theStreamTransform) {
088                try (InputStream stream = loadResourceAsStream(theClasspath)) {
089                        InputStream newStream = theStreamTransform.apply(stream);
090                        return IOUtils.toString(newStream, Charsets.UTF_8);
091                } catch (IOException e) {
092                        throw new InternalErrorException(e);
093                }
094        }
095
096        @Nonnull
097        public static String loadCompressedResource(String theClasspath) {
098                Function<InputStream, InputStream> streamTransform = t -> {
099                        try {
100                                return new GZIPInputStream(t);
101                        } catch (IOException e) {
102                                throw new InternalErrorException(e);
103                        }
104                };
105                return loadResource(theClasspath, streamTransform);
106        }
107
108        @Nonnull
109        public static <T extends IBaseResource> T loadResource(FhirContext theCtx, Class<T> theType, String theClasspath) {
110                String raw = loadResource(theClasspath);
111                return EncodingEnum.detectEncodingNoDefault(raw).newParser(theCtx).parseResource(theType, raw);
112        }
113
114        public static void close(InputStream theInput) {
115                try {
116                        if (theInput != null) {
117                                theInput.close();
118                        }
119                } catch (IOException e) {
120                        ourLog.debug("Closing InputStream threw exception", e);
121                }
122        }
123
124        public static Function<InputStream, InputStream> withBom() {
125                return t -> new BOMInputStream(t);
126        }
127
128        public static byte[] loadResourceAsByteArray(String theClasspath) {
129                InputStream stream = loadResourceAsStream(theClasspath);
130                try {
131                        return IOUtils.toByteArray(stream);
132                } catch (IOException e) {
133                        throw new InternalErrorException(e);
134                } finally {
135                        close(stream);
136                }
137        }
138}