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}