001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.oozie.util;
019
020import java.io.File;
021import java.io.FileInputStream;
022import java.io.FileReader;
023import java.io.IOException;
024import java.io.InputStreamReader;
025import java.io.Reader;
026import java.util.ArrayList;
027import java.util.zip.GZIPInputStream;
028
029/**
030 * Implementation of a {@link Reader} which can be used to read in multiple files sequentially.  That is, when the first file ends
031 * it will silently move to the next file and so on.  If the file has a ".gz" extension, this Reader will properly handle it; all
032 * other types of files will simply be read using a {@link FileReader}.
033 */
034public class MultiFileReader extends Reader {
035
036    private ArrayList<File> files;
037    private int index;
038    private Reader reader;
039    private boolean closed;
040
041    /**
042     * Constructs the MultiFileReader with the given files.  The files will be read in the order given in the ArrayList.
043     *
044     * @param files The files to read
045     * @throws IOException If there was a problem opening the first file
046     */
047    public MultiFileReader(ArrayList<File> files) throws IOException {
048        this.files = files;
049        closed = false;
050        index = 0;
051        reader = null;
052        openNextReader();
053    }
054
055    @Override
056    public int read(char[] cbuf, int off, int len) throws IOException {
057        int numRead = -1;
058        while(!closed && numRead == -1) {
059            numRead = reader.read(cbuf, off, len);
060            if (numRead == -1) {
061                reader.close();
062                openNextReader();
063            }
064        }
065        return numRead;
066    }
067
068    @Override
069    public void close() throws IOException {
070        if (reader != null) {
071            reader.close();
072        }
073        closed = true;
074    }
075
076    private void openNextReader() throws IOException {
077        if (index < files.size()) {
078            // gzip files
079            if (files.get(index).getName().endsWith(".gz")) {
080                GZIPInputStream gzipInputStream = new GZIPInputStream(new FileInputStream(files.get(index)));
081                reader = new InputStreamReader(gzipInputStream);
082            }
083            // regular files
084            else {
085                reader = new FileReader(files.get(index));
086            }
087            index++;
088        }
089        else {
090            closed = true;
091        }
092    }
093}