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 */
018
019package org.apache.oozie.util;
020
021import java.io.File;
022import java.io.FileInputStream;
023import java.io.FileReader;
024import java.io.IOException;
025import java.io.InputStreamReader;
026import java.io.Reader;
027import java.util.ArrayList;
028import java.util.zip.GZIPInputStream;
029
030/**
031 * Implementation of a {@link Reader} which can be used to read in multiple files sequentially.  That is, when the first file ends
032 * 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
033 * other types of files will simply be read using a {@link FileReader}.
034 */
035public class MultiFileReader extends Reader {
036
037    private ArrayList<File> files;
038    private int index;
039    private Reader reader;
040    private boolean closed;
041
042    /**
043     * Constructs the MultiFileReader with the given files.  The files will be read in the order given in the ArrayList.
044     *
045     * @param files The files to read
046     * @throws IOException If there was a problem opening the first file
047     */
048    public MultiFileReader(ArrayList<File> files) throws IOException {
049        this.files = files;
050        closed = false;
051        index = 0;
052        reader = null;
053        openNextReader();
054    }
055
056    @Override
057    public int read(char[] cbuf, int off, int len) throws IOException {
058        int numRead = -1;
059        while(!closed && numRead == -1) {
060            numRead = reader.read(cbuf, off, len);
061            if (numRead == -1) {
062                reader.close();
063                openNextReader();
064            }
065        }
066        return numRead;
067    }
068
069    @Override
070    public void close() throws IOException {
071        if (reader != null) {
072            reader.close();
073        }
074        closed = true;
075    }
076
077    private void openNextReader() throws IOException {
078        if (index < files.size()) {
079            // gzip files
080            if (files.get(index).getName().endsWith(".gz")) {
081                GZIPInputStream gzipInputStream = new GZIPInputStream(new FileInputStream(files.get(index)));
082                reader = new InputStreamReader(gzipInputStream);
083            }
084            // regular files
085            else {
086                reader = new FileReader(files.get(index));
087            }
088            index++;
089        }
090        else {
091            closed = true;
092        }
093    }
094}