/* * Copyright (C) 2014 Indeed Inc. * * 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.indeed.imhotep.io; import javax.annotation.Nullable; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.concurrent.atomic.AtomicLong; /** * Extension of the BufferedOutputStream that throws an WriteLimitExceededException * when the number of bytes written exceeds the provided limit. * @author vladimir */ public class LimitedBufferedOutputStream extends BufferedOutputStream { @Nullable private final AtomicLong maxBytesToWrite; /** * Creates a new buffered output stream to write data to the * specified underlying output stream. * Throws a WriteLimitExceededException if written more than maxBytesToWrite bytes. * * @param out the underlying output stream. * @param maxBytesToWrite byte limit as an AtomicLong can be shared between multiple * LimitedBufferedOutputStreams running in parallel threads. If null, no limit is applied. */ public LimitedBufferedOutputStream(OutputStream out, @Nullable AtomicLong maxBytesToWrite) { this(out, maxBytesToWrite, 8192); } /** * Creates a new buffered output stream to write data to the * specified underlying output stream with the specified buffer * size. * Throws a WriteLimitExceededException if written more than maxBytesToWrite bytes. * * @param out the underlying output stream. * @param maxBytesToWrite byte limit as an AtomicLong can be shared between multiple * LimitedBufferedOutputStreams running in parallel threads. If null, no limit is applied. * @param size the buffer size. * @exception IllegalArgumentException if size <= 0. */ public LimitedBufferedOutputStream(OutputStream out, @Nullable AtomicLong maxBytesToWrite, int size) { super(out, size); this.maxBytesToWrite = maxBytesToWrite; } @Override public synchronized void write(int b) throws IOException { if(maxBytesToWrite != null && maxBytesToWrite.decrementAndGet() < 0) { throw new WriteLimitExceededException(); } super.write(b); } @Override public synchronized void write(byte[] b, int off, int len) throws IOException { if(maxBytesToWrite != null && maxBytesToWrite.addAndGet(-len) < 0) { throw new WriteLimitExceededException(); } super.write(b, off, len); } }