aboutsummaryrefslogtreecommitdiff
path: root/subsonic-main/src/main/java/net/sourceforge/subsonic/controller/StatusChartController.java
diff options
context:
space:
mode:
Diffstat (limited to 'subsonic-main/src/main/java/net/sourceforge/subsonic/controller/StatusChartController.java')
-rw-r--r--subsonic-main/src/main/java/net/sourceforge/subsonic/controller/StatusChartController.java149
1 files changed, 149 insertions, 0 deletions
diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/controller/StatusChartController.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/controller/StatusChartController.java
new file mode 100644
index 00000000..878b8ae8
--- /dev/null
+++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/controller/StatusChartController.java
@@ -0,0 +1,149 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2009 (C) Sindre Mehus
+ */
+package net.sourceforge.subsonic.controller;
+
+import net.sourceforge.subsonic.domain.*;
+import net.sourceforge.subsonic.service.*;
+import org.jfree.chart.*;
+import org.jfree.chart.axis.*;
+import org.jfree.chart.plot.*;
+import org.jfree.chart.renderer.xy.*;
+import org.jfree.data.*;
+import org.jfree.data.time.*;
+import org.springframework.web.servlet.*;
+
+import javax.servlet.http.*;
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+/**
+ * Controller for generating a chart showing bitrate vs time.
+ *
+ * @author Sindre Mehus
+ */
+public class StatusChartController extends AbstractChartController {
+
+ private StatusService statusService;
+
+ public static final int IMAGE_WIDTH = 350;
+ public static final int IMAGE_HEIGHT = 150;
+
+ public synchronized ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
+ String type = request.getParameter("type");
+ int index = Integer.parseInt(request.getParameter("index"));
+
+ List<TransferStatus> statuses = Collections.emptyList();
+ if ("stream".equals(type)) {
+ statuses = statusService.getAllStreamStatuses();
+ } else if ("download".equals(type)) {
+ statuses = statusService.getAllDownloadStatuses();
+ } else if ("upload".equals(type)) {
+ statuses = statusService.getAllUploadStatuses();
+ }
+
+ if (index < 0 || index >= statuses.size()) {
+ return null;
+ }
+ TransferStatus status = statuses.get(index);
+
+ TimeSeries series = new TimeSeries("Kbps", Millisecond.class);
+ TransferStatus.SampleHistory history = status.getHistory();
+ long to = System.currentTimeMillis();
+ long from = to - status.getHistoryLengthMillis();
+ Range range = new DateRange(from, to);
+
+ if (!history.isEmpty()) {
+
+ TransferStatus.Sample previous = history.get(0);
+
+ for (int i = 1; i < history.size(); i++) {
+ TransferStatus.Sample sample = history.get(i);
+
+ long elapsedTimeMilis = sample.getTimestamp() - previous.getTimestamp();
+ long bytesStreamed = Math.max(0L, sample.getBytesTransfered() - previous.getBytesTransfered());
+
+ double kbps = (8.0 * bytesStreamed / 1024.0) / (elapsedTimeMilis / 1000.0);
+ series.addOrUpdate(new Millisecond(new Date(sample.getTimestamp())), kbps);
+
+ previous = sample;
+ }
+ }
+
+ // Compute moving average.
+ series = MovingAverage.createMovingAverage(series, "Kbps", 20000, 5000);
+
+ // Find min and max values.
+ double min = 100;
+ double max = 250;
+ for (Object obj : series.getItems()) {
+ TimeSeriesDataItem item = (TimeSeriesDataItem) obj;
+ double value = item.getValue().doubleValue();
+ if (item.getPeriod().getFirstMillisecond() > from) {
+ min = Math.min(min, value);
+ max = Math.max(max, value);
+ }
+ }
+
+ // Add 10% to max value.
+ max *= 1.1D;
+
+ // Subtract 10% from min value.
+ min *= 0.9D;
+
+ TimeSeriesCollection dataset = new TimeSeriesCollection();
+ dataset.addSeries(series);
+ JFreeChart chart = ChartFactory.createTimeSeriesChart(null, null, null, dataset, false, false, false);
+ XYPlot plot = (XYPlot) chart.getPlot();
+
+ plot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
+ Paint background = new GradientPaint(0, 0, Color.lightGray, 0, IMAGE_HEIGHT, Color.white);
+ plot.setBackgroundPaint(background);
+
+ XYItemRenderer renderer = plot.getRendererForDataset(dataset);
+ renderer.setSeriesPaint(0, Color.blue.darker());
+ renderer.setSeriesStroke(0, new BasicStroke(2f));
+
+ // Set theme-specific colors.
+ Color bgColor = getBackground(request);
+ Color fgColor = getForeground(request);
+
+ chart.setBackgroundPaint(bgColor);
+
+ ValueAxis domainAxis = plot.getDomainAxis();
+ domainAxis.setRange(range);
+ domainAxis.setTickLabelPaint(fgColor);
+ domainAxis.setTickMarkPaint(fgColor);
+ domainAxis.setAxisLinePaint(fgColor);
+
+ ValueAxis rangeAxis = plot.getRangeAxis();
+ rangeAxis.setRange(new Range(min, max));
+ rangeAxis.setTickLabelPaint(fgColor);
+ rangeAxis.setTickMarkPaint(fgColor);
+ rangeAxis.setAxisLinePaint(fgColor);
+
+ ChartUtilities.writeChartAsPNG(response.getOutputStream(), chart, IMAGE_WIDTH, IMAGE_HEIGHT);
+
+ return null;
+ }
+
+ public void setStatusService(StatusService statusService) {
+ this.statusService = statusService;
+ }
+}