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

org.diablitozzz.jin.impl.JinFactoryAbstract Maven / Gradle / Ivy

Go to download

Jin is a small library, without the dependencies, that implements the dependency injection using annotations or XML.

The newest version!
package org.diablitozzz.jin.impl;

import java.io.Closeable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.diablitozzz.jin.Jin;
import org.diablitozzz.jin.JinClose;
import org.diablitozzz.jin.JinException;
import org.diablitozzz.jin.JinFactoryInterface;
import org.diablitozzz.jin.JinInit;
import org.diablitozzz.jin.JinInject;

/**
 * A default abstract implementation of the Jin factory.
 *
 * @author Vladimir Ionov
 */
abstract public class JinFactoryAbstract implements JinFactoryInterface {

    protected static class InjectField {
        private final Field field;
        private final Class injectClass;
        private final String injectName;
        private final boolean singleton;
        
        public InjectField(final Field field) throws JinException {
            this.field = field;
            this.field.setAccessible(true);
            final JinInject annotation = field.getAnnotation(JinInject.class);
            this.injectClass = field.getType();
            this.injectName = annotation.name();
            this.singleton = annotation.singleton();
        }

        @Override
        public boolean equals(final Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (this.getClass() != obj.getClass()) {
                return false;
            }
            final InjectField other = (InjectField) obj;
            if (this.field == null) {
                if (other.field != null) {
                    return false;
                }
            } else if (!this.field.equals(other.field)) {
                return false;
            }
            return true;
        }
        
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((this.field == null) ? 0 : this.field.hashCode());
            return result;
        }

        public void inject(final Jin jin, final Object instance) throws JinException {
            final Object injectInstance = this.singleton ? jin.singleton(this.injectClass, this.injectName) : jin.instance(this.injectClass, this.injectName, true);
            try {
                this.field.setAccessible(true);
                this.field.set(instance, injectInstance);
            } catch (final Throwable e) {
                throw JinException.create(e, "Can't inject depends");
            }
        }
        
    }

    protected static Method findInitOrCloseMethod(final Class clazz, final boolean init) throws JinException {
        
        for (final Method method : clazz.getDeclaredMethods()) {
            if (method.getParameterTypes().length != 0) {
                continue;
            }
            if (method.isAnnotationPresent(init ? JinInit.class : JinClose.class)) {
                method.setAccessible(true);
                return method;
            }
        }
        return null;
    }
    
    protected static Set findInjectFields(final Class clazz) throws JinException {
        
        final LinkedHashSet result = new LinkedHashSet<>();
        final List> classChain = JinFactoryAbstract.getClassChain(clazz);
        // make protected
        for (final Class chainItem : classChain) {
            for (final Field field : chainItem.getDeclaredFields()) {
                if (!Modifier.isPrivate(field.getModifiers())) {
                    continue;
                }
                if (!field.isAnnotationPresent(JinInject.class)) {
                    continue;
                }
                field.setAccessible(true);
                result.add(new InjectField(field));
            }
        }
        // make not protected
        for (final Class chainItem : classChain) {
            for (final Field field : chainItem.getDeclaredFields()) {
                if (Modifier.isPrivate(field.getModifiers())) {
                    continue;
                }
                if (!field.isAnnotationPresent(JinInject.class)) {
                    continue;
                }
                field.setAccessible(true);
                result.add(new InjectField(field));
            }
        }
        return result;
    }

    protected static List> getClassChain(final Class clazz) {

        final List> out = new ArrayList>();
        Class current = clazz;
        while (true) {
            if (current.isInterface()) {
                break;
            }
            out.add(current);
            current = current.getSuperclass();
            if ((current == null) || current == Object.class) {
                break;
            }
        }
        Collections.reverse(out);
        return out;
    }
    
    protected T singleton;
    protected final Jin jin;
    protected final Class targetClass;
    protected final Set injectFields;
    protected Method initMethod;
    protected Method closeMethod;
    protected final String name;
    protected final boolean lazy;

    public JinFactoryAbstract(final Jin jin, final Class targetClass, final String name, final boolean lazy) throws JinException {
        this.targetClass = targetClass;
        this.jin = jin;
        this.lazy = lazy;
        this.name = name;
        if (targetClass == null) {
            throw JinException.create("Can't create factory. Target class can't be a null");
        }
        this.injectFields = JinFactoryAbstract.findInjectFields(targetClass);
        this.initMethod = JinFactoryAbstract.findInitOrCloseMethod(this.targetClass, true);
        this.closeMethod = JinFactoryAbstract.findInitOrCloseMethod(this.targetClass, false);
    }
    
    @Override
    public void close() {
        if (this.singleton != null) {
            this.close(this.singleton);
        }
        this.singleton = null;
    }
    
    protected void close(final T instance) {
        try {
            if (this.closeMethod != null) {
                this.closeMethod.invoke(instance, new Object[] {});
            } else if (instance instanceof AutoCloseable) {
                ((AutoCloseable) instance).close();
            } else if (instance instanceof Closeable) {
                ((Closeable) instance).close();
            }
        } catch (final Throwable e) {
            //ignore
        }
    }

    abstract protected T createInstance() throws JinException;

    @Override
    public String getName() {
        return this.name;
    }
    
    @Override
    public Class getTargetClass() {
        return this.targetClass;
    }

    protected void init(final T instance) throws JinException {
        try {
            if (this.initMethod != null) {
                this.initMethod.invoke(instance, new Object[] {});
            }

        } catch (final Throwable e) {
            throw JinException.create(e);
        }
    }
    
    @Override
    public JinFactoryInterface inject(final T instance) throws JinException {
        if (instance == null) {
            throw JinException.create("Can't inject to null instance");
        }
        if (!this.targetClass.isAssignableFrom(instance.getClass())) {
            throw JinException.create("Can't inject instance class:%s not equals manager class:%s", instance.getClass(), this.targetClass);
        }
        for (final InjectField injectField : this.injectFields) {
            injectField.inject(this.jin, instance);
        }
        return this;
    }
    
    @Override
    public T instance(final boolean injectDepends) throws JinException {
        final T instance = this.createInstance();
        if (injectDepends) {
            this.inject(instance);
        }
        this.init(instance);
        return instance;
    }

    @Override
    public boolean isLazy() {
        return this.lazy;
    }

    @Override
    public T singleton() throws JinException {
        if (this.singleton == null) {
            this.singleton = this.instance(true);
        }
        return this.singleton;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy