com.opengamma.strata.collect.io.ResourceLocator.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.strata.collect.io.ResourceLocator.java

Source

/**
 * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
 * 
 * Please see distribution for license.
 */
package com.opengamma.strata.collect.io;

import static com.google.common.base.MoreObjects.firstNonNull;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;

import org.joda.convert.FromString;
import org.joda.convert.ToString;

import com.google.common.io.ByteSource;
import com.google.common.io.CharSource;
import com.google.common.io.Files;
import com.google.common.io.Resources;
import com.opengamma.strata.collect.ArgChecker;

/**
 * A locator for a resource, specified as a file, URL, path or classpath resource.
 * <p>
 * An instance of this class provides access to a resource, such as a configuration file.
 * The resource data is accessed using {@link CharSource} or {@link ByteSource}.
 */
public final class ResourceLocator {

    /**
     * The prefix for classpath resource locators.
     */
    public static final String CLASSPATH_URL_PREFIX = "classpath:";
    /**
     * The prefix for file resource locators.
     */
    public static final String FILE_URL_PREFIX = "file:";
    /**
     * The prefix for URL resource locators.
     */
    public static final String URL_PREFIX = "url:";

    /**
     * The resource locator.
     */
    private final String locator;
    /**
     * The source.
     */
    private final ByteSource source;

    //-------------------------------------------------------------------------
    /**
     * Creates a resource from a string locator.
     * <p>
     * This accepts locators starting with 'classpath:', 'url:' or 'file:'.
     * It also accepts unprefixed locators, treated as files.
     * 
     * @param locator  the string form of the resource locator
     * @return the resource locator
     */
    @FromString
    public static ResourceLocator of(String locator) {
        ArgChecker.notNull(locator, "locator");
        try {
            if (locator.startsWith(CLASSPATH_URL_PREFIX)) {
                String urlStr = locator.substring(CLASSPATH_URL_PREFIX.length());
                return ofClasspath(urlStr);

            } else if (locator.startsWith(FILE_URL_PREFIX)) {
                String fileStr = locator.substring(FILE_URL_PREFIX.length());
                return ofFile(new File(fileStr));

            } else if (locator.startsWith(URL_PREFIX)) {
                String pathStr = locator.substring(URL_PREFIX.length());
                return ofUrl(new URL(pathStr));

            } else {
                return ofFile(new File(locator));
            }
        } catch (Exception ex) {
            throw new IllegalArgumentException("Invalid resource locator: " + locator, ex);
        }
    }

    /**
     * Creates a resource from a {@code File}.
     * <p>
     * Windows separators are converted to UNIX style.
     * This takes no account of possible '/' characters in the name.
     * 
     * @param file  the file to wrap
     * @return the resource locator
     */
    public static ResourceLocator ofFile(File file) {
        ArgChecker.notNull(file, "file");
        String filename = file.toString();
        // convert Windows separators to unix
        filename = (File.separatorChar == '\\' ? filename.replace('\\', '/') : filename);
        return new ResourceLocator(FILE_URL_PREFIX + filename, Files.asByteSource(file));
    }

    /**
     * Creates a resource from a {@code Path}.
     * <p>
     * This will return either a file locator or a URL locator.
     *
     * @param path  path to the file to wrap
     * @return the resource locator
     * @throws IllegalArgumentException if the path is neither a file nor a URL
     */
    public static ResourceLocator ofPath(Path path) {
        ArgChecker.notNull(path, "path");
        try {
            return ofFile(path.toFile());
        } catch (UnsupportedOperationException ex) {
            try {
                return ofUrl(path.toUri().toURL());
            } catch (MalformedURLException ex2) {
                throw new IllegalArgumentException("Path could not be converted to a File or URL: " + path);
            }
        }
    }

    /**
     * Creates a resource from a {@code URL}.
     *
     * @param url  path to the file to wrap
     * @return the resource locator
     */
    public static ResourceLocator ofUrl(URL url) {
        ArgChecker.notNull(url, "url");
        String filename = url.toString();
        return new ResourceLocator(URL_PREFIX + filename, Resources.asByteSource(url));
    }

    /**
     * Creates a resource from a fully qualified resource name.
     * 
     * @param resourceName  the classpath resource name
     * @return the resource locator
     */
    public static ResourceLocator ofClasspath(String resourceName) {
        ArgChecker.notNull(resourceName, "classpathLocator");
        URL url = classLoader().getResource(resourceName);
        if (url == null) {
            throw new IllegalArgumentException("Resource not found: " + resourceName);
        }
        return ofClasspathUrl(url);
    }

    /**
     * Creates a resource locator for a classpath resource which is associated with a class.
     * <p>
     * The classpath is searched using the same method as {@code Class.getResource}.
     * <ul>
     *   <li>If the resource name starts with '/' it is treated as an absolute path relative to the classpath root</li>
     *   <li>Otherwise the resource name is treated as a path relative to the package containing the class</li>
     * </ul>
     *
     * @param cls  the class
     * @param resourceName  the resource name
     * @return the resource locator
     */
    public static ResourceLocator ofClasspath(Class<?> cls, String resourceName) {
        ArgChecker.notNull(resourceName, "classpathLocator");
        URL url = cls.getResource(resourceName);
        if (url == null) {
            throw new IllegalArgumentException("Resource not found: " + resourceName);
        }
        return ofClasspathUrl(url);
    }

    /**
     * Creates a resource from a {@code URL}.
     * 
     * @param url  the URL to wrap
     * @return the resource locator
     */
    public static ResourceLocator ofClasspathUrl(URL url) {
        ArgChecker.notNull(url, "url");
        String locator = CLASSPATH_URL_PREFIX + url.toString();
        return new ResourceLocator(locator, Resources.asByteSource(url));
    }

    /**
     * Selects a suitable class loader.
     * 
     * @return the class loader
     */
    static ClassLoader classLoader() {
        return firstNonNull(Thread.currentThread().getContextClassLoader(), ResourceConfig.class.getClassLoader());
    }

    //-------------------------------------------------------------------------
    /**
     * Creates an instance of the locator.
     * 
     * @param locator  the locator
     * @param source  the byte source
     */
    private ResourceLocator(String locator, ByteSource source) {
        super();
        this.locator = locator;
        this.source = source;
    }

    //-------------------------------------------------------------------------
    /**
     * Gets the string form of the locator.
     * <p>
     * The string form of the locator describes the location of the resource.
     * 
     * @return the locator string
     */
    public String getLocator() {
        return locator;
    }

    /**
     * Gets the byte source to access the resource.
     * <p>
     * A byte source is a supplier of data.
     * The source itself is neither opened nor closed.
     * 
     * @return the byte source
     */
    public ByteSource getByteSource() {
        return source;
    }

    /**
     * Gets the char source to access the resource using UTF-8.
     * <p>
     * A char source is a supplier of data.
     * The source itself is neither opened nor closed.
     * 
     * @return the char source
     */
    public CharSource getCharSource() {
        return getCharSource(StandardCharsets.UTF_8);
    }

    /**
     * Gets the char source to access the resource specifying the character set.
     * <p>
     * A char source is a supplier of data.
     * The source itself is neither opened nor closed.
     * 
     * @param charset  the character set to use
     * @return the char source
     */
    public CharSource getCharSource(Charset charset) {
        return source.asCharSource(charset);
    }

    //-------------------------------------------------------------------------
    /**
     * Checks if this locator equals another locator.
     * <p>
     * The comparison checks the locator string.
     * 
     * @param obj  the other locator, null returns false
     * @return true if equal
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (obj instanceof ResourceLocator) {
            return locator.equals(((ResourceLocator) obj).locator);
        }
        return false;
    }

    /**
     * Returns a suitable hash code for the locator.
     * 
     * @return the hash code
     */
    @Override
    public int hashCode() {
        return locator.hashCode();
    }

    /**
     * Returns a string describing the locator.
     * <p>
     * This can be parsed using {@link #of(String)}.
     * 
     * @return the descriptive string
     */
    @ToString
    @Override
    public String toString() {
        return locator;
    }

}