package com.griddynamics.jagger.engine.e1.reporting;
import com.griddynamics.jagger.dbapi.DatabaseService;
import com.griddynamics.jagger.dbapi.dto.PlotIntegratedDto;
import com.griddynamics.jagger.dbapi.dto.PlotSingleDto;
import com.griddynamics.jagger.dbapi.dto.PointDto;
import com.griddynamics.jagger.dbapi.dto.TaskDataDto;
import com.griddynamics.jagger.dbapi.model.*;
import com.griddynamics.jagger.dbapi.util.SessionMatchingSetup;
import com.griddynamics.jagger.reporting.chart.ChartHelper;
import com.griddynamics.jagger.util.Pair;
import net.sf.jasperreports.renderers.JCommonDrawableRenderer;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import java.util.*;
public class PlotsReporter {
public static final Comparator<TestDetailsNode> BY_TASK_NAME = Comparator.comparing(TestDetailsNode::getDisplayName);
private Logger log = LoggerFactory.getLogger(PlotsReporter.class);
private DatabaseService databaseService;
private String sessionId;
private Map<Long, MetricPlotDTOs> testIdToPlotsMap;
private MetricPlotDTOs sessionScopePlots;
@Required
public void setDatabaseService(DatabaseService databaseService) {
this.databaseService = databaseService;
}
public MetricPlotDTOs getSessionScopePlots(String sessionId) {
getData(sessionId);
return sessionScopePlots;
}
public Map<Long, MetricPlotDTOs> getTestIdToPlotsMap(String sessionId) {
getData(sessionId);
return testIdToPlotsMap;
}
private void getData(String sessionId) {
if (sessionId.equals(this.sessionId)) {
// data already fetched
return;
}
// fetch data
this.sessionId = sessionId;
SessionMatchingSetup sessionMatchingSetup = new SessionMatchingSetup(
true,
EnumSet.of(SessionMatchingSetup.MatchBy.ALL));
RootNode controlTree = databaseService.getControlTreeForSessions(
new HashSet<>(Collections.singletonList(sessionId)),
sessionMatchingSetup);
Collections.sort(controlTree.getDetailsNode().getTests(), BY_TASK_NAME);
fetchSessionScopeData(controlTree);
fetchPerTestData(controlTree);
}
private void fetchPerTestData(RootNode controlTree) {
Set<MetricNode> allMetrics = new HashSet<MetricNode>();
DetailsNode detailsNode = controlTree.getDetailsNode();
if (detailsNode.getTests().isEmpty())
return;
for (TestDetailsNode testDetailsNode : detailsNode.getTests()) {
allMetrics.addAll(testDetailsNode.getMetrics());
}
try {
Map<MetricNode, PlotIntegratedDto> dataMap = databaseService.getPlotDataByMetricNode(allMetrics);
for (TestDetailsNode testDetailsNode : detailsNode.getTests()) {
TaskDataDto taskDataDto = testDetailsNode.getTaskDataDto();
getPlotsReport(
dataMap,
testDetailsNode,
new PerTestReportPlotHelper(taskDataDto.getId(), taskDataDto.getTaskName())
);
}
} catch (Exception e) {
log.error("Unable to get metrics plots information for session " + this.sessionId, e);
}
}
/**
* Populate sessionScopePlots field with data.
*
* @param controlTree data structure
*/
private void fetchSessionScopeData(RootNode controlTree) {
MetricGroupNode<PlotNode> sessionScopeNode = controlTree.getDetailsNode().getSessionScopeNode();
if (sessionScopeNode == null || sessionScopeNode.getChildren().isEmpty()) {
sessionScopePlots = null;
// no session scope plots
return;
}
Set<MetricNode> allMetrics = new HashSet<MetricNode>(sessionScopeNode.getMetrics());
try {
getPlotsReport(
databaseService.getPlotDataByMetricNode(allMetrics),
sessionScopeNode,
new SessionScopeReportPlotHelper());
} catch (Exception e) {
log.error("Unable to fetch session scope plots for metrics ", allMetrics);
}
}
private void getPlotsReport(
Map<MetricNode, PlotIntegratedDto> dataMap,
MetricGroupNode<? extends MetricNode> metricGroupNode,
ReportPlotHelper reportPlotHelper) {
if (metricGroupNode.getMetricGroupNodeList() != null) {
for (MetricGroupNode<? extends MetricNode> metricGroup : metricGroupNode.getMetricGroupNodeList())
getPlotsReport(dataMap, metricGroup, reportPlotHelper);
}
if (metricGroupNode.getMetricsWithoutChildren() != null) {
String groupTitle = metricGroupNode.getDisplayName();
for (MetricNode node : metricGroupNode.getMetricsWithoutChildren()) {
if (dataMap.get(node).getPlotSeries().isEmpty()) {
log.warn(reportPlotHelper.getEmptyPlotSeriesWarnMessage(node));
continue;
}
MetricPlotDTOs metricPlotDTOs = reportPlotHelper.getMetricPlotDTOs();
metricPlotDTOs.getMetricPlotDTOs().add(new MetricPlotDTO(
node.getDisplayName(),
node.getDisplayName(),
groupTitle,
makePlot(dataMap.get(node))));
groupTitle = "";
}
}
}
public static class MetricPlotDTOs {
private Collection<MetricPlotDTO> metricPlotDTOs;
public MetricPlotDTOs() {
metricPlotDTOs = new LinkedList<MetricPlotDTO>();
}
public Collection<MetricPlotDTO> getMetricPlotDTOs() {
return metricPlotDTOs;
}
public void setPlot(Collection<MetricPlotDTO> metricPlotDTOs) {
this.metricPlotDTOs = metricPlotDTOs;
}
}
public static class MetricPlotDTO {
private JCommonDrawableRenderer metricPlot;
private String metricName;
private String title;
private String groupTitle;
public MetricPlotDTO(String metricName, String title, String groupTitle, JCommonDrawableRenderer metricPlot) {
this.metricPlot = metricPlot;
this.metricName = metricName;
this.title = title;
this.groupTitle = groupTitle;
}
public MetricPlotDTO() {
}
public JCommonDrawableRenderer getMetricPlot() {
return metricPlot;
}
public void setMetricPlot(JCommonDrawableRenderer metricPlot) {
this.metricPlot = metricPlot;
}
public String getMetricName() {
return metricName;
}
public void setMetricName(String metricName) {
this.metricName = metricName;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getGroupTitle() {
return groupTitle;
}
public void setGroupTitle(String groupTitle) {
this.groupTitle = groupTitle;
}
}
/**
* Interface to use same function of plot generation for session scope and per test metrics (getPlotsReport(...))
*/
private interface ReportPlotHelper {
MetricPlotDTOs getMetricPlotDTOs();
String getEmptyPlotSeriesWarnMessage(MetricNode metricNode);
}
/**
* Use while session scope plot generation
*/
private class SessionScopeReportPlotHelper implements ReportPlotHelper {
@Override
public MetricPlotDTOs getMetricPlotDTOs() {
if (sessionScopePlots == null) {
sessionScopePlots = new MetricPlotDTOs();
}
return sessionScopePlots;
}
@Override
public String getEmptyPlotSeriesWarnMessage(MetricNode metricNode) {
return "No session scope plot data for metric " + metricNode.getDisplayName() + " in session " + sessionId;
}
}
/**
* Use while per test plot generation
*/
private class PerTestReportPlotHelper implements ReportPlotHelper {
private final Long testId;
private final String testName;
public PerTestReportPlotHelper(Long testId, String testName) {
this.testId = testId;
this.testName = testName;
}
@Override
public MetricPlotDTOs getMetricPlotDTOs() {
if (testIdToPlotsMap == null) {
testIdToPlotsMap = new HashMap<Long, MetricPlotDTOs>();
}
if (!testIdToPlotsMap.containsKey(testId))
testIdToPlotsMap.put(testId, new MetricPlotDTOs());
return testIdToPlotsMap.get(testId);
}
@Override
public String getEmptyPlotSeriesWarnMessage(MetricNode metricNode) {
return "No plot data for metric " + metricNode.getDisplayName() + " in test " + testName + " in session " + sessionId;
}
}
private JCommonDrawableRenderer makePlot(PlotIntegratedDto plotIntegratedDto) {
XYSeriesCollection plotCollection = new XYSeriesCollection();
for (PlotSingleDto datasetDto : plotIntegratedDto.getPlotSeries()) {
XYSeries plotEntry = new XYSeries(datasetDto.getLegend());
for (PointDto point : datasetDto.getPlotData()) { // draw one line
plotEntry.add(point.getX(), point.getY());
}
plotCollection.addSeries(plotEntry);
}
Pair<String, XYSeriesCollection> pair = ChartHelper.adjustTime(plotCollection, null);
plotCollection = pair.getSecond();
JFreeChart chartMetric = ChartHelper.createXYChart(null, plotCollection,
plotIntegratedDto.getXAxisLabel(), null, 2, 2, ChartHelper.ColorTheme.LIGHT);
return new JCommonDrawableRenderer(chartMetric);
}
}