/*******************************************************************************
* Copyright (c) 2005 Vlad Dumitrescu and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Vlad Dumitrescu
*******************************************************************************/
package org.erlide.runtime.epmd;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.erlide.util.ErlLogger;
import com.ericsson.otp.erlang.OtpEpmd;
/**
* Query epmd to see if there are any new nodes that have been registered and
* notify listeners.
*/
public final class EpmdWatcher {
public EpmdWatcher() {
try {
addHost(InetAddress.getLocalHost().getHostName());
} catch (final UnknownHostException e) {
addHost("localhost");
}
}
private final List<String> hosts = new ArrayList<>();
private final Map<String, List<String>> nodeMap = new HashMap<>();
private final List<IEpmdListener> listeners = new ArrayList<>();
private final Map<String, List<IErlNodeMonitor>> monitors = new HashMap<>();
private boolean epmdStarted = false;
public synchronized void addHost(final String host) {
if (hosts.contains(host)) {
return;
}
hosts.add(host);
nodeMap.put(host, new ArrayList<String>());
}
public synchronized void removeHost(final String host) {
hosts.remove(host);
nodeMap.remove(host);
}
public synchronized void checkEpmd() {
for (final Entry<String, List<String>> entry : nodeMap.entrySet()) {
try {
final String host = entry.getKey();
final List<String> nodes = entry.getValue();
final String[] names = OtpEpmd.lookupNames(InetAddress.getByName(host));
final List<String> labels = clean(Arrays.asList(names));
final List<String> started = getDiff(labels, nodes);
final List<String> stopped = getDiff(nodes, labels);
if (started.size() > 0 || stopped.size() > 0) {
for (final IEpmdListener listener : listeners) {
listener.updateNodeStatus(host, started, stopped);
}
for (final String s : started) {
final List<IErlNodeMonitor> ms = monitors.get(s);
if (ms != null) {
for (final IErlNodeMonitor m : ms) {
m.nodeUp(s);
}
}
}
for (final String s : stopped) {
final List<IErlNodeMonitor> ms = monitors.get(s);
if (ms != null) {
for (final IErlNodeMonitor m : ms) {
m.nodeDown(s);
}
}
}
}
entry.setValue(labels);
epmdStarted = true;
} catch (final IOException e) {
if (epmdStarted) {
final String msg = "Erlide warning: epmd daemon went down on host "
+ entry.getKey() + "...";
// InterfacePlugin.getDefault().getLog().log(
// new Status(IStatus.WARNING,
// InterfacePlugin.PLUGIN_ID, msg));
ErlLogger.warn(msg);
epmdStarted = false;
}
}
}
}
/**
* Register interest in all changes of node status
*
* @param listener
*/
public void addEpmdListener(final IEpmdListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
/**
* Unregister interest in all changes of node status
*
* @param listener
*/
public void removeEpmdListener(final IEpmdListener listener) {
listeners.remove(listener);
}
public static List<String> clean(final List<String> list) {
final List<String> result = new ArrayList<>();
for (final String label : list) {
if ("".equals(label)) {
continue;
}
// label is "name X at port N"
final String[] parts = label.split(" ");
if (parts.length == 5) {
String alabel = parts[1];
if (alabel.length() == 0) {
alabel = "??" + label;
}
result.add(alabel);
}
}
return result;
}
private List<String> getDiff(final List<String> list1, final List<String> list2) {
final List<String> result = new ArrayList<>(list1);
result.removeAll(list2);
return result;
}
public Map<String, List<String>> getData() {
return nodeMap;
}
/**
* Register interest in the status of a certain node.
*
* @param node
* @param monitor
*/
public void addNodeMonitor(final String node, final IErlNodeMonitor monitor) {
List<IErlNodeMonitor> mons = monitors.get(node);
if (mons == null) {
mons = new ArrayList<>();
}
if (mons.contains(monitor)) {
return;
}
mons.add(monitor);
monitors.put(node, mons);
}
/**
* Unregister interest in the status of a certain node.
*
* @param node
* @param monitor
*/
public void removeNodeMonitor(final String node, final IErlNodeMonitor monitor) {
final List<IErlNodeMonitor> mons = monitors.get(node);
if (mons == null) {
return;
}
if (mons.contains(monitor)) {
mons.remove(monitor);
monitors.put(node, mons);
}
}
public boolean hasLocalNode(final String nodeName) {
try {
final String[] names = OtpEpmd.lookupNames(InetAddress.getByName(null));
final List<String> labels = EpmdWatcher.clean(Arrays.asList(names));
return labels.contains(nodeName);
} catch (final IOException e) {
return false;
}
}
}