killbill-uncached
Changes
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/AnalyticsServlet.java 6(+5 -1)
Details
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/AnalyticsServlet.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/AnalyticsServlet.java
index f6c3254..fbef095 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/AnalyticsServlet.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/AnalyticsServlet.java
@@ -45,6 +45,7 @@ import com.ning.billing.util.callcontext.UserType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Objects;
+import com.google.common.base.Strings;
import com.google.common.io.Resources;
public class AnalyticsServlet extends HttpServlet {
@@ -175,8 +176,11 @@ public class AnalyticsServlet extends HttpServlet {
return;
}
+ final LocalDate startDate = Strings.emptyToNull(req.getParameter(QUERY_START_DATE)) != null ? DATE_FORMAT.parseLocalDate(req.getParameter(QUERY_START_DATE)) : null;
+ final LocalDate endDate = Strings.emptyToNull(req.getParameter(QUERY_END_DATE)) != null ? DATE_FORMAT.parseLocalDate(req.getParameter(QUERY_END_DATE)) : null;
+
// TODO PIERRE Switch to an equivalent of StreamingOutputStream?
- final List<NamedXYTimeSeries> result = reportsUserApi.getTimeSeriesDataForReport(reportNames);
+ final List<NamedXYTimeSeries> result = reportsUserApi.getTimeSeriesDataForReport(reportNames, startDate, endDate);
resp.getOutputStream().write(mapper.writeValueAsBytes(result));
resp.setContentType("application/json");
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/reports/ReportsUserApi.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/reports/ReportsUserApi.java
index 02f317a..945bd54 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/reports/ReportsUserApi.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/reports/ReportsUserApi.java
@@ -19,12 +19,17 @@ package com.ning.billing.osgi.bundles.analytics.reports;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.IDBI;
@@ -34,8 +39,12 @@ import com.ning.billing.osgi.bundles.analytics.json.NamedXYTimeSeries;
import com.ning.billing.osgi.bundles.analytics.json.XY;
import com.ning.killbill.osgi.libs.killbill.OSGIKillbillDataSource;
+import com.google.common.collect.Ordering;
+
public class ReportsUserApi {
+ private static final String NO_PIVOT = "____NO_PIVOT____";
+
private final IDBI dbi;
private final ReportsConfiguration reportsConfiguration;
@@ -46,49 +55,87 @@ public class ReportsUserApi {
}
public List<NamedXYTimeSeries> getTimeSeriesDataForReport(final String[] reportNames) {
- final Map<String, List<XY>> dataForReports = new LinkedHashMap<String, List<XY>>();
+ return getTimeSeriesDataForReport(reportNames, null, null);
+ }
+
+ public List<NamedXYTimeSeries> getTimeSeriesDataForReport(final String[] reportNames, @Nullable final LocalDate startDate, @Nullable final LocalDate endDate) {
+ // Mapping of report name -> pivots -> data
+ final Map<String, Map<String, List<XY>>> dataForReports = new LinkedHashMap<String, Map<String, List<XY>>>();
// TODO parallel
for (final String reportName : reportNames) {
final String tableName = reportsConfiguration.getTableNameForReport(reportName);
if (tableName != null) {
- final List<XY> data = getData(tableName);
+ final Map<String, List<XY>> data = getData(tableName);
dataForReports.put(reportName, data);
}
}
normalizeXValues(dataForReports);
+ filterValues(dataForReports, startDate, endDate);
final List<NamedXYTimeSeries> results = new LinkedList<NamedXYTimeSeries>();
for (final String reportName : dataForReports.keySet()) {
- results.add(new NamedXYTimeSeries(reportsConfiguration.getPrettyNameForReport(reportName), dataForReports.get(reportName)));
+ // Sort the pivots by name for a consistent display in the dashboard
+ for (final String pivotName : Ordering.natural().sortedCopy(dataForReports.get(reportName).keySet())) {
+ final String timeSeriesName;
+ if (NO_PIVOT.equals(pivotName)) {
+ timeSeriesName = reportsConfiguration.getPrettyNameForReport(reportName);
+ } else {
+ timeSeriesName = String.format("%s (%s)", reportsConfiguration.getPrettyNameForReport(reportName), pivotName);
+ }
+
+ final List<XY> timeSeries = dataForReports.get(reportName).get(pivotName);
+ results.add(new NamedXYTimeSeries(timeSeriesName, timeSeries));
+ }
}
return results;
}
- private void normalizeXValues(final Map<String, List<XY>> dataForReports) {
+ private void filterValues(final Map<String, Map<String, List<XY>>> dataForReports, @Nullable final LocalDate startDate, @Nullable final LocalDate endDate) {
+ for (final Map<String, List<XY>> dataForReport : dataForReports.values()) {
+ for (final List<XY> dataForPivot : dataForReport.values()) {
+ final Iterator<XY> iterator = dataForPivot.iterator();
+ while (iterator.hasNext()) {
+ final XY xy = iterator.next();
+ if (startDate != null && new DateTime(xy.getX(), DateTimeZone.UTC).toLocalDate().isBefore(startDate) ||
+ endDate != null && new DateTime(xy.getX(), DateTimeZone.UTC).toLocalDate().isAfter(endDate)) {
+ iterator.remove();
+ }
+ }
+ }
+ }
+ }
+
+ private void normalizeXValues(final Map<String, Map<String, List<XY>>> dataForReports) {
final Set<String> xValues = new HashSet<String>();
- for (final List<XY> dataForReport : dataForReports.values()) {
- for (final XY xy : dataForReport) {
- xValues.add(xy.getX());
+ for (final Map<String, List<XY>> dataForReport : dataForReports.values()) {
+ for (final List<XY> dataForPivot : dataForReport.values()) {
+ for (final XY xy : dataForPivot) {
+ xValues.add(xy.getX());
+ }
}
}
- for (final List<XY> dataForReport : dataForReports.values()) {
- for (final String x : xValues) {
- if (!hasX(dataForReport, x)) {
- dataForReport.add(new XY(x, 0));
+ for (final Map<String, List<XY>> dataForReport : dataForReports.values()) {
+ for (final List<XY> dataForPivot : dataForReport.values()) {
+ for (final String x : xValues) {
+ if (!hasX(dataForPivot, x)) {
+ dataForPivot.add(new XY(x, 0));
+ }
}
}
}
for (final String reportName : dataForReports.keySet()) {
- Collections.sort(dataForReports.get(reportName), new Comparator<XY>() {
- @Override
- public int compare(final XY o1, final XY o2) {
- return new LocalDate(o1.getX()).compareTo(new LocalDate(o2.getX()));
- }
- });
+ for (final String pivotName : dataForReports.get(reportName).keySet()) {
+ Collections.sort(dataForReports.get(reportName).get(pivotName), new Comparator<XY>() {
+ @Override
+ public int compare(final XY o1, final XY o2) {
+ return new DateTime(o1.getX(), DateTimeZone.UTC).compareTo(new DateTime(o2.getX(), DateTimeZone.UTC));
+ }
+ });
+ }
}
}
@@ -101,13 +148,13 @@ public class ReportsUserApi {
return false;
}
- private List<XY> getData(final String tableName) {
- final List<XY> timeSeries = new LinkedList<XY>();
+ private Map<String, List<XY>> getData(final String tableName) {
+ final Map<String, List<XY>> timeSeries = new LinkedHashMap<String, List<XY>>();
Handle handle = null;
try {
handle = dbi.open();
- final List<Map<String, Object>> results = handle.select("select day, count from " + tableName);
+ final List<Map<String, Object>> results = handle.select("select * from " + tableName);
for (final Map<String, Object> row : results) {
if (row.get("day") == null || row.get("count") == null) {
continue;
@@ -115,7 +162,20 @@ public class ReportsUserApi {
final String date = row.get("day").toString();
final Float value = Float.valueOf(row.get("count").toString());
- timeSeries.add(new XY(date, value));
+
+ if (row.keySet().size() == 2) {
+ // No pivot
+ if (timeSeries.get(NO_PIVOT) == null) {
+ timeSeries.put(NO_PIVOT, new LinkedList<XY>());
+ }
+ timeSeries.get(NO_PIVOT).add(new XY(date, value));
+ } else if (row.get("pivot") != null) {
+ final String pivot = row.get("pivot").toString();
+ if (timeSeries.get(pivot) == null) {
+ timeSeries.put(pivot, new LinkedList<XY>());
+ }
+ timeSeries.get(pivot).add(new XY(date, value));
+ }
}
} finally {
if (handle != null) {
diff --git a/osgi-bundles/bundles/analytics/src/main/resources/static/analytics.html b/osgi-bundles/bundles/analytics/src/main/resources/static/analytics.html
index acae4a1..fa59a85 100644
--- a/osgi-bundles/bundles/analytics/src/main/resources/static/analytics.html
+++ b/osgi-bundles/bundles/analytics/src/main/resources/static/analytics.html
@@ -65,19 +65,29 @@
}
// Get the data for a set of reports
- function doGetData(position, reports, fn) {
- var request_url = "http://" + $VAR_SERVER + ":" + $VAR_PORT + "/plugins/killbill-analytics/reports?name=" + reports.join("&name=");
+ function doGetData(position, reports, from, to, fn) {
+ var request_url = "http://" + $VAR_SERVER + ":" + $VAR_PORT + "/plugins/killbill-analytics/reports?startDate=" + from + "&endDate=" + to + "&name=" + reports.join("&name=");
return $.ajax({
type: "GET",
contentType: "application/json",
+ dataType: "json",
url: request_url
- }).done(function(data) { fn(position, reports, data); })
+ }).done(function(data) { console.log(typeof data); fn(position, reports, data); })
.fail(function(jqXHR, textStatus) { alert("Request failed: " + textStatus); });
}
// The URL structure is expected to be in the form: analytics.html?report1=new_trials_per_day&report1=cancellations_per_day&report2=conversions_per_day
$(document).ready(function() {
+ var from = $.url().param('startDate');
+ if (!from) {
+ from = '';
+ }
+ var to = $.url().param('endDate');
+ if (!to) {
+ to = '';
+ }
+
// Map of position (starting from the top) to an array of reports
var reports = {}
for (var i = 1; i < 10; i++) {
@@ -104,9 +114,10 @@
var futuresData = {}
for (var position in reports) {
// Fetch the data
- var future = doGetData(position, reports[position], function(zePosition, reports, reportsData) {
+ var future = doGetData(position, reports[position], from, to, function(zePosition, reports, reportsData) {
+ console.log(typeof reportsData);
if (!(reportsData instanceof Array) || reportsData.length == 0) {
- futuresData[zePosition] = [ { "name": "No data", "values": [] }];
+ futuresData[zePosition] = [ { "name": "No data", "values": [] } ];
} else {
futuresData[zePosition] = reportsData;
}