001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.flatfile.util;
018
019import java.io.IOException;
020import java.io.InputStream;
021
022import org.apache.commons.io.input.CountingInputStream;
023
024/**
025 * FilterInputStream that limits the data returned from the proxy.
026 * @version $Revision: 1301244 $ $Date: 2012-03-15 17:16:23 -0500 (Thu, 15 Mar 2012) $
027 */
028public class ThresholdingInputStream extends CountingInputStream {
029    private static final int EOF = -1;
030
031    private final int maximum;
032    private boolean closed;
033
034    /**
035     * Create a new ThresholdingInputStream.
036     * @param in the filtered stream
037     * @param maximum length
038     */
039    public ThresholdingInputStream(InputStream in, int maximum) {
040        super(in);
041        this.maximum = maximum;
042    }
043
044    /*
045     * NOTICE: implementing all three read(...) methods such that corresponding
046     * super methods are called
047     */
048
049    /**
050     * {@inheritDoc}
051     */
052    public synchronized int read() throws IOException {
053        assertNotClosed();
054        if (getCount() >= maximum) {
055            return EOF;
056        }
057        return super.read();
058    }
059
060    /**
061     * {@inheritDoc}
062     */
063    public synchronized int read(byte[] b, int off, int len) throws IOException {
064        assertNotClosed();
065        int n = maximum - getCount();
066        return n == 0 ? EOF : super.read(b, off, n < len ? n : len);
067    }
068
069    /**
070     * {@inheritDoc}
071     */
072    public synchronized int read(byte[] b) throws IOException {
073        assertNotClosed();
074        int n = maximum - getCount();
075        if (n == 0) {
076            return EOF;
077        }
078        if (n < b.length) {
079            byte[] buf = new byte[n];
080            System.arraycopy(b, 0, buf, 0, n);
081            try {
082                return super.read(buf);
083            } finally {
084                System.arraycopy(buf, 0, b, 0, n);
085            }
086        }
087        return super.read(b);
088    }
089
090    /**
091     * {@inheritDoc}
092     */
093    public synchronized void close() throws IOException {
094        this.closed = true;
095        super.close();
096    }
097
098    /**
099     * Make sure the stream is not closed.
100     * @throws IOException if stream has been closed.
101     */
102    private synchronized void assertNotClosed() throws IOException {
103        if (closed) {
104            throw new IOException("Stream closed");
105        }
106    }
107}