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

io.nuls.core.rpc.modulebootstrap.RpcModule Maven / Gradle / Ivy

package io.nuls.core.rpc.modulebootstrap;

import io.nuls.core.basic.InitializingBean;
import io.nuls.core.core.annotation.Autowired;
import io.nuls.core.core.annotation.Order;
import io.nuls.core.core.config.ConfigurationLoader;
import io.nuls.core.core.ioc.SpringLiteContext;
import io.nuls.core.exception.NulsException;
import io.nuls.core.log.Log;
import io.nuls.core.parse.I18nUtils;
import io.nuls.core.parse.MapUtils;
import io.nuls.core.rpc.model.ModuleE;
import io.nuls.core.rpc.model.message.Response;
import io.nuls.core.rpc.netty.bootstrap.NettyServer;
import io.nuls.core.rpc.netty.channel.ConnectData;
import io.nuls.core.rpc.netty.channel.manager.ConnectManager;
import io.nuls.core.rpc.netty.processor.ResponseMessageProcessor;
import io.nuls.core.rpc.util.SetUtil;
import io.nuls.core.thread.ThreadUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @Author: zhoulijun
 * @Time: 2019-02-27 17:41
 * @Description: RPC模块基础类
 * 管理module的启动,状态管理,模块生命周期管理
 * 负责连接servic manager,并调用registerAPI
 * 管理模块生命周期,根据依赖模块的运行状况控制模块本身的生命周期。
 * 定义抽象方法onStart,onDependenciesReady,ononDependenciesLoss等方式抽象生命周期的实现
 */
@Order(Integer.MIN_VALUE)
public abstract class RpcModule implements InitializingBean {
    @Override
    public String toString() {
        return new StringJoiner(", ", RpcModule.class.getSimpleName() + "[", "]")
                .add("dependencies=" + dependencies)
                .add("state=" + state)
                .add("followerList=" + followerList)
                .add("dependentReadyState=" + dependentReadyState)
                .toString();
    }

    private static final String LANGUAGE = "en";
    private static final String LANGUAGE_PATH =  "languages";
    protected static final String ROLE = "1.0";

    private Set dependencies;

    /**
     * 模块运行状态
     */
    private RpcModuleState state = RpcModuleState.Start;

    /**
     * 依赖当前模块的其他模块列表
     */
    private Map followerList = new ConcurrentHashMap<>();

    /**
     * 当前模块依赖的其他模块的运行状态(是否接收到模块推送的ready通知)
     */
    private Map dependentReadyState = new ConcurrentHashMap<>();

    @Autowired
    NotifySender notifySender;

    @Override
    public final void afterPropertiesSet() throws NulsException {
        try {
            dependencies = new HashSet<>();
            Module[] depend = declareDependent();
            if(depend != null){
                dependencies.addAll(Arrays.asList(depend));
            }
            ConfigurationLoader configLoader = SpringLiteContext.getBean(ConfigurationLoader.class);
            String configDomain = moduleInfo().name;
            if(ModuleE.hasOfAbbr(moduleInfo().name)){
                configDomain = ModuleE.valueOfAbbr(moduleInfo().getName()).name;
            }
            String dependentList = configLoader.getValue(configDomain,"dependent");
            if(dependentList != null){
                ConfigurationLoader.ConfigItem configItem = configLoader.getConfigItem(configDomain,"dependent");
                Log.info("{}.dependent : {} ==> {}[{}] ",this.getClass().getSimpleName(),dependentList,configItem.getConfigFile(),configDomain);
                String[] temp = dependentList.split(",");
                Arrays.stream(temp).forEach(ds->{
                    dependencies.add(new Module(ds, ROLE));
                });
            }
            Log.info("module dependents:");
            dependencies.forEach(d->{
                Log.info("{}:{}",d.name,d.version);
            });
            I18nUtils.loadLanguage(this.getClass(), getLanguagePath(),LANGUAGE);
            init();
        } catch (Exception e) {
            Log.error("rpc module init fail", e);
            throw new NulsException(e);
        }
    }

    /**
     * 监听依赖的模块进入ready状态的通知
     *
     * @param module
     */
    void listenerDependenciesReady(Module module) {
        try {

            if (dependentReadyState.containsKey(module)) {
                if(dependentReadyState.get(module).equals(Boolean.TRUE)){
                    return ;
                }
                dependentReadyState.put(module, Boolean.TRUE);
            }
            Log.info("RMB:ModuleReadyListener :{}", module);
            tryRunModule();
            ConnectData connectData = ConnectManager.getConnectDataByRole(module.getName());
            connectData.addCloseEvent(() -> {
                if (!ConnectManager.ROLE_CHANNEL_MAP.containsKey(module.getName())) {
                    Log.warn("RMB:dependencie:{}模块触发连接断开事件", module);
                    dependentReadyState.put(module, Boolean.FALSE);
                    if(followerList.containsKey(module)){
                        followerList.remove(module);
                    }
                    if (isRunning()) {
                        state = this.onDependenciesLoss(module);
                        if (state == null) {
                            Log.error("onDependenciesReady return null state", new NullPointerException("onDependenciesReady return null state"));
                            System.exit(0);
                        }
                        Log.info("RMB:module state : {}", state);
                    }
                }
            });
            this.onDependenciesReady(module);
        } catch (Exception e) {
            Log.error("");
            e.printStackTrace();
        }
    }

    /**
     * 监听依赖当前模块的其他模块的注册
     *
     * @param module
     */
    void addFollower(Module module) {
        synchronized (this) {
            if (!followerList.containsKey(module)) {
                Log.info("RMB:registerModuleDependencies :{}", module);
                followerList.put(module, Boolean.FALSE);
                if(dependentReadyState.containsKey(module)){
                    dependentReadyState.put(module, Boolean.FALSE);
                }
                try {
                    //监听与follower的连接,如果断开后需要修改通知状态
                    ConnectData connectData = ConnectManager.getConnectDataByRole(module.getName());
                    connectData.addCloseEvent(() -> {
                        if (!ConnectManager.ROLE_CHANNEL_MAP.containsKey(module.getName())) {
                            Log.warn("RMB:follower:{}模块触发连接断开事件", module);
                            //修改通知状态为未通知
                            followerList.remove(module);
                        }
                    });
                    Log.debug("绑定连接断开事件:{}",module.name);
                } catch (Exception e) {
                    Log.error("RMB:获取follower:{}模块连接发生异常.", module, e);
                }
            }
        }
        if (this.isReady()) {
            notifyFollowerReady(module);
        }
    }

    /**
     * 通知follower当前模块已经进入ready状态
     *
     * @param module
     */
    private void notifyFollowerReady(Module module) {
        notifySender.send("notifyFollowerReady_"+module.toString(),10,() -> {
//            if (followerList.get(module)) {
//                return true;
//            }
            try {
                Response cmdResp = ResponseMessageProcessor.requestAndResponse(module.getName(), "listenerDependenciesReady", MapUtils.beanToLinkedMap(this.moduleInfo()),1000L);
                if (cmdResp.isSuccess()) {
                    followerList.put(module, Boolean.TRUE);
                    Log.info("notify follower {} is Ready success", module);
                    return true;
                } else {
                    return false;
                }
            } catch (Exception e) {
                Log.error("Calling remote interface failed. module:{} - interface:{} - message:{}", module, "registerModuleDependencies", e.getMessage());
                return false;
            }
        });
    }

    /**
     * 通知所有follower当前模块已经进入ready状态
     */
    private void notifyFollowerReady() {
        followerList.keySet().forEach(this::notifyFollowerReady);
    }

    /**
     * 启动模块
     *
     * @param serviceManagerUrl
     */
    void run(String modulePackage, String serviceManagerUrl) {
        //初始化依赖模块的ready状态
        this.getDependencies().forEach(d -> dependentReadyState.put(d, Boolean.FALSE));
        try {
            // Start server instance
            Set scanCmdPackage = new TreeSet<>();
            scanCmdPackage.add("io.nuls.core.rpc.cmd");
            scanCmdPackage.add("io.nuls.base.protocol.cmd");
            scanCmdPackage.addAll((getRpcCmdPackage() == null) ? SetUtil.of(modulePackage) : getRpcCmdPackage());
            NettyServer server = NettyServer.getInstance(moduleInfo().getName(), moduleInfo().getName(), ModuleE.DOMAIN)
                    .moduleRoles(new String[]{getRole()})
                    .moduleVersion(moduleInfo().getVersion())
                    .scanPackage(scanCmdPackage)
                    //注册管理模块状态的RPC接口ifc
                    .addCmdDetail(ModuleStatusCmd.class);
            dependentReadyState.keySet().forEach(d -> server.dependencies(d.getName(), d.getVersion()));
            // Get information from kernel
            ConnectManager.getConnectByUrl(serviceManagerUrl);
            Log.info("RMB:开始连接service manager:{}",serviceManagerUrl);
            ResponseMessageProcessor.syncKernel(serviceManagerUrl, new RegisterInvoke(moduleInfo(), dependentReadyState.keySet()));
            //模块进入ready状态的准备工作,如果条件未达到,等待10秒重新尝试
            while (!doStart()) {
                TimeUnit.SECONDS.sleep(10L);
            }
            Log.info("RMB:module is READY");
            state = RpcModuleState.Ready;
            this.notifyFollowerReady();
            tryRunModule();
        } catch (Exception e) {
            Log.error(moduleInfo().toString() + " initServer failed", e);
            System.exit(0);
        }
    }

    /**
     * 尝试启动模块
     * 如果所有依赖准备就绪就触发onDependenciesReady
     */
    private synchronized void tryRunModule() {
        if (!isReady()) {
            return;
        }
        boolean dependencieReady = dependentReadyState.isEmpty();
        if (!dependencieReady) {
            dependencieReady = dependentReadyState.entrySet().stream().allMatch(Map.Entry::getValue);
        }
        if (dependencieReady) {
            if (!isRunning()) {
                Log.info("RMB:dependencie state");
                dependentReadyState.forEach((key, value) -> Log.debug("{}:{}", key.getName(), value));
                Log.info("RMB:module try running");
                CountDownLatch latch = new CountDownLatch(1);
                ThreadUtils.createAndRunThread("module running", () -> {
                    try {
                        state = onDependenciesReady();
                        if (state == null) {
                            Log.error("onDependenciesReady return null state", new NullPointerException("onDependenciesReady return null state"));
                            System.exit(0);
                        }
                    } catch (Exception e) {
                        Log.error("RMB:try running module fail ", e);
                        System.exit(0);
                    }

                    latch.countDown();
                });
                try {
                    latch.await(getTryRuningTimeout(), TimeUnit.SECONDS);
                    if (state != RpcModuleState.Running) {
                        Log.error("RMB:module try running timeout");
                        System.exit(0);
                    }
                } catch (InterruptedException e) {
                    Log.error("wait module running fail");
                    System.exit(0);
                }
                Log.info("RMB:module state : " + state);
            }
        } else {
            Log.info("RMB:dependencie is not all ready");
            Log.info("RMB:dependencie state");
            dependentReadyState.forEach((key, value) -> Log.debug("{}:{}", key.getName(), value));
        }
    }

    protected long getTryRuningTimeout() {
        return 30;
    }

    protected String getRole() {
        return ROLE;
    }

    ;

    /**
     * 模块是否已运行
     *
     * @return
     */
    protected boolean isRunning() {
        return state.getIndex() >= RpcModuleState.Running.getIndex();
    }

    /**
     * 模块是否已准备好
     *
     * @return
     */
    protected boolean isReady() {
        return state.getIndex() >= RpcModuleState.Ready.getIndex();
    }

    /**
     * 获取依赖模块的准备状态
     *
     * @param module
     * @return true 已准备好
     */
    public boolean isDependencieReady(Module module) {
        if (!dependentReadyState.containsKey(module)) {
            throw new IllegalArgumentException("can not found " + module.getName());
        }
        return dependentReadyState.get(module);
    }

    public boolean hasDependent(ModuleE moduleE){
        return hasDependent(Module.build(moduleE));
    }

    public boolean hasDependent(Module module){
        return getDependencies().stream().anyMatch(module::equals);
    }

    public boolean isDependencieReady(String moduleName){
        return isDependencieReady(new Module(moduleName,ROLE));
    }

    /**
     * 依赖模块都以进入Ready状态
     */
    protected boolean isDependencieReady() {
        return dependentReadyState.entrySet().stream().allMatch(d -> d.getValue());
    }

    public Set getDependencies() {
        return dependencies;
    }

    /**
     * 申明此模块的依赖模块
     *
     * @return
     */
    public abstract Module[] declareDependent();

    /**
     * 指定RpcCmd的包名
     *
     * @return
     */
    public Set getRpcCmdPackage() {
        return null;
    }


    /**
     * 返回当前模块的描述
     *
     * @return
     */
    public abstract Module moduleInfo();


    public void onDependenciesReady(Module module){
        Log.debug("dependentReadyState module {} ready",module);
    }


    /**
     * 初始化模块
     * 在onStart前会调用此方法
     */
    public void init() {
        Log.info("module inited");
    }


    /**
     * 已完成spring init注入,开始启动模块
     * 模块进入ready状态前的准备工作,模块启动时触发
     * 如果准备完毕返回true
     * 条件未达到返回false
     *
     * @return
     */
    public abstract boolean doStart();

    /**
     * 所有外部依赖进入ready状态后会调用此方法,正常启动后返回Running状态
     *
     * @return
     */
    public abstract RpcModuleState onDependenciesReady();

    /**
     * 某个外部依赖连接丢失后,会调用此方法,
     * 可控制模块状态,如果返回Ready,则表明模块退化到Ready状态,当依赖重新准备完毕后,将重新触发onDependenciesReady方法,
     * 若返回的状态是Running,将不会重新触发onDependenciesReady
     *
     * @param dependenciesModule
     * @return
     */
    public abstract RpcModuleState onDependenciesLoss(Module dependenciesModule);

    protected String getLanguagePath(){
        return LANGUAGE_PATH;
    }

    public static String getROLE() {
        return ROLE;
    }

    public RpcModuleState getState() {
        return state;
    }

    public void setState(RpcModuleState state) {
        this.state = state;
    }

    public Map getFollowerList() {
        return followerList;
    }

    public void setFollowerList(Map followerList) {
        this.followerList = followerList;
    }

    public void setDependentReadyState(Map dependentReadyState) {
        this.dependentReadyState = dependentReadyState;
    }

    public NotifySender getNotifySender() {
        return notifySender;
    }

    public void setNotifySender(NotifySender notifySender) {
        this.notifySender = notifySender;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy