Package com.buschmais.jqassistant.core.scanner.impl

Source Code of com.buschmais.jqassistant.core.scanner.impl.ArtifactScannerImpl

package com.buschmais.jqassistant.core.scanner.impl;

import com.buschmais.jqassistant.core.model.api.descriptor.ArtifactDescriptor;
import com.buschmais.jqassistant.core.model.api.descriptor.Descriptor;
import com.buschmais.jqassistant.core.scanner.api.ArtifactScanner;
import com.buschmais.jqassistant.core.scanner.api.ArtifactScannerPlugin;
import com.buschmais.jqassistant.core.store.api.Store;
import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.URI;
import java.net.URL;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import static com.buschmais.jqassistant.core.scanner.api.ArtifactScannerPlugin.InputStreamSource;

/**
* Implementation of the {@link ArtifactScanner}.
*/
public class ArtifactScannerImpl implements ArtifactScanner {

    private static final Logger LOGGER = LoggerFactory.getLogger(ArtifactScannerImpl.class);

    private Store store;
    private Collection<ArtifactScannerPlugin> plugins;

    /**
     * Constructor.
     *
     * @param plugins The {@link ArtifactScannerPlugin}s to use for scanning.
     */
    public ArtifactScannerImpl(Store store, Collection<ArtifactScannerPlugin> plugins) {
        this.store = store;
        this.plugins = plugins;
    }

    @Override
    public void scanArchive(ArtifactDescriptor artifactDescriptor, File archive) throws IOException {
        if (!archive.exists()) {
            LOGGER.warn("Archive '{}' not found, skipping.", archive.getAbsolutePath());
        } else {
            LOGGER.info("Scanning archive '{}'.", archive.getAbsolutePath());
            long start = System.currentTimeMillis();
            final ZipFile zipFile = new ZipFile(archive);
            int totalFiles = 0;
            int totalDirectories = 0;
            try {
                final Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
                Map<String, SortedSet<ZipEntry>> entries = new TreeMap<>();
                Comparator<ZipEntry> zipEntryComparator = new Comparator<ZipEntry>() {
                    @Override
                    public int compare(ZipEntry o1, ZipEntry o2) {
                        return o1.getName().compareTo(o2.getName());
                    }
                };
                while (zipEntries.hasMoreElements()) {
                    ZipEntry e = zipEntries.nextElement();
                    String name = e.getName();
                    String directory;
                    if (!e.isDirectory()) {
                        directory = name;
                    } else {
                        directory = name.substring(0, name.lastIndexOf('/'));
                    }
                    SortedSet<ZipEntry> directoryEntries = entries.get(directory);
                    if (directoryEntries == null) {
                        directoryEntries = new TreeSet<>(zipEntryComparator);
                        entries.put(directory, directoryEntries);
                        totalDirectories++;
                    }
                    directoryEntries.add(e);
                }
                int currentDirectories = 0;
                int currentFiles = 0;
                LOGGER.info("Archive '{}' contains {} directories.", archive.getAbsolutePath(), entries.size());
                for (Map.Entry<String, SortedSet<ZipEntry>> e : entries.entrySet()) {
                    LOGGER.info("Scanning " + e.getKey() + " (" + currentDirectories + "/" + totalDirectories + " directories, " + currentFiles + "/" + totalFiles + " files)");
                    for (final ZipEntry zipEntry : e.getValue()) {
                        String name = zipEntry.getName();
                        if (zipEntry.isDirectory()) {
                            scanDirectory(artifactDescriptor, name);
                        } else {
                            scanFile(artifactDescriptor, name, getStreamSource(zipFile.getInputStream(zipEntry)));
                        }
                        currentFiles++;
                    }
                    currentDirectories++;
                }
            } finally {
                zipFile.close();
            }
            long end = System.currentTimeMillis();
            LOGGER.info("Scanned archive '{}' in {}ms.", archive.getAbsolutePath(), Long.valueOf(end - start));
        }
    }

    @Override
    public void scanDirectory(ArtifactDescriptor artifactDescriptor, File directory) throws IOException {
        final List<File> files = new ArrayList<>();
        new DirectoryWalker<File>() {

            @Override
            protected boolean handleDirectory(File directory, int depth, Collection<File> results) throws IOException {
                results.add(directory);
                return true;
            }

            @Override
            protected void handleFile(File file, int depth, Collection<File> results) throws IOException {
                results.add(file);
            }

            public void scan(File directory) throws IOException {
                super.walk(directory, files);
            }
        }.scan(directory);
        if (files.isEmpty()) {
            LOGGER.info("Directory '{}' does not contain files, skipping.", directory.getAbsolutePath(), files.size());
        } else {
            LOGGER.info("Scanning directory '{}' [{} files].", directory.getAbsolutePath(), files.size());
            URI directoryURI = directory.toURI();
            for (final File file : files) {
                String name = directoryURI.relativize(file.toURI()).toString();
                if (file.isDirectory()) {
                    if (!StringUtils.isEmpty(name)) {
                        String directoryName = name.substring(0, name.length() - 1);
                        scanDirectory(artifactDescriptor, directoryName);
                    }
                } else {
                    scanFile(artifactDescriptor, name, getStreamSource(new FileInputStream(file)));
                }
            }
        }
    }

    @Override
    public void scanClasses(ArtifactDescriptor artifactDescriptor, Class<?>... classes) throws IOException {
        for (final Class<?> classType : classes) {
            final String resourceName = "/" + classType.getName().replace('.', '/') + ".class";
            scanFile(artifactDescriptor, resourceName, getStreamSource(classType.getResourceAsStream(resourceName)));
        }
    }

    @Override
    public void scanURLs(ArtifactDescriptor artifactDescriptor, URL... urls) throws IOException {
        for (final URL url : urls) {
            scanFile(artifactDescriptor, url.getPath() + "/" + url.getFile(), getStreamSource(url.openStream()));
        }
    }

    /**
     * Return a {@link InputStreamSource} for the given input stream.
     *
     * @param inputStream The input stream.
     * @return The {@link InputStreamSource}.
     */
    private InputStreamSource getStreamSource(final InputStream inputStream) {
        return new InputStreamSource() {
            @Override
            public InputStream openStream() throws IOException {
                return new BufferedInputStream((inputStream));
            }
        };
    }

    /**
     * Scans the given stream source                                          .
     *
     * @param artifactDescriptor The artifact descriptor containing the file.
     * @param name               The name of the file, relative to the artifact root directory.
     * @param streamSource       The stream source.
     * @throws IOException If scanning fails.
     */
    private void scanFile(ArtifactDescriptor artifactDescriptor, String name, InputStreamSource streamSource) throws IOException {
        for (ArtifactScannerPlugin plugin : this.plugins) {
            if (plugin.matches(name, false)) {
                LOGGER.info("Scanning file '{}'", name);
                Descriptor descriptor = plugin.scanFile(store, streamSource);
                artifactDescriptor.getContains().add(descriptor);
            }
        }
    }

    /**
     * Scans the given stream source                                          .
     *
     * @param artifactDescriptor The artifact descriptor containing the file.
     * @param name               The name of the file, relative to the artifact root directory.
     * @throws IOException If scanning fails.
     */
    private void scanDirectory(ArtifactDescriptor artifactDescriptor, String name) throws IOException {
        for (ArtifactScannerPlugin plugin : this.plugins) {
            if (plugin.matches(name, true)) {
                LOGGER.info("Scanning directory '{}'", name);
                Descriptor descriptor = plugin.scanDirectory(store, name);
                artifactDescriptor.getContains().add(descriptor);
            }
        }
    }
}
TOP

Related Classes of com.buschmais.jqassistant.core.scanner.impl.ArtifactScannerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.