migrate from marinara
This commit is contained in:
		@@ -0,0 +1,7 @@
 | 
			
		||||
package net.tomatentum.cutin;
 | 
			
		||||
 | 
			
		||||
public interface MethodExecutor {
 | 
			
		||||
 | 
			
		||||
    void handle(Object context);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								lib/src/main/java/net/tomatentum/cutin/MethodParser.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lib/src/main/java/net/tomatentum/cutin/MethodParser.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
package net.tomatentum.cutin;
 | 
			
		||||
 | 
			
		||||
public interface MethodParser {
 | 
			
		||||
	void parse();
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
package net.tomatentum.cutin;
 | 
			
		||||
 | 
			
		||||
public interface MethodProcessor {
 | 
			
		||||
 | 
			
		||||
    void process(Object context);
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
package net.tomatentum.cutin;
 | 
			
		||||
 | 
			
		||||
public interface ProcessorContainer {
 | 
			
		||||
 | 
			
		||||
    ProcessorContainer addProcessor(MethodProcessor processor);
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
package net.tomatentum.cutin;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
public class ProcessorMethodExecutor implements MethodExecutor, ProcessorContainer {
 | 
			
		||||
 | 
			
		||||
    private Logger logger = LoggerFactory.getLogger(getClass());
 | 
			
		||||
 | 
			
		||||
    private Set<MethodProcessor> processors;
 | 
			
		||||
 | 
			
		||||
    public ProcessorMethodExecutor() {
 | 
			
		||||
        this.processors = new HashSet<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ProcessorContainer addProcessor(MethodProcessor processor) {
 | 
			
		||||
        processors.add(processor);
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void handle(Object context) {
 | 
			
		||||
        logger.debug("Received {} interaction ", context);
 | 
			
		||||
        processors.forEach(x -> x.process(context));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								lib/src/main/java/net/tomatentum/cutin/ReflectedMethod.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								lib/src/main/java/net/tomatentum/cutin/ReflectedMethod.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
package net.tomatentum.cutin;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.InvocationTargetException;
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import java.security.InvalidParameterException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import net.tomatentum.cutin.util.ReflectionUtil;
 | 
			
		||||
 | 
			
		||||
public abstract class ReflectedMethod {
 | 
			
		||||
 | 
			
		||||
    private Logger logger = LoggerFactory.getLogger(getClass());
 | 
			
		||||
 | 
			
		||||
    private Method method;
 | 
			
		||||
    private Object containingObject;
 | 
			
		||||
 | 
			
		||||
    public ReflectedMethod(Method method, Object containingObject) {
 | 
			
		||||
        if (!Arrays.asList(containingObject.getClass().getMethods()).contains(method))
 | 
			
		||||
            throw new InvalidParameterException("Method does not apply to specified handler");
 | 
			
		||||
        this.method = method;
 | 
			
		||||
        this.containingObject = containingObject;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public abstract Object getParameter(Object context, int index);
 | 
			
		||||
 | 
			
		||||
    public Object run(Object context) {
 | 
			
		||||
        method.setAccessible(true);
 | 
			
		||||
        try {
 | 
			
		||||
            return method.invoke(containingObject, getParameters(context));
 | 
			
		||||
        }catch (IllegalAccessException | InvocationTargetException ex) {
 | 
			
		||||
            logger.error("ReflectedMethod failed to run", ex);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Method method() {
 | 
			
		||||
        return this.method;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Object containingObject() {
 | 
			
		||||
        return this.containingObject;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Object[] getParameters(Object context) {
 | 
			
		||||
        int parameterCount = method.getParameterCount();
 | 
			
		||||
        List<Object> parameters = new ArrayList<>();
 | 
			
		||||
        
 | 
			
		||||
        for (int i = 0; i < parameterCount; i++) {
 | 
			
		||||
            Object parameter;
 | 
			
		||||
            if (i == 0) {
 | 
			
		||||
                parameter = context;
 | 
			
		||||
            }else
 | 
			
		||||
                parameter = getParameter(context, i-1);
 | 
			
		||||
 | 
			
		||||
            logger.trace("Found parameter {}={} for method {}", parameter != null ? parameter.getClass().toString() : " ", parameter, ReflectionUtil.getFullMethodName(method));
 | 
			
		||||
            parameters.add(parameter);   
 | 
			
		||||
        }
 | 
			
		||||
        return parameters.toArray();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
package net.tomatentum.cutin;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public interface ReflectedMethodFactory {
 | 
			
		||||
    Optional<ReflectedMethod> produce(Method method, Object containingClass);
 | 
			
		||||
    ReflectedMethodFactory addFactory(Factory factory);
 | 
			
		||||
 | 
			
		||||
    public interface Factory {
 | 
			
		||||
 | 
			
		||||
        Optional<ReflectedMethod> produce(Method method, Object containingObject);
 | 
			
		||||
        void addParser(ReflectedMethod method, List<MethodParser> parser);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
package net.tomatentum.cutin;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import net.tomatentum.cutin.util.ReflectionUtil;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class ReflectedMethodFactoryImpl implements ReflectedMethodFactory {
 | 
			
		||||
 | 
			
		||||
    private Logger logger = LoggerFactory.getLogger(getClass());
 | 
			
		||||
 | 
			
		||||
    private List<Factory> factories;
 | 
			
		||||
 | 
			
		||||
    public ReflectedMethodFactoryImpl() {
 | 
			
		||||
        this(new ArrayList<>());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ReflectedMethodFactoryImpl(List<Factory> factories) {
 | 
			
		||||
        this.factories = factories;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Optional<ReflectedMethod> produce(Method method, Object containingClass) {
 | 
			
		||||
        Optional<ReflectedMethod> imethod = this.factories.stream()
 | 
			
		||||
            .map(f -> factoryProduce(f, method, containingClass))
 | 
			
		||||
            .filter(Optional::isPresent)
 | 
			
		||||
            .map(Optional::get)
 | 
			
		||||
            .findFirst();
 | 
			
		||||
 | 
			
		||||
        if (imethod.isEmpty()) {
 | 
			
		||||
            logger.debug("Could not produce a ReflectedMethod for Method {}", ReflectionUtil.getFullMethodName(method));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return imethod;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ReflectedMethodFactory addFactory(Factory factory) {
 | 
			
		||||
        this.factories.add(factory);
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Optional<ReflectedMethod> factoryProduce(Factory factory, Method method, Object containingClass) {
 | 
			
		||||
        List<MethodParser> parser = new ArrayList<>();
 | 
			
		||||
        Optional<ReflectedMethod> m = factory.produce(method, containingClass);
 | 
			
		||||
        m.ifPresent(x -> {
 | 
			
		||||
            factory.addParser(x, parser); 
 | 
			
		||||
            parser.forEach(MethodParser::parse);
 | 
			
		||||
        });
 | 
			
		||||
        return m;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										107
									
								
								lib/src/main/java/net/tomatentum/cutin/util/ReflectionUtil.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								lib/src/main/java/net/tomatentum/cutin/util/ReflectionUtil.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
package net.tomatentum.cutin.util;
 | 
			
		||||
 | 
			
		||||
import java.lang.annotation.Annotation;
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
public final class ReflectionUtil {
 | 
			
		||||
 | 
			
		||||
    public static <T extends Annotation> boolean isAnnotationPresent(Method method, Class<T> annotationClass) {
 | 
			
		||||
        if (method.isAnnotationPresent(annotationClass) || method.getDeclaringClass().isAnnotationPresent(annotationClass))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static <T extends Annotation> T getAnnotation(Method method, Class<T> annotationClass) {
 | 
			
		||||
        return method.isAnnotationPresent(annotationClass) ? 
 | 
			
		||||
            method.getAnnotation(annotationClass) : 
 | 
			
		||||
            method.getDeclaringClass().getAnnotation(annotationClass);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static int getCastDepth(Class<?> child, Class<?> parent) {
 | 
			
		||||
 | 
			
		||||
        if (parent.equals(Object.class))
 | 
			
		||||
            return Integer.MAX_VALUE;
 | 
			
		||||
 | 
			
		||||
        if (!parent.isAssignableFrom(child)) {
 | 
			
		||||
            throw new IllegalArgumentException("The specified class is not a child class of the specified parent.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int depth = 0;
 | 
			
		||||
        Class<?> curr = child;
 | 
			
		||||
        List<Class<?>> parents = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        while (!curr.equals(parent)) {
 | 
			
		||||
            depth++;
 | 
			
		||||
            parents.add(curr.getSuperclass());
 | 
			
		||||
            parents.addAll(Arrays.asList(curr.getInterfaces()));
 | 
			
		||||
 | 
			
		||||
            for (Class<?> currParent : parents) {
 | 
			
		||||
                if (currParent != null && parent.isAssignableFrom(currParent)) {
 | 
			
		||||
                    curr = currParent;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            parents.clear();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return depth;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static Method getMostSpecificMethod(Method[] methods, Class<?>... parameters) {
 | 
			
		||||
        List<Method> compatibleMethods = Arrays.stream(methods)
 | 
			
		||||
            .filter(x -> isMethodCallable(x, parameters))
 | 
			
		||||
            .toList();
 | 
			
		||||
 | 
			
		||||
        if (compatibleMethods.size() == 0)
 | 
			
		||||
            throw new IllegalArgumentException("There are no compatible Methods provided");
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < parameters.length; i++) {
 | 
			
		||||
            final int currI = i;
 | 
			
		||||
            Class<?>[] parameterTypes = compatibleMethods.stream()
 | 
			
		||||
                .map(x -> x.getParameterTypes()[currI])
 | 
			
		||||
                .toArray(x -> new Class[x]);
 | 
			
		||||
 | 
			
		||||
            Class<?> mostSpecific = getMostSpecificClass(parameterTypes, parameters[i]);
 | 
			
		||||
 | 
			
		||||
            compatibleMethods = compatibleMethods.stream()
 | 
			
		||||
                .filter(x -> Objects.equals(x.getParameterTypes()[currI], mostSpecific))
 | 
			
		||||
                .toList();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return compatibleMethods.getFirst();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Class<?> getMostSpecificClass(Class<?>[] classes, Class<?> base) {
 | 
			
		||||
        int min = Integer.MAX_VALUE;
 | 
			
		||||
        Class<?> currMostSpecific = null;
 | 
			
		||||
        for (Class<?> currClass : classes) {
 | 
			
		||||
            int currCastDepth = getCastDepth(base, currClass);
 | 
			
		||||
            if (currCastDepth <= min) {
 | 
			
		||||
                min = currCastDepth;
 | 
			
		||||
                currMostSpecific = currClass;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return currMostSpecific;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean isMethodCallable(Method method, Class<?>... parameters) {
 | 
			
		||||
        if (!Objects.equals(method.getParameterCount(), parameters.length))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        Class<?>[] methodParams = method.getParameterTypes();
 | 
			
		||||
        for (int i = 0; i < parameters.length; i++) {
 | 
			
		||||
            if (!methodParams[i].isAssignableFrom(parameters[i]))
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getFullMethodName(Method method) {
 | 
			
		||||
        return method.getDeclaringClass().getName() + "." + method.getName();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user