public void export()

in src/core/src/main/java/org/apache/jmeter/report/dashboard/HtmlTemplateExporter.java [287:461]


    public void export(SampleContext context, File file,
            ReportGeneratorConfiguration configuration) throws ExportException {
        Objects.requireNonNull(context, "context must not be null");
        Objects.requireNonNull(file, "file must not be null");
        Objects.requireNonNull(configuration, "configuration must not be null");

        log.debug("Start template processing");

        // Create data context and populate it
        DataContext dataContext = new DataContext();

        // Get the configuration of the current exporter
        final ExporterConfiguration exportCfg =
                configuration.getExportConfigurations().get(getName());

        // Get template directory property value
        File templateDirectory = getPropertyFromConfig(
                exportCfg,
                TEMPLATE_DIR,
                new File(JMeterUtils.getJMeterBinDir(), TEMPLATE_DIR_NAME_DEFAULT),
                File.class);
        if (!templateDirectory.isDirectory()) {
            String message = String.format(
                    "\"%s\" is not a valid template directory",
                    templateDirectory.getAbsolutePath());
            log.error(message);
            throw new ExportException(message);
        }

        // Get output directory property value
        File outputDir = getPropertyFromConfig(exportCfg, OUTPUT_DIR,
                new File(JMeterUtils.getJMeterBinDir(), OUTPUT_DIR_NAME_DEFAULT), File.class);
        String globallyDefinedOutputDir = JMeterUtils.getProperty(JMeter.JMETER_REPORT_OUTPUT_DIR_PROPERTY);
        if(!StringUtils.isEmpty(globallyDefinedOutputDir)) {
            outputDir = new File(globallyDefinedOutputDir);
        }

        JOrphanUtils.canSafelyWriteToFolder(outputDir, HtmlTemplateExporter::htmlReportFileFilter);

        if (log.isInfoEnabled()) {
            log.info("Will generate dashboard in folder: {}", outputDir.getAbsolutePath());
        }

        // Add a flag defining if only sample series are filtered to the context
        final boolean filtersOnlySampleSeries = exportCfg.filtersOnlySampleSeries();
        addToContext(
                DATA_CTX_FILTERS_ONLY_SAMPLE_SERIES,
                filtersOnlySampleSeries,
                dataContext);

        // Add the series filter to the context
        final String seriesFilter = exportCfg.getSeriesFilter();
        Pattern filterPattern = null;
        if (StringUtils.isNotBlank(seriesFilter)) {
            try {
                filterPattern = Pattern.compile(seriesFilter);
            } catch (PatternSyntaxException ex) {
                log.error("Invalid series filter: '{}', {}", seriesFilter, ex.getDescription());
            }
        }
        addToContext(DATA_CTX_SERIES_FILTER, seriesFilter, dataContext);

        // Add the flag defining whether only controller series are displayed
        final boolean showControllerSeriesOnly = exportCfg.showControllerSeriesOnly();
        addToContext(
                DATA_CTX_SHOW_CONTROLLERS_ONLY,
                showControllerSeriesOnly,
                dataContext);

        JsonizerVisitor jsonizer = new JsonizerVisitor();
        Map<String, Object> storedData = context.getData();

        // Add begin date consumer result to the data context
        addResultToContext(
                ReportGenerator.BEGIN_DATE_CONSUMER_NAME, storedData, dataContext, jsonizer);

        // Add end date summary consumer result to the data context
        addResultToContext(
                ReportGenerator.END_DATE_CONSUMER_NAME, storedData, dataContext, jsonizer);

        // Add Apdex summary consumer result to the data context
        addResultToContext(
                ReportGenerator.APDEX_SUMMARY_CONSUMER_NAME, storedData, dataContext, jsonizer);

        // Add errors summary consumer result to the data context
        addResultToContext(
                ReportGenerator.ERRORS_SUMMARY_CONSUMER_NAME, storedData, dataContext, jsonizer);

        // Add requests summary consumer result to the data context
        addResultToContext(
                ReportGenerator.REQUESTS_SUMMARY_CONSUMER_NAME, storedData, dataContext, jsonizer);

        // Add statistics summary consumer result to the data context
        addResultToContext(
                ReportGenerator.STATISTICS_SUMMARY_CONSUMER_NAME, storedData, dataContext, jsonizer);

        // Add Top 5 errors by sampler consumer result to the data context
        addResultToContext(
                ReportGenerator.TOP5_ERRORS_BY_SAMPLER_CONSUMER_NAME, storedData, dataContext, jsonizer);

        // Collect graph results from sample context and transform them into
        // Json strings to inject in the data context
        ExtraOptionsResultCustomizer customizer = new ExtraOptionsResultCustomizer();
        EmptyGraphChecker checker =
                new EmptyGraphChecker(filtersOnlySampleSeries, showControllerSeriesOnly, filterPattern);
        Map<String, GraphConfiguration> mapConfiguration = new HashMap<>();
        DataContext customGraphs = new DataContext();

        for (Map.Entry<String, GraphConfiguration> graphEntry : configuration.getGraphConfigurations().entrySet()) {
            final String graphId = graphEntry.getKey();
            final GraphConfiguration graphConfiguration = graphEntry.getValue();

            // Initialize customizer and checker
            customizer.setExtraOptions(exportCfg.getGraphExtraConfigurations().get(graphId));
            checker.setExcludesControllers(graphConfiguration.excludesControllers());
            checker.setGraphId(graphId);
            mapConfiguration.put(graphId, graphConfiguration);
            if (graphId.startsWith(CUSTOM_GRAPH_PREFIX)) {
                addResultToContext(
                        graphId, storedData, customGraphs, jsonizer, customizer, checker);
            } else {
                // Export graph data
                addResultToContext(
                        graphId, storedData, dataContext, jsonizer, customizer, checker);
            }
        }
        dataContext.put("graphConfigurations", mapConfiguration);
        dataContext.put("customsGraphsData", customGraphs);

        // Replace the begin date with its formatted string and store the old timestamp
        long oldTimestamp = formatTimestamp(
                ReportGenerator.BEGIN_DATE_CONSUMER_NAME, dataContext);

        // Replace the end date with its formatted string
        formatTimestamp(ReportGenerator.END_DATE_CONSUMER_NAME, dataContext);

        // Add time zone offset (that matches the begin date) to the context
        TimeZone timezone = TimeZone.getDefault();
        addToContext(
                DATA_CTX_TIMEZONE_OFFSET,
                timezone.getOffset(oldTimestamp),
                dataContext);

        // Add report title to the context
        if (StringUtils.isNotEmpty(configuration.getReportTitle())) {
            dataContext.put(DATA_CTX_REPORT_TITLE, StringEscapeUtils.escapeHtml4(configuration.getReportTitle()));
        }

        // Add the test file name to the context
        addToContext(DATA_CTX_TESTFILE, file.getName(), dataContext);

        // Add the overall filter property to the context
        addToContext(DATA_CTX_OVERALL_FILTER, configuration.getSampleFilter(), dataContext);

        // Walk template directory to copy files and process templated ones
        Configuration templateCfg = new Configuration(Configuration.VERSION_2_3_30);
        try {
            templateCfg.setDirectoryForTemplateLoading(templateDirectory);
            templateCfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
            if (log.isInfoEnabled()) {
                log.info("Report will be generated in: {}, creating folder structure", outputDir.getAbsolutePath());
            }
            FileUtils.forceMkdir(outputDir);
            TemplateVisitor visitor = new TemplateVisitor(
                    templateDirectory.toPath(),
                    outputDir.toPath(),
                    templateCfg,
                    dataContext);
            Files.walkFileTree(templateDirectory.toPath(), visitor);
        } catch (IOException ex) {
            throw new ExportException("Unable to process template files.", ex);
        }

        log.debug("End of template processing");
    }