You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by jc...@apache.org on 2005/11/23 14:16:51 UTC

svn commit: r348429 - in /jakarta/commons/proper/collections/trunk: ./ data/test/ src/java/org/apache/commons/collections/ src/java/org/apache/commons/collections/buffer/ src/test/org/apache/commons/collections/buffer/

Author: jcarman
Date: Wed Nov 23 05:16:43 2005
New Revision: 348429

URL: http://svn.apache.org/viewcvs?rev=348429&view=rev
Log:
37473: Implement a BoundedBuffer class

Added:
    jakarta/commons/proper/collections/trunk/data/test/BoundedBuffer.emptyCollection.version3.2.obj   (with props)
    jakarta/commons/proper/collections/trunk/data/test/BoundedBuffer.fullCollection.version3.2.obj   (with props)
    jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java   (with props)
    jakarta/commons/proper/collections/trunk/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java   (with props)
Modified:
    jakarta/commons/proper/collections/trunk/RELEASE-NOTES.html
    jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/BufferUtils.java

Modified: jakarta/commons/proper/collections/trunk/RELEASE-NOTES.html
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/collections/trunk/RELEASE-NOTES.html?rev=348429&r1=348428&r2=348429&view=diff
==============================================================================
--- jakarta/commons/proper/collections/trunk/RELEASE-NOTES.html (original)
+++ jakarta/commons/proper/collections/trunk/RELEASE-NOTES.html Wed Nov 23 05:16:43 2005
@@ -58,6 +58,7 @@
 <li>DefaultedMap - Returns a default value when the key is not found, without adding the default value to the map itself [30911]</li>
 <li>GrowthList - Decorator that causes set and indexed add to expand the list rather than throw IndexOutOfBoundsException [34171]</li>
 <li>LoopingListIterator - When the end of the list is reached the iteration continues from the start [30166]</li>
+<li>BoundedBuffer - A new wrapper class which can make any buffer bounded [37473]</li>
 </ul>
 
 <center><h3>ENHANCEMENTS</h3></center>

Added: jakarta/commons/proper/collections/trunk/data/test/BoundedBuffer.emptyCollection.version3.2.obj
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/collections/trunk/data/test/BoundedBuffer.emptyCollection.version3.2.obj?rev=348429&view=auto
==============================================================================
Binary file - no diff available.

Propchange: jakarta/commons/proper/collections/trunk/data/test/BoundedBuffer.emptyCollection.version3.2.obj
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: jakarta/commons/proper/collections/trunk/data/test/BoundedBuffer.fullCollection.version3.2.obj
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/collections/trunk/data/test/BoundedBuffer.fullCollection.version3.2.obj?rev=348429&view=auto
==============================================================================
Binary file - no diff available.

Propchange: jakarta/commons/proper/collections/trunk/data/test/BoundedBuffer.fullCollection.version3.2.obj
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/BufferUtils.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/BufferUtils.java?rev=348429&r1=348428&r2=348429&view=diff
==============================================================================
--- jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/BufferUtils.java (original)
+++ jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/BufferUtils.java Wed Nov 23 05:16:43 2005
@@ -21,6 +21,7 @@
 import org.apache.commons.collections.buffer.TransformedBuffer;
 import org.apache.commons.collections.buffer.TypedBuffer;
 import org.apache.commons.collections.buffer.UnmodifiableBuffer;
+import org.apache.commons.collections.buffer.BoundedBuffer;
 
 /**
  * Provides utility methods and decorators for {@link Buffer} instances.
@@ -102,6 +103,33 @@
         return BlockingBuffer.decorate(buffer, timeout);
     }
 
+    /**
+     * Returns a synchronized buffer backed by the given buffer that will block on {@link Buffer#add(Object)} and
+     * {@link Buffer#addAll(java.util.Collection)} until enough object(s) are removed from the buffer to allow
+     * the object(s) to be added and still maintain the maximum size.
+     * @param buffer the buffer to make bounded
+     * @param maximumSize the maximum size
+     * @return a bounded buffer backed by the given buffer
+     * @throws IllegalArgumentException if the given buffer is null
+     */
+    public static Buffer boundedBuffer( Buffer buffer, int maximumSize ) {
+        return BoundedBuffer.decorate( buffer, maximumSize );
+    }
+
+    /**
+     * Returns a synchronized buffer backed by the given buffer that will block on {@link Buffer#add(Object)} and
+     * {@link Buffer#addAll(java.util.Collection)} until enough object(s) are removed from the buffer to allow
+     * the object(s) to be added and still maintain the maximum size or the timeout expires.
+     * @param buffer the buffer to make bounded
+     * @param maximumSize the maximum size
+     * @param timeout the maximum time to wait
+     * @return a bounded buffer backed by the given buffer
+     * @throws IllegalArgumentException if the given buffer is null
+     */
+    public static Buffer boundedBuffer( Buffer buffer, int maximumSize, long timeout ) {
+        return BoundedBuffer.decorate( buffer, maximumSize, timeout );
+    }
+    
     /**
      * Returns an unmodifiable buffer backed by the given buffer.
      *

Added: jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java?rev=348429&view=auto
==============================================================================
--- jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java (added)
+++ jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java Wed Nov 23 05:16:43 2005
@@ -0,0 +1,161 @@
+/*
+ *  Copyright 2001-2005 The Apache Software Foundation
+ *
+ *  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 org.apache.commons.collections.buffer;
+
+import org.apache.commons.collections.Buffer;
+import org.apache.commons.collections.BufferOverflowException;
+import org.apache.commons.collections.BufferUnderflowException;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * A wrapper class for buffers which makes them bounded.
+ * @author James Carman
+ * @since 3.2
+ */
+public class BoundedBuffer extends SynchronizedBuffer {
+
+    private static final long serialVersionUID = 1536432911093974264L;
+
+    private final int maximumSize;
+    private final long timeout;
+
+    /**
+     * Factory method to create a bounded buffer.
+     * @param buffer the buffer to decorate, must not be null
+     * @param maximumSize the maximum size
+     * @return a new bounded buffer
+     * @throws IllegalArgumentException if the buffer is null
+     */
+    public static Buffer decorate( Buffer buffer, int maximumSize ) {
+        return new BoundedBuffer( buffer, maximumSize );
+    }
+
+    /**
+     * Factory method to create a bounded buffer that blocks for a maximum
+     * amount of time.
+     * @param buffer the buffer to decorate, must not be null
+     * @param maximumSize the maximum size
+     * @param timeout the maximum amount of time to wait.
+     * @return a new bounded buffer
+     * @throws IllegalArgumentException if the buffer is null
+     */
+    public static Buffer decorate( Buffer buffer, int maximumSize, long timeout ) {
+        return new BoundedBuffer( buffer, maximumSize, timeout );
+    }
+
+    /**
+     * Constructor that wraps (not copies) another buffer, making it bounded.
+     * @param buffer the buffer to wrap, must not be null
+     * @param maximumSize the maximum size of the buffer
+     * @throws IllegalArgumentException if the buffer is null
+     */
+    protected BoundedBuffer( Buffer buffer, int maximumSize ) {
+        this( buffer, maximumSize, -1 );
+    }
+
+    /**
+     * 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
+     * @throws IllegalArgumentException if the buffer is null
+     */
+    protected BoundedBuffer( Buffer buffer, int maximumSize, long timeout ) {
+        super( buffer );
+        this.maximumSize = maximumSize;
+        this.timeout = timeout;
+    }
+
+    public Object remove() {
+        synchronized( lock ) {
+            Object returnValue = getBuffer().remove();
+            lock.notifyAll();
+            return returnValue;
+        }
+    }
+
+    public boolean add( Object o ) {
+        synchronized( lock ) {
+            timeoutWait( 1 );
+            return getBuffer().add( o );
+        }
+    }
+
+    public boolean addAll( final Collection c ) {
+        synchronized( lock ) {
+            timeoutWait( c.size() );
+            return getBuffer().addAll( c );
+        }
+    }
+
+    public Iterator iterator() {
+        return new NotifyingIterator( collection.iterator() );
+    }
+
+    private void timeoutWait( final int nAdditions ) {
+        synchronized( lock ) {
+            if( timeout < 0 && getBuffer().size() + 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( getBuffer().size() + nAdditions > maximumSize ) {
+                throw new BufferOverflowException( "Timeout expired." );
+            }
+        }
+    }
+
+    private class NotifyingIterator implements Iterator {
+
+        private final Iterator i;
+
+        public NotifyingIterator( Iterator i ) {
+            this.i = i;
+        }
+
+        public void remove() {
+            synchronized( lock ) {
+                i.remove();
+                lock.notifyAll();
+            }
+        }
+
+        public boolean hasNext() {
+            return i.hasNext();
+        }
+
+        public Object next() {
+            return i.next();
+        }
+    }
+}
+

Propchange: jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/collections/trunk/src/java/org/apache/commons/collections/buffer/BoundedBuffer.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/proper/collections/trunk/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/collections/trunk/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java?rev=348429&view=auto
==============================================================================
--- jakarta/commons/proper/collections/trunk/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java (added)
+++ jakarta/commons/proper/collections/trunk/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java Wed Nov 23 05:16:43 2005
@@ -0,0 +1,181 @@
+/*
+ *  Copyright 2001-2005 The Apache Software Foundation
+ *
+ *  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 org.apache.commons.collections.buffer;
+
+import org.apache.commons.collections.AbstractTestObject;
+import org.apache.commons.collections.Buffer;
+import org.apache.commons.collections.BufferOverflowException;
+
+import java.util.Iterator;
+import java.util.Collections;
+import java.util.Arrays;
+
+public class TestBoundedBuffer extends AbstractTestObject {
+
+    public TestBoundedBuffer( String testName ) {
+        super( testName );
+    }
+
+    public String getCompatibilityVersion() {
+        return "3.2";
+    }
+
+    public boolean isEqualsCheckable() {
+        return false;
+    }
+
+    public Object makeObject() {
+        return BoundedBuffer.decorate( new UnboundedFifoBuffer(), 1 );
+    }
+
+    public void testAddToFullBufferNoTimeout() {
+        final Buffer bounded = BoundedBuffer.decorate( new UnboundedFifoBuffer(), 1 );
+        bounded.add( "Hello" );
+        try {
+            bounded.add( "World" );
+            fail();
+        }
+        catch( BufferOverflowException e ) {
+        }
+    }
+
+    public void testAddAllToFullBufferNoTimeout() {
+        final Buffer bounded = BoundedBuffer.decorate( new UnboundedFifoBuffer(), 1 );
+        bounded.add( "Hello" );
+        try {
+            bounded.addAll( Collections.singleton( "World" ) );
+            fail();
+        }
+        catch( BufferOverflowException e ) {
+        }
+    }
+
+    public void testAddToFullBufferRemoveViaIterator() {
+        final Buffer bounded = BoundedBuffer.decorate( new UnboundedFifoBuffer(), 1, 500 );
+        bounded.add( "Hello" );
+        new DelayedIteratorRemove( bounded, 200 ).start();
+        bounded.add( "World" );
+        assertEquals( 1, bounded.size() );
+        assertEquals( "World", bounded.get() );
+
+    }
+
+    public void testAddAllToFullBufferRemoveViaIterator() {
+        final Buffer bounded = BoundedBuffer.decorate( new UnboundedFifoBuffer(), 2, 500 );
+        bounded.add( "Hello" );
+        bounded.add( "World" );
+        new DelayedIteratorRemove( bounded, 200, 2 ).start();
+        bounded.addAll( Arrays.asList( new String[] { "Foo", "Bar" } ) );
+        assertEquals( 2, bounded.size() );
+        assertEquals( "Foo", bounded.remove() );
+        assertEquals( "Bar", bounded.remove() );
+    }
+
+    public void testAddToFullBufferWithTimeout() {
+        final Buffer bounded = BoundedBuffer.decorate( new UnboundedFifoBuffer(), 1, 500 );
+        bounded.add( "Hello" );
+        new DelayedRemove( bounded, 200 ).start();
+        bounded.add( "World" );
+        assertEquals( 1, bounded.size() );
+        assertEquals( "World", bounded.get() );
+        try {
+            bounded.add( "!" );
+            fail();
+        }
+        catch( BufferOverflowException e ) {
+        }
+    }
+
+    public void testAddAllToFullBufferWithTimeout() {
+        final Buffer bounded = BoundedBuffer.decorate( new UnboundedFifoBuffer(), 2, 500 );
+        bounded.add( "Hello" );
+        bounded.add( "World" );
+        new DelayedRemove( bounded, 200, 2 ).start();
+
+        bounded.addAll( Arrays.asList( new String[] { "Foo", "Bar" } ) );
+        assertEquals( 2, bounded.size() );
+        assertEquals( "Foo", bounded.get() );
+        try {
+            bounded.add( "!" );
+            fail();
+        }
+        catch( BufferOverflowException e ) {
+        }
+    }
+
+    private class DelayedIteratorRemove extends Thread {
+
+        private final Buffer buffer;
+
+        private final long delay;
+
+        private final int nToRemove;
+
+        public DelayedIteratorRemove( Buffer buffer, long delay, int nToRemove ) {
+            this.buffer = buffer;
+            this.delay = delay;
+            this.nToRemove = nToRemove;
+        }
+
+        public DelayedIteratorRemove( Buffer buffer, long delay ) {
+            this( buffer, delay, 1 );
+        }
+
+        public void run() {
+            try {
+                Thread.sleep( delay );
+                Iterator iter = buffer.iterator();
+                for( int i = 0; i < nToRemove; ++i ) {
+                    iter.next();
+                    iter.remove();
+                }
+
+            }
+            catch( InterruptedException e ) {
+            }
+        }
+    }
+
+    private class DelayedRemove extends Thread {
+
+        private final Buffer buffer;
+
+        private final long delay;
+
+        private final int nToRemove;
+
+        public DelayedRemove( Buffer buffer, long delay, int nToRemove ) {
+            this.buffer = buffer;
+            this.delay = delay;
+            this.nToRemove = nToRemove;
+        }
+
+        public DelayedRemove( Buffer buffer, long delay ) {
+            this( buffer, delay, 1 );
+        }
+
+        public void run() {
+            try {
+                Thread.sleep( delay );
+                for( int i = 0; i < nToRemove; ++i ) {
+                    buffer.remove();
+                }
+            }
+            catch( InterruptedException e ) {
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: jakarta/commons/proper/collections/trunk/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/collections/trunk/src/test/org/apache/commons/collections/buffer/TestBoundedBuffer.java
------------------------------------------------------------------------------
    svn:keywords = Id



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org