package de.skuzzle.polly.tools.io; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; public class BandwidthOutputStream extends FilterOutputStream implements StrategyChangedListener { private AllocationStrategy strategy; private final SpeedHelper speedHelper; private BandwidthManager manager; public BandwidthOutputStream(OutputStream stream, int maxBytesPerSecond) { this(stream, new IntervalAllocationStrategy(maxBytesPerSecond, 1000)); } public BandwidthOutputStream(OutputStream stream, AllocationStrategy strategy) { super(stream); if (strategy == null) { throw new NullPointerException(); } this.strategy = strategy; this.speedHelper = new SpeedHelper(); } BandwidthOutputStream(OutputStream stream, AllocationStrategy strategy, BandwidthManager manager) { this(stream, strategy); this.manager = manager; } @Override public void strategyChanged(StrategyChangedEvent e) { this.strategy.consumerFinished(this); this.strategy = e.getNewStrategy(); this.strategy.registerConsumer(this); } public double getSpeed() { return this.speedHelper.calculateAvgSpeed(); } @Override public void write(int b) throws IOException { final long start = System.currentTimeMillis(); if (this.strategy.allocate(this, 1) == 1) { this.out.write(b); } final double time = (double) (System.currentTimeMillis() - start); this.speedHelper.record(1.0 / time); } @Override public void write(byte[] b) throws IOException { this.write(b, 0, b.length); } @Override public void write(byte[] b, int off, int len) throws IOException { int l = len; int allocated = 0; final long start = System.currentTimeMillis(); do { l = this.strategy.allocate(this, len - allocated); this.out.write(b, off + allocated, l); allocated += l; } while (allocated < len); final double time = (double) (System.currentTimeMillis() - start); this.speedHelper.record((double) len / time); } @Override public void close() throws IOException { this.strategy.consumerFinished(this); if (this.manager != null) { this.manager.removeOutputStrategyChangedListener(this); } super.close(); } }