diff --git a/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java b/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java index cd9789210..2640f1a74 100644 --- a/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java +++ b/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java @@ -45,6 +45,7 @@ public class BoundedBuffer extends SynchronizedBuffer implements BoundedCollecti /** The serialization version. */ private static final long serialVersionUID = 1536432911093974264L; + /** The maximum size. */ private final int maximumSize; /** The timeout milliseconds. */ @@ -52,13 +53,17 @@ public class BoundedBuffer extends SynchronizedBuffer implements BoundedCollecti /** * Factory method to create a bounded buffer. + *

+ * When the buffer is full, it will immediately throw a + * BufferOverflowException on calling add(). * * @param buffer the buffer to decorate, must not be null - * @param maximumSize the maximum size + * @param maximumSize the maximum size, must be size one or greater * @return a new bounded buffer * @throws IllegalArgumentException if the buffer is null + * @throws IllegalArgumentException if the maximum size is zero or less */ - public static Buffer decorate(Buffer buffer, int maximumSize) { + public static BoundedBuffer decorate(Buffer buffer, int maximumSize) { return new BoundedBuffer(buffer, maximumSize, 0L); } @@ -67,26 +72,32 @@ public class BoundedBuffer extends SynchronizedBuffer implements BoundedCollecti * amount of time. * * @param buffer the buffer to decorate, must not be null - * @param maximumSize the maximum size + * @param maximumSize the maximum size, must be size one or greater * @param timeout the maximum amount of time to wait in milliseconds * @return a new bounded buffer * @throws IllegalArgumentException if the buffer is null + * @throws IllegalArgumentException if the maximum size is zero or less */ - public static Buffer decorate(Buffer buffer, int maximumSize, long timeout) { + public static BoundedBuffer decorate(Buffer buffer, int maximumSize, long timeout) { return new BoundedBuffer(buffer, maximumSize, timeout); } //----------------------------------------------------------------------- /** - * Constructor that wraps (not copies) another buffer, making it bounded waiting only up to - * a maximum amount of time. - * @param buffer the buffer to wrap, must not be null - * @param maximumSize the maximum size of the buffer - * @param timeout the maximum amount of time to wait + * Constructor that wraps (not copies) another buffer, making it bounded + * waiting only up to a maximum amount of time. + * + * @param buffer the buffer to wrap, must not be null + * @param maximumSize the maximum size, must be size one or greater + * @param timeout the maximum amount of time to wait * @throws IllegalArgumentException if the buffer is null + * @throws IllegalArgumentException if the maximum size is zero or less */ - protected BoundedBuffer( Buffer buffer, int maximumSize, long timeout ) { - super( buffer ); + protected BoundedBuffer(Buffer buffer, int maximumSize, long timeout) { + super(buffer); + if (maximumSize < 1) { + throw new IllegalArgumentException(); + } this.maximumSize = maximumSize; this.timeout = timeout; } @@ -119,32 +130,40 @@ public class BoundedBuffer extends SynchronizedBuffer implements BoundedCollecti } private void timeoutWait(final int nAdditions) { - synchronized (lock) { - if (timeout < 0 && getBuffer().size() + nAdditions > maximumSize) { - throw new BufferOverflowException( + // method synchronized by callers + if (nAdditions > maximumSize) { + throw new BufferOverflowException( "Buffer size cannot exceed " + maximumSize); - } - final long expiration = System.currentTimeMillis() + timeout; - long timeLeft = expiration - System.currentTimeMillis(); - while (timeLeft > 0 && getBuffer().size() + nAdditions > maximumSize) { - try { - lock.wait(timeLeft); - timeLeft = expiration - System.currentTimeMillis(); - } catch (InterruptedException e) { - PrintWriter out = new PrintWriter(new StringWriter()); - e.printStackTrace(out); - throw new BufferUnderflowException( - "Caused by InterruptedException: " + out.toString()); - } - } + } + if (timeout <= 0) { + // no wait period (immediate timeout) if (getBuffer().size() + nAdditions > maximumSize) { - throw new BufferOverflowException("Timeout expired"); + throw new BufferOverflowException( + "Buffer size cannot exceed " + maximumSize); } + return; + } + final long expiration = System.currentTimeMillis() + timeout; + long timeLeft = expiration - System.currentTimeMillis(); + while (timeLeft > 0 && getBuffer().size() + nAdditions > maximumSize) { + try { + lock.wait(timeLeft); + timeLeft = expiration - System.currentTimeMillis(); + } catch (InterruptedException ex) { + PrintWriter out = new PrintWriter(new StringWriter()); + ex.printStackTrace(out); + throw new BufferUnderflowException( + "Caused by InterruptedException: " + out.toString()); + } + } + if (getBuffer().size() + nAdditions > maximumSize) { + throw new BufferOverflowException("Timeout expired"); } } public boolean isFull() { - return (collection.size() == maxSize()); + // size() is synchronized + return (size() == maxSize()); } public int maxSize() { diff --git a/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java b/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java index 0a5372861..a788ef056 100644 --- a/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java +++ b/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java @@ -66,6 +66,14 @@ public class TestBoundedBuffer extends AbstractTestObject { assertEquals(true, bc.isFull()); bounded.remove(); assertEquals(false, bc.isFull()); + try { + BoundedBuffer.decorate(new UnboundedFifoBuffer(), 0); + fail(); + } catch (IllegalArgumentException ex) {} + try { + BoundedBuffer.decorate(new UnboundedFifoBuffer(), -1); + fail(); + } catch (IllegalArgumentException ex) {} } public void testAddToFullBufferNoTimeout() { @@ -88,6 +96,15 @@ public class TestBoundedBuffer extends AbstractTestObject { } } + public void testAddAllToEmptyBufferExceedMaxSizeNoTimeout() { + final Buffer bounded = BoundedBuffer.decorate(new UnboundedFifoBuffer(), 1); + try { + bounded.addAll(Collections.nCopies(2, "test")); + fail(); + } catch (BufferOverflowException e) { + } + } + public void testAddToFullBufferRemoveViaIterator() { final Buffer bounded = BoundedBuffer.decorate(new UnboundedFifoBuffer(), 1, 500); bounded.add( "Hello" );