1bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2007 The Guava Authors
3bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
4bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Licensed under the Apache License, Version 2.0 (the "License");
5bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * you may not use this file except in compliance with the License.
6bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * You may obtain a copy of the License at
7bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
8bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * http://www.apache.org/licenses/LICENSE-2.0
9bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
10bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Unless required by applicable law or agreed to in writing, software
11bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * distributed under the License is distributed on an "AS IS" BASIS,
12bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * See the License for the specific language governing permissions and
14bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * limitations under the License.
15bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor */
16bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
17bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorpackage com.google.common.io;
18bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
19bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport static com.google.common.base.Preconditions.checkArgument;
20bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport static com.google.common.base.Preconditions.checkNotNull;
21bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.Beta;
237dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.base.Charsets;
243ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffinimport com.google.common.base.MoreObjects;
250888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.collect.Lists;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.IOException;
28bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.InputStream;
29bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.OutputStream;
30bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.net.URL;
31bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.nio.charset.Charset;
32bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.util.List;
33bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
34bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor/**
35bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Provides utility methods for working with resources in the classpath.
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Note that even though these methods use {@link URL} parameters, they
37bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * are usually not appropriate for HTTP or other non-classpath resources.
38bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
39bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * <p>All method parameters must be non-null unless documented otherwise.
40bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
41bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * @author Chris Nokleberg
42bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * @author Ben Yu
437dd252788645e940eada959bdde927426e2531c9Paul Duffin * @author Colin Decker
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 1.0
45bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor */
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@Beta
47bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorpublic final class Resources {
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private Resources() {}
49bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
50bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
517dd252788645e940eada959bdde927426e2531c9Paul Duffin   * Returns a {@link ByteSource} that reads from the given URL.
527dd252788645e940eada959bdde927426e2531c9Paul Duffin   *
537dd252788645e940eada959bdde927426e2531c9Paul Duffin   * @since 14.0
547dd252788645e940eada959bdde927426e2531c9Paul Duffin   */
557dd252788645e940eada959bdde927426e2531c9Paul Duffin  public static ByteSource asByteSource(URL url) {
567dd252788645e940eada959bdde927426e2531c9Paul Duffin    return new UrlByteSource(url);
577dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
587dd252788645e940eada959bdde927426e2531c9Paul Duffin
597dd252788645e940eada959bdde927426e2531c9Paul Duffin  /**
607dd252788645e940eada959bdde927426e2531c9Paul Duffin   * A byte source that reads from a URL using {@link URL#openStream()}.
617dd252788645e940eada959bdde927426e2531c9Paul Duffin   */
627dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static final class UrlByteSource extends ByteSource {
637dd252788645e940eada959bdde927426e2531c9Paul Duffin
647dd252788645e940eada959bdde927426e2531c9Paul Duffin    private final URL url;
657dd252788645e940eada959bdde927426e2531c9Paul Duffin
667dd252788645e940eada959bdde927426e2531c9Paul Duffin    private UrlByteSource(URL url) {
677dd252788645e940eada959bdde927426e2531c9Paul Duffin      this.url = checkNotNull(url);
687dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
697dd252788645e940eada959bdde927426e2531c9Paul Duffin
707dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override
717dd252788645e940eada959bdde927426e2531c9Paul Duffin    public InputStream openStream() throws IOException {
727dd252788645e940eada959bdde927426e2531c9Paul Duffin      return url.openStream();
737dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
747dd252788645e940eada959bdde927426e2531c9Paul Duffin
757dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override
767dd252788645e940eada959bdde927426e2531c9Paul Duffin    public String toString() {
770888a09821a98ac0680fad765217302858e70fa4Paul Duffin      return "Resources.asByteSource(" + url + ")";
787dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
79bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
80bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
81bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
820888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * Returns a {@link CharSource} that reads from the given URL using the given
830888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * character set.
847dd252788645e940eada959bdde927426e2531c9Paul Duffin   *
857dd252788645e940eada959bdde927426e2531c9Paul Duffin   * @since 14.0
867dd252788645e940eada959bdde927426e2531c9Paul Duffin   */
877dd252788645e940eada959bdde927426e2531c9Paul Duffin  public static CharSource asCharSource(URL url, Charset charset) {
887dd252788645e940eada959bdde927426e2531c9Paul Duffin    return asByteSource(url).asCharSource(charset);
89bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
90bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
91bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
92bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Reads all bytes from a URL into a byte array.
93bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
94bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param url the URL to read from
95bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return a byte array containing all the bytes from the URL
96bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
97bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
98bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static byte[] toByteArray(URL url) throws IOException {
997dd252788645e940eada959bdde927426e2531c9Paul Duffin    return asByteSource(url).read();
100bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
101bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
102bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
103bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Reads all characters from a URL into a {@link String}, using the given
104bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * character set.
105bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
106bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param url the URL to read from
1077dd252788645e940eada959bdde927426e2531c9Paul Duffin   * @param charset the charset used to decode the input stream; see {@link
1087dd252788645e940eada959bdde927426e2531c9Paul Duffin   *     Charsets} for helpful predefined constants
109bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return a string containing all the characters from the URL
110bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs.
111bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
112bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static String toString(URL url, Charset charset) throws IOException {
1137dd252788645e940eada959bdde927426e2531c9Paul Duffin    return asCharSource(url, charset).read();
114bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
115bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
116bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
117bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Streams lines from a URL, stopping when our callback returns false, or we
118bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * have read all of the lines.
119bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
120bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param url the URL to read from
1217dd252788645e940eada959bdde927426e2531c9Paul Duffin   * @param charset the charset used to decode the input stream; see {@link
1227dd252788645e940eada959bdde927426e2531c9Paul Duffin   *     Charsets} for helpful predefined constants
123bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param callback the LineProcessor to use to handle the lines
124bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return the output of processing the lines
125bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
126bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
1270888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public static <T> T readLines(URL url, Charset charset,
1280888a09821a98ac0680fad765217302858e70fa4Paul Duffin      LineProcessor<T> callback) throws IOException {
1293ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin    return asCharSource(url, charset).readLines(callback);
130bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
131bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
132bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
133bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Reads all of the lines from a URL. The lines do not include
134bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * line-termination characters, but do include other leading and trailing
135bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * whitespace.
136bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
1370888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * <p>This method returns a mutable {@code List}. For an
1380888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * {@code ImmutableList}, use
1390888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * {@code Resources.asCharSource(url, charset).readLines()}.
1400888a09821a98ac0680fad765217302858e70fa4Paul Duffin   *
141bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param url the URL to read from
1427dd252788645e940eada959bdde927426e2531c9Paul Duffin   * @param charset the charset used to decode the input stream; see {@link
1437dd252788645e940eada959bdde927426e2531c9Paul Duffin   *     Charsets} for helpful predefined constants
144bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return a mutable {@link List} containing all the lines
145bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
146bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
1470888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public static List<String> readLines(URL url, Charset charset)
1480888a09821a98ac0680fad765217302858e70fa4Paul Duffin      throws IOException {
1490888a09821a98ac0680fad765217302858e70fa4Paul Duffin    // don't use asCharSource(url, charset).readLines() because that returns
1500888a09821a98ac0680fad765217302858e70fa4Paul Duffin    // an immutable list, which would change the behavior of this method
1510888a09821a98ac0680fad765217302858e70fa4Paul Duffin    return readLines(url, charset, new LineProcessor<List<String>>() {
1520888a09821a98ac0680fad765217302858e70fa4Paul Duffin      final List<String> result = Lists.newArrayList();
1530888a09821a98ac0680fad765217302858e70fa4Paul Duffin
1540888a09821a98ac0680fad765217302858e70fa4Paul Duffin      @Override
1550888a09821a98ac0680fad765217302858e70fa4Paul Duffin      public boolean processLine(String line) {
1560888a09821a98ac0680fad765217302858e70fa4Paul Duffin        result.add(line);
1570888a09821a98ac0680fad765217302858e70fa4Paul Duffin        return true;
1580888a09821a98ac0680fad765217302858e70fa4Paul Duffin      }
1590888a09821a98ac0680fad765217302858e70fa4Paul Duffin
1600888a09821a98ac0680fad765217302858e70fa4Paul Duffin      @Override
1610888a09821a98ac0680fad765217302858e70fa4Paul Duffin      public List<String> getResult() {
1620888a09821a98ac0680fad765217302858e70fa4Paul Duffin        return result;
1630888a09821a98ac0680fad765217302858e70fa4Paul Duffin      }
1640888a09821a98ac0680fad765217302858e70fa4Paul Duffin    });
165bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
166bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
167bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
168bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Copies all bytes from a URL to an output stream.
169bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
170bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param from the URL to read from
171bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param to the output stream
172bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
173bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
174bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static void copy(URL from, OutputStream to) throws IOException {
1757dd252788645e940eada959bdde927426e2531c9Paul Duffin    asByteSource(from).copyTo(to);
176bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
1770888a09821a98ac0680fad765217302858e70fa4Paul Duffin
178bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
179bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Returns a {@code URL} pointing to {@code resourceName} if the resource is
1800888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * found using the {@linkplain Thread#getContextClassLoader() context class
1810888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * loader}. In simple environments, the context class loader will find
1820888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * resources from the class path. In environments where different threads can
1830888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * have different class loaders, for example app servers, the context class
1840888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * loader will typically have been set to an appropriate loader for the
1850888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * current thread.
1860888a09821a98ac0680fad765217302858e70fa4Paul Duffin   *
1870888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * <p>In the unusual case where the context class loader is null, the class
1880888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * loader that loaded this class ({@code Resources}) will be used instead.
189bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
1900888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * @throws IllegalArgumentException if the resource is not found
191bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
192bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static URL getResource(String resourceName) {
1933ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin    ClassLoader loader = MoreObjects.firstNonNull(
1940888a09821a98ac0680fad765217302858e70fa4Paul Duffin        Thread.currentThread().getContextClassLoader(),
1950888a09821a98ac0680fad765217302858e70fa4Paul Duffin        Resources.class.getClassLoader());
1960888a09821a98ac0680fad765217302858e70fa4Paul Duffin    URL url = loader.getResource(resourceName);
197bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    checkArgument(url != null, "resource %s not found.", resourceName);
198bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return url;
199bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
200bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
201bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
2020888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * Given a {@code resourceName} that is relative to {@code contextClass},
2030888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * returns a {@code URL} pointing to the named resource.
204bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
2050888a09821a98ac0680fad765217302858e70fa4Paul Duffin   * @throws IllegalArgumentException if the resource is not found
206bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
207bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static URL getResource(Class<?> contextClass, String resourceName) {
208bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    URL url = contextClass.getResource(resourceName);
2090888a09821a98ac0680fad765217302858e70fa4Paul Duffin    checkArgument(url != null, "resource %s relative to %s not found.",
2100888a09821a98ac0680fad765217302858e70fa4Paul Duffin        resourceName, contextClass.getName());
211bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return url;
212bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
213bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor}
214