package org.openamq.client.util;
import edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue;
import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
/**
* A blocking queue that emits events above a user specified threshold allowing
* the caller to take action (e.g. flow control) to try to prevent the queue
* growing (much) further. The underlying queue itself is not bounded therefore
* the caller is not obliged to react to the events.
* <p/>
* This implementation is <b>only</b> safe where we have a single thread adding
* items and a single (different) thread removing items.
*
*/
public class FlowControllingBlockingQueue
{
/**
* This queue is bounded and is used to store messages before being dispatched to the consumer
*/
private final BlockingQueue _queue = new LinkedBlockingQueue();
private final int _flowControlThreshold;
private final ThresholdListener _listener;
/**
* We require a separate count so we can track whether we have reached the
* threshold
*/
private int _count;
public interface ThresholdListener
{
void aboveThreshold(int currentValue);
void underThreshold(int currentValue);
}
public FlowControllingBlockingQueue(int threshold, ThresholdListener listener)
{
_flowControlThreshold = threshold;
_listener = listener;
}
public Object take() throws InterruptedException
{
Object o = _queue.take();
synchronized (_listener)
{
if (--_count == (_flowControlThreshold - 1))
{
_listener.underThreshold(_count);
}
}
return o;
}
public void add(Object o)
{
_queue.add(o);
synchronized (_listener)
{
if (++_count == _flowControlThreshold)
{
_listener.aboveThreshold(_count);
}
}
}
}