io.yields.plugins.kpi.KPIReportProjectAction.java Source code

Java tutorial

Introduction

Here is the source code for io.yields.plugins.kpi.KPIReportProjectAction.java

Source

/*
 * Copyright 2014 by Yields.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.yields.plugins.kpi;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.CompareToBuilder;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.CategoryDataset;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

import java.awt.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.util.DataSetBuilder;
import hudson.util.Graph;
import io.yields.math.framework.kpi.ScoreResult;

import static io.yields.plugins.kpi.LocalMessages.PROJECT_ACTION_DISPLAY_NAME;
import static java.util.Collections.sort;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;

/**
 * Project action showing the overall trend of KPIs for multiple builds.
 */
public class KPIReportProjectAction implements Action {

    private static final String PLUGIN_NAME = "yields-dashboard";

    private final AbstractProject<?, ?> project;
    private KPIReportConfig config;

    public KPIReportProjectAction(final AbstractProject project, final KPIReportConfig config) {
        this.project = project;
        this.config = config;
    }

    public String getDisplayName() {
        return PROJECT_ACTION_DISPLAY_NAME.toString();
    }

    public String getUrlName() {
        return PLUGIN_NAME;
    }

    public String getIconFileName() {
        return "/plugin/kpis/yields.png";
    }

    /**
     * Method necessary to get the side-panel included in the Jelly file
     *
     * @return this {@link hudson.model.AbstractProject}
     */
    public AbstractProject<?, ?> getProject() {
        return this.project;
    }

    public boolean showSummary() {
        return isNotEmpty(getKPIReports());
    }

    public List<KPIReport> getKPIReportsForDetail() {

        List<KPIReport> kpiReports = getKPIReports();
        if (kpiReports.size() > config.getDetailSize()) {
            kpiReports = kpiReports.subList(kpiReports.size() - config.getDetailSize(), kpiReports.size());
        }

        return kpiReports;
    }

    public List<KPIReport> getKPIReports() {

        final List<KPIReport> kpiReports = new ArrayList<KPIReport>();

        if (null == this.project) {
            return kpiReports;
        }

        final List<? extends AbstractBuild<?, ?>> builds = project.getBuilds();
        int count = 0;
        for (AbstractBuild<?, ?> currentBuild : builds) {

            if (count > config.getTrendSize()) {
                break;
            }

            final KPIReportBuildAction buildAction = currentBuild.getAction(KPIReportBuildAction.class);

            if (buildAction == null) {
                // try previous build
                continue;
            }

            final KPIReport report = buildAction.getBuildActionResultsDisplay().getKPIReport();
            if (report == null) {
                break;
            }

            kpiReports.add(report);
            count++;

        }

        sort(kpiReports, new Comparator<KPIReport>() {
            @Override
            public int compare(KPIReport kpiReport, KPIReport other) {
                return new CompareToBuilder().append(kpiReport.getBuildNumber(), other.getBuildNumber())
                        .toComparison();
            }
        });

        return kpiReports;
    }

    public void doSummaryGraph(final StaplerRequest request, final StaplerResponse response) throws IOException {

        final Integer width = getOrElse(request, "width", 400);
        final Integer height = getOrElse(request, "height", 300);

        final Graph graph = new KPIGraph("", width, height) {

            protected DataSetBuilder<String, Integer> createDataSet() {
                DataSetBuilder<String, Integer> dataSetBuilder = new DataSetBuilder<String, Integer>();

                List<KPIReport> kpiReports = getKPIReports();

                Map<Integer, Map<String, ScoreResult>> testResults = new TreeMap<Integer, Map<String, ScoreResult>>();

                if (CollectionUtils.isNotEmpty(kpiReports)) {

                    for (KPIReport kpiReport : kpiReports) {
                        int buildNumber = kpiReport.getBuildAction().getBuild().getNumber();
                        Map<String, ScoreResult> buildScores = testResults.get(buildNumber);
                        if (buildScores == null) {
                            buildScores = new HashMap<String, ScoreResult>();
                            testResults.put(buildNumber, buildScores);
                        }

                        for (String kpiName : kpiReport.getKpiScoreNames()) {
                            ScoreResult kpiScore = kpiReport.getKpiScore(kpiName);
                            if (kpiScore.isOfficial()) {
                                buildScores.put(kpiName, kpiScore);
                            }
                        }
                    }
                }

                for (Map.Entry<Integer, Map<String, ScoreResult>> entry : testResults.entrySet()) {
                    Integer buildNumber = entry.getKey();
                    Map<String, ScoreResult> buildScores = entry.getValue();
                    for (Map.Entry<String, ScoreResult> buildEntry : buildScores.entrySet()) {
                        dataSetBuilder.add(buildEntry.getValue().getScore(), buildEntry.getKey(), buildNumber);
                    }
                }

                return dataSetBuilder;
            }
        };

        graph.doPng(request, response);
    }

    public void doTrendGraph(final StaplerRequest request, final StaplerResponse response) throws IOException {

        final Integer width = getOrElse(request, "width", 400);
        final Integer height = getOrElse(request, "height", 300);

        final Graph graph = new KPIGraph("", width, height) {

            protected DataSetBuilder<String, Integer> createDataSet() {
                DataSetBuilder<String, Integer> dataSetBuilder = new DataSetBuilder<String, Integer>();

                List<KPIReport> kpiReports = getKPIReports();

                Map<Integer, Map<String, ScoreResult>> testResults = new TreeMap<Integer, Map<String, ScoreResult>>();

                if (CollectionUtils.isNotEmpty(kpiReports)) {

                    for (KPIReport kpiReport : kpiReports) {
                        int buildNumber = kpiReport.getBuildAction().getBuild().getNumber();
                        Map<String, ScoreResult> buildScores = testResults.get(buildNumber);
                        if (buildScores == null) {
                            buildScores = new HashMap<String, ScoreResult>();
                            testResults.put(buildNumber, buildScores);
                        }

                        for (String kpiName : kpiReport.getKpiScoreNames()) {
                            ScoreResult kpiScore = kpiReport.getKpiScore(kpiName);
                            if (kpiScore.isOfficial()) {
                                buildScores.put(kpiName, kpiScore);
                            }
                        }
                    }
                }

                for (Map.Entry<Integer, Map<String, ScoreResult>> entry : testResults.entrySet()) {
                    Integer buildNumber = entry.getKey();
                    Map<String, ScoreResult> buildScores = entry.getValue();
                    for (Map.Entry<String, ScoreResult> buildEntry : buildScores.entrySet()) {
                        dataSetBuilder.add(buildEntry.getValue().getScore(), buildEntry.getKey(), buildNumber);
                    }
                }

                return dataSetBuilder;
            }
        };

        graph.doPng(request, response);
    }

    private Integer getOrElse(StaplerRequest request, String parameterName, int defaultValue) {
        String value = request.getParameter(parameterName);
        if (StringUtils.isNotBlank(value)) {
            return Integer.parseInt(value);
        } else {
            return defaultValue;
        }
    }

    private abstract class KPIGraph extends Graph {

        private final String title;
        private final String xLabel;

        protected KPIGraph(final String title, final int width, final int height) {
            super(-1, width, height);
            this.title = title;
            this.xLabel = "Build Number";
        }

        protected abstract DataSetBuilder<String, Integer> createDataSet();

        protected JFreeChart createGraph() {
            final CategoryDataset dataSet = createDataSet().build();

            double min = 1;
            double max = 0;

            for (int row = 0; row < dataSet.getRowCount(); row++) {
                for (int column = 0; column < dataSet.getColumnCount(); column++) {
                    Number value = dataSet.getValue(row, column);
                    if (value != null) {
                        min = Math.min(min, value.doubleValue());
                        max = Math.max(max, value.doubleValue());
                    }
                }
            }

            final JFreeChart chart = ChartFactory.createLineChart(title, xLabel, null, dataSet,
                    PlotOrientation.VERTICAL, true, true, false);

            chart.setBackgroundPaint(Color.white);

            CategoryPlot plot = ChartUtil.enhanceColors((CategoryPlot) chart.getPlot());

            // if min would be eq to max, this range would render and empty graph
            if (min == max) {
                min = min - (min * 0.1);
                max = max + (max * 0.1);
            }

            NumberAxis yAxis = new NumberAxis("");
            yAxis.setLowerMargin(0.1);
            yAxis.setUpperMargin(0.1);
            yAxis.setRangeWithMargins(min, max);

            plot.setRangeAxis(yAxis);

            chart.getLegend().setPosition(RectangleEdge.BOTTOM);
            chart.getLegend().setMargin(new RectangleInsets(0, 10, 0, 0));

            return chart;
        }
    }

    public SortedSet<String> getTestNames() {
        SortedSet<String> testNames = new TreeSet<String>();
        for (KPIReport kpiReport : getKPIReports()) {
            for (ScoreResult scoreResult : kpiReport.getKpiScores()) {
                if (scoreResult.isOfficial()) {
                    testNames.add(scoreResult.getName());
                }
            }
        }
        return testNames;
    }

}