All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.buschmais.jqassistant.plugin.common.api.scanner.ContainerFileResolver Maven / Gradle / Ivy

package com.buschmais.jqassistant.plugin.common.api.scanner;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import com.buschmais.jqassistant.core.scanner.api.ScannerContext;
import com.buschmais.jqassistant.core.store.api.model.Descriptor;
import com.buschmais.jqassistant.plugin.common.api.model.FileContainerDescriptor;
import com.buschmais.jqassistant.plugin.common.api.model.FileDescriptor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A file resolver strategy for file containers.
 */
public class ContainerFileResolver extends AbstractFileResolver {

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

    private static final String CACHE_KEY = ContainerFileResolver.class.getName();

    private FileContainerDescriptor fileContainerDescriptor;

    private final ScannerContext scannerContext;

    private final Map requiredFiles;

    private final Map containedFiles;

    public ContainerFileResolver(ScannerContext scannerContext, FileContainerDescriptor fileContainerDescriptor) {
        super(CACHE_KEY + "/" + fileContainerDescriptor.getId());
        this.fileContainerDescriptor = fileContainerDescriptor;
        this.scannerContext = scannerContext;
        this.containedFiles = getCache(fileContainerDescriptor.getContains());
        this.requiredFiles = getCache(fileContainerDescriptor.getRequires());
    }

    @Override
    public  D require(String requiredPath, String containedPath, Class type, ScannerContext context) {
        final FileDescriptor fileDescriptor = containedFiles.get(containedPath);
        D result;
        if (fileDescriptor != null) {
            result = getOrCreateAs(containedPath, type, path -> fileDescriptor, context);
            containedFiles.put(containedPath, result);
        } else {
            result = getOrCreateAs(containedPath, type, path -> requiredFiles.get(containedPath), context);
            requiredFiles.put(containedPath, result);
        }
        return result;
    }

    @Override
    public  D match(String containedPath, Class type, ScannerContext context) {
        FileDescriptor fileDescriptor = requiredFiles.remove(containedPath);
        return getOrCreateAs(containedPath, type, path -> fileDescriptor, context);
    }

    /**
     * Flush the caches to the store.
     */
    public void flush() {
        createHierarchy();
        sync(fileContainerDescriptor.getRequires(), requiredFiles);
        sync(fileContainerDescriptor.getContains(), containedFiles);
        scannerContext.getStore().invalidateCache(CACHE_KEY);
    }

    /**
     * Sync the given target collection with the new state from the cache map.
     *
     * @param target
     *            The target collection.
     * @param after
     *            The new state to sync to.
     */
    private void sync(Collection target, Map after) {
        Map before = getCache(target);
        Map all = new HashMap<>();
        all.putAll(before);
        all.putAll(after);
        for (Map.Entry entry : all.entrySet()) {
            String key = entry.getKey();
            FileDescriptor fileDescriptor = entry.getValue();
            boolean hasBefore = before.containsKey(key);
            boolean hasAfter = after.containsKey(key);
            if (hasBefore && !hasAfter) {
                target.remove(fileDescriptor);
            } else if (!hasBefore && hasAfter) {
                target.add(fileDescriptor);
            }
        }
    }

    /**
     * Creates cache map from the given collection of file descriptors.
     *
     * @param fileDescriptors
     *            The collection of file descriptors.
     * @return The cache map.
     */
    private Map getCache(Iterable fileDescriptors) {
        Map cache = new HashMap<>();
        for (Descriptor descriptor : fileDescriptors) {
            if (descriptor instanceof FileDescriptor) {
                FileDescriptor fileDescriptor = (FileDescriptor) descriptor;
                cache.put(fileDescriptor.getFileName(), fileDescriptor);
            } else {
                LOGGER.warn("{} is not a file descriptor, container={}", descriptor, fileContainerDescriptor);
            }
        }
        return cache;
    }

    /**
     * Build the hierarchy of the container entries, i.e. add contains relations
     * from containers to their children.
     */
    private void createHierarchy() {
        for (Map.Entry entry : containedFiles.entrySet()) {
            String relativePath = entry.getKey();
            FileDescriptor fileDescriptor = entry.getValue();
            int separatorIndex = relativePath.lastIndexOf('/');
            if (separatorIndex != -1) {
                String parentName = relativePath.substring(0, separatorIndex);
                FileDescriptor parentDescriptor = containedFiles.get(parentName);
                if (parentDescriptor instanceof FileContainerDescriptor) {
                    ((FileContainerDescriptor) parentDescriptor).getContains().add(fileDescriptor);
                }
            }
        }
    }

    /**
     * Adds a file to the container.
     *
     * @param path
     *            The path of the file.
     * @param fileDescriptor
     *            The file descriptor.
     */
    public void put(String path, FileDescriptor fileDescriptor) {
        containedFiles.put(path, fileDescriptor);
    }

    /**
     * Returns the size of the container.
     *
     * @return The size of the container.
     */
    public int size() {
        return containedFiles.size();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy