/*
* Copyright 1999-2011 Alibaba Group.
*
* 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.alibaba.dubbo.registry.simple;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.ConcurrentHashSet;
import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.common.utils.UrlUtils;
import com.alibaba.dubbo.registry.NotifyListener;
import com.alibaba.dubbo.registry.RegistryService;
import com.alibaba.dubbo.registry.support.AbstractRegistry;
import com.alibaba.dubbo.rpc.RpcContext;
/**
* SimpleRegistryService
*
* @author william.liangf
*/
public class SimpleRegistryService extends AbstractRegistry {
private final ConcurrentMap<String, Set<URL>> remoteRegistered = new ConcurrentHashMap<String, Set<URL>>();
private final ConcurrentMap<String, ConcurrentMap<URL, Set<NotifyListener>>> remoteSubscribed = new ConcurrentHashMap<String, ConcurrentMap<URL, Set<NotifyListener>>>();
private final static Logger logger = LoggerFactory.getLogger(SimpleRegistryService.class);
public SimpleRegistryService() {
super(new URL("dubbo", NetUtils.getLocalHost(), 0, RegistryService.class.getName(), "file", "N/A"));
}
public boolean isAvailable() {
return true;
}
public List<URL> lookup(URL url) {
List<URL> urls = new ArrayList<URL>();
for (URL u: getRegistered()) {
if (UrlUtils.isMatch(url, u)) {
urls.add(u);
}
}
return urls;
}
public void register(URL url) {
String client = RpcContext.getContext().getRemoteAddressString();
Set<URL> urls = remoteRegistered.get(client);
if (urls == null) {
remoteRegistered.putIfAbsent(client, new ConcurrentHashSet<URL>());
urls = remoteRegistered.get(client);
}
urls.add(url);
super.register(url);
registered(url);
}
public void unregister(URL url) {
String client = RpcContext.getContext().getRemoteAddressString();
Set<URL> urls = remoteRegistered.get(client);
if (urls != null && urls.size() > 0) {
urls.remove(url);
}
super.unregister(url);
unregistered(url);
}
public void subscribe(URL url, NotifyListener listener) {
if (getUrl().getPort() == 0) {
URL registryUrl = RpcContext.getContext().getUrl();
if (registryUrl != null && registryUrl.getPort() > 0
&& RegistryService.class.getName().equals(registryUrl.getPath())) {
super.setUrl(registryUrl);
super.register(registryUrl);
}
}
String client = RpcContext.getContext().getRemoteAddressString();
ConcurrentMap<URL, Set<NotifyListener>> clientListeners = remoteSubscribed.get(client);
if (clientListeners == null) {
remoteSubscribed.putIfAbsent(client, new ConcurrentHashMap<URL, Set<NotifyListener>>());
clientListeners = remoteSubscribed.get(client);
}
Set<NotifyListener> listeners = clientListeners.get(url);
if (listeners == null) {
clientListeners.putIfAbsent(url, new ConcurrentHashSet<NotifyListener>());
listeners = clientListeners.get(url);
}
listeners.add(listener);
super.subscribe(url, listener);
subscribed(url, listener);
}
public void unsubscribe(URL url, NotifyListener listener) {
if (! Constants.ANY_VALUE.equals(url.getServiceInterface())
&& url.getParameter(Constants.REGISTER_KEY, true)) {
unregister(url);
}
String client = RpcContext.getContext().getRemoteAddressString();
Map<URL, Set<NotifyListener>> clientListeners = remoteSubscribed.get(client);
if (clientListeners != null && clientListeners.size() > 0) {
Set<NotifyListener> listeners = clientListeners.get(url);
if (listeners != null && listeners.size() > 0) {
listeners.remove(listener);
}
}
}
protected void registered(URL url) {
for (Map.Entry<URL, Set<NotifyListener>> entry : getSubscribed().entrySet()) {
URL key = entry.getKey();
if (UrlUtils.isMatch(key, url)) {
List<URL> list = lookup(key);
for (NotifyListener listener : entry.getValue()) {
listener.notify(list);
}
}
}
}
protected void unregistered(URL url) {
for (Map.Entry<URL, Set<NotifyListener>> entry : getSubscribed().entrySet()) {
URL key = entry.getKey();
if (UrlUtils.isMatch(key, url)) {
List<URL> list = lookup(key);
for (NotifyListener listener : entry.getValue()) {
listener.notify(list);
}
}
}
}
protected void subscribed(final URL url, final NotifyListener listener) {
if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {
new Thread(new Runnable() {
public void run() {
Map<String, List<URL>> map = new HashMap<String, List<URL>>();
for (URL u: getRegistered()) {
if (UrlUtils.isMatch(url, u)) {
String service = u.getServiceInterface();
List<URL> list = map.get(service);
if (list == null) {
list = new ArrayList<URL>();
map.put(service, list);
}
list.add(u);
}
}
for (List<URL> list : map.values()) {
try {
listener.notify(list);
} catch (Throwable e) {
logger.warn("Discard to notify " + url.getServiceKey() + " to listener " + listener);
}
}
}
}, "DubboMonitorNotifier").start();
} else {
List<URL> list = lookup(url);
try {
listener.notify(list);
} catch (Throwable e) {
logger.warn("Discard to notify " + url.getServiceKey() + " to listener " + listener);
}
}
}
public void disconnect() {
String client = RpcContext.getContext().getRemoteAddressString();
if (logger.isInfoEnabled()) {
logger.info("Disconnected " + client);
}
Set<URL> urls = remoteRegistered.get(client);
if (urls != null && urls.size() > 0) {
for (URL url : urls) {
unregister(url);
}
}
Map<URL, Set<NotifyListener>> listeners = remoteSubscribed.get(client);
if (listeners != null && listeners.size() > 0) {
for (Map.Entry<URL, Set<NotifyListener>> entry : listeners.entrySet()) {
URL url = entry.getKey();
for (NotifyListener listener : entry.getValue()) {
unsubscribe(url, listener);
}
}
}
}
}