FetchChartDataHandler implements
    ActionHandler<FetchChartData, FetchChartData.Result> { protected List<DataPoint> downsample(long duration, Aggregator aggregator, List<DataPoint> points) { List<DataPoint> result = Lists.newArrayList(); int offset = 0; long maxSampleTimestamp = 0; for (int i = 0; i < points.size(); i++) { DataPoint dataPoint = points.get(i); if (dataPoint.getTimestamp() > maxSampleTimestamp) { if (i > offset) { result.add(aggregator.aggregate(points, offset, i)); } offset = i; long timestampDelta = dataPoint.getTimestamp() - maxSampleTimestamp; maxSampleTimestamp += Math.ceil((double)timestampDelta / duration) * duration; } } if (points.size() > offset) { result.add(aggregator.aggregate(points, offset, points.size())); } return result; }  @Override FetchChartData.Result execute(FetchChartData action, ExecutionContext context); @Override Class<FetchChartData> getActionType(); @Override void undo(FetchChartData action, FetchChartData.Result result, ExecutionContext context);  }
@Test public void downsample() { FetchChartDataHandler handler = new FetchChartDataHandler(); List<DataPoint> points = Lists.newArrayList(); for (int i = 0; i < 10; i++) { points.add(new DataPoint(i, i * 10)); } List<DataPoint> downsampledPoints = handler.downsample(3, new Aggregators.AvgAggregator(), points); assertEquals(downsampledPoints, Lists.newArrayList( new DataPoint(0, 0), new DataPoint(2, 20), new DataPoint(5, 50), new DataPoint(8, 80))); }