/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.io;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
/**
* @author Shuyang Zhou
*/
public class RestrictedByteArrayCacheOutputStream extends OutputStream {
public RestrictedByteArrayCacheOutputStream(
OutputStream outputStream, int cacheCapacity,
FlushPreAction flushPreAction) {
this(outputStream, 32, cacheCapacity, flushPreAction);
}
public RestrictedByteArrayCacheOutputStream(
OutputStream outputStream, int initialCacheSize, int cacheCapacity,
FlushPreAction flushPreAction) {
if (initialCacheSize > cacheCapacity) {
throw new IllegalArgumentException(
"Initial cache size " + initialCacheSize +
" is larger than cache capacity " + cacheCapacity);
}
this.outputStream = outputStream;
this.cacheCapacity = cacheCapacity;
this.flushPreAction = flushPreAction;
cache = new byte[initialCacheSize];
}
@Override
public void flush() throws IOException {
if (overflowed) {
return;
}
if (flushPreAction != null) {
flushPreAction.beforeFlush();
}
overflowed = true;
outputStream.write(cache, 0, index);
cache = null;
index = -1;
}
public int getCacheCapacity() {
return cacheCapacity;
}
public boolean isOverflowed() {
return overflowed;
}
public void reset() {
if (overflowed) {
throw new IllegalStateException("Cache overflowed");
}
index = 0;
}
public int size() {
return index;
}
public byte[] toByteArray() {
if (overflowed) {
throw new IllegalStateException("Cache overflowed");
}
byte[] newCache = new byte[index];
System.arraycopy(cache, 0, newCache, 0, index);
return newCache;
}
public byte[] unsafeGetByteArray() {
if (overflowed) {
throw new IllegalStateException("Cache overflowed");
}
return cache;
}
public ByteBuffer unsafeGetByteBuffer() {
if (overflowed) {
throw new IllegalStateException("Cache overflowed");
}
return ByteBuffer.wrap(cache, 0, index);
}
@Override
public void write(byte[] bytes) throws IOException {
write(bytes, 0, bytes.length);
}
@Override
public void write(byte[] bytes, int offset, int length) throws IOException {
if (length <= 0) {
return;
}
if (overflowed) {
outputStream.write(bytes, offset, length);
return;
}
int newIndex = index + length;
if (newIndex > cacheCapacity) {
flush();
outputStream.write(bytes, offset, length);
return;
}
ensureCacheSize(newIndex);
System.arraycopy(bytes, offset, cache, index, length);
index = newIndex;
}
@Override
public void write(int b) throws IOException {
if (overflowed) {
outputStream.write(b);
return;
}
int newIndex = index + 1;
if (newIndex > cacheCapacity) {
flush();
outputStream.write(b);
return;
}
ensureCacheSize(newIndex);
cache[index] = (byte)b;
index = newIndex;
}
public interface FlushPreAction {
public void beforeFlush() throws IOException;
}
protected void ensureCacheSize(int newIndex) {
if (newIndex <= cache.length) {
return;
}
int newCacheSize = Math.max(cache.length << 1, newIndex);
if (newCacheSize > cacheCapacity) {
newCacheSize = cacheCapacity;
}
byte[] newCache = new byte[newCacheSize];
System.arraycopy(cache, 0, newCache, 0, cache.length);
cache = newCache;
}
protected byte[] cache;
protected int cacheCapacity;
protected FlushPreAction flushPreAction;
protected int index;
protected OutputStream outputStream;
protected boolean overflowed;
}