se.crisp.codekvast.warehouse.file_import.ZipFileImporterImpl.java Source code

Java tutorial

Introduction

Here is the source code for se.crisp.codekvast.warehouse.file_import.ZipFileImporterImpl.java

Source

/**
 * Copyright (c) 2015-2016 Crisp AB
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
 * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package se.crisp.codekvast.warehouse.file_import;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import se.crisp.codekvast.agent.lib.model.ExportFileMetaInfo;
import se.crisp.codekvast.agent.lib.model.v1.ExportFileEntry;
import se.crisp.codekvast.agent.lib.model.v1.JvmData;
import se.crisp.codekvast.agent.lib.model.v1.SignatureStatus;
import se.crisp.codekvast.warehouse.file_import.ImportDAO.Jvm;

import javax.inject.Inject;
import java.io.*;
import java.nio.charset.Charset;
import java.time.Duration;
import java.time.Instant;
import java.util.function.Function;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import static java.lang.String.format;
import static java.time.Instant.now;

/**
 * @author olle.hallin@crisp.se
 */
@Service
@Slf4j
public class ZipFileImporterImpl implements ZipFileImporter {

    private final ImportDAO importDAO;
    private final Charset charset = Charset.forName("UTF-8");
    private final ObjectMapper objectMapper;

    @Inject
    public ZipFileImporterImpl(ImportDAO importDAO, ObjectMapper objectMapper) {
        this.importDAO = importDAO;
        this.objectMapper = objectMapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importZipFile(File file) {
        log.debug("Importing {}", file);
        Instant startedAt = now();

        ExportFileMetaInfo metaInfo = null;
        ImportDAO.ImportContext context = new ImportDAO.ImportContext();

        try (ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
                InputStreamReader reader = new InputStreamReader(zipInputStream, charset)) {

            ZipEntry zipEntry;
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                ExportFileEntry exportFileEntry = ExportFileEntry.fromString(zipEntry.getName());
                log.debug("Reading {} ...", zipEntry.getName());

                switch (exportFileEntry) {
                case META_INFO:
                    metaInfo = ExportFileMetaInfo.fromInputStream(zipInputStream);
                    if (importDAO.isFileImported(metaInfo)) {
                        log.debug("{} with uuid {} has already been imported", file, metaInfo.getUuid());
                        return;
                    }
                    break;
                case APPLICATIONS:
                    readApplications(reader, context);
                    break;
                case METHODS:
                    readMethods(reader, context);
                    break;
                case JVMS:
                    readJvms(reader, context);
                    break;
                case INVOCATIONS:
                    readInvocations(reader, context);
                    break;
                }
            }
            if (metaInfo != null) {
                importDAO.recordFileAsImported(metaInfo,
                        ImportDAO.ImportStatistics.builder().importFile(file)
                                .fileSize(humanReadableByteCount(file.length()))
                                .processingTime(Duration.between(startedAt, now())).build());
            }
        } catch (IllegalArgumentException | IOException e) {
            log.error("Cannot import " + file, e);
        }
    }

    private String humanReadableByteCount(long bytes) {
        if (bytes < 1000) {
            return bytes + " B";
        }
        int exponent = (int) (Math.log(bytes) / Math.log(1000));
        String unit = " kMGTPE".charAt(exponent) + "B";
        return format("%.1f %s", bytes / Math.pow(1000, exponent), unit);
    }

    private void doReadCsv(InputStreamReader reader, String what, Function<String[], Boolean> lineProcessor) {
        CSVReader csvReader = new CSVReaderBuilder(reader).withSkipLines(1).build();
        int count = 0;
        Instant startedAt = now();
        for (String[] columns : csvReader) {
            if (lineProcessor.apply(columns)) {
                count += 1;

                if (count % 1000 == 0) {
                    log.debug("Imported {} {}...", count, what);
                }
            }
        }
        if (count > 0) {
            log.debug("Imported {} {} in {} ms", count, what, Duration.between(startedAt, now()).toMillis());
        }
    }

    private void readApplications(InputStreamReader reader, ImportDAO.ImportContext context) {
        doReadCsv(reader, "applications", (String[] columns) -> {
            ImportDAO.Application app = ImportDAO.Application.builder().localId(Long.valueOf(columns[0]))
                    .name(columns[1]).version(columns[2]).createdAtMillis(Long.valueOf(columns[3])).build();

            return importDAO.saveApplication(app, context);
        });
    }

    private void readMethods(InputStreamReader reader, ImportDAO.ImportContext context) {
        doReadCsv(reader, "methods", (String[] columns) -> {
            ImportDAO.Method method = ImportDAO.Method.builder().localId(Long.valueOf(columns[0]))
                    .visibility(columns[1]).signature(columns[2]).createdAtMillis(Long.valueOf(columns[3]))
                    .declaringType(columns[4]).exceptionTypes(columns[5]).methodName(columns[6])
                    .modifiers(columns[7]).packageName(columns[8]).parameterTypes(columns[9])
                    .returnType(columns[10]).build();
            return importDAO.saveMethod(method, context);
        });
    }

    private void readJvms(InputStreamReader reader, ImportDAO.ImportContext context) {
        doReadCsv(reader, "JVMs", (String[] columns) -> doProcessJvm(context, columns));
    }

    @SneakyThrows(IOException.class)
    private boolean doProcessJvm(ImportDAO.ImportContext context, String[] columns) {
        Jvm jvm = Jvm.builder().localId(Long.valueOf(columns[0])).uuid(columns[1])
                .startedAtMillis(Long.valueOf(columns[2])).dumpedAtMillis(Long.valueOf(columns[3]))
                .jvmDataJson(columns[4]).build();
        JvmData jvmData = objectMapper.readValue(jvm.getJvmDataJson(), JvmData.class);
        return importDAO.saveJvm(jvm, jvmData, context);
    }

    private void readInvocations(InputStreamReader reader, ImportDAO.ImportContext context) {
        doReadCsv(reader, "invocations", (String[] columns) -> {
            ImportDAO.Invocation invocation = ImportDAO.Invocation.builder()
                    .localApplicationId(Long.valueOf(columns[0])).localMethodId(Long.valueOf(columns[1]))
                    .localJvmId(Long.valueOf(columns[2])).invokedAtMillis(Long.valueOf(columns[3]))
                    .invocationCount(Long.valueOf(columns[4]))
                    .status(SignatureStatus.fromOrdinal(Integer.valueOf(columns[5]))).build();
            return importDAO.saveInvocation(invocation, context);
        });
    }

}