use of io.datatree.Tree in project moleculer-java by moleculer-java.
the class TcpTransporter method processGossipResponse.
// --- GOSSIP RESPONSE MESSAGE RECEIVED ---
protected void processGossipResponse(Tree data) throws Exception {
// Debug
if (debug) {
String sender = data.get("sender", (String) null);
logger.info("Gossip response received from \"" + sender + "\" node:\r\n" + data);
}
// Online / offline nodes in responnse
Tree online = data.get("online");
Tree offline = data.get("offline");
// Process "online" block
if (online != null) {
for (Tree row : online) {
// Get nodeID
String nodeID = row.getName();
if (this.nodeID.equals(nodeID)) {
continue;
}
int size = row.size();
if (!row.isEnumeration() || size < 1 || size > 3) {
logger.warn("Invalid \"offline\" block: " + row);
continue;
}
// Get parameters from input
Tree info = null;
long cpuSeq = 0;
int cpu = 0;
if (row.size() == 1) {
info = row.get(0);
} else if (row.size() == 2) {
cpuSeq = row.get(0).asLong();
cpu = row.get(1).asInteger();
} else if (row.size() == 3) {
info = row.get(0);
cpuSeq = row.get(1).asLong();
cpu = row.get(2).asInteger();
} else {
logger.warn("Invalid \"online\" block: " + row.toString(false));
continue;
}
if (info != null) {
// Update "info" block,
// send updated, connected or reconnected event
updateNodeInfo(nodeID, info);
}
if (cpuSeq > 0) {
// We update our CPU info
NodeDescriptor node = nodes.get(nodeID);
if (node != null) {
node.writeLock.lock();
try {
node.updateCpu(cpuSeq, cpu);
} finally {
node.writeLock.unlock();
}
}
}
}
}
// Process "offline" block
if (offline != null) {
for (Tree row : offline) {
String nodeID = row.getName();
NodeDescriptor node;
if (this.nodeID.equals(nodeID)) {
long seq = row.asLong();
node = getDescriptor();
node.writeLock.lock();
try {
long newSeq = Math.max(node.seq, seq + 1);
if (node.seq < newSeq) {
node.seq = newSeq;
node.info.put("seq", newSeq);
}
} finally {
node.writeLock.unlock();
}
continue;
}
node = nodes.get(nodeID);
if (node == null) {
return;
}
if (!row.isPrimitive()) {
logger.warn("Invalid \"offline\" block: " + row);
continue;
}
// Get parameters from input
boolean disconnected = false;
node.writeLock.lock();
try {
long seq = row.asLong();
if (node.seq < seq && node.markAsOffline(seq)) {
// We know it is online, so we change it to offline
// Remove remote actions and listeners
registry.removeActions(node.nodeID);
eventbus.removeListeners(node.nodeID);
writer.close(node.nodeID);
disconnected = true;
}
} finally {
node.writeLock.unlock();
}
if (node != null && disconnected) {
// Notify listeners (not unexpected disconnection)
logger.info("Node \"" + node.nodeID + "\" disconnected.");
broadcastNodeDisconnected(node.info, false);
}
}
}
}
use of io.datatree.Tree in project moleculer-java by moleculer-java.
the class TcpTransporter method registerAsNewNode.
protected void registerAsNewNode(String sender, String host, int port) {
// Check node
if (sender == null || sender.isEmpty()) {
throw new IllegalArgumentException("Empty sender field!");
}
if (host == null || host.isEmpty()) {
throw new IllegalArgumentException("Empty host field!");
}
if (port < 1) {
throw new IllegalArgumentException("Invalid port value (" + port + ")!");
}
if (nodeID.equalsIgnoreCase(sender)) {
return;
}
NodeDescriptor node = nodes.get(sender);
if (node == null) {
// Add as new, offline node
try {
nodes.put(sender, new NodeDescriptor(sender, useHostname, host, port));
logger.info("Node \"" + sender + "\" registered.");
} catch (Exception cause) {
logger.warn("Unable to register new node!", cause);
}
} else {
node.writeLock.lock();
try {
// Host or port number changed
if (!node.host.equalsIgnoreCase(host) || node.port != port) {
node.host = host;
node.port = port;
if (node.info != null) {
if (useHostname) {
node.info.put("hostname", host);
} else {
Tree ipList = node.info.get("ipList");
if (ipList == null) {
ipList = node.info.putList("ipList");
} else {
ipList.clear();
}
ipList.add(host);
}
node.info.put("port", port);
}
writer.close(sender);
}
} finally {
node.writeLock.unlock();
}
}
}
use of io.datatree.Tree in project moleculer-java by moleculer-java.
the class DefaultServiceRegistry method addActions.
// --- ADD A REMOTE SERVICE ---
@Override
public void addActions(Tree config) {
Tree actions = config.get("actions");
if (actions != null && actions.isMap()) {
String nodeID = Objects.requireNonNull(config.get("nodeID", (String) null));
writeLock.lock();
try {
for (Tree actionConfig : actions) {
actionConfig.putObject("nodeID", nodeID, true);
String actionName = actionConfig.get("name", "");
// Register remote action
RemoteActionEndpoint endpoint = new RemoteActionEndpoint(this, transporter, nodeID, actionConfig);
Strategy<ActionEndpoint> actionStrategy = strategies.get(actionName);
if (actionStrategy == null) {
actionStrategy = strategyFactory.create();
strategies.put(actionName, actionStrategy);
}
actionStrategy.addEndpoint(endpoint);
}
} finally {
writeLock.unlock();
}
// Notify local listeners about the new REMOTE service
broadcastServicesChanged(false);
}
}
use of io.datatree.Tree in project moleculer-java by moleculer-java.
the class DefaultServiceRegistry method receiveRequest.
// --- RECEIVE REQUEST FROM REMOTE SERVICE ---
@Override
public void receiveRequest(Tree message) {
// Verify protocol version
if (checkVersion) {
String ver = message.get("ver", "unknown");
if (!ServiceBroker.PROTOCOL_VERSION.equals(ver)) {
logger.warn("Invalid protocol version (" + ver + ")!");
return;
}
}
// Get action property
String action = message.get("action", (String) null);
if (action == null || action.isEmpty()) {
logger.warn("Missing \"action\" property!");
return;
}
// Get strategy (action endpoint array) by action name
Strategy<ActionEndpoint> strategy;
readLock.lock();
try {
strategy = strategies.get(action);
} finally {
readLock.unlock();
}
if (strategy == null) {
logger.warn("Invalid action name (" + action + ")!");
return;
}
// Get local action endpoint (with cache handling)
ActionEndpoint endpoint = strategy.getEndpoint(nodeID);
if (endpoint == null) {
logger.warn("Not a local action (" + action + ")!");
return;
}
// Get request's unique ID
String id = message.get("id", (String) null);
if (id == null || id.isEmpty()) {
logger.warn("Missing \"id\" property!");
return;
}
// Get sender's nodeID
String sender = message.get("sender", (String) null);
if (sender == null || sender.isEmpty()) {
logger.warn("Missing \"sender\" property!");
return;
}
// Create CallOptions
int timeout = message.get("timeout", 0);
Tree params = message.get("params");
// TODO Process other properties:
// Tree meta = message.get("meta");
// int level = message.get("level", 1);
// boolean metrics = message.get("metrics", false);
// String parentID = message.get("parentID", (String) null);
// String requestID = message.get("requestID", (String) null);
CallOptions.Options opts = CallOptions.nodeID(nodeID).timeout(timeout);
Context ctx = contextFactory.create(action, params, opts, null);
// Invoke action
try {
new Promise(endpoint.handler(ctx)).then(data -> {
// Send response
FastBuildTree msg = new FastBuildTree(5);
msg.putUnsafe("sender", nodeID);
msg.putUnsafe("id", id);
msg.putUnsafe("ver", ServiceBroker.PROTOCOL_VERSION);
msg.putUnsafe("success", true);
msg.putUnsafe("data", data);
transporter.publish(Transporter.PACKET_RESPONSE, sender, msg);
}).catchError(error -> {
// Send error
transporter.publish(Transporter.PACKET_RESPONSE, sender, throwableToTree(id, sender, error));
});
} catch (Throwable error) {
// Send error
transporter.publish(Transporter.PACKET_RESPONSE, sender, throwableToTree(id, sender, error));
}
}
use of io.datatree.Tree in project moleculer-java by moleculer-java.
the class DefaultServiceRegistry method currentDescriptor.
protected synchronized Tree currentDescriptor() {
if (descriptor == null) {
// Create new descriptor block
descriptor = new Tree();
// Services array
Tree services = descriptor.putList("services");
Tree servicesMap = new Tree();
readLock.lock();
try {
for (Map.Entry<String, Strategy<ActionEndpoint>> entry : strategies.entrySet()) {
// Split into parts ("math.add" -> "math" and "add")
String name = entry.getKey();
int i = name.lastIndexOf('.');
String service = name.substring(0, i);
// Get endpoint
ActionEndpoint endpoint = entry.getValue().getEndpoint(nodeID);
if (endpoint == null) {
continue;
}
// Service block
Tree serviceMap = servicesMap.putMap(service, true);
serviceMap.put("name", service);
// Node ID
serviceMap.put("nodeID", nodeID);
// Action block
@SuppressWarnings("unchecked") Map<String, Object> actionBlock = (Map<String, Object>) serviceMap.putMap("actions", true).asObject();
actionBlock.put(name, endpoint.getConfig().asObject());
// Listener block
Tree listeners = eventbus.generateListenerDescriptor(service);
if (listeners != null && !listeners.isEmpty()) {
serviceMap.putObject("events", listeners);
}
}
} finally {
readLock.unlock();
}
for (Tree service : servicesMap) {
services.addObject(service);
}
// Host name
descriptor.put("hostname", getHostName());
// IP array
Tree ipList = descriptor.putList("ipList");
HashSet<String> ips = new HashSet<>();
try {
InetAddress local = InetAddress.getLocalHost();
String defaultAddress = local.getHostAddress();
if (!defaultAddress.startsWith("127.")) {
ips.add(defaultAddress);
ipList.add(defaultAddress);
}
} catch (Exception ignored) {
}
try {
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
while (e.hasMoreElements()) {
NetworkInterface n = (NetworkInterface) e.nextElement();
Enumeration<InetAddress> ee = n.getInetAddresses();
while (ee.hasMoreElements()) {
InetAddress i = (InetAddress) ee.nextElement();
if (!i.isLoopbackAddress()) {
String test = i.getHostAddress();
if (ips.add(test)) {
ipList.add(test);
}
}
}
}
} catch (Exception ignored) {
}
// Client descriptor
Tree client = descriptor.putMap("client");
client.put("type", "java");
client.put("version", ServiceBroker.SOFTWARE_VERSION);
client.put("langVersion", System.getProperty("java.version", "1.8"));
// Config (not used in this version)
// root.putMap("config");
// Set timestamp
timestamp.set(System.currentTimeMillis());
}
return descriptor;
}
Aggregations