package org.appwork.utils;
import java.io.ByteArrayOutputStream;
import java.lang.ref.SoftReference;
import java.util.Iterator;
import java.util.LinkedList;
public class ReusableByteArrayOutputStreamPool {
public static class ReusableByteArrayOutputStream extends ByteArrayOutputStream {
protected ReusableByteArrayOutputStream(final int size) {
super(size);
}
public int bufferSize() {
return this.buf.length;
}
public synchronized int free() {
return this.buf.length - this.count;
}
public byte[] getInternalBuffer() {
return this.buf;
}
public synchronized void increaseUsed(final int increase) {
this.count = this.count + increase;
}
public synchronized void setUsed(final int used) {
this.count = used;
}
}
private static final LinkedList<SoftReference<ReusableByteArrayOutputStream>> pool = new LinkedList<SoftReference<ReusableByteArrayOutputStream>>();
public static ReusableByteArrayOutputStream getReusableByteArrayOutputStream() {
return ReusableByteArrayOutputStreamPool.getReusableByteArrayOutputStream(32);
}
public static ReusableByteArrayOutputStream getReusableByteArrayOutputStream(final int wishedMinimumSize) {
return ReusableByteArrayOutputStreamPool.getReusableByteArrayOutputStream(wishedMinimumSize, true);
}
public static ReusableByteArrayOutputStream getReusableByteArrayOutputStream(final int wishedMinimumSize, final boolean allowSmaller) {
final int wished = Math.max(32, wishedMinimumSize);
synchronized (ReusableByteArrayOutputStreamPool.pool) {
ReusableByteArrayOutputStream ret = null;
ReusableByteArrayOutputStream best = null;
if (!ReusableByteArrayOutputStreamPool.pool.isEmpty()) {
Iterator<SoftReference<ReusableByteArrayOutputStream>> it = ReusableByteArrayOutputStreamPool.pool.iterator();
while (it.hasNext()) {
final SoftReference<ReusableByteArrayOutputStream> next = it.next();
ret = next.get();
if (ret == null) {
/* buffer already gced, remove it from pool */
it.remove();
} else {
if (ret.bufferSize() >= wishedMinimumSize) {
/*
* hit with >= desired Size, remove it from pool and
* return it
*/
it.remove();
return ret;
} else if (best == null) {
/* first best hit */
best = ret;
} else if (ret.bufferSize() > best.bufferSize()) {
/* a better hit */
best = ret;
}
}
}
if (best != null && allowSmaller) {
/* return best hit from previous search */
it = ReusableByteArrayOutputStreamPool.pool.iterator();
while (it.hasNext()) {
final SoftReference<ReusableByteArrayOutputStream> next = it.next();
ret = next.get();
if (ret == null) {
/* buffer already gced, remove it from pool */
it.remove();
} else if (ret == best) {
/* we reuse best hit */
it.remove();
return ret;
}
}
}
}
/* create new buffer */
return new ReusableByteArrayOutputStream(wished);
}
}
public static void reuseReusableByteArrayOutputStream(final ReusableByteArrayOutputStream buf) {
if (buf == null) { return; }
synchronized (ReusableByteArrayOutputStreamPool.pool) {
/* TODO: this cannot work!, fix it by using iterator and compare */
if (ReusableByteArrayOutputStreamPool.pool.contains(buf)) { return; }
ReusableByteArrayOutputStreamPool.pool.add(new SoftReference<ReusableByteArrayOutputStream>(buf));
buf.reset();
}
}
}