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

be.atbash.util.resource.ResourceUtil Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014-2022 Rudy De Busscher (https://www.atbash.be)
 *
 * 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 be.atbash.util.resource;

import be.atbash.util.PublicAPI;
import be.atbash.util.StringUtils;
import be.atbash.util.ordered.OrderComparator;
import be.atbash.util.resource.internal.ClassPathResourceReader;
import be.atbash.util.resource.internal.FileResourceReader;
import be.atbash.util.resource.internal.URLResourceReader;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.*;

@PublicAPI
public class ResourceUtil {

    /**
     * Resource path prefix that specifies to load from a file location, value is {@code file:}
     */
    public static final String FILE_PREFIX = "file:";

    /**
     * Resource path prefix that specifies to load from a url location, value is {@code url:}
     */
    public static final String URL_PREFIX = "url:";

    /**
     * Resource path prefix that specifies to load from a classpath location, value is {@code classpath:}
     */
    public static final String CLASSPATH_PREFIX = "classpath:";


    private static ResourceUtil INSTANCE;

    private final List readers;

    private ResourceUtil() {
        readers = new ArrayList<>();
        readers.add(new ClassPathResourceReader());
        readers.add(new URLResourceReader());
        readers.add(new FileResourceReader());
        // current Thread
        for (ResourceReader resourceReader : ServiceLoader.load(ResourceReader.class)) {
            readers.add(resourceReader);
        }
        // Classloader for deployment
        for (ResourceReader resourceReader : ServiceLoader.load(ResourceReader.class, ResourceUtil.class.getClassLoader())) {
            if (!isReaderFound(resourceReader)) {
                readers.add(resourceReader);
            }
        }
        readers.sort(new OrderComparator());
    }

    private boolean isReaderFound(ResourceReader resourceReader) {
        boolean result = false;
        for (ResourceReader reader : readers) {
            // We need to check the class here, but since we are using FQCN Sonar check can be disabled here.
            if (reader.getClass().getName().equals(resourceReader.getClass().getName())) { // NOSONAR
                result = true;
            }
        }
        return result;
    }

    /**
     * Returns {@code true} if the resource can be read by an implementation (based on the prefix in most cases)
     *
     * @param resourcePath Location of the resource to be tested.
     * @return true when resource can be read, false otherwise.
     */
    public boolean isSupported(String resourcePath) {
        return isSupported(resourcePath, null);
    }

    /**
     * Returns {@code true} if the resource can be read by an implementation (based on the prefix in most cases)
     *
     * @param resourcePath Location of the resource to be tested.
     * @param context      Optional value defining the context (like servletContext) from which resource must be read
     * @return true when resource can be read, false otherwise.
     */
    public boolean isSupported(String resourcePath, Object context) {
        if (StringUtils.isEmpty(resourcePath)) {
            // When null or empty, we can't read it!
            return false;
        }
        boolean result = false;
        Iterator iterator = getInstance().readers.iterator();
        while (!result && iterator.hasNext()) {
            result = iterator.next().canRead(resourcePath, context);
        }
        return result;
    }

    /**
     * Returns {@code true} if the resource at the specified path exists, {@code false} otherwise.  This
     * method supports scheme prefixes on the path.
     *
     * @param resourcePath the path of the resource to check.
     * @return {@code true} if the resource at the specified path exists, {@code false} otherwise.
     */
    public boolean resourceExists(String resourcePath) {
        return resourceExists(resourcePath, null);
    }

    /**
     * Returns {@code true} if the resource at the specified path exists, {@code false} otherwise.  This
     * method supports scheme prefixes on the path.
     *
     * @param resourcePath the path of the resource to check.
     * @param context      Optional value defining the context (like servletContext) from which resource must be read
     * @return {@code true} if the resource at the specified path exists, {@code false} otherwise.
     */
    public boolean resourceExists(String resourcePath, Object context) {
        boolean result = false;
        Iterator iterator = getInstance().readers.iterator();
        while (!result && iterator.hasNext()) {
            result = iterator.next().exists(resourcePath, context);
        }
        return result;

    }

    /**
     * Returns the InputStream for the resource represented by the specified path, supporting scheme
     * prefixes that direct how to acquire the input stream
     * ({@link #CLASSPATH_PREFIX CLASSPATH_PREFIX},
     * {@link #URL_PREFIX URL_PREFIX}, or {@link #FILE_PREFIX FILE_PREFIX}).  If the path is not prefixed by one
     * of these schemes, the path is assumed to be a file-based path that can be loaded with a
     * {@link FileInputStream FileInputStream}.
     *
     * @param path the String path representing the resource to obtain.
     * @return the InputStream for the specified resource.
     * @throws IOException if there is a problem acquiring the resource at the specified path.
     */
    public InputStream getStream(String path) throws IOException {
        return getStream(path, null);
    }

    /**
     * Returns the InputStream for the resource represented by the specified path, supporting scheme
     * prefixes that direct how to acquire the input stream
     * ({@link #CLASSPATH_PREFIX CLASSPATH_PREFIX},
     * {@link #URL_PREFIX URL_PREFIX}, or {@link #FILE_PREFIX FILE_PREFIX}).  If the path is not prefixed by one
     * of these schemes, the path is assumed to be a file-based path that can be loaded with a
     * {@link FileInputStream FileInputStream}.
     *
     * @param path    the String path representing the resource to obtain.
     * @param context Optional value defining the context (like servletContext) from which resource must be read
     * @return the InputStream for the specified resource.
     * @throws IOException if there is a problem acquiring the resource at the specified path.
     */
    public InputStream getStream(String path, Object context) throws IOException {

        InputStream result = null;
        if (StringUtils.hasText(path)) {
            Iterator iterator = getInstance().readers.iterator();
            while (result == null && iterator.hasNext()) {
                ResourceReader reader = iterator.next();
                if (reader.canRead(path, context)) {
                    result = reader.load(path, context);
                }
            }

        }
        return result;

    }

    /**
     * Returns the content of the resource represented by the specified path. Underlying, it uses
     * {@code getStream} to access the resource.
     *
     * @param path the String path representing the resource to obtain.
     * @return the content of the resource or null when resource could not be handled (unknown type)
     * @throws IOException if there is a problem acquiring the resource at the specified path.
     */
    public String getContent(String path) throws IOException {
        return getContent(path, null);
    }

    /**
     * Returns the content of the resource represented by the specified path. Underlying, it uses
     * {@code getStream} to access the resource.
     *
     * @param path    the String path representing the resource to obtain.
     * @param context Optional value defining the context (like servletContext) from which resource must be read
     * @return the content of the resource or null when resource could not be handled (unknown type)
     * @throws IOException if there is a problem acquiring the resource at the specified path.
     */
    public String getContent(String path, Object context) throws IOException {
        InputStream stream = getStream(path, context);
        if (stream == null) {
            return null;
        }
        Scanner s = new Scanner(stream).useDelimiter("\\A");
        String result = s.hasNext() ? s.next() : "";
        stream.close();
        return result;
    }


    public List getResources(String resourcePath) {
        List result = new ArrayList<>();
        readers.forEach(rr -> result.addAll(rr.getResources(resourcePath)));
        return result;
    }

    public static synchronized ResourceUtil getInstance() {
        // Synchronize methods are not so bad for performance anymore and since only 1 synchronized static there are no side effects
        if (INSTANCE == null) {
            INSTANCE = new ResourceUtil();
        }
        return INSTANCE;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy