All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.gov.gchq.gaffer.commonutil.StreamUtil Maven / Gradle / Ivy

There is a newer version: 2.3.1
Show newest version
/*
 * Copyright 2016-2019 Crown Copyright
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package uk.gov.gchq.gaffer.commonutil;

import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;
import org.reflections.scanners.ResourcesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.HashSet;
import java.util.regex.Pattern;

/**
 * Utility methods for opening {@link InputStream}s.
 */
public final class StreamUtil {
    public static final String VIEW = "/view.json";
    public static final String SCHEMA_FOLDER = "/schema/";
    public static final String SCHEMA = SCHEMA_FOLDER + "schema.json";
    public static final String ELEMENTS_SCHEMA = SCHEMA_FOLDER + "elements.json";
    public static final String TYPES_SCHEMA = SCHEMA_FOLDER + "types.json";
    public static final String STORE_PROPERTIES = "/store.properties";
    public static final String GRAPH_CONFIG = "/graphConfig.json";
    public static final String FAILED_TO_CREATE_INPUT_STREAM_FOR_PATH = "Failed to create input stream for path: ";
    public static final String LOG_FAILED_TO_CREATE_INPUT_STREAM_FOR_PATH = FAILED_TO_CREATE_INPUT_STREAM_FOR_PATH + "{}";
    private static final Logger LOGGER = LoggerFactory.getLogger(StreamUtil.class);

    private StreamUtil() {
        // Private constructor to prevent instantiation.
    }

    /**
     * Open the graph config file located at the same location as the provided
     * class.
     *
     * @param clazz the class determining the location of the graph config file
     * @return an {@link InputStream} representing the graph config file
     */
    public static InputStream graphConfig(final Class clazz) {
        return openStream(clazz, GRAPH_CONFIG);
    }

    /**
     * Open the view file located at the same location as the provided class.
     *
     * @param clazz the class determining the location of the view file
     * @return an {@link InputStream} representing the view file
     */
    public static InputStream view(final Class clazz) {
        return openStream(clazz, VIEW);
    }

    /**
     * Open the schema files located at the same location as the provided
     * class.
     *
     * @param clazz the class determining the location of the schema files
     * @return an array of {@link InputStream}s representing the schema files
     */
    public static InputStream[] schemas(final Class clazz) {
        return openStreams(clazz, SCHEMA_FOLDER);
    }

    /**
     * Open the schema file located at the same location as the provided
     * class.
     *
     * @param clazz the class determining the location of the schema file
     * @return an {@link InputStream} representing the schema file
     */
    public static InputStream schema(final Class clazz) {
        return openStream(clazz, SCHEMA);
    }

    /**
     * Open the elements schema file located at the same location as the provided
     * class.
     *
     * @param clazz the class determining the location of the elements schema file
     * @return an {@link InputStream} representing the elements schema file
     */
    public static InputStream elementsSchema(final Class clazz) {
        return openStream(clazz, ELEMENTS_SCHEMA);
    }

    /**
     * Open the types schema file located at the same location as the provided
     * class.
     *
     * @param clazz the class determining the location of the types schema file
     * @return an {@link InputStream} representing the types schema file
     */
    public static InputStream typesSchema(final Class clazz) {
        return openStream(clazz, TYPES_SCHEMA);
    }

    /**
     * Open the store properties file located at the same location as the provided
     * class.
     *
     * @param clazz the class determining the location of the store properties file
     * @return an {@link InputStream} representing the store properties file
     */
    public static InputStream storeProps(final Class clazz) {
        return openStream(clazz, STORE_PROPERTIES);
    }

    /**
     * Open all of the files found in the specified subdirectory of the provided
     * class.
     *
     * @param clazz      the class location
     * @param folderPath the subdirectory in the class location
     * @return an array of {@link InputStream}s representing the files found
     */
    public static InputStream[] openStreams(final Class clazz, final String folderPath) {
        if (null == folderPath) {
            return new InputStream[0];
        }

        String folderPathChecked = getFormattedPath(folderPath);

        final HashSet inputStreams = Sets.newHashSet();

        new Reflections(new ConfigurationBuilder()
                .setScanners(new ResourcesScanner())
                .setUrls(ClasspathHelper.forClass(clazz)))
                .getResources(Pattern.compile(".*"))
                .stream()
                .filter(file -> file.startsWith(folderPathChecked))
                .forEach(file -> {
                            try {
                                inputStreams.add(openStream(clazz, file));
                            } catch (final Exception e) {
                                int closedStreamsCount = closeStreams(inputStreams.toArray(new InputStream[inputStreams.size()]));
                                LOGGER.info(String.format("Closed %s input streams", closedStreamsCount));
                            }
                        }
                );

        if (inputStreams.isEmpty()) {
            throw new IllegalArgumentException("No file could be found in path: " + folderPath);
        }

        return inputStreams.toArray(new InputStream[inputStreams.size()]);
    }

    private static String getFormattedPath(final String folderPath) {
        String folderPathChecked = folderPath.endsWith("/") ? folderPath : folderPath + "/";
        if (folderPathChecked.startsWith("/")) {
            folderPathChecked = folderPathChecked.substring(1);
        }
        return folderPathChecked;
    }

    /**
     * Create an array of {@link InputStream}s from the provided list of {@link URI}s.
     *
     * @param uris the URIs to open as input streams
     * @return an array of input streams
     * @throws IOException if there was an error opening the streams
     */
    public static InputStream[] openStreams(final URI... uris) throws IOException {
        final InputStream[] schemas = new InputStream[uris.length];
        for (int pos = 0; pos < uris.length; pos++) {
            try {
                schemas[pos] = openStream(uris[pos]);
            } catch (final Exception e) {
                int closedStreamsCount = closeStreams(schemas);
                LOGGER.info("Closed {} input streams", closedStreamsCount);
                throw e;
            }
        }
        return schemas;
    }

    /**
     * Create an {@link InputStream}s from the provided {@link URI}.
     *
     * @param uri the URI to open as an input stream
     * @return an input streams
     * @throws IOException if there was an error opening the stream
     */
    public static InputStream openStream(final URI uri) throws IOException {
        try {
            return uri.toURL().openStream();
        } catch (final IOException e) {
            LOGGER.error("Failed to create input stream: {}", uri, e);
            throw e;
        }
    }

    /**
     * Safely close the supplied list of {@link InputStream}s.
     *
     * @param inputStreams the input streams to close
     * @return an integer indicating the number of streams which were successfully closed.
     */
    public static int closeStreams(final InputStream... inputStreams) {
        int closedStreamsCount = 0;
        for (final InputStream stream : inputStreams) {
            try {
                stream.close();
            } catch (final Exception e) {
                LOGGER.debug("Exception while closing input streams", e);
            }
            closedStreamsCount++;
        }
        return closedStreamsCount;
    }

    /**
     * Open the file found at the the specified path under the location of the given
     * class.
     *
     * @param clazz the class location
     * @param path  the path in the class location
     * @return an input stream representating the requested file
     * @throws IllegalArgumentException if there was an error opening the stream
     */
    public static InputStream openStream(final Class clazz, final String path) throws IllegalArgumentException {
        final String checkedPath = formatPathForOpenStream(path);
        final InputStream resourceAsStream = clazz.getResourceAsStream(checkedPath);
        return (null != resourceAsStream) ? resourceAsStream : processException(path);
    }

    private static InputStream processException(final String path) throws IllegalArgumentException {
        LOGGER.error(LOG_FAILED_TO_CREATE_INPUT_STREAM_FOR_PATH, path);
        throw new IllegalArgumentException(FAILED_TO_CREATE_INPUT_STREAM_FOR_PATH + path);
    }

    /**
     * Format a path to ensure that it begins with a '/' character.
     *
     * @param path the path to format
     * @return a correctly formatted path string
     */
    public static String formatPathForOpenStream(final String path) {
        if (StringUtils.isEmpty(path)) {
            processException(path);
        }
        return path.startsWith("/") ? path : "/" + path;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy