001package com.credibledoc.substitution.doc.module.substitution.activity.modules;
002
003import com.credibledoc.combiner.log.buffered.LogBufferedReader;
004import com.credibledoc.combiner.log.reader.ReaderService;
005import com.credibledoc.plantuml.svggenerator.SvgGeneratorService;
006import com.credibledoc.substitution.content.generator.jar.LocalJarNameContentGenerator;
007import com.credibledoc.substitution.core.resource.ResourceService;
008import com.credibledoc.substitution.doc.SubstitutionDocMain;
009import com.credibledoc.enricher.deriving.Deriving;
010import com.credibledoc.substitution.doc.module.substitution.exception.SubstitutionDocRuntimeException;
011import com.credibledoc.substitution.doc.module.substitution.logmessage.LogMessageService;
012import com.credibledoc.enricher.transformer.Transformer;
013import com.credibledoc.substitution.reporting.report.ReportService;
014import lombok.NonNull;
015import lombok.RequiredArgsConstructor;
016import org.springframework.stereotype.Service;
017
018import javax.inject.Inject;
019import java.util.*;
020
021/**
022 * Create a part of PlantUML activity diagram, for example
023 * <pre>
024 *     |Swimlane1|
025 *         :foo4;
026 * </pre>
027 * from log lines, for example
028 * <i>04.03.2019 18:41:13.658|main|INFO |com.credibledoc.substitution.core.configuration.ConfigurationService - Properties loaded by ClassLoader from the resource: file..</i>.
029 */
030@Service
031@RequiredArgsConstructor(onConstructor = @__(@Inject))
032public class ModulesActivityTransformer implements Transformer {
033
034    @NonNull
035    public final LogMessageService logMessageService;
036
037    private static final String PLANTUML_CORE_MODULE_NAME = "plantuml-core";
038    private static Map<String, String> packagePrefixToModuleName = new HashMap<>();
039
040    static {
041        packagePrefixToModuleName.put("com.credibledoc.substitution.core",
042            ResourceService.SUBSTITUTION_CORE_MODULE_NAME);
043        packagePrefixToModuleName.put("com.credibledoc.substitution.doc",
044            SubstitutionDocMain.SUBSTITUTION_DOC);
045        packagePrefixToModuleName.put("com.credibledoc.plantuml",
046            PLANTUML_CORE_MODULE_NAME);
047        packagePrefixToModuleName.put("com.credibledoc.combiner",
048            ReaderService.COMBINER_CORE_MODULE_NAME);
049        packagePrefixToModuleName.put("com.credibledoc.substitution.content.generator",
050            LocalJarNameContentGenerator.MODULE_NAME);
051        packagePrefixToModuleName.put("com.credibledoc.substitution.reporting",
052            ReportService.MODULE_NAME);
053        packagePrefixToModuleName.put("org.springframework.context.annotation",
054            "spring-libraries");
055
056        // Should be here for activating of the "com.credibledoc.plantuml" class loader
057        SvgGeneratorService.class.getPackage();
058        LocalJarNameContentGenerator.class.getPackage();
059        validatePackagesExist();
060    }
061
062    private static void validatePackagesExist() {
063        Set<String> foundPrefixes = new HashSet<>();
064        for (Package pkg : Package.getPackages()) {
065            String name = pkg.getName();
066            for (String prefix : packagePrefixToModuleName.keySet()) {
067                if (name.startsWith(prefix)) {
068                    foundPrefixes.add(prefix);
069                    if (foundPrefixes.size() == packagePrefixToModuleName.size()) {
070                        return;
071                    }
072                }
073            }
074        }
075        Set<String> missingPrefixes = new HashSet<>(packagePrefixToModuleName.keySet());
076        missingPrefixes.removeAll(foundPrefixes);
077
078        throw new SubstitutionDocRuntimeException("Package(s) not found: " + missingPrefixes);
079    }
080
081    @Override
082    public String transform(Deriving deriving,
083                            List<String> multiLine, LogBufferedReader logBufferedReader) {
084        String canonicalClassName = parseClassName(multiLine.get(0));
085        String moduleName = findModuleName(canonicalClassName);
086
087        int maxRowLength = moduleName.length() * 2 + moduleName.length() / 2;
088        List<String> cacheLines = deriving.getCacheLines();
089        addMessageToCache(multiLine, moduleName, maxRowLength, cacheLines);
090
091        return null;
092    }
093
094    private String findModuleName(String canonicalClassName) {
095        for (Map.Entry<String, String> entry : packagePrefixToModuleName.entrySet()) {
096            if (canonicalClassName.startsWith(entry.getKey())) {
097                return entry.getValue();
098            }
099        }
100        throw new SubstitutionDocRuntimeException("Module name cannot be found for package: " + canonicalClassName);
101    }
102
103    private void addMessageToCache(List<String> multiLine, String canonicalClassName, int maxRowLength,
104                                   List<String> cacheLines) {
105        String message = logMessageService.parseMessage(multiLine.get(0), maxRowLength);
106        String result = "|" + canonicalClassName + "|" + LogMessageService.LINE_SEPARATOR +
107            LogMessageService.FOUR_SPACES + ":" + message + ";" + LogMessageService.LINE_SEPARATOR;
108        cacheLines.add(result);
109    }
110
111    private String parseClassName(String line) {
112        int separatorIndex = line.indexOf(LogMessageService.LOG_SEPARATOR);
113        String firstPart = line.substring(0, separatorIndex);
114        int startIndex = firstPart.lastIndexOf('|') + 1;
115        return firstPart.substring(startIndex);
116    }
117}