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

org.sam.server.context.BeanFactory Maven / Gradle / Ivy

package org.sam.server.context;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;

/**
 * 빈을 관리하는 클래스입니다. BeanContainer는 이미 선언 된 클래스를 기반으로 빈을 생성하지만
 * BeanFactory는 런타임시 동적으로 빈을 관리합니다.
 *
 * @author hypernova1
 * @see org.sam.server.context.BeanContainer
 * */
public class BeanFactory {

    private static final BeanFactory beanFactory;

    static {
        beanFactory = new BeanFactory();
        List list = new ArrayList<>();
        BeanInfo beanInfo = new BeanInfo("beanFactory", beanFactory);
        list.add(beanInfo);
        BeanContainer.getBeanInfoMap().put(BeanFactory.class, list);
    }

    private BeanFactory() {}

    /**
     * 인스턴스를 반환합니다.
     *
     * @return 인스턴스
     * */
    public static BeanFactory getInstance() {
        return beanFactory;
    }

    /**
     * 인자로 받은 이름과, 타입에 해당하는 빈을 반환합니다.
     *
     * @param  빈 클래스 타입
     * @param name 빈 이름
     * @param type 빈 클래스
     * @return 빈
     * */
    @SuppressWarnings("unchecked")
    public  T getBean(String name, Class type) {
        List beanInfos = BeanContainer.getBeanInfoList(type);
        BeanInfo savedBeanInfo = beanInfos.stream()
                .filter(beanInfo -> beanInfo.getName().equals(name))
                .findFirst()
                .orElse(null);
        return (T) savedBeanInfo;
    }

    /**
     * 인자로 받은 타입에 해당하는 빈 목록을 반환합니다.
     *
     * @param type 빈 타입
     * @return 빈 목록
     * */
    public List getBeanList(Class type) {
        Set> classes = BeanContainer.getBeanInfoMap().keySet();
        Class beanType = classes.stream()
                .filter(savedBeanType -> savedBeanType.isAssignableFrom(type))
                .findFirst()
                .orElseGet(() -> getMatchType(classes, type));
        List beanInfos = BeanContainer.getBeanInfoList(beanType);
        List result = new ArrayList<>();
        for (BeanInfo beanInfo : beanInfos) {
            result.add(beanInfo.getInstance());
        }
        return result;
    }

    /**
     * 인자로 받은 인스턴스를 빈으로 만들어 저장합니다.
     *
     * @param  인스턴스 타입
     * @param name 빈 이름
     * @param instance 인스턴스
     * */
    public  void registerBean(String name, T instance) {
        List list = Optional
                .ofNullable(BeanContainer.getBeanInfoList(instance.getClass()))
                .orElseGet(ArrayList::new);
        boolean isExist = list.stream()
                .anyMatch(beanInfo -> beanInfo.getName().equals(name));
        if (isExist) return;
        BeanInfo beanInfo = new BeanInfo(name, instance);
        list.add(beanInfo);
    }

    /**
     * 해당 클래스 타입과 일치하는 빈의 클래스 타입을 반환합니다.
     *
     * @param classes 빈 클래스 타입 목록
     * @param type 확인할 클래스 타입
     * @return 일치하는 클래스 타입
     * */
    private Class getMatchType(Set> classes, Class type) {
        for (Class savedClass : classes) {
            Class[] interfaces = savedClass.getInterfaces();
            for (Class interfaceClass : interfaces) {
                if (!interfaceClass.equals(type)) continue;
                return savedClass;
            }
        }
        return null;
    }

}