001// Generated by delombok at Thu May 02 07:34:48 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     * @param fileNumber an order number. Can be 'null' if a single file
035     *                   should be created in the directory. If not 'null',
036     *                   this number will be appended to the file name,
037     *                   for example index_001.html
038     * @param fileName the file name without extension
039     * @param reportDirectory where the new file will be created
040     * @param fileExtension for example html or txt
041     *
042     * @return the new file with context transformed from the source log file.
043     */
044    public File generateFile(Integer fileNumber, String fileName, File reportDirectory, String fileExtension) {
045        String num = null;
046        if (fileNumber != null) {
047            num = String.format("%03d", fileNumber);
048        }
049        StringBuilder newFileName = new StringBuilder(fileName);
050        if (num != null) {
051            newFileName.append(DOT).append(num);
052        }
053        newFileName.append(DOT).append(fileExtension);
054        File file = new File(reportDirectory, newFileName.toString());
055        logger.info("The new empty file created: \'{}\'", file.getAbsolutePath());
056        return file;
057    }
058
059    /**
060     * Sort files in a directory from the first argument.
061     * For each {@link Application} creates its own list of files.
062     *
063     * @param directory       cannot be 'null'. Can have files from different {@link Application}s.<br>
064     *                        Cannot contain other files. But can have directories. These directories
065     *                        will be processed recursively.
066     * @param applicationLogs at first invocation an empty, and it will be filled with files
067     */
068    private void collectApplicationLogs(File directory, List<ApplicationLog> applicationLogs) {
069        Preconditions.checkNotNull(directory);
070        Preconditions.checkState(directory.isDirectory());
071        Map<Application, Map<Date, File>> map = new HashMap<>();
072        File[] files = Objects.requireNonNull(directory.listFiles());
073        for (File file : files) {
074            addFileToMap(applicationLogs, map, files, file);
075        }
076        ApplicationService applicationService = ApplicationService.getInstance();
077        for (Entry<Application, Map<Date, File>> appEntry : map.entrySet()) {
078            Application application = appEntry.getKey();
079            ApplicationLog applicationLog = applicationService.findOrCreate(applicationLogs, application);
080            NodeFileService.getInstance().appendToNodeLogs(appEntry.getValue(), applicationLog);
081        }
082    }
083
084    private void addFileToMap(List<ApplicationLog> applicationLogs, Map<Application, Map<Date, File>> map, File[] files, File file) {
085        if (file.isFile()) {
086            if (file.getName().endsWith(".zip")) {
087                file = unzipIfNotExists(file, files);
088            }
089            Application application = FileService.getInstance().findApplication(file);
090            if (!map.containsKey(application)) {
091                map.put(application, new TreeMap<>());
092            }
093            Date date = FileService.getInstance().findDate(file, application);
094            if (date == null) {
095                throw new SubstitutionRuntimeException("Cannot find a date in the file: " + file.getAbsolutePath());
096            }
097            map.get(application).put(date, file);
098        } else {
099            // directories
100            if (!file.getName().endsWith(REPORT_FOLDER_EXTENSION)) {
101                collectApplicationLogs(file, applicationLogs);
102            }
103        }
104    }
105
106    /**
107     * If the second argument contains unzipped first argument, do not unzip it.
108     * Else unzip it and return a file from this zipFile.
109     * @param zipFile zipped log file
110     * @param files all files in a directory
111     * @return an unzipped file or file from files
112     */
113    private File unzipIfNotExists(File zipFile, File[] files) {
114        try (
115            InputStream is = new FileInputStream(zipFile);
116            ArchiveInputStream ais = new ArchiveStreamFactory().createArchiveInputStream("zip", is)) {
117            ZipArchiveEntry zipArchiveEntry = (ZipArchiveEntry) ais.getNextEntry();
118            String zipArchiveEntryName = zipArchiveEntry.getName();
119            for (File file : files) {
120                if (file.getName().equals(zipArchiveEntryName)) {
121                    return file;
122                }
123            }
124            File outputFile = new File(zipFile.getParentFile(), zipArchiveEntryName);
125            logger.info("File {}:{} will be decompressed to {}", zipFile.getName(), zipArchiveEntryName, outputFile.getAbsolutePath());
126            IOUtils.copy(ais, new FileOutputStream(outputFile));
127            return outputFile;
128        } catch (Exception e) {
129            throw new SubstitutionRuntimeException("Cannot unzipIfNotExists file: " + zipFile.getAbsolutePath(), e);
130        }
131    }
132
133    @Inject
134    @java.lang.SuppressWarnings("all")
135    public FileUtilService() {
136    }
137}