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

io.github.karlatemp.mxlib.common.utils.BeanManagers Maven / Gradle / Ivy

/*
 * Copyright (c) 2018-2021 Karlatemp. All rights reserved.
 * @author Karlatemp  
 *
 * MXLib/MXLib.mxlib-common.main/BeanManagers.java
 *
 * Use of this source code is governed by the MIT license that can be found via the following link.
 *
 * https://github.com/Karlatemp/MxLib/blob/master/LICENSE
 */

package io.github.karlatemp.mxlib.common.utils;

import io.github.karlatemp.caller.CallerFinder;
import io.github.karlatemp.caller.StackFrame;
import io.github.karlatemp.mxlib.MxLib;
import io.github.karlatemp.mxlib.annotations.injector.Inject;
import io.github.karlatemp.mxlib.bean.IBeanManager;
import io.github.karlatemp.mxlib.bean.SimpleBeanManager;
import io.github.karlatemp.mxlib.common.injector.SimpleInjector;
import io.github.karlatemp.mxlib.common.injector.SimpleMethodCallerWithBeans;
import io.github.karlatemp.mxlib.common.injector.SimpleObjectCreator;
import io.github.karlatemp.mxlib.exception.ScanException;
import io.github.karlatemp.mxlib.injector.IInjector;
import io.github.karlatemp.mxlib.injector.IObjectCreator;
import io.github.karlatemp.mxlib.injector.MethodCallerWithBeans;
import io.github.karlatemp.mxlib.reflect.Reflections;
import io.github.karlatemp.mxlib.utils.ClassLocator;
import io.github.karlatemp.mxlib.utils.IJarScanner;
import io.github.karlatemp.mxlib.utils.IteratorSupplier;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@SuppressWarnings({"unchecked", "rawtypes"})
public class BeanManagers {
    private static final Set registeredSets = new HashSet<>();
    private static final Lock lock = new ReentrantLock();

    public static IBeanManager newStandardManager() {
        IBeanManager beanManager = new SimpleBeanManager();
        registerStandardBeans(beanManager, Reflections.getClassLoader(CallerFinder.getCaller()));
        return beanManager;
    }

    public static void registerStandardBeans(
            @NotNull IBeanManager beanManager,
            @Nullable ClassLoader loader
    ) {
        if (loader == null) {
            loader = Reflections.getClassLoader(CallerFinder.getCaller());
        }
        SimpleClassLocator locator = new SimpleClassLocator(loader);
        beanManager.register(IInjector.class, new SimpleInjector(beanManager));
        beanManager.register(IObjectCreator.class, new SimpleObjectCreator(beanManager));
        beanManager.register(MethodCallerWithBeans.class, new SimpleMethodCallerWithBeans());
        beanManager.register(ClassLocator.class, locator);
        beanManager.register(IJarScanner.class, new SimpleJarScanner(beanManager));
    }

    public static void registerAll(@NotNull Path path) {
        ClassLoader loader;
        {
            StackFrame frame = CallerFinder.getCaller();
            if (frame != null) {
                loader = Objects.requireNonNull(frame.getClassInstance(), "CallerFinder cannot find caller")
                        .getClassLoader();
            } else {
                throw new RuntimeException("No caller frame found");
            }
        }
        registerAll(path, loader, null);
    }

    public static void registerAll(@NotNull Path path, ClassLoader loader, IBeanManager beanManager) {
        if (beanManager == null) {
            beanManager = MxLib.getBeanManager();
        }
        lock.lock();
        try {
            if (registeredSets.contains(path)) return;
            registeredSets.add(path);

            IJarScanner scanner = beanManager.getBeanNonNull(IJarScanner.class);
            IObjectCreator objectCreator = beanManager.getBeanNonNull(IObjectCreator.class);
            MethodCallerWithBeans caller = beanManager.getBeanNonNull(MethodCallerWithBeans.class);

            List classes;
            try {
                classes = scanner.scan(path, new ArrayList<>());
            } catch (ScanException e) {
                MxLib.getLogger().warn("Exception in scanning path " + path, e);
                return;
            }
            for (String klass : classes) {
                InputStream i0x;
                try {
                    i0x = Files.newInputStream(path.resolve(klass.replace('.', '/') + ".class"));
                } catch (IOException ignore) {
                    continue;
                }
                ClassNode node;
                try (InputStream ixw = i0x) {
                    node = new ClassNode();
                    new ClassReader(ixw).accept(node, 0);
                } catch (Exception err) {
                    MxLib.getLogger().warn("Exception in reading class file " + path, err);
                    continue;
                }
                List annotations = node.visibleAnnotations;
                boolean process = false;
                if (annotations != null) {
                    for (AnnotationNode an : annotations) {
                        if (an.desc.equals("Lio/github/karlatemp/mxlib/annotations/injector/Configuration;")) {
                            process = true;
                            break;
                        }
                    }
                }
                if (process) {
                    try {
                        Class klassX = Class.forName(node.name.replace('/', '.'), false, loader);
                        Object instance = objectCreator.newInstance(klassX);
                        for (Method method : new IteratorSupplier<>(Reflections.allMethods(klassX)
                                .filter(Reflections.withAnnotated(Inject.class))
                                .filter(Reflections.ModifierFilter.NON_STATIC)
                                .peek(Reflections.openAccess())
                                .iterator())) {
                            Inject inject = method.getDeclaredAnnotation(Inject.class);
                            String name = inject.name();
                            if (name.equals(Inject.NAME_UNSET)) name = null;
                            Class type = inject.value();
                            if (type == Void.class) type = method.getReturnType();
                            beanManager.register(type, name, caller.callMethod(beanManager, method, instance));
                        }

                    } catch (Throwable throwable) {
                        MxLib.getLogger().warn("Exception in processing " + path, throwable);
                    }
                }
            }
        } finally {
            lock.unlock();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy