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

io.magentys.cinnamon.guice.GuiceModuleAggregator Maven / Gradle / Ivy

There is a newer version: 0.2.0
Show newest version
package io.magentys.cinnamon.guice;

import com.google.inject.Module;
import com.google.inject.util.Modules;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.vfs2.*;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.util.*;

import static java.util.Arrays.asList;

public class GuiceModuleAggregator {

    private final List> moduleAnnotations;
    private final List> overridesModuleAnnotations;
    private final List packages;

    public GuiceModuleAggregator(Builder builder) {
        this.moduleAnnotations = builder.moduleAnnotations;
        this.overridesModuleAnnotations = builder.overridesModuleAnnotations;
        this.packages = builder.packages;
    }

    public List> getModuleAnnotations() {
        return moduleAnnotations;
    }

    public List> getOverridesModuleAnnotations() {
        return overridesModuleAnnotations;
    }

    public List getPackages() {
        return packages;
    }

    public static class Builder {
        private static final String GUICE_PACKAGE = "com.google.inject";
        private final Logger logger = LoggerFactory.getLogger(getClass());
        private List> moduleAnnotations = new ArrayList<>();
        private List> overridesModuleAnnotations = new ArrayList<>(Collections.singletonList(OverridesModule.class));
        private List packages = new ArrayList<>();

        @SuppressWarnings("unchecked")
        public Builder withModuleAnnotations(Class... moduleAnnotations) {
            this.moduleAnnotations = new ArrayList<>(asList(moduleAnnotations));
            return this;
        }

        @SuppressWarnings("unchecked")
        public Builder withOverrideModuleAnnotations(Class... overridesModuleAnnotations) {
            this.overridesModuleAnnotations = new ArrayList<>(asList(overridesModuleAnnotations));
            return this;
        }

        public Builder withPackages(String... packages) {
            this.packages = new ArrayList<>(asList(packages));
            return this;
        }

        public Module build() {
            try {
                Map modules = getModulesAnnotatedWith(moduleAnnotations);
                Map overridesModules = getModulesAnnotatedWith(overridesModuleAnnotations);
                modules = modules.isEmpty() ? getSubTypesOfModule() : modules;
                logger.debug("Modules [" + Collections.singletonList(modules.keySet()) + "]");
                logger.debug("Overrides modules [" + (overridesModules.isEmpty() ? "" : Collections.singletonList(overridesModules.keySet())) + "]");
                return overridesModules.isEmpty() ?
                        Modules.combine(modules.values()) :
                        Modules.override(modules.values()).with(overridesModules.values());
            } catch (FileSystemException e) {
                logger.error(e.getMessage());
            }
            return null;
        }

        private Map getModulesAnnotatedWith(List> annotations) throws FileSystemException {
            Map modules = new HashMap<>();
            packages = packages.isEmpty() ? getPackages() : packages;
            Reflections reflections = new Reflections(packages);
            for (Class annotation : annotations) {
                reflections.getTypesAnnotatedWith(annotation).stream().filter(Module.class::isAssignableFrom).forEachOrdered(clazz -> {
                    try {
                        Module instance = (Module) clazz.newInstance();
                        if (!modules.containsKey(clazz.getName()))
                            modules.put(clazz.getName(), instance);
                    } catch (InstantiationException | IllegalAccessException e) {
                        logger.error(e.getMessage());
                    }
                });
            }
            return modules;
        }

        private Map getSubTypesOfModule() throws FileSystemException {
            Map modules = new HashMap<>();
            packages = packages.isEmpty() ? getPackages() : packages;
            // To getEventBus a type within the scan result that has some super types,
            // one of which implements/extends the relevant interface/class,
            // then you have to include the packages in which the super types
            // reside.
            Reflections reflections = new Reflections(packages, GUICE_PACKAGE);
            reflections.getSubTypesOf(Module.class).stream()
                    .filter(module -> !hasOverridesAnnotation(module) && !module.getName().startsWith(GUICE_PACKAGE) && !module.getName()
                            .equals(CinnamonModule.class.getName())).forEachOrdered(module -> {
                try {
                    Module instance = module.newInstance();
                    if (!modules.containsKey(module.getName()))
                        modules.put(module.getName(), instance);
                } catch (InstantiationException | IllegalAccessException e) {
                    logger.error(e.getMessage());
                }
            });
            return modules;
        }

        private boolean hasOverridesAnnotation(Class module) {
            for (Class annotation : overridesModuleAnnotations) {
                if (module.isAnnotationPresent(annotation))
                    return true;
            }
            return false;
        }

        private List getPackages() throws FileSystemException {
            FileSystemManager fileSystemManager = VFS.getManager();
            HashSet packageNames = new HashSet<>();
            for (String element : System.getProperty("java.class.path").split(";")) {
                if (element.endsWith("jar")) {
                    FileObject fileObject = fileSystemManager.resolveFile("jar://" + element);
                    addPackages(fileObject, "", packageNames);
                } else {
                    FileObject fileObject = fileSystemManager.resolveFile(element);
                    if (fileObject.getType() == FileType.FOLDER)
                        addPackages(fileObject, fileObject.getName().getPath(), packageNames);
                }
            }
            return new ArrayList<>(packageNames);
        }

        private void addPackages(FileObject fileObject, String filePath, HashSet packageNames) throws FileSystemException {
            for (FileObject child : fileObject.getChildren()) {
                if (!child.getName().getBaseName().equals("META-INF")) {
                    if (child.getType() == FileType.FOLDER) {
                        addPackages(child, filePath, packageNames);
                    } else if (child.getName().getExtension().equals("class")) {
                        String parentPath = child.getParent().getName().getPath();
                        parentPath = StringUtils.remove(parentPath, filePath);
                        parentPath = StringUtils.removeStart(parentPath, "/");
                        parentPath = parentPath.replaceAll("/", ".");
                        packageNames.add(parentPath);
                    }
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy