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

com.github.ltsopensource.core.cluster.AbstractJobNode Maven / Gradle / Ivy

package com.github.ltsopensource.core.cluster;

import com.github.ltsopensource.cmd.HttpCmdServer;
import com.github.ltsopensource.core.AppContext;
import com.github.ltsopensource.core.cmd.JVMInfoGetHttpCmd;
import com.github.ltsopensource.core.cmd.StatusCheckHttpCmd;
import com.github.ltsopensource.core.commons.utils.CollectionUtils;
import com.github.ltsopensource.core.commons.utils.GenericsUtils;
import com.github.ltsopensource.core.commons.utils.NetUtils;
import com.github.ltsopensource.core.commons.utils.StringUtils;
import com.github.ltsopensource.core.compiler.AbstractCompiler;
import com.github.ltsopensource.core.constant.EcTopic;
import com.github.ltsopensource.core.constant.ExtConfig;
import com.github.ltsopensource.core.factory.JobNodeConfigFactory;
import com.github.ltsopensource.core.factory.NodeFactory;
import com.github.ltsopensource.core.json.JSONFactory;
import com.github.ltsopensource.core.listener.MasterChangeListener;
import com.github.ltsopensource.core.listener.MasterElectionListener;
import com.github.ltsopensource.core.listener.NodeChangeListener;
import com.github.ltsopensource.core.listener.SelfChangeListener;
import com.github.ltsopensource.core.logger.Logger;
import com.github.ltsopensource.core.logger.LoggerFactory;
import com.github.ltsopensource.core.protocol.command.CommandBodyWrapper;
import com.github.ltsopensource.core.registry.*;
import com.github.ltsopensource.core.spi.ServiceLoader;
import com.github.ltsopensource.core.support.AliveKeeping;
import com.github.ltsopensource.core.support.ConfigValidator;
import com.github.ltsopensource.ec.EventCenter;
import com.github.ltsopensource.ec.EventInfo;
import com.github.ltsopensource.remoting.serialize.AdaptiveSerializable;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author Robert HG ([email protected]) on 8/15/14.
 *         抽象节点
 */
public abstract class AbstractJobNode implements JobNode {

    protected static final Logger LOGGER = LoggerFactory.getLogger(JobNode.class);

    protected Registry registry;
    protected T node;
    protected Config config;
    protected Context appContext;
    private List nodeChangeListeners;
    private List masterChangeListeners;
    protected AtomicBoolean started = new AtomicBoolean(false);

    public AbstractJobNode() {
        appContext = getAppContext();
        node = NodeFactory.create(getNodeClass());
        config = JobNodeConfigFactory.getDefaultConfig();
        config.setNodeType(node.getNodeType());
        appContext.setConfig(config);
        nodeChangeListeners = new ArrayList();
        masterChangeListeners = new ArrayList();
    }

    final public void start() {
        try {
            if (started.compareAndSet(false, true)) {

                configValidate();

                // 初始化配置
                initConfig();

                // 初始化HttpCmdServer
                initHttpCmdServer();

                beforeRemotingStart();

                remotingStart();

                afterRemotingStart();

                initRegistry();

                registry.register(node);

                AliveKeeping.start();

                LOGGER.info("========== Start success, nodeType={}, identity={}", config.getNodeType(), config.getIdentity());
            }
        } catch (Throwable e) {
            if (e.getMessage().contains("Address already in use")) {
                LOGGER.error("========== Start failed at listen port {}, nodeType={}, identity={}", config.getListenPort(), config.getNodeType(), config.getIdentity(), e);
            } else {
                LOGGER.error("========== Start failed, nodeType={}, identity={}", config.getNodeType(), config.getIdentity(), e);
            }
        }
    }

    private void initHttpCmdServer() {
        // 命令中心
        int port = appContext.getConfig().getParameter(ExtConfig.HTTP_CMD_PORT, 8719);
        appContext.setHttpCmdServer(HttpCmdServer.Factory.getHttpCmdServer(config.getIp(), port));

        // 先启动,中间看端口是否被占用
        appContext.getHttpCmdServer().start();
        // 设置command端口,会暴露到注册中心上
        node.setHttpCmdPort(appContext.getHttpCmdServer().getPort());

        appContext.getHttpCmdServer().registerCommands(
                new StatusCheckHttpCmd(appContext.getConfig()),
                new JVMInfoGetHttpCmd(appContext.getConfig()));        // 状态检查
    }

    final public void stop() {
        try {
            if (started.compareAndSet(true, false)) {

                if (registry != null) {
                    registry.unregister(node);
                }

                beforeRemotingStop();

                remotingStop();

                afterRemotingStop();

                appContext.getEventCenter().publishSync(new EventInfo(EcTopic.NODE_SHUT_DOWN));

                AliveKeeping.stop();

                LOGGER.info("========== Stop success, nodeType={}, identity={}", config.getNodeType(), config.getIdentity());
            }
        } catch (Throwable e) {
            LOGGER.error("========== Stop failed, nodeType={}, identity={}", config.getNodeType(), config.getIdentity(), e);
        }
    }

    @Override
    public void destroy() {
        try {
            registry.destroy();
            LOGGER.info("Destroy success, nodeType={}, identity={}", config.getNodeType(), config.getIdentity());
        } catch (Throwable e) {
            LOGGER.error("Destroy failed, nodeType={}, identity={}", config.getNodeType(), config.getIdentity(), e);
        }
    }

    protected void configValidate() {
        ConfigValidator.validateNodeGroup(config.getNodeGroup());
        ConfigValidator.validateClusterName(config.getClusterName());
        ConfigValidator.validateIdentity(config.getIdentity());
    }

    protected void initConfig() {

        String compiler = config.getParameter(ExtConfig.COMPILER);
        if (StringUtils.isNotEmpty(compiler)) {
            AbstractCompiler.setCompiler(compiler);
        }

        if (StringUtils.isEmpty(config.getIp())) {
            config.setIp(NetUtils.getLocalHost());
        }
        if (StringUtils.isEmpty(config.getIdentity())) {
            JobNodeConfigFactory.buildIdentity(config);
        }
        NodeFactory.build(node, config);

        LOGGER.info("Current Node config :{}", config);

        appContext.setEventCenter(ServiceLoader.load(EventCenter.class, config));

        appContext.setCommandBodyWrapper(new CommandBodyWrapper(config));
        appContext.setMasterElector(new MasterElector(appContext));
        appContext.getMasterElector().addMasterChangeListener(masterChangeListeners);
        appContext.setRegistryStatMonitor(new RegistryStatMonitor(appContext));

        // 订阅的node管理
        SubscribedNodeManager subscribedNodeManager = new SubscribedNodeManager(appContext);
        appContext.setSubscribedNodeManager(subscribedNodeManager);
        nodeChangeListeners.add(subscribedNodeManager);
        // 用于master选举的监听器
        nodeChangeListeners.add(new MasterElectionListener(appContext));
        // 监听自己节点变化(如,当前节点被禁用了)
        nodeChangeListeners.add(new SelfChangeListener(appContext));

        setSpiConfig();
    }

    private void setSpiConfig() {
        // 设置默认序列化方式
        String defaultSerializable = config.getParameter(ExtConfig.REMOTING_SERIALIZABLE_DFT);
        if (StringUtils.isNotEmpty(defaultSerializable)) {
            AdaptiveSerializable.setDefaultSerializable(defaultSerializable);
        }

        // 设置json
        String ltsJson = config.getParameter(ExtConfig.LTS_JSON);
        if (StringUtils.isNotEmpty(ltsJson)) {
            JSONFactory.setJSONAdapter(ltsJson);
        }

        // 设置logger
        String logger = config.getParameter(ExtConfig.LTS_LOGGER);
        if (StringUtils.isNotEmpty(logger)) {
            LoggerFactory.setLoggerAdapter(logger);
        }
    }

    private void initRegistry() {
        registry = RegistryFactory.getRegistry(appContext);
        if (registry instanceof AbstractRegistry) {
            ((AbstractRegistry) registry).setNode(node);
        }
        registry.subscribe(node, new NotifyListener() {
            private final Logger NOTIFY_LOGGER = LoggerFactory.getLogger(NotifyListener.class);

            @Override
            public void notify(NotifyEvent event, List nodes) {
                if (CollectionUtils.isEmpty(nodes)) {
                    return;
                }
                switch (event) {
                    case ADD:
                        for (NodeChangeListener listener : nodeChangeListeners) {
                            try {
                                listener.addNodes(nodes);
                            } catch (Throwable t) {
                                NOTIFY_LOGGER.error("{} add nodes failed , cause: {}", listener.getClass().getName(), t.getMessage(), t);
                            }
                        }
                        break;
                    case REMOVE:
                        for (NodeChangeListener listener : nodeChangeListeners) {
                            try {
                                listener.removeNodes(nodes);
                            } catch (Throwable t) {
                                NOTIFY_LOGGER.error("{} remove nodes failed , cause: {}", listener.getClass().getName(), t.getMessage(), t);
                            }
                        }
                        break;
                }
            }
        });
    }

    protected abstract void remotingStart();

    protected abstract void remotingStop();

    protected abstract void beforeRemotingStart();

    protected abstract void afterRemotingStart();

    protected abstract void beforeRemotingStop();

    protected abstract void afterRemotingStop();

    @SuppressWarnings("unchecked")
    private Context getAppContext() {
        try {
            return ((Class)
                    GenericsUtils.getSuperClassGenericType(this.getClass(), 1))
                    .newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unchecked")
    private Class getNodeClass() {
        return (Class)
                GenericsUtils.getSuperClassGenericType(this.getClass(), 0);
    }


    /**
     * 设置zookeeper注册中心地址
     */
    public void setRegistryAddress(String registryAddress) {
        config.setRegistryAddress(registryAddress);
    }

    /**
     * 设置远程调用超时时间
     */
    public void setInvokeTimeoutMillis(int invokeTimeoutMillis) {
        config.setInvokeTimeoutMillis(invokeTimeoutMillis);
    }

    /**
     * 设置集群名字
     */
    public void setClusterName(String clusterName) {
        config.setClusterName(clusterName);
    }

    /**
     * 节点标识(必须要保证这个标识是唯一的才能设置,请谨慎设置)
     * 这个是非必须设置的,建议使用系统默认生成
     */
    public void setIdentity(String identity) {
        config.setIdentity(identity);
    }

    /**
     * 添加节点监听器
     */
    public void addNodeChangeListener(NodeChangeListener notifyListener) {
        if (notifyListener != null) {
            nodeChangeListeners.add(notifyListener);
        }
    }

    /**
     * 显示设置绑定ip
     */
    public void setBindIp(String bindIp) {
        if (StringUtils.isEmpty(bindIp)
                || !NetUtils.isValidHost(bindIp)
                ) {
            throw new IllegalArgumentException("Invalided bind ip:" + bindIp);
        }
        config.setIp(bindIp);
    }

    /**
     * 添加 master 节点变化监听器
     */
    public void addMasterChangeListener(MasterChangeListener masterChangeListener) {
        if (masterChangeListener != null) {
            masterChangeListeners.add(masterChangeListener);
        }
    }

    public void setDataPath(String path) {
        if (StringUtils.isNotEmpty(path)) {
            config.setDataPath(path);
        }
    }

    /**
     * 设置额外的配置参数
     */
    public void addConfig(String key, String value) {
        config.setParameter(key, value);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy