001// Generated by delombok at Sat May 11 08:17:52 CEST 2019
002package com.credibledoc.substitution.doc.module.substitution.file;
003
004import com.credibledoc.combiner.application.Application;
005import com.credibledoc.combiner.application.ApplicationService;
006import com.credibledoc.combiner.file.FileService;
007import com.credibledoc.combiner.node.applicationlog.ApplicationLog;
008import com.credibledoc.combiner.node.file.NodeFileService;
009import com.credibledoc.substitution.core.exception.SubstitutionRuntimeException;
010import com.google.common.base.Preconditions;
011import org.apache.commons.compress.archivers.ArchiveInputStream;
012import org.apache.commons.compress.archivers.ArchiveStreamFactory;
013import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
014import org.apache.commons.compress.utils.IOUtils;
015import org.slf4j.Logger;
016import org.slf4j.LoggerFactory;
017import org.springframework.stereotype.Service;
018import javax.inject.Inject;
019import java.io.File;
020import java.io.FileInputStream;
021import java.io.FileOutputStream;
022import java.io.InputStream;
023import java.util.*;
024import java.util.Map.Entry;
025
026@Service
027public class FileUtilService {
028    private static final Logger logger = LoggerFactory.getLogger(FileUtilService.class);
029    private static final char DOT = '.';
030    private static final String REPORT_FOLDER_EXTENSION = ".report";
031
032    /**
033     * Generate a new file with transformed content of source log files.
034
035     * @param fileNumber an order number. Can be 'null' if a single file
036
037     *                   should be created in the directory. If not 'null',
038
039     *                   this number will be appended to the file name,
040
041     *                   for example index_001.html
042
043     * @param fileName the file name without extension
044
045     * @param reportDirectory where the new file will be created
046
047     * @param fileExtension for example html or txt
048
049     *
050
051     * @return the new file with context transformed from the source log file.
052     */
053    public File generateFile(Integer fileNumber, String fileName, File reportDirectory, String fileExtension) {
054        String num = null;
055        if (fileNumber != null) {
056            num = String.format("%03d", fileNumber);
057        }
058        StringBuilder newFileName = new StringBuilder(fileName);
059        if (num != null) {
060            newFileName.append(DOT).append(num);
061        }
062        newFileName.append(DOT).append(fileExtension);
063        File file = new File(reportDirectory, newFileName.toString());
064        logger.info("The new empty file created: \'{}\'", file.getAbsolutePath());
065        return file;
066    }
067
068    /**
069     * Sort files in a directory from the first argument.
070
071     * For each {@link Application} creates its own list of files.
072
073     *
074
075     * @param directory       cannot be 'null'. Can have files from different {@link Application}s.<br>
076
077     *                        Cannot contain other files. But can have directories. These directories
078
079     *                        will be processed recursively.
080
081     * @param applicationLogs at first invocation an empty, and it will be filled with files
082     */
083    private void collectApplicationLogs(File directory, List<ApplicationLog> applicationLogs) {
084        Preconditions.checkNotNull(directory);
085        Preconditions.checkState(directory.isDirectory());
086        Map<Application, Map<Date, File>> map = new HashMap<>();
087        File[] files = Objects.requireNonNull(directory.listFiles());
088        for (File file : files) {
089            addFileToMap(applicationLogs, map, files, file);
090        }
091        ApplicationService applicationService = ApplicationService.getInstance();
092        for (Entry<Application, Map<Date, File>> appEntry : map.entrySet()) {
093            Application application = appEntry.getKey();
094            ApplicationLog applicationLog = applicationService.findOrCreate(applicationLogs, application);
095            NodeFileService.getInstance().appendToNodeLogs(appEntry.getValue(), applicationLog);
096        }
097    }
098
099    private void addFileToMap(List<ApplicationLog> applicationLogs, Map<Application, Map<Date, File>> map, File[] files, File file) {
100        if (file.isFile()) {
101            if (file.getName().endsWith(".zip")) {
102                file = unzipIfNotExists(file, files);
103            }
104            Application application = FileService.getInstance().findApplication(file);
105            if (!map.containsKey(application)) {
106                map.put(application, new TreeMap<>());
107            }
108            Date date = FileService.getInstance().findDate(file, application);
109            if (date == null) {
110                throw new SubstitutionRuntimeException("Cannot find a date in the file: " + file.getAbsolutePath());
111            }
112            map.get(application).put(date, file);
113        } else {
114            // directories
115            if (!file.getName().endsWith(REPORT_FOLDER_EXTENSION)) {
116                collectApplicationLogs(file, applicationLogs);
117            }
118        }
119    }
120
121    /**
122     * If the second argument contains unzipped first argument, do not unzip it.
123
124     * Else unzip it and return a file from this zipFile.
125
126     * @param zipFile zipped log file
127
128     * @param files all files in a directory
129
130     * @return an unzipped file or file from files
131     */
132    private File unzipIfNotExists(File zipFile, File[] files) {
133        try (
134            InputStream is = new FileInputStream(zipFile);
135            ArchiveInputStream ais = new ArchiveStreamFactory().createArchiveInputStream("zip", is)) {
136            ZipArchiveEntry zipArchiveEntry = (ZipArchiveEntry) ais.getNextEntry();
137            String zipArchiveEntryName = zipArchiveEntry.getName();
138            for (File file : files) {
139                if (file.getName().equals(zipArchiveEntryName)) {
140                    return file;
141                }
142            }
143            File outputFile = new File(zipFile.getParentFile(), zipArchiveEntryName);
144            logger.info("File {}:{} will be decompressed to {}", zipFile.getName(), zipArchiveEntryName, outputFile.getAbsolutePath());
145            IOUtils.copy(ais, new FileOutputStream(outputFile));
146            return outputFile;
147        } catch (Exception e) {
148            throw new SubstitutionRuntimeException("Cannot unzipIfNotExists file: " + zipFile.getAbsolutePath(), e);
149        }
150    }
151
152    @Inject
153    @java.lang.SuppressWarnings("all")
154    public FileUtilService() {
155    }
156}