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 */
022package org.biojava.nbio.core.sequence.io.util;
023
024import org.biojava.nbio.core.exceptions.ParserException;
025
026import java.io.*;
027import java.util.List;
028import java.util.zip.GZIPInputStream;
029
030import static org.biojava.nbio.core.sequence.io.util.IOUtils.close;
031import static org.biojava.nbio.core.sequence.io.util.IOUtils.copy;
032
033/**
034 * This object represents a classpath resource on the local system. It allows
035 * you to specify a location and then extract the inputstream, reader or
036 * lines of the resource. We also support GZiped files (so long as the resource
037 * ends with a .gz) and pre-caching of the data so we read only once from
038 * the classpath and close that link down. This is useful if you want to keep
039 * IO handles down but not very useful if the file is very large.
040 *
041 * @author ayates
042 *
043 */
044public class ClasspathResource {
045
046        private final String location;
047        private final boolean preCache;
048        private final Boolean isGzip;
049
050        /**
051         * Basic constructor only allowing you to specify where to find the file.
052         *
053         * @param location Specified as <i>my/classpath/loc.txt</i>
054         */
055        public ClasspathResource(String location) {
056                this(location, false);
057        }
058
059        /**
060         * Advanced constructor which allows you to optionally pre-cache the
061         * data
062         *
063         * @param location Specified as <i>my/classpath/loc.txt</i>
064         * @param preCache If set to true will cause the data to be copied
065         * to an in memory byte array and then an InputStream will be wrapped around
066         * that.
067         */
068        public ClasspathResource(String location, boolean preCache) {
069                this.location = location;
070                this.preCache = preCache;
071                this.isGzip = null;
072        }
073
074        /**
075         * Advanced constructor which lets you set the preCache variable and to
076         * force the type of file we are decompressing. If this constructor is
077         * used we trust your call as to the file's compression status.
078         *
079         * @param location Specified as <i>my/classpath/loc.txt</i>
080         * @param preCache If set to true will cause the data to be copied
081         * to an in memory byte array and then an InputStream will be wrapped around
082         * that.
083         * @param isGzip Set to true or false if the file is gziped.
084         */
085        public ClasspathResource(String location, boolean preCache, boolean isGzip) {
086                this.location = location;
087                this.preCache = preCache;
088                this.isGzip = isGzip;
089        }
090
091        /**
092         * Returns the InputStream instance of this classpath resource
093         */
094        public InputStream getInputStream() {
095                return createClasspathInputStream();
096        }
097
098        /**
099         * Returns the reader representation of this classpath resource
100         */
101        public BufferedReader getBufferedReader() {
102                return new BufferedReader(new InputStreamReader(getInputStream()));
103        }
104
105        /**
106         * Returns this resource as a list of Strings
107         */
108        public List<String> getList() {
109                return IOUtils.getList(getBufferedReader());
110        }
111
112        private InputStream createClasspathInputStream() {
113                final InputStream is;
114                final InputStream classpathIs = getClass().getClassLoader().getResourceAsStream(location);
115                if(classpathIs == null) {
116                        throw new IllegalArgumentException("Location "+
117                                        location+" resulted in a null InputStream");
118                }
119                if(preCache) {
120                        ByteArrayOutputStream os = new ByteArrayOutputStream();
121                        try {
122                                copy(classpathIs, os);
123                        } catch (IOException e) {
124                                throw new ParserException("Cannot copy classpath InputStream", e);
125                        }
126                        finally {
127                                close(classpathIs);
128                        }
129                        is = new ByteArrayInputStream(os.toByteArray());
130                }
131                else {
132                        is = classpathIs;
133                }
134
135                if(isGzip()) {
136                        try {
137                                return new GZIPInputStream(is);
138                        }
139                        catch (IOException e) {
140                                throw new ParserException("Cannot open stream as a GZIP stream", e);
141                        }
142                }
143
144                return is;
145        }
146
147        /**
148         * Returns true if the location given ends with a .gz extension. No magic
149         * number investigation is done.
150         */
151        private boolean isGzip() {
152                if(isGzip != null) {
153                        return isGzip;
154                }
155                else {
156                        return this.location.endsWith(".gz");
157                }
158        }
159}