001    /*
002     *                    BioJava development code
003     *
004     * This code may be freely distributed and modified under the
005     * terms of the GNU Lesser General Public Licence.  This should
006     * be distributed with the code.  If you do not have a copy,
007     * see:
008     *
009     *      http://www.gnu.org/copyleft/lesser.html
010     *
011     * Copyright for this code is held jointly by the individual
012     * authors.  These should be listed in @author doc comments.
013     *
014     * For more information on the BioJava project and its aims,
015     * or to join the biojava-l mailing list, visit the home page
016     * at:
017     *
018     *      http://www.biojava.org/
019     *
020     * Created on 01-21-2010
021     */
022    package org.biojava3.core.sequence.io.util;
023    
024    import static org.biojava3.core.sequence.io.util.IOUtils.close;
025    import static org.biojava3.core.sequence.io.util.IOUtils.copy;
026    
027    import java.io.BufferedReader;
028    import java.io.ByteArrayInputStream;
029    import java.io.ByteArrayOutputStream;
030    import java.io.IOException;
031    import java.io.InputStream;
032    import java.io.InputStreamReader;
033    import java.util.List;
034    import java.util.zip.GZIPInputStream;
035    
036    import org.biojava3.core.exceptions.ParserException;
037    
038    /**
039     * This object represents a classpath resource on the local system. It allows
040     * you to specify a location and then extract the inputstream, reader or
041     * lines of the resource. We also support GZiped files (so long as the resource
042     * ends with a .gz) and pre-caching of the data so we read only once from
043     * the classpath and close that link down. This is useful if you want to keep
044     * IO handles down but not very useful if the file is very large.
045     *
046     * @author ayates
047     *
048     */
049    public class ClasspathResource {
050    
051      private final String location;
052      private final boolean preCache;
053      private final Boolean isGzip;
054    
055      /**
056       * Basic constructor only allowing you to specify where to find the file.
057       *
058       * @param location Specified as <i>my/classpath/loc.txt</i>
059       */
060      public ClasspathResource(String location) {
061        this(location, false);
062      }
063    
064      /**
065       * Advanced constructor which allows you to optionally pre-cache the
066       * data
067       *
068       * @param location Specified as <i>my/classpath/loc.txt</i>
069       * @param preCache If set to true will cause the data to be copied
070       * to an in memory byte array and then an InputStream will be wrapped around
071       * that.
072       */
073      public ClasspathResource(String location, boolean preCache) {
074        this.location = location;
075        this.preCache = preCache;
076        this.isGzip = null;
077      }
078    
079      /**
080       * Advanced constructor which lets you set the preCache variable and to
081       * force the type of file we are decompressing. If this constructor is
082       * used we trust your call as to the file's compression status.
083       *
084       * @param location Specified as <i>my/classpath/loc.txt</i>
085       * @param preCache If set to true will cause the data to be copied
086       * to an in memory byte array and then an InputStream will be wrapped around
087       * that.
088       * @param isGzip Set to true or false if the file is gziped.
089       */
090      public ClasspathResource(String location, boolean preCache, boolean isGzip) {
091        this.location = location;
092        this.preCache = preCache;
093        this.isGzip = isGzip;
094      }
095    
096      /**
097       * Returns the InputStream instance of this classpath resource
098       */
099      public InputStream getInputStream() {
100        return createClasspathInputStream();
101      }
102    
103      /**
104       * Returns the reader representation of this classpath resource
105       */
106      public BufferedReader getBufferedReader() {
107        return new BufferedReader(new InputStreamReader(getInputStream()));
108      }
109    
110      /**
111       * Returns this resource as a list of Strings
112       */
113      public List<String> getList() {
114        return IOUtils.getList(getBufferedReader());
115      }
116    
117      private InputStream createClasspathInputStream() {
118        final InputStream is;
119        final InputStream classpathIs = getClass().getClassLoader().getResourceAsStream(location);
120        if(classpathIs == null) {
121          throw new IllegalArgumentException("Location "+
122              location+" resulted in a null InputStream");
123        }
124        if(preCache) {
125          ByteArrayOutputStream os = new ByteArrayOutputStream();
126          try {
127            copy(classpathIs, os);
128          } catch (IOException e) {
129            throw new ParserException("Cannot copy classpath InputStream", e);
130          }
131          finally {
132            close(classpathIs);
133          }
134          is = new ByteArrayInputStream(os.toByteArray());
135        }
136        else {
137          is = classpathIs;
138        }
139    
140        if(isGzip()) {
141          try {
142            return new GZIPInputStream(is);
143          }
144          catch (IOException e) {
145            throw new ParserException("Cannot open stream as a GZIP stream", e);
146          }
147        }
148    
149        return is;
150      }
151    
152      /**
153       * Returns true if the location given ends with a .gz extension. No magic
154       * number investigation is done.
155       */
156      private boolean isGzip() {
157        if(isGzip != null) {
158          return isGzip;
159        }
160        else {
161          return this.location.endsWith(".gz");
162        }
163      }
164    }