com.weibo.api.motan.registry.support.LocalRegistryService.java Source code

Java tutorial

Introduction

Here is the source code for com.weibo.api.motan.registry.support.LocalRegistryService.java

Source

/*
 *  Copyright 2009-2016 Weibo, Inc.
 *
 *    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 com.weibo.api.motan.registry.support;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.commons.lang3.ObjectUtils;

import com.weibo.api.motan.common.MotanConstants;
import com.weibo.api.motan.common.URLParamType;
import com.weibo.api.motan.core.extension.SpiMeta;
import com.weibo.api.motan.registry.NotifyListener;
import com.weibo.api.motan.registry.RegistryService;
import com.weibo.api.motan.rpc.URL;
import com.weibo.api.motan.util.CollectionUtil;
import com.weibo.api.motan.util.ConcurrentHashSet;
import com.weibo.api.motan.util.LoggerUtil;
import com.weibo.api.motan.util.NetUtils;

/**
 * 
 * @author maijunsheng
 * @version 2013-5-24
 * 
 */
@SpiMeta(name = "local")
public class LocalRegistryService extends AbstractRegistry {

    /** Map<interface/nodeType, List<URL>>, List urlidentity/id? */
    private ConcurrentMap<String, List<URL>> registeredServices = new ConcurrentHashMap<String, List<URL>>();

    private ConcurrentHashMap<String, ConcurrentHashMap<URL, ConcurrentHashSet<NotifyListener>>> subscribeListeners = new ConcurrentHashMap<String, ConcurrentHashMap<URL, ConcurrentHashSet<NotifyListener>>>();
    private URL registryUrl;

    public LocalRegistryService() {
        this(new URL(MotanConstants.REGISTRY_PROTOCOL_LOCAL, NetUtils.LOCALHOST, MotanConstants.DEFAULT_INT_VALUE,
                RegistryService.class.getName()));
    }

    public LocalRegistryService(URL url) {
        super(url);
        this.registryUrl = url;
    }

    @Override
    public void doSubscribe(URL url, NotifyListener listener) {

        String subscribeKey = getSubscribeKey(url);
        ConcurrentHashMap<URL, ConcurrentHashSet<NotifyListener>> urlListeners = subscribeListeners
                .get(subscribeKey);
        if (urlListeners == null) {
            subscribeListeners.putIfAbsent(subscribeKey,
                    new ConcurrentHashMap<URL, ConcurrentHashSet<NotifyListener>>());
            urlListeners = subscribeListeners.get(subscribeKey);
        }

        ConcurrentHashSet<NotifyListener> listeners = urlListeners.get(url);
        if (listeners == null) {
            urlListeners.putIfAbsent(url, new ConcurrentHashSet<NotifyListener>());
            listeners = urlListeners.get(url);
        }

        listeners.add(listener);

        List<URL> urls = discover(url);
        if (urls != null && urls.size() > 0) {
            listener.notify(getUrl(), urls);
        }

        LoggerUtil.info("LocalRegistryService subscribe: url={}", url);
    }

    @Override
    public void doUnsubscribe(URL url, NotifyListener listener) {
        String subscribeKey = getSubscribeKey(url);
        ConcurrentHashMap<URL, ConcurrentHashSet<NotifyListener>> urlListeners = subscribeListeners
                .get(subscribeKey);
        if (urlListeners != null) {
            urlListeners.remove(url);
        }

        LoggerUtil.info("LocalRegistryService unsubscribe: url={}", url);
    }

    @Override
    public List<URL> doDiscover(URL url) {
        return registeredServices.get(getRegistryKey(url));
    }

    @Override
    protected void doAvailable(URL url) {
        //do nothing
    }

    @Override
    protected void doUnavailable(URL url) {
        //do nothing
    }

    @Override
    public void doRegister(URL url) {
        String registryKey = getRegistryKey(url);
        synchronized (registeredServices) {
            List<URL> urls = registeredServices.get(registryKey);

            if (urls == null) {
                registeredServices.putIfAbsent(registryKey, new ArrayList<URL>());
                urls = registeredServices.get(registryKey);
            }
            add(url, urls);

            LoggerUtil.info("LocalRegistryService register: url={}", url);

            notifyListeners(url);
        }
    }

    @Override
    public void doUnregister(URL url) {
        synchronized (registeredServices) {
            List<URL> urls = registeredServices.get(getRegistryKey(url));

            if (urls == null) {
                return;
            }

            remove(url, urls);

            LoggerUtil.info("LocalRegistryService unregister: url={}", url);
            // ???
            notifyListeners(url);
        }
    }

    @Override
    public URL getUrl() {
        return registryUrl;
    }

    /**
     * ??copy
     * 
     * @return
     */
    public Map<String, List<URL>> getAllUrl() {
        Map<String, List<URL>> copyMap = new HashMap<String, List<URL>>(registeredServices.size());

        for (Map.Entry<String, List<URL>> entry : registeredServices.entrySet()) {
            String key = entry.getKey();

            List<URL> copyList = new ArrayList<URL>(entry.getValue().size());
            for (URL url : entry.getValue()) {
                copyList.add(url.createCopy());
            }

            copyMap.put(key, copyList);
        }

        return copyMap;
    }

    private void remove(URL url, List<URL> urls) {
        if (CollectionUtil.isEmpty(urls)) {
            return;
        }
        removeCachedUrlByIdentity(url, urls);
    }

    private void add(URL url, List<URL> urls) {
        removeCachedUrlByIdentity(url, urls);
        urls.add(url);
    }

    private void removeCachedUrlByIdentity(URL url, List<URL> urls) {
        if (CollectionUtil.isEmpty(urls)) {
            return;
        }
        URL oldUrl = null;
        for (URL cachedUrl : urls) {
            if (ObjectUtils.equals(url, cachedUrl)) {
                oldUrl = cachedUrl;
                break;
            }
        }

        if (oldUrl != null) {
            urls.remove(oldUrl);
        }
    }

    private void notifyListeners(URL changedUrl) {
        List<URL> interestingUrls = discover(changedUrl);
        if (interestingUrls != null) {
            ConcurrentHashMap<URL, ConcurrentHashSet<NotifyListener>> urlListeners = subscribeListeners
                    .get(getSubscribeKey(changedUrl));
            if (urlListeners == null) {
                return;
            }

            for (ConcurrentHashSet<NotifyListener> listeners : urlListeners.values()) {
                for (NotifyListener ln : listeners) {
                    try {
                        ln.notify(getUrl(), interestingUrls);
                    } catch (Exception e) {
                        LoggerUtil.warn(
                                String.format("Exception when notify listerner %s, changedUrl: %s", ln, changedUrl),
                                e);
                    }
                }
            }

        }
    }

    private String getRegistryKey(URL url) {
        String keyPrefix = url.getPath();
        String nodeType = url.getParameter(URLParamType.nodeType.getName());
        if (nodeType != null) {
            return keyPrefix + MotanConstants.PATH_SEPARATOR + nodeType;
        } else {
            LoggerUtil.warn("Url need a nodeType as param in localRegistry, url={}", url);
            return keyPrefix;
        }
    }

    private String getSubscribeKey(URL url) {
        return getRegistryKey(url);
    }
}