001package com.credibledoc.substitution.reporting.visualizer;
002
003import com.credibledoc.combiner.context.CombinerContext;
004import com.credibledoc.combiner.log.buffered.LogBufferedReader;
005import com.credibledoc.combiner.log.reader.ReaderService;
006import com.credibledoc.combiner.node.file.NodeFile;
007import com.credibledoc.combiner.node.file.NodeFileTreeSet;
008import com.credibledoc.combiner.state.FilesMergerState;
009import com.credibledoc.enricher.context.EnricherContext;
010import com.credibledoc.enricher.transformer.TransformerService;
011import com.credibledoc.substitution.core.exception.SubstitutionRuntimeException;
012import com.credibledoc.substitution.reporting.context.ReportingContext;
013import com.credibledoc.substitution.reporting.report.Report;
014import com.credibledoc.substitution.reporting.reportdocument.ReportDocument;
015import com.credibledoc.substitution.reporting.reportdocument.ReportDocumentService;
016import com.credibledoc.substitution.reporting.reportdocument.ReportDocumentType;
017import org.slf4j.Logger;
018import org.slf4j.LoggerFactory;
019
020import java.util.Collection;
021import java.util.List;
022
023/**
024 * Visualizer creates reports. The reports describes scenarios recorded in log files,
025 * see the {@link #createReports(Collection, CombinerContext, ReportingContext, EnricherContext)} method.
026 *
027 * @author Kyrylo Semenko
028 */
029public class VisualizerService {
030
031    private static final Logger logger = LoggerFactory.getLogger(VisualizerService.class);
032    
033    /**
034     * Should an exception be thrown in case when the exception occurred?
035     * Default is true. In case when System property -DcredibledocIgnoreFailures=true set, exception will not thrown.
036     */
037    private static final String IGNORE_FAILURES = "credibledocIgnoreFailures";
038
039    /**
040     * Singleton.
041     */
042    private static final VisualizerService instance = new VisualizerService();
043
044    /**
045     * @return The {@link VisualizerService} singleton.
046     */
047    public static VisualizerService getInstance() {
048        return instance;
049    }
050
051    /**
052     * Read files(s), parse them and create reports.
053     *
054     * @param reportDocumentTypes defines which {@link ReportDocumentType}s
055     *                            can be transformed in a particular invocation
056     * @param combinerContext the current state
057     * @param reportingContext the current state
058     * @param enricherContext the current state
059     */
060    public void createReports(Collection<Class<? extends ReportDocumentType>> reportDocumentTypes, CombinerContext combinerContext,
061                              ReportingContext reportingContext, EnricherContext enricherContext) {
062        logger.info("Method createReports started, reportDocumentTypes: '{}'", reportDocumentTypes);
063        List<Report> reports = reportingContext.getReportRepository().getReports();
064        for (Report report : reports) {
065            createReport(reportDocumentTypes, report, combinerContext, reportingContext, enricherContext);
066        }
067    }
068
069    private void createReport(Collection<Class<? extends ReportDocumentType>> reportDocumentTypes,
070                              Report report, CombinerContext combinerContext, ReportingContext reportingContext,
071                              EnricherContext enricherContext) {
072        logger.info("Method createReports started. Report: {}", report);
073        ReportDocumentService reportDocumentService = ReportDocumentService.getInstance();
074        List<ReportDocument> reportDocuments = reportDocumentService.getReportDocuments(report, reportingContext);
075        NodeFileTreeSet<NodeFile> nodeFiles = (NodeFileTreeSet<NodeFile>) reportDocumentService.getNodeFiles(reportDocuments);
076        ReaderService readerService = ReaderService.getInstance();
077        readerService.prepareBufferedReaders(combinerContext, nodeFiles);
078        String line = null;
079
080        FilesMergerState filesMergerState = new FilesMergerState();
081        filesMergerState.setNodeFiles(nodeFiles);
082
083        LogBufferedReader currentReader = null;
084        int currentLineNumber = 0;
085        TransformerService transformerService = TransformerService.getInstance();
086        try {
087            line = readerService.readLineFromReaders(filesMergerState);
088            int endIndex = Math.max(line.length(), 35);
089            String substring = line.substring(0, endIndex);
090            logger.trace("The first line is read from {}. Line: '{}...'", getClass().getSimpleName(), substring);
091            while (line != null) {
092                currentReader = filesMergerState.getCurrentNodeFile().getLogBufferedReader();
093                List<String> multiLine = readerService.readMultiline(line, currentReader, combinerContext);
094
095                currentLineNumber = transformMultiLine(multiLine, reportDocumentTypes, report, reportDocuments,
096                    currentReader, currentLineNumber, transformerService, combinerContext, enricherContext);
097
098                reportDocumentService.mergeReportDocumentsForAddition(reportingContext);
099                reportDocuments = reportDocumentService.getReportDocuments(report, reportingContext);
100
101                line = readerService.readLineFromReaders(filesMergerState);
102            }
103            logger.debug("{} lines processed (100%)", currentLineNumber);
104        } catch (Exception e) {
105            String fileName = "null";
106            if (currentReader != null) {
107                fileName = readerService.getFile(currentReader).getAbsolutePath();
108            }
109            String message =
110                "Reports creation failed. File: '" + fileName +
111                    "', ReportDirectory: '" + getReportDirectoryPath(report) +
112                    "', line: '" + line + "'";
113            throw new SubstitutionRuntimeException(message, e);
114        } finally {
115            for (ReportDocument reportDocument : reportDocuments) {
116                if (reportDocument.getFooterMethod() != null) {
117                    reportDocument.getFooterMethod().accept(reportDocument);
118                }
119            }
120        }
121    }
122
123    private int transformMultiLine(List<String> multiLine,
124                                   Collection<Class<? extends ReportDocumentType>> reportDocumentTypes,
125                                   Report report, List<ReportDocument> reportDocuments,
126                                   LogBufferedReader currentReader,
127                                   int currentLineNumber,
128                                   TransformerService transformerService,
129                                   CombinerContext combinerContext,
130                                   EnricherContext enricherContext) {
131        currentLineNumber = currentLineNumber + multiLine.size();
132        try {
133            if (report.getLinesNumber() > 0 && currentLineNumber % 100000 == 0) {
134                int perCent = (int) (currentLineNumber * 100f) / report.getLinesNumber();
135                logger.debug("{} lines processed ({}%)", currentLineNumber, perCent);
136            }
137
138            for (ReportDocument reportDocument : reportDocuments) {
139                if (reportDocumentTypes.contains(reportDocument.getReportDocumentType())) {
140                    transformerService.transformToReport(reportDocument, multiLine, currentReader,
141                        combinerContext, enricherContext);
142                }
143            }
144        } catch (Exception e) {
145            String message =
146                "Reports creation failed." +
147                    " ReportDirectory: '" + getReportDirectoryPath(report) +
148                    "', line: '" + multiLine.get(0) + "'";
149            if ("true".equals(System.getProperty(IGNORE_FAILURES))) {
150                logger.error(message);
151            } else {
152                throw new SubstitutionRuntimeException(message, e);
153            }
154        }
155        return currentLineNumber;
156    }
157
158    private String getReportDirectoryPath(Report report) {
159        if (report.getDirectory() != null) {
160            return report.getDirectory().getAbsolutePath();
161        }
162        return null;
163    }
164}