package link.at17.mid.tushare.component;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;

import link.at17.mid.tushare.config.ConstructionGuard;
import link.at17.mid.tushare.interfaces.IConfig;
import link.at17.mid.tushare.service.ConfigService;
import lombok.extern.slf4j.Slf4j;

/**
 * 实现配置项自动载入
 * @param <T>
 */
@Slf4j
public class ConfigServiceFactoryBean<T extends IConfig<T>> implements FactoryBean<T>, BeanNameAware {

    private final Class<T> targetClass;
    
    private String beanName;

    @Autowired
    private AutowireCapableBeanFactory beanFactory;
    
    @Autowired
    private ConfigService configService;

    public ConfigServiceFactoryBean(Class<T> targetClass) {
        this.targetClass = targetClass;
    }
    
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public T getObject() throws Exception {
        ConstructionGuard.enter(targetClass);
        boolean success = true;
        try {
            T bean = configService.getConfig(targetClass);
            beanFactory.autowireBean(bean);
            beanFactory.initializeBean(bean, beanName);
            configService.saveOrUpdate(bean);
            return bean;
        }
        catch (Exception e) {
            log.error("Fail to load config: " + targetClass.getName(), e);
            success = false;
            throw e;
        }
        finally {
            ConstructionGuard.exit(targetClass);
            if (success) {
                log.debug("getObject() for {} success", targetClass.toString());
            }
        }
    }

    @Override
    public Class<?> getObjectType() {
        return targetClass;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
