001package com.credibledoc.substitution.reporting.reportdocument.creator;
002
003import com.credibledoc.combiner.context.CombinerContext;
004import com.credibledoc.combiner.file.FileService;
005import com.credibledoc.combiner.file.FileWithSources;
006import com.credibledoc.combiner.node.file.NodeFile;
007import com.credibledoc.combiner.node.file.NodeFileService;
008import com.credibledoc.combiner.node.log.NodeLog;
009import com.credibledoc.combiner.node.log.NodeLogService;
010import com.credibledoc.combiner.tactic.Tactic;
011import com.credibledoc.enricher.context.EnricherContext;
012import com.credibledoc.substitution.core.context.SubstitutionContext;
013import com.credibledoc.substitution.core.exception.SubstitutionRuntimeException;
014import com.credibledoc.substitution.core.placeholder.Placeholder;
015import com.credibledoc.substitution.core.placeholder.PlaceholderService;
016import com.credibledoc.substitution.core.resource.TemplateResource;
017import com.credibledoc.substitution.reporting.context.ReportingContext;
018import com.credibledoc.substitution.reporting.placeholder.PlaceholderToReportDocumentRepository;
019import com.credibledoc.substitution.reporting.placeholder.PlaceholderToReportDocumentService;
020import com.credibledoc.substitution.reporting.report.Report;
021import com.credibledoc.substitution.reporting.reportdocument.ReportDocument;
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024
025import java.io.File;
026import java.util.Collection;
027import java.util.Collections;
028import java.util.Date;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032
033/**
034 * Stateless service for working with {@link ReportDocumentCreator}s.
035 *
036 * @author Kyrylo Semenko
037 */
038public class ReportDocumentCreatorService {
039    private static final Logger logger = LoggerFactory.getLogger(ReportDocumentCreatorService.class);
040    private static final String SOURCE_FILE_RELATIVE_PATH_PLACEHOLDER_PARAMETER = "sourceFileRelativePath";
041
042    /**
043     * Singleton.
044     */
045    private static final ReportDocumentCreatorService instance = new ReportDocumentCreatorService();
046
047    /**
048     * @return The {@link ReportDocumentCreatorService} singleton.
049     */
050    public static ReportDocumentCreatorService getInstance() {
051        return instance;
052    }
053
054    /**
055     * Add all items to the {@link ReportDocumentCreatorRepository#getMap()} entries.
056     *
057     * @param reportDocumentCreators items for addition
058     * @param reportingContext contains the {@link ReportDocumentCreatorRepository} data store
059     */
060    public void addReportDocumentCreators(Collection<ReportDocumentCreator> reportDocumentCreators, ReportingContext reportingContext) {
061        Map<Class<? extends ReportDocumentCreator>, ReportDocumentCreator> map = new HashMap<>();
062        for (ReportDocumentCreator reportDocumentCreator : reportDocumentCreators) {
063            map.put(reportDocumentCreator.getClass(), reportDocumentCreator);
064        }
065        reportingContext.getReportDocumentCreatorRepository().getMap().putAll(map);
066    }
067
068    /**
069     * Iterate {@link Placeholder}s from template resources and for each {@link Placeholder} find the appropriate
070     * {@link ReportDocumentCreator} from the {@link ReportDocumentCreatorRepository}.
071     * Then create a {@link ReportDocument} for the {@link Placeholder}.
072     * 
073     * @param combinerContext the current state
074     * @param reportingContext the current state
075     * @param substitutionContext the current state
076     * @param enricherContext the current state
077     * @param templateResources contains templates with placeholders
078     */
079    public void createReportDocuments(CombinerContext combinerContext, ReportingContext reportingContext,
080                                      SubstitutionContext substitutionContext, EnricherContext enricherContext,
081                                      List<TemplateResource> templateResources) {
082        TemplateResource lastTemplateResource = null;
083        String lastTemplatePlaceholder = null;
084        ReportDocumentCreatorRepository reportDocumentCreatorRepository
085            = reportingContext.getReportDocumentCreatorRepository();
086        try {
087            PlaceholderService placeholderService = PlaceholderService.getInstance();
088            for (TemplateResource templateResource : templateResources) {
089                lastTemplateResource = templateResource;
090                List<String> placeholders = placeholderService.parsePlaceholders(templateResource, substitutionContext);
091                int position = 1;
092                for (String templatePlaceholder : placeholders) {
093                    lastTemplatePlaceholder = templatePlaceholder;
094                    Placeholder placeholder =
095                        placeholderService.parseJsonFromPlaceholder(templatePlaceholder, templateResource, substitutionContext);
096                    placeholder.setId(Integer.toString(position++));
097                    Class<?> placeholderClass = Class.forName(placeholder.getClassName());
098                    ReportDocumentCreator reportDocumentCreator =
099                        reportDocumentCreatorRepository.getMap().get(placeholderClass);
100                    if (reportDocumentCreator != null && ReportDocumentCreator.class.isAssignableFrom(placeholderClass)) {
101                        createReportDocumentForPlaceholder(placeholder,
102                            reportDocumentCreator, combinerContext, substitutionContext, reportingContext, enricherContext);
103                    }
104                }
105            }
106            logger.info("Report documents created");
107        } catch (ClassNotFoundException e) {
108            throw new SubstitutionRuntimeException("Class defined in the placeholder cannot be found, " +
109                    "templateResource: '" +
110                    lastTemplateResource +
111                    "', " +
112                    "templatePlaceholder: '" +
113                    lastTemplatePlaceholder +
114                    "'.", e);
115        } catch (Exception e) {
116            throw new SubstitutionRuntimeException(e);
117        }
118    }
119
120    /**
121     * Prepare relations between {@link Placeholder}s and {@link ReportDocument}s.
122     * <p>
123     * Create {@link ReportDocument}, see the {@link ReportDocumentCreator#prepareReportDocument(EnricherContext)} method.
124     * <p>
125     * Put the {@link Placeholder} and {@link ReportDocument} to the
126     * {@link PlaceholderToReportDocumentRepository}.
127     * <p>
128     * Add the {@link ReportDocument} to the
129     * {@link com.credibledoc.substitution.reporting.reportdocument.ReportDocumentRepository#getReportDocuments()} list.
130     * <p>
131     * Add the {@link Placeholder} to the {@link com.credibledoc.substitution.core.placeholder.PlaceholderRepository#getPlaceholders()} list.
132     *
133     * @param placeholder           for addition
134     * @param reportDocumentCreator for addition
135     * @param combinerContext               the current state
136     * @param substitutionContext   the current state
137     * @param reportingContext      the current state
138     * @param enricherContext       the current state
139     */
140    private void createReportDocumentForPlaceholder(Placeholder placeholder,
141                                                    ReportDocumentCreator reportDocumentCreator,
142                                                    CombinerContext combinerContext,
143                                                    SubstitutionContext substitutionContext,
144                                                    ReportingContext reportingContext,
145                                                    EnricherContext enricherContext) {
146        ReportDocument reportDocument = reportDocumentCreator.prepareReportDocument(enricherContext);
147        PlaceholderToReportDocumentService.getInstance().putPlaceholderToReportDocument(placeholder, reportDocument);
148        substitutionContext.getPlaceholderRepository().getPlaceholders().add(placeholder);
149        if (placeholder.getParameters() != null &&
150            placeholder.getParameters().get(SOURCE_FILE_RELATIVE_PATH_PLACEHOLDER_PARAMETER) != null) {
151            File file = new File(placeholder.getParameters().get(SOURCE_FILE_RELATIVE_PATH_PLACEHOLDER_PARAMETER));
152            FileWithSources fileWithSources = new FileWithSources();
153            fileWithSources.setFile(file);
154            fileWithSources.getSources().add(file);
155            if (!file.exists()) {
156                logger.info("File doesn't exist. Report will not be created. File: '{}'", file.getAbsolutePath());
157            } else {
158                logger.trace("File will be parsed: {}", file.getAbsolutePath());
159                prepareReport(fileWithSources, reportDocument, combinerContext, reportingContext);
160            }
161        }
162        reportingContext.getReportDocumentRepository().getReportDocuments().add(reportDocument);
163    }
164
165    /**
166     * Create a new {@link Report}
167     * @param fileWithSources a source file
168     * @param reportDocument belonging to the {@link Report}
169     * @param combinerContext the current state
170     * @param reportingContext the current state
171     */
172    private void prepareReport(FileWithSources fileWithSources, ReportDocument reportDocument, CombinerContext combinerContext, ReportingContext reportingContext) {
173        Report report = new Report();
174        reportingContext.getReportRepository().addReports(Collections.singletonList(report));
175        reportDocument.setReport(report);
176        FileService fileService = FileService.getInstance();
177        Tactic tactic = fileService.findTactic(fileWithSources.getFile(), combinerContext);
178
179        Date date = fileService.findDate(fileWithSources.getFile(), tactic);
180        NodeLogService nodeLogService = NodeLogService.getInstance();
181        NodeLog nodeLog = nodeLogService.createNodeLog(fileWithSources, combinerContext, tactic);
182        nodeLog.setTactic(tactic);
183        NodeFile nodeFile = NodeFileService.getInstance().createNodeFile(date, fileWithSources, combinerContext, nodeLog);
184        reportDocument.getNodeFiles().add(nodeFile);
185        nodeLogService.findNodeLogs(tactic, combinerContext).add(nodeLog);
186        logger.info("Report prepared. Report: {}", report.hashCode());
187    }
188}