/******************************************************************************* * Copyright (c) 2012 Pivotal Software, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Pivotal Software, Inc. - initial API and implementation *******************************************************************************/ package org.grails.ide.eclipse.core.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; /** * This is a ByteArrayOutputStream that puts an upper bound on the amount of * data that is kept in its buffer. If the allowed buffer size is exceeded, * then the oldest data in the buffer is discarded to remain within the * allowed limit. * * TODO: This is a poor implementation in terms of performance. A better implementation * would use a cyclic byte buffer which would never need to copy the contents of the buffer * to shrink it down to size. * * @author Kris De Volder */ public class LimitedByteArrayOutputStream extends ByteArrayOutputStream { private int MAX_BYTES; public LimitedByteArrayOutputStream(int maxBytes) { this.MAX_BYTES = maxBytes; } /** * Shrink buffer to allowable size. The agressive flag controls whether we * must shrink the buffer aggressively or if it is ok to allow some excess data above the limit. * Allowing for this 'margin' over the limit is to avoid excessive copying of the buffer on every * byte read. * <p> * Generally, the aggressive flag should be set to true when the buffer size or * contents could be observed by the client calling the api method that is requesting * buffer shrinkage. */ private void shrink(boolean aggressive) { boolean mustShrink = aggressive ? count>MAX_BYTES : count > MAX_BYTES + MAX_BYTES / 10; if (mustShrink) { System.arraycopy(buf, count-MAX_BYTES, buf, 0, MAX_BYTES); count = MAX_BYTES; } } public synchronized void write(int b) { super.write(b); shrink(false); } public synchronized void write(byte b[], int off, int len) { super.write(b, off, len); shrink(false); } @Override public synchronized int size() { int actualSz = super.size(); if (actualSz>MAX_BYTES) { return MAX_BYTES; } else { return actualSz; } } @Override public synchronized String toString() { shrink(true); return super.toString(); } @Override public synchronized String toString(String charsetName) throws UnsupportedEncodingException { shrink(true); return super.toString(charsetName); } @Override public synchronized void writeTo(OutputStream out) throws IOException { shrink(true); super.writeTo(out); } }