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

io.seata.config.FileConfiguration Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 *  Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package io.seata.config;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import io.seata.common.thread.NamedThreadFactory;
import io.seata.config.ConfigFuture.ConfigOperation;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import org.apache.commons.lang.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The type FileConfiguration.
 *
 * @author jimin.jm @alibaba-inc.com
 * @date 2018 /9/10
 */
public class FileConfiguration extends AbstractConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(FileConfiguration.class);

    private final Config CONFIG;

    private ExecutorService configOperateExecutor;

    private ExecutorService configChangeExecutor;

    private static final int CORE_CONFIG_OPERATE_THREAD = 1;

    private static final int CORE_CONFIG_CHANGE_THREAD = 1;

    private static final int MAX_CONFIG_OPERATE_THREAD = 2;

    private static final long LISTENER_CONFIG_INTERNAL = 1 * 1000;

    private static final String REGISTRY_TYPE = "file";

    private final ConcurrentMap> configListenersMap = new ConcurrentHashMap<>(8);

    private final ConcurrentMap listenedConfigMap = new ConcurrentHashMap<>(8);

    /**
     * Instantiates a new File configuration.
     */
    public FileConfiguration() {
        this(null);
    }

    /**
     * Instantiates a new File configuration.
     *
     * @param name the name
     */
    public FileConfiguration(String name) {
        if (null == name) {
            CONFIG = ConfigFactory.load();
        } else {
            CONFIG = ConfigFactory.load(name);
        }
        configOperateExecutor = new ThreadPoolExecutor(CORE_CONFIG_OPERATE_THREAD, MAX_CONFIG_OPERATE_THREAD,
            Integer.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(),
            new NamedThreadFactory("configOperate", MAX_CONFIG_OPERATE_THREAD));
        configChangeExecutor = new ThreadPoolExecutor(CORE_CONFIG_CHANGE_THREAD, CORE_CONFIG_CHANGE_THREAD,
            Integer.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(),
            new NamedThreadFactory("configChange", CORE_CONFIG_CHANGE_THREAD));
        configChangeExecutor.submit(new ConfigChangeRunnable());
    }

    @Override
    public String getConfig(String dataId, String defaultValue, long timeoutMills) {
        ConfigFuture configFuture = new ConfigFuture(dataId, defaultValue, ConfigOperation.GET, timeoutMills);
        configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
        return (String) configFuture.get();
    }

    @Override
    public boolean putConfig(String dataId, String content, long timeoutMills) {
        ConfigFuture configFuture = new ConfigFuture(dataId, content, ConfigOperation.PUT, timeoutMills);
        configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
        return (Boolean) configFuture.get();
    }

    @Override
    public boolean putConfigIfAbsent(String dataId, String content, long timeoutMills) {
        ConfigFuture configFuture = new ConfigFuture(dataId, content, ConfigOperation.PUTIFABSENT, timeoutMills);
        configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
        return (Boolean) configFuture.get();
    }

    @Override
    public boolean removeConfig(String dataId, long timeoutMills) {
        ConfigFuture configFuture = new ConfigFuture(dataId, null, ConfigOperation.REMOVE, timeoutMills);
        configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
        return (Boolean) configFuture.get();
    }

    @Override
    public void addConfigListener(String dataId, ConfigChangeListener listener) {
        configListenersMap.putIfAbsent(dataId, new ArrayList());
        configListenersMap.get(dataId).add(listener);
        listenedConfigMap.putIfAbsent(dataId, getConfig(dataId));
        if (null != listener.getExecutor()) {
            ConfigChangeRunnable configChangeTask = new ConfigChangeRunnable(dataId, listener);
            listener.getExecutor().submit(configChangeTask);
        }
    }

    @Override
    public void removeConfigListener(String dataId, ConfigChangeListener listener) {
        List configChangeListeners = getConfigListeners(dataId);
        if (configChangeListeners == null) {
            return;
        }
        List newChangeListenerList = new ArrayList<>();
        for (ConfigChangeListener changeListener : configChangeListeners) {
            if (!changeListener.equals(listener)) {
                newChangeListenerList.add(changeListener);
            }
        }
        configListenersMap.put(dataId, newChangeListenerList);
        if (newChangeListenerList.isEmpty()) {
            listenedConfigMap.remove(dataId);
        }
        if (null != listener.getExecutor()) {
            listener.getExecutor().shutdownNow();
        }

    }

    @Override
    public List getConfigListeners(String dataId) {
        return configListenersMap.get(dataId);
    }

    @Override
    public String getTypeName() {
        return REGISTRY_TYPE;
    }

    /**
     * The type Config operate runnable.
     */
    class ConfigOperateRunnable implements Runnable {

        private ConfigFuture configFuture;

        /**
         * Instantiates a new Config operate runnable.
         *
         * @param configFuture the config future
         */
        public ConfigOperateRunnable(ConfigFuture configFuture) {
            this.configFuture = configFuture;
        }

        @Override
        public void run() {
            if (null != configFuture) {
                if (configFuture.isTimeout()) {
                    setFailResult(configFuture);
                    return;
                }
                if (configFuture.getOperation() == ConfigOperation.GET) {
                    String result = CONFIG.getString(configFuture.getDataId());
                    configFuture.setResult(result == null ? configFuture.getContent() : result);
                } else if (configFuture.getOperation() == ConfigOperation.PUT) {
                    //todo
                    configFuture.setResult(Boolean.TRUE);
                } else if (configFuture.getOperation() == ConfigOperation.PUTIFABSENT) {
                    //todo
                    configFuture.setResult(Boolean.TRUE);
                } else if (configFuture.getOperation() == ConfigOperation.REMOVE) {
                    //todo
                    configFuture.setResult(Boolean.TRUE);
                }
            }
        }

        private void setFailResult(ConfigFuture configFuture) {
            if (configFuture.getOperation() == ConfigOperation.GET) {
                String result = configFuture.getContent();
                configFuture.setResult(result);
            } else {
                configFuture.setResult(Boolean.FALSE);
            }
        }

    }

    /**
     * The type Config change runnable.
     */
    class ConfigChangeRunnable implements Runnable {

        private String dataId;
        private ConfigChangeListener listener;

        /**
         * Instantiates a new Config change runnable.
         */
        public ConfigChangeRunnable() {
        }

        /**
         * Instantiates a new Config change runnable.
         *
         * @param dataId   the data id
         * @param listener the listener
         */
        public ConfigChangeRunnable(String dataId, ConfigChangeListener listener) {

            if (null == listener.getExecutor()) {
                throw new IllegalArgumentException("getExecutor is null.");
            }
            this.dataId = dataId;
            this.listener = listener;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    Map> configListenerMap;
                    if (null != dataId && null != listener) {
                        configListenerMap = new ConcurrentHashMap<>(8);
                        configListenerMap.put(dataId, new ArrayList<>());
                        configListenerMap.get(dataId).add(listener);
                    } else {
                        configListenerMap = configListenersMap;
                    }
                    for (Map.Entry> entry : configListenerMap.entrySet()) {
                        String configId = entry.getKey();
                        String currentConfig = getConfig(configId);
                        if (ObjectUtils.notEqual(currentConfig, listenedConfigMap.get(configId))) {
                            listenedConfigMap.put(configId, currentConfig);
                            notifyAllListener(configId, configListenerMap.get(configId));

                        }
                    }
                    Thread.sleep(LISTENER_CONFIG_INTERNAL);
                } catch (Exception exx) {
                    LOGGER.error(exx.getMessage());
                }

            }
        }

        private void notifyAllListener(String dataId, List configChangeListeners) {
            List needNotifyListeners = new ArrayList<>();
            if (null != dataId && null != listener) {
                needNotifyListeners.addAll(configChangeListeners);
            } else {
                for (ConfigChangeListener configChangeListener : configChangeListeners) {
                    if (null == configChangeListener.getExecutor()) {
                        needNotifyListeners.add(configChangeListener);
                    }
                }
            }
            for (ConfigChangeListener configChangeListener : needNotifyListeners) {
                configChangeListener.receiveConfigInfo(listenedConfigMap.get(dataId));
            }
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy