com.oschrenk.flatfiles.util.PredicateFilterReader.java Source code

Java tutorial

Introduction

Here is the source code for com.oschrenk.flatfiles.util.PredicateFilterReader.java

Source

/*
 * Copyright 2011 Oliver Schrenk
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.oschrenk.flatfiles.util;

import java.io.BufferedReader;
import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;

/**
 * This class takes a {@link Reader} and a {@link Predicate} and keeps lines to
 * which the predicate applies. Line terminators are converted to a
 * <code>\n</code>.
 *
 * @author Oliver Schrenk <oliver.schrenk@gmail.com>
 */
public class PredicateFilterReader extends FilterReader {

    /**
     * The current line. If null and emitNewline is false, a newline must be
     * fetched.
     */
    private String currentLine;

    /**
     * The index of the first unread character in curLine. If at any time
     * <code>curLineIx == curLine.length</code>, <code>currentLine</code> is set
     * to <code>null</code>.
     */
    int currentLineIndex;

    /**
     * If <code>true</code>, the newline at the end of currentLine has not been
     * returned.
     *
     * It would have been more convenient to append the newline onto freshly
     * fetched lines. However, that would incur another allocation and copy.
     */
    boolean emitNewline;

    /** The buffered reader. */
    private final BufferedReader bufferedReader;

    /** The line predicate. */
    private final Predicate<String> linePredicate;

    /**
     * Instantiates a new comment filter reader.
     *
     * @param in
     *            the in
     */
    protected PredicateFilterReader(final Reader in) {
        super(in);
        bufferedReader = new BufferedReader(in);
        linePredicate = Predicates.alwaysTrue();
    }

    /**
     * Instantiates a new comment filter reader.
     *
     * @param in
     *            the reader
     * @param linePredicate
     *            the line predicate
     */
    public PredicateFilterReader(final Reader in, final Predicate<String> linePredicate) {
        super(in);
        bufferedReader = new BufferedReader(in);
        this.linePredicate = linePredicate;
    }

    @Override
    public int read() throws IOException {
        final char[] chars = new char[1];
        final int read = read(chars, 0, 1);
        if (read == -1) {
            return -1;

        }
        return chars[0];
    }

    /*
     * (non-Javadoc)
     *
     * @see java.io.FilterReader#read(char[], int, int)
     */
    @Override
    public int read(final char cbuf[], int off, final int len) throws IOException {

        // Fetch new line if necessary
        if (currentLine == null && !emitNewline) {
            setNextMatchingLine();
        }

        // Return characters from current line
        if (currentLine != null) {
            int num = Math.min(len, Math.min(cbuf.length - off, currentLine.length() - currentLineIndex));
            // Copy characters from curLine to cbuf
            for (int i = 0; i < num; i++) {
                cbuf[off++] = currentLine.charAt(currentLineIndex++);
            }

            // No more characters in curLine
            if (currentLineIndex == currentLine.length()) {
                currentLine = null;

                // Is there room for the newline?
                if (num < len && off < cbuf.length) {
                    cbuf[off++] = '\n';
                    emitNewline = false;
                    num++;
                }
            }

            // Return number of character read
            return num;
        } else if (emitNewline && len > 0) {
            // Emit just the newline
            cbuf[off] = '\n';
            emitNewline = false;
            return 1;
        } else if (len > 0) {
            // No more characters left in input reader
            return -1;
        } else {
            // Client did not ask for any characters
            return 0;
        }
    }

    /**
     * Gets the next line.
     *
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    private void setNextMatchingLine() throws IOException {
        currentLine = bufferedReader.readLine();
        while (currentLine != null) {
            if (linePredicate.apply(currentLine)) {
                emitNewline = true;
                currentLineIndex = 0;
                return;
            }
            currentLine = bufferedReader.readLine();
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see java.io.FilterReader#ready()
     */
    @Override
    public boolean ready() throws IOException {
        return currentLine != null || emitNewline || in.ready();
    }

    /*
     * (non-Javadoc)
     *
     * @see java.io.FilterReader#markSupported()
     */
    @Override
    public boolean markSupported() {
        return false;
    }

    @Override
    public void close() throws IOException {
        bufferedReader.close();
        super.close();
    }

}