package bandwidth;
import bandwidth.listener.NullUsageListener;
import bandwidth.listener.UsageListenerInterface;
import bandwidth.window.Flusher;
import bandwidth.window.WindowManagerInterface;
public abstract class AbstractBandwidthController implements WindowManagerInterface
{
private volatile int totalBandwidth;
private volatile int availableBandwidth;
private volatile int availableBytes;
private volatile UsageListenerInterface listener;
private volatile int bytesProducedInLastWindow;
private volatile Flusher flusher;
protected AbstractBandwidthController(int totalBandwidth)
{
this.totalBandwidth = totalBandwidth;
this.availableBandwidth = totalBandwidth;
availableBytes = 0;
listener = new NullUsageListener();
bytesProducedInLastWindow = 0;
flusher = new Flusher(this);
}
protected void startFlusher()
{
flusher.start();
}
public void setTotalBandwidth(int value)
{
if (value < availableBandwidth)
{
setAvailableBandwidth(value);
}
totalBandwidth = value;
listener.setMaximumValue(value);
}
public void setAvailableBandwidth(int value)
{
if (value > totalBandwidth)
{
value = totalBandwidth;
}
availableBandwidth = value;
listener.setLimitValue(value);
}
public void setUsageListener(UsageListenerInterface listener)
{
this.listener = listener;
listener.setMaximumValue(totalBandwidth);
listener.setLimitValue(availableBandwidth);
}
public void produce()
{
produce(1);
}
public synchronized int produce(int request)
{
int produced = 0;
waitAvailableBytes();
if (availableBytes < request)
{
produced = availableBytes;
availableBytes = 0;
}
else
{
availableBytes -= request;
produced = request;
}
bytesProducedInLastWindow += produced;
return produced;
}
private void waitAvailableBytes()
{
while (!(availableBytes > 0))
{
flusher.waitFlush();
}
}
protected int getAvailableBandwidth()
{
return availableBandwidth;
}
public abstract void resetWindow();
protected void resetAvailableBytes()
{
resetAvailableBytesTo(availableBandwidth);
}
protected void resetAvailableBytesTo(int value)
{
availableBytes = value;
}
protected void updateListener()
{
listener.notifyOfUsage(bytesProducedInLastWindow);
bytesProducedInLastWindow = 0;
}
}