All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metaeffekt.artifact.enrichment.other.VulnerabilityOverviewChartGenerator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021-2024 the original author or authors.
 *
 * 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 com.metaeffekt.artifact.enrichment.other;

import com.metaeffekt.artifact.analysis.utils.JFreeChartUtils;
import com.metaeffekt.artifact.analysis.utils.StringUtils;
import com.metaeffekt.artifact.analysis.vulnerability.enrichment.vulnerabilitystatus.VulnerabilityStatusHistoryEntry;
import com.metaeffekt.artifact.enrichment.other.vad.VulnerabilityAssessmentDashboard;
import com.metaeffekt.mirror.contents.base.VulnerabilityContextInventory;
import com.metaeffekt.mirror.contents.vulnerability.Vulnerability;
import de.yanwittmann.j2chartjs.chart.DoughnutChart;
import de.yanwittmann.j2chartjs.data.DoughnutPieChartData;
import de.yanwittmann.j2chartjs.dataset.DoughnutPieChartDataset;
import de.yanwittmann.j2chartjs.options.ChartOptions;
import de.yanwittmann.j2chartjs.options.plugins.legend.LegendOption;
import de.yanwittmann.j2chartjs.options.plugins.title.TitleOption;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
import org.metaeffekt.core.inventory.processor.model.Artifact;
import org.metaeffekt.core.inventory.processor.model.VulnerabilityMetaData;
import org.metaeffekt.core.inventory.processor.report.StatisticsOverviewTable;
import org.metaeffekt.core.inventory.processor.report.configuration.CentralSecurityPolicyConfiguration;
import org.metaeffekt.core.security.cvss.CvssSeverityRanges;
import org.metaeffekt.core.security.cvss.CvssVector;
import org.metaeffekt.core.util.ColorScheme;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.util.List;
import java.util.*;

import static j2html.TagCreator.canvas;
import static j2html.TagCreator.span;

public class VulnerabilityOverviewChartGenerator {

    private final static Logger LOG = LoggerFactory.getLogger(VulnerabilityOverviewChartGenerator.class);

    private final CentralSecurityPolicyConfiguration securityPolicy;
    private final VulnerabilityContextInventory vInventory;

    private final List effectiveVulnerabilities;
    private final Map> vulnerabilitiesPerArtifact;

    /**
     * When passing the applyEffectiveCalculations parameter, the vInventory passed as
     * parameter must not have the
     * {@link VulnerabilityContextInventory#calculateEffectiveCvssVectorsForVulnerabilities(CentralSecurityPolicyConfiguration)}
     * and
     * {@link VulnerabilityContextInventory#applyEffectiveVulnerabilityStatus(CentralSecurityPolicyConfiguration)}
     * methods already called, since they will be called by this constructor.
     *
     * @param vInventory                 the vulnerability inventory to be used for generating the charts
     * @param securityPolicy             the security policy to be used for calculating the effective CVSS vectors and vulnerability status
     * @param applyEffectiveCalculations whether to bake the effective CVSS vectors and apply the effective vulnerability status
     */
    public VulnerabilityOverviewChartGenerator(VulnerabilityContextInventory vInventory, CentralSecurityPolicyConfiguration securityPolicy, boolean applyEffectiveCalculations) {
        this.securityPolicy = securityPolicy;
        this.vInventory = vInventory;

        if (applyEffectiveCalculations) {
            LOG.info("Baking effective CVSS vectors");
            vInventory.calculateEffectiveCvssVectorsForVulnerabilities(securityPolicy);
            LOG.info("Applying effective vulnerability status");
            vInventory.applyEffectiveVulnerabilityStatus(securityPolicy);
        }

        LOG.info("Using calculated values for potential vulnerability filtering");
        this.effectiveVulnerabilities = VulnerabilityAssessmentDashboard.getEffectiveVulnerabilitiesAll(vInventory, securityPolicy);

        LOG.info("Mapping artifacts to matched vulnerabilities");
        this.vulnerabilitiesPerArtifact = Vulnerability.groupVulnerabilitiesByArtifact(effectiveVulnerabilities);
    }

    public VulnerabilityOverviewChartGenerator(VulnerabilityContextInventory vInventory, CentralSecurityPolicyConfiguration securityPolicy, List effectiveVulnerabilities, Map> vulnerabilitiesPerArtifact) {
        this.securityPolicy = securityPolicy;
        this.vInventory = vInventory;
        this.effectiveVulnerabilities = effectiveVulnerabilities;
        this.vulnerabilitiesPerArtifact = vulnerabilitiesPerArtifact;
    }

    public List generateOverviewCharts() {
        final List generatedCharts = new ArrayList<>();

        // pre-calculate data for the charts
        final Map initialSeverityCategories = new HashMap<>();
        final Map contextSeverityCategories = new HashMap<>();
        final Map statusPerVulnerability = new HashMap<>();

        for (Vulnerability vulnerability : effectiveVulnerabilities) {
            final VulnerabilityStatusHistoryEntry latestStatusHistoryEntry = vulnerability.getOrCreateNewVulnerabilityStatus().getLatestActiveStatusHistoryEntry();
            final String baseStatus = (latestStatusHistoryEntry != null) ? latestStatusHistoryEntry.getStatus() : null;
            final String mappedStatus = CentralSecurityPolicyConfiguration.VULNERABILITY_STATUS_DISPLAY_MAPPER_UNMODIFIED.getMapper().apply(baseStatus);
            statusPerVulnerability.put(vulnerability, mappedStatus);

            initialSeverityCategories.put(vulnerability, this.securityPolicy.getCvssSeverityRanges().getRange(getOverallScore(vulnerability.getCvssSelectionResult().getSelectedInitialCvss(), 0)));

            // see StatisticsOverviewTable for more details on this mapping
            if (VulnerabilityMetaData.STATUS_VALUE_NOTAPPLICABLE.equals(baseStatus) || VulnerabilityMetaData.STATUS_VALUE_VOID.equals(baseStatus)) {
                contextSeverityCategories.put(vulnerability, this.securityPolicy.getCvssSeverityRanges().getRange(0));
            } else {
                contextSeverityCategories.put(vulnerability, this.securityPolicy.getCvssSeverityRanges().getRange(getOverallScore(vulnerability.getCvssSelectionResult().getSelectedContextIfAvailableOtherwiseInitial(), 0)));
            }
        }

        final List vulnerabilitiesPotentiallyAffected = filterVulnerabilitiesForStatus(statusPerVulnerability, VulnerabilityMetaData.STATUS_VALUE_IN_REVIEW);
        final List vulnerabilitiesReviewed = filterVulnerabilitiesForStatus(statusPerVulnerability, "reviewed"); // "review state" mapper is used here

        final Map> vulnerabilitiesByComponent = this.groupVulnerabilitiesByComponent(vulnerabilitiesPerArtifact);

        // generate charts
        generatedCharts.add(generateOverviewChartCvssSeverityInitial(initialSeverityCategories));
        generatedCharts.add(generateOverviewChartVulnerabilityAssessmentStatus(statusPerVulnerability));
        generatedCharts.add(generateOverviewChartCvssSeverityContext(contextSeverityCategories));
        generatedCharts.add(generateOverviewChartCvssSeverityContextByStatusInReview(contextSeverityCategories, vulnerabilitiesPotentiallyAffected));
        generatedCharts.add(generateOverviewChartCvssSeverityContextByStatusApplicable(contextSeverityCategories, vulnerabilitiesReviewed));
        generatedCharts.add(generateOverviewChartCvssSeverityContextByComponent(contextSeverityCategories, vulnerabilitiesByComponent));

        return generatedCharts;
    }

    private Map> groupVulnerabilitiesByComponent(Map> vulnerabilitiesPerArtifact) {
        final Map> vulnerabilitiesByComponent = new HashMap<>();

        for (Map.Entry> entry : vulnerabilitiesPerArtifact.entrySet()) {
            final Artifact artifact = entry.getKey();
            final List vulnerabilities = entry.getValue();
            final String component = artifact.getComponent();

            final String effectiveComponent = StringUtils.hasText(component) ? component : (StringUtils.hasText(artifact.getId()) ? artifact.getId() : UUID.randomUUID().toString());

            vulnerabilitiesByComponent.computeIfAbsent(effectiveComponent, c -> new ArrayList<>())
                    .addAll(vulnerabilities);
        }

        return vulnerabilitiesByComponent;
    }

    private List filterVulnerabilitiesForStatus(Map statusPerVulnerability, String status) {
        final List filteredVulnerabilities = new ArrayList<>();
        for (Map.Entry entry : statusPerVulnerability.entrySet()) {
            if (entry.getValue().equals(status)) {
                filteredVulnerabilities.add(entry.getKey());
            }
        }
        return filteredVulnerabilities;
    }

    private double getOverallScore(CvssVector vector, double defaultValue) {
        if (vector == null) {
            return defaultValue;
        }
        return vector.getBakedScores().getOverallScore();
    }

    /**
     * 
     *     title: Initial CVSS Severity
     *     id: vulnerabilityOverviewChartCvssSeverityInitial
     *     file: vulnerability-overview-chart-cvss-severity-initial.svg
     *     unit: by vulnerability
     *     notes: uses the `cvssSeverityRanges` on the vector selected by the `initialCvssSelector` + `cvssVersionSelectionPolicy`
     * 
* * @return the generated chart based on the metrics above */ private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityInitial(Map initialSeverityCategories) { return this.generateOverviewChartCvssSeverity(initialSeverityCategories, "vulnerabilityOverviewChartCvssSeverityInitial", "vulnerability-overview-chart-cvss-severity-initial", "Initial CVSS Severity"); } /** *
     *     title: Context CVSS Severity
     *     id: vulnerabilityOverviewChartCvssSeverityContext
     *     file: vulnerability-overview-chart-cvss-severity-context.svg
     *     unit: by vulnerability
     *     notes: uses the `cvssSeverityRanges` on the vector selected by the `contextCvssSelector` + `cvssVersionSelectionPolicy`
     * 
* * @return the generated chart based on the metrics above */ private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityContext(Map contextSeverityCategories) { return this.generateOverviewChartCvssSeverity(contextSeverityCategories, "vulnerabilityOverviewChartCvssSeverityContext", "vulnerability-overview-chart-cvss-severity-context", "Context CVSS Severity"); } /** *
     *     title: Vulnerability Assessment Status
     *     id: vulnerabilityOverviewChartVulnerabilityStatus
     *     file: vulnerability-overview-chart-vulnerability-status.svg
     *     unit: by vulnerability
     *     notes: uses unmodified as `vulnerabilityStatusDisplayMapperName`
     * 
* * @return the generated chart based on the metrics above */ private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartVulnerabilityAssessmentStatus(Map statusPerVulnerability) { final Map countsPerStatus = new LinkedHashMap<>(); for (String status : CentralSecurityPolicyConfiguration.VULNERABILITY_STATUS_DISPLAY_MAPPER_UNMODIFIED.getStatusNames()) { countsPerStatus.put(status, 0); } for (Map.Entry entry : statusPerVulnerability.entrySet()) { countsPerStatus.put(entry.getValue(), countsPerStatus.getOrDefault(entry.getValue(), 0) + 1); } // JFreeChart final DefaultPieDataset jFreeChartDataset = new DefaultPieDataset<>(); final JFreeChart jFreeChart = ChartFactory.createPieChart("", jFreeChartDataset, true, true, false); final PiePlot jFreeChartPlot = (PiePlot) jFreeChart.getPlot(); JFreeChartUtils.applyDefaultForPieChartPlot(jFreeChartPlot); jFreeChartPlot.setBackgroundPaint(new Color(255, 255, 255)); jFreeChart.setBackgroundPaint(new Color(255, 255, 255)); for (Map.Entry entry : countsPerStatus.entrySet()) { JFreeChartUtils.addPieChartData(jFreeChartDataset, jFreeChartPlot, StatisticsOverviewTable.capitalizeWords(entry.getKey()), entry.getValue(), getStatusCategoryColor(entry.getKey().toLowerCase())); } // Chart.js final DoughnutPieChartDataset chartJsChartDataset = new DoughnutPieChartDataset() .addHoverOffset(3) .setCutout("35%"); final DoughnutPieChartData chartJsChartData = new DoughnutPieChartData() .addDataset(chartJsChartDataset); final DoughnutChart chartJsChart = new DoughnutChart() .setChartData(chartJsChartData) .setChartOptions(this.createChartOptionsForOverviewCharts("Vulnerability Assessment Status")); for (Map.Entry entry : countsPerStatus.entrySet()) { chartJsChartDataset .addData(entry.getValue()) .addBackgroundColor(getStatusCategoryColor(entry.getKey().toLowerCase())); chartJsChartData .addLabels(StatisticsOverviewTable.capitalizeWords(entry.getKey())); } return new VulnerabilityAssessmentDashboard.GeneratedChartBuilder() .setjFreeChart(jFreeChart) .setjFreeChartName("vulnerability-overview-chart-vulnerability-status") .setChartJsChart(chartJsChart) .setChartJsChartId("vulnerabilityOverviewChartVulnerabilityStatus") .setCanvasOrParentTag(span().attr("width", "300").attr("height", "300").withStyle("width:300px;height:300px;display:inline-block;").withClass("overview-chart-filterable").with( canvas().withClass("chart-js-remove-display-block") )) .setCharJsChartJsVarName("vulnerabilityOverviewChartVulnerabilityStatus") .createGeneratedChart(); } /** *
     *     title: Context CVSS Severity (by vulnerabilities in review)
     *     id: vulnerabilityOverviewChartCvssSeverityContextByStatusInReview
     *     file: vulnerability-overview-chart-cvss-severity-context-by-status-in-review.svg
     *     unit: by vulnerability
     *     notes: 1. maps the vulnerability status using `unmodified` as `vulnerabilityStatusDisplayMapperName`
     *            2. filters the vulnerabilities to only those with a status `in review`
     *            3. for each vulnerability, uses the `cvssSeverityRanges` on the vector selected by the `contextCvssSelector` + `cvssVersionSelectionPolicy`
     * 
* * @return the generated chart based on the metrics above */ private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityContextByStatusInReview(Map contextSeverityCategories, List vulnerabilitiesPotentiallyAffected) { return this.generateOverviewChartCvssSeverityContextByStatus(contextSeverityCategories, vulnerabilitiesPotentiallyAffected, "vulnerabilityOverviewChartCvssSeverityContextByStatusInReview", "vulnerability-overview-chart-cvss-severity-context-by-status-in-review", "Context CVSS Severity (by vulnerabilities in review)", ColorScheme.PASTEL_BLUE); } /** *
     *     title: Context CVSS Severity (by reviewed vulnerabilities)
     *     id: vulnerabilityOverviewChartCvssSeverityContextByStatusApplicable
     *     file: vulnerability-overview-chart-cvss-severity-context-by-status-applicable.svg
     *     unit: by vulnerability
     *     notes: 1. maps the vulnerability status using `unmodified` as `vulnerabilityStatusDisplayMapperName`
     *            2. filters the vulnerabilities to only those with a status `applicable`
     *            3. for each vulnerability, uses the `cvssSeverityRanges` on the vector selected by the `contextCvssSelector` + `cvssVersionSelectionPolicy`
     * 
* * @return the generated chart based on the metrics above */ private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityContextByStatusApplicable(Map contextSeverityCategories, List vulnerabilitiesReviewed) { return this.generateOverviewChartCvssSeverityContextByStatus(contextSeverityCategories, vulnerabilitiesReviewed, "vulnerabilityOverviewChartCvssSeverityContextByStatusApplicable", "vulnerability-overview-chart-cvss-severity-context-by-status-applicable", "Context CVSS Severity (by applicable vulnerabilities)", ColorScheme.STRONG_DARK_BLUE); } /** *
     *     title: Context CVSS Severity (by component)
     *     id: vulnerabilityOverviewChartCvssSeverityContextByComponent
     *     file: vulnerability-overview-chart-cvss-severity-context-by-component.svg
     *     unit: by component
     *     notes: 1. builds a `Map>` using the matching information collected during vulnerability enrichment
     *            2. maps all artifact keys with the same component into a `Map>`
     *            3. for each vulnerability on each component, uses the `cvssSeverityRanges` on the vector selected by the `contextCvssSelector` + `cvssVersionSelectionPolicy`
     *            4. picks the highest severity category on each component
     * 
* * @return the generated chart based on the metrics above */ private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityContextByComponent(Map contextSeverityCategories, Map> vulnerabilitiesByComponent) { final Map countsPerSeverityCategory = new LinkedHashMap<>(); for (Map.Entry> entry : vulnerabilitiesByComponent.entrySet()) { final String component = entry.getKey(); final List vulnerabilities = entry.getValue(); CvssSeverityRanges.SeverityRange highestSeverityCategory = null; for (Vulnerability vulnerability : vulnerabilities) { final CvssSeverityRanges.SeverityRange severityCategory = contextSeverityCategories.get(vulnerability); if (highestSeverityCategory == null || severityCategory.getIndex() > highestSeverityCategory.getIndex()) { highestSeverityCategory = severityCategory; } } countsPerSeverityCategory.put(highestSeverityCategory, countsPerSeverityCategory.getOrDefault(highestSeverityCategory, 0) + 1); } // JFreeChart final DefaultPieDataset jFreeChartDataset = new DefaultPieDataset<>(); final JFreeChart jFreeChart = ChartFactory.createPieChart("", jFreeChartDataset, true, true, false); final PiePlot jFreeChartPlot = (PiePlot) jFreeChart.getPlot(); JFreeChartUtils.applyDefaultForPieChartPlot(jFreeChartPlot); jFreeChartPlot.setBackgroundPaint(new Color(255, 255, 255)); jFreeChart.setBackgroundPaint(new Color(255, 255, 255)); for (Map.Entry entry : countsPerSeverityCategory.entrySet()) { JFreeChartUtils.addPieChartData(jFreeChartDataset, jFreeChartPlot, entry.getKey().getName(), entry.getValue(), entry.getKey().getColor().getColor()); } // Chart.js final DoughnutPieChartDataset chartJsChartDataset = new DoughnutPieChartDataset() .addHoverOffset(3) .setCutout("35%"); final DoughnutPieChartData chartJsChartData = new DoughnutPieChartData() .addDataset(chartJsChartDataset); final DoughnutChart chartJsChart = new DoughnutChart() .setChartData(chartJsChartData) .setChartOptions(this.createChartOptionsForOverviewCharts("Context CVSS Severity (by component)")); for (Map.Entry entry : countsPerSeverityCategory.entrySet()) { chartJsChartDataset .addData(entry.getValue()) .addBackgroundColor(entry.getKey().getColor().getColor()); chartJsChartData .addLabels(entry.getKey().getName()); } return new VulnerabilityAssessmentDashboard.GeneratedChartBuilder() .setjFreeChart(jFreeChart) .setjFreeChartName("vulnerability-overview-chart-cvss-severity-context-by-component") .setChartJsChart(chartJsChart) .setChartJsChartId("vulnerabilityOverviewChartCvssSeverityContextByComponent") .setCanvasOrParentTag(span().attr("width", "300").attr("height", "300").withStyle("width:300px;height:300px;display:inline-block;").withClass("overview-chart-filterable").with( canvas().withClass("chart-js-remove-display-block") )) .setCharJsChartJsVarName("vulnerabilityOverviewChartCvssSeverityContextByComponent") .createGeneratedChart(); } private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverity(Map severityCategories, String chartId, String filename, String title) { final Map countsPerSeverityCategory = new LinkedHashMap<>(); for (CvssSeverityRanges.SeverityRange range : this.securityPolicy.getCvssSeverityRanges().getRanges()) { countsPerSeverityCategory.put(range, 0); } for (Map.Entry entry : severityCategories.entrySet()) { countsPerSeverityCategory.put(entry.getValue(), countsPerSeverityCategory.getOrDefault(entry.getValue(), 0) + 1); } // JFreeChart final DefaultPieDataset jFreeChartDataset = new DefaultPieDataset<>(); final JFreeChart jFreeChart = ChartFactory.createPieChart("", jFreeChartDataset, true, true, false); final PiePlot jFreeChartPlot = (PiePlot) jFreeChart.getPlot(); JFreeChartUtils.applyDefaultForPieChartPlot(jFreeChartPlot); jFreeChartPlot.setBackgroundPaint(new Color(255, 255, 255)); jFreeChart.setBackgroundPaint(new Color(255, 255, 255)); for (Map.Entry entry : countsPerSeverityCategory.entrySet()) { JFreeChartUtils.addPieChartData(jFreeChartDataset, jFreeChartPlot, entry.getKey().getName(), entry.getValue(), entry.getKey().getColor().getColor()); } // Chart.js final DoughnutPieChartDataset chartJsChartDataset = new DoughnutPieChartDataset() .addHoverOffset(3) .setCutout("35%"); final DoughnutPieChartData chartJsChartData = new DoughnutPieChartData() .addDataset(chartJsChartDataset); final DoughnutChart chartJsChart = new DoughnutChart() .setChartData(chartJsChartData) .setChartOptions(this.createChartOptionsForOverviewCharts(title)); for (Map.Entry entry : countsPerSeverityCategory.entrySet()) { chartJsChartDataset .addData(entry.getValue()) .addBackgroundColor(entry.getKey().getColor().getColor()); chartJsChartData .addLabels(entry.getKey().getName()); } return new VulnerabilityAssessmentDashboard.GeneratedChartBuilder() .setjFreeChart(jFreeChart) .setjFreeChartName(filename) .setChartJsChart(chartJsChart) .setChartJsChartId(chartId) .setCanvasOrParentTag(span().attr("width", "300").attr("height", "300").withStyle("width:300px;height:300px;display:inline-block;").withClass("overview-chart-filterable").with( canvas().withClass("chart-js-remove-display-block") )) .setCharJsChartJsVarName(chartId) .createGeneratedChart(); } private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityContextByStatus(Map contextSeverityCategories, List filteredVulnerabilities, String chartId, String filename, String title, ColorScheme centerDotColor) { final Map countsPerSeverityCategory = new LinkedHashMap<>(); for (CvssSeverityRanges.SeverityRange range : this.securityPolicy.getCvssSeverityRanges().getRanges()) { countsPerSeverityCategory.put(range, 0); } for (Vulnerability vulnerability : filteredVulnerabilities) { countsPerSeverityCategory.put(contextSeverityCategories.get(vulnerability), countsPerSeverityCategory.getOrDefault(contextSeverityCategories.get(vulnerability), 0) + 1); } // JFreeChart final DefaultPieDataset jFreeChartDataset = new DefaultPieDataset<>(); final JFreeChart jFreeChart = ChartFactory.createPieChart("", jFreeChartDataset, true, true, false); final PiePlot jFreeChartPlot = (PiePlot) jFreeChart.getPlot(); JFreeChartUtils.applyDefaultForPieChartPlot(jFreeChartPlot); jFreeChartPlot.setBackgroundPaint(new Color(255, 255, 255)); jFreeChart.setBackgroundPaint(new Color(255, 255, 255)); for (Map.Entry entry : countsPerSeverityCategory.entrySet()) { JFreeChartUtils.addPieChartData(jFreeChartDataset, jFreeChartPlot, entry.getKey().getName(), entry.getValue(), entry.getKey().getColor().getColor()); } // Chart.js final DoughnutPieChartDataset chartJsChartDataset = new DoughnutPieChartDataset() .addHoverOffset(3) .setCutout("35%"); final DoughnutPieChartData chartJsChartData = new DoughnutPieChartData() .addDataset(chartJsChartDataset); final DoughnutChart chartJsChart = new DoughnutChart() .setChartData(chartJsChartData) .setChartOptions(this.createChartOptionsForOverviewCharts(title)); for (Map.Entry entry : countsPerSeverityCategory.entrySet()) { chartJsChartDataset .addData(entry.getValue()) .addBackgroundColor(entry.getKey().getColor().getColor()); chartJsChartData .addLabels(entry.getKey().getName()); } return new VulnerabilityAssessmentDashboard.GeneratedChartBuilder() .setjFreeChart(jFreeChart) .setjFreeChartName(filename) .setChartJsChart(chartJsChart) .setChartJsChartId(chartId) .setCanvasOrParentTag(span().attr("width", "300").attr("height", "300").withStyle("width:300px;height:300px;display:inline-block;position:relative;").withClass("overview-chart-filterable").with( canvas().withClass("chart-js-remove-display-block").withStyle("z-index: 2;position: inherit;"), span().withClasses("overview-chart-circle", centerDotColor.getCssRootName()) )) .setCharJsChartJsVarName(chartId) .createGeneratedChart(); } private ChartOptions createChartOptionsForOverviewCharts(String title) { return new ChartOptions() .setResponsive(false) .setMaintainAspectRatio(false) .setLegend(new LegendOption().setAlign("top")) .setTitle(new TitleOption().setDisplay(true).setText(title)); } public final static Map STATUS_CATEGORY_COLOR_MAPPING = new HashMap() {{ put("in review", ColorScheme.PASTEL_BLUE.getColor()); put("reviewed", ColorScheme.STRONG_DARK_BLUE.getColor()); put("applicable", ColorScheme.STRONG_DARK_BLUE.getColor()); put("not applicable", ColorScheme.STRONG_LIGHT_GREEN.getColor()); put("insignificant", ColorScheme.PASTEL_GRAY.getColor()); put("void", ColorScheme.PASTEL_WHITE.getColor()); put("ineffective", ColorScheme.STRONG_GRAY.getColor()); put("affected", ColorScheme.STRONG_DARK_BLUE.getColor()); put("potentially affected", ColorScheme.PASTEL_BLUE.getColor()); put("potentially vulnerability", ColorScheme.PASTEL_BLUE.getColor()); put("not affected", ColorScheme.PASTEL_GRAY.getColor()); }}; private static Color getStatusCategoryColor(String statusCategory) { return STATUS_CATEGORY_COLOR_MAPPING.getOrDefault(statusCategory.toLowerCase(), ColorScheme.PASTEL_WHITE.getColor()); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy