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

org.datafx.controller.injection.InjectionHandler Maven / Gradle / Ivy

There is a newer version: 8.0b5
Show newest version
package org.datafx.controller.injection;

import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import org.datafx.controller.context.AbstractContext;
import org.datafx.controller.context.ViewContext;
import org.datafx.controller.injection.provider.ContextProvider;
import org.datafx.util.DataFXUtils;

import javax.inject.Inject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.ServiceLoader;


public class InjectionHandler {

    private final static DependendContext DEPENDEND_CONTEXT = new DependendContext();
    private ViewContext viewContext;

    public InjectionHandler(ViewContext viewContext) {
        this.viewContext = viewContext;
    }

    private  T registerNewInstance(final Class propertyClass, final AbstractContext context) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
        for (Constructor constructor : propertyClass.getConstructors()) {
            if (constructor.getParameterCount() == 0) {
                T instance = propertyClass.newInstance();
                context.register(instance);
                injectAllSupportedFields(instance);
                return instance;
            }
        }
        //TODO: Special Exception
        throw new RuntimeException("No default constructor present!");
    }

    public  T createProxy(final Class propertyClass) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        final AbstractContext context = getContextForClass(propertyClass);
        T registeredObject = context.getRegisteredObject(propertyClass);
        if (registeredObject == null) {
            registeredObject = registerNewInstance(propertyClass, context);
        }

        final T innerObject = registeredObject;

        ProxyFactory factory = new ProxyFactory();
        factory.setSuperclass(propertyClass);


        MethodHandler handler = new MethodHandler() {
            @Override
            public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
                AbstractContext context = getContextForClass(propertyClass);
                if (context.getRegisteredObject(propertyClass) == null) {
                    registerNewInstance(propertyClass, context);
                }
                return thisMethod.invoke(innerObject, args);
            }
        };

        return (T) factory.create(new Class[0], new Object[0], handler);
    }

    private  void injectAllSupportedFields(T bean) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        Class cls = (Class) bean.getClass();
        for (final Field field : DataFXUtils.getInheritedPrivateFields(cls)) {
            if (field.isAnnotationPresent(Inject.class)) {
                DataFXUtils.setPrivileged(field, bean, createProxy(field.getType()));
            }
        }
    }

    private AbstractContext getContextForClass(Class cls) {
        ServiceLoader contextProvidersLoader = ServiceLoader.load(ContextProvider.class);
        Iterator iterator = contextProvidersLoader.iterator();

        while (iterator.hasNext()) {
            ContextProvider provider = iterator.next();
            if (cls.isAnnotationPresent(provider.supportedAnnotation())) {
                return provider.getContext(viewContext);
            }
        }

        return DEPENDEND_CONTEXT;
    }

}