/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.collect.io; import static com.google.common.base.MoreObjects.firstNonNull; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; import java.net.URL; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.stream.Stream; 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.collect.ArgChecker; /** * A locator for a resource, specified as a file 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 Guava {@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 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:' or 'file:'. * It also accepts unprefixed locators, treated as 'file:'. * * @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 ofClasspathUrl(Resources.getResource(urlStr)); } else if (locator.startsWith(FILE_URL_PREFIX)) { String fileStr = locator.substring(FILE_URL_PREFIX.length()); return ofFile(new File(fileStr)); } else { return ofFile(new File(locator)); } } catch (RuntimeException ex) { throw new IllegalArgumentException("Invalid resource locator: " + locator, ex); } } /** * Creates a resource from a {@code File}. * * @param file the file to wrap * @return the resource */ 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 URL}. * * @param url the URL to wrap * @return the resource */ public static ResourceLocator ofClasspathUrl(URL url) { ArgChecker.notNull(url, "url"); String locator = CLASSPATH_URL_PREFIX + url.toString(); return new ResourceLocator(locator, Resources.asByteSource(url)); } /** * Creates a stream of resource locators. * <p> * This finds all occurrences of the resource name in the classpath and returns them. * * @param classpathResourceName the classpath resource name * @return the resource locators */ @FromString public static Stream<ResourceLocator> streamOfClasspathResources(String classpathResourceName) { ArgChecker.notNull(classpathResourceName, "classpathResourceName"); try { ClassLoader classLoader = firstNonNull( Thread.currentThread().getContextClassLoader(), ResourceLocator.class.getClassLoader()); return Collections.list(classLoader.getResources(classpathResourceName)).stream() .map(url -> ResourceLocator.ofClasspathUrl(url)); } catch (IOException ex) { throw new UncheckedIOException(ex); } } //------------------------------------------------------------------------- /** * 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; } }