class ExponentialAverageRetryStatistics extends DefaultRetryStatistics {

	private long window = 15000;

	private ExponentialAverage started;

	private ExponentialAverage error;

	private ExponentialAverage complete;

	private ExponentialAverage recovery;

	private ExponentialAverage abort;

	public ExponentialAverageRetryStatistics(String name) {
		super(name);
		init();
	}

	private void init() {
		started = new ExponentialAverage(window);
		error = new ExponentialAverage(window);
		complete = new ExponentialAverage(window);
		abort = new ExponentialAverage(window);
		recovery = new ExponentialAverage(window);
	}

	/**
	 * Window in milliseconds for exponential decay factor in rolling average.
	 * @param window the window to set
	 */
	public void setWindow(long window) {
		this.window = window;
		init();
	}

	public int getRollingStartedCount() {
		return (int) Math.round(started.getValue());
	}

	public int getRollingErrorCount() {
		return (int) Math.round(error.getValue());
	}

	public int getRollingAbortCount() {
		return (int) Math.round(abort.getValue());
	}

	public int getRollingRecoveryCount() {
		return (int) Math.round(recovery.getValue());
	}

	public int getRollingCompleteCount() {
		return (int) Math.round(complete.getValue());
	}

	public double getRollingErrorRate() {<FILL_FUNCTION_BODY>}

	@Override
	public void incrementStartedCount() {
		super.incrementStartedCount();
		started.increment();
	}

	@Override
	public void incrementCompleteCount() {
		super.incrementCompleteCount();
		complete.increment();
	}

	@Override
	public void incrementRecoveryCount() {
		super.incrementRecoveryCount();
		recovery.increment();
	}

	@Override
	public void incrementErrorCount() {
		super.incrementErrorCount();
		error.increment();
	}

	@Override
	public void incrementAbortCount() {
		super.incrementAbortCount();
		abort.increment();
	}

	private class ExponentialAverage {

		private final double alpha;

		private volatile long lastTime = System.currentTimeMillis();

		private volatile double value = 0;

		public ExponentialAverage(long window) {
			alpha = 1. / window;
		}

		public synchronized void increment() {
			long time = System.currentTimeMillis();
			value = value * Math.exp(-alpha * (time - lastTime)) + 1;
			lastTime = time;
		}

		public double getValue() {
			long time = System.currentTimeMillis();
			return value * Math.exp(-alpha * (time - lastTime));
		}

	}

}

		if (Math.round(started.getValue()) == 0) {
			return 0.;
		}
		return (abort.getValue() + recovery.getValue()) / started.getValue();
	
<methods>public void <init>(java.lang.String) ,public int getAbortCount() ,public int getCompleteCount() ,public int getErrorCount() ,public java.lang.String getName() ,public int getRecoveryCount() ,public int getStartedCount() ,public void incrementAbortCount() ,public void incrementCompleteCount() ,public void incrementErrorCount() ,public void incrementRecoveryCount() ,public void incrementStartedCount() ,public void setName(java.lang.String) ,public java.lang.String toString() <variables>private final java.util.concurrent.atomic.AtomicInteger abortCount,private final java.util.concurrent.atomic.AtomicInteger completeCount,private final java.util.concurrent.atomic.AtomicInteger errorCount,private java.lang.String name,private final java.util.concurrent.atomic.AtomicInteger recoveryCount,private final java.util.concurrent.atomic.AtomicInteger startedCount