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.i18n.Msg;
025import ca.uhn.fhir.rest.api.EncodingEnum;
026import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
027import com.google.common.base.Charsets;
028import org.apache.commons.io.IOUtils;
029import org.apache.commons.io.input.BOMInputStream;
030import org.hl7.fhir.instance.model.api.IBaseResource;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034import javax.annotation.Nonnull;
035import java.io.IOException;
036import java.io.InputStream;
037import java.util.function.Function;
038import java.util.zip.GZIPInputStream;
039
040/**
041 * Use this API with caution, it may change!
042 */
043public class ClasspathUtil {
044
045        private static final Logger ourLog = LoggerFactory.getLogger(ClasspathUtil.class);
046
047        /**
048         * Non instantiable
049         */
050        private ClasspathUtil() {
051                // nothing
052        }
053
054        /**
055         * Load a classpath resource, throw an {@link InternalErrorException} if not found
056         *
057         * @throws InternalErrorException If the resource can't be found
058         */
059        public static String loadResource(String theClasspath) throws InternalErrorException {
060                return loadResource(theClasspath, Function.identity());
061        }
062
063        /**
064         * Load a classpath resource, throw an {@link InternalErrorException} if not found
065         *
066         * @throws InternalErrorException If the resource can't be found
067         */
068        @Nonnull
069        public static InputStream loadResourceAsStream(String theClasspath) throws InternalErrorException {
070                String classpath = theClasspath;
071                if (classpath.startsWith("classpath:")) {
072                        classpath = classpath.substring("classpath:".length());
073                }
074
075                InputStream retVal = ClasspathUtil.class.getResourceAsStream(classpath);
076                if (retVal == null) {
077                        if (classpath.startsWith("/")) {
078                                retVal = ClasspathUtil.class.getResourceAsStream(classpath.substring(1));
079                        } else {
080                                retVal = ClasspathUtil.class.getResourceAsStream("/" + classpath);
081                        }
082                        if (retVal == null) {
083                                throw new InternalErrorException(Msg.code(1758) + "Unable to find classpath resource: " + classpath);
084                        }
085                }
086                return retVal;
087        }
088
089        /**
090         * Load a classpath resource, throw an {@link InternalErrorException} if not found
091         */
092        @Nonnull
093        public static String loadResource(String theClasspath, Function<InputStream, InputStream> theStreamTransform) {
094                try (InputStream stream = loadResourceAsStream(theClasspath)) {
095                        InputStream newStream = theStreamTransform.apply(stream);
096                        return IOUtils.toString(newStream, Charsets.UTF_8);
097                } catch (IOException e) {
098                        throw new InternalErrorException(Msg.code(1759) + e);
099                }
100        }
101
102        @Nonnull
103        public static String loadCompressedResource(String theClasspath) {
104                Function<InputStream, InputStream> streamTransform = t -> {
105                        try {
106                                return new GZIPInputStream(t);
107                        } catch (IOException e) {
108                                throw new InternalErrorException(Msg.code(1760) + e);
109                        }
110                };
111                return loadResource(theClasspath, streamTransform);
112        }
113
114        @Nonnull
115        public static <T extends IBaseResource> T loadResource(FhirContext theCtx, Class<T> theType, String theClasspath) {
116                String raw = loadResource(theClasspath);
117                return EncodingEnum.detectEncodingNoDefault(raw).newParser(theCtx).parseResource(theType, raw);
118        }
119
120        public static void close(InputStream theInput) {
121                try {
122                        if (theInput != null) {
123                                theInput.close();
124                        }
125                } catch (IOException e) {
126                        ourLog.debug("Closing InputStream threw exception", e);
127                }
128        }
129
130        public static Function<InputStream, InputStream> withBom() {
131                return t -> new BOMInputStream(t);
132        }
133
134        public static byte[] loadResourceAsByteArray(String theClasspath) {
135                InputStream stream = loadResourceAsStream(theClasspath);
136                try {
137                        return IOUtils.toByteArray(stream);
138                } catch (IOException e) {
139                        throw new InternalErrorException(Msg.code(1761) + e);
140                } finally {
141                        close(stream);
142                }
143        }
144}