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

org.graylog2.restclient.lib.ServerNodes Maven / Gradle / Ivy

The newest version!
/**
 * This file is part of Graylog.
 *
 * Graylog is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Graylog is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Graylog.  If not, see .
 */
package org.graylog2.restclient.lib;

import com.google.common.collect.*;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.inject.Named;
import org.graylog2.restclient.models.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

@Singleton
public class ServerNodes {
    private static final Logger log = LoggerFactory.getLogger(ServerNodes.class);
    private final CopyOnWriteArrayList serverNodes = Lists.newCopyOnWriteArrayList();
    private final BiMap configuredNodes = Maps.synchronizedBiMap(HashBiMap.create());
    private final Random random = new Random();

    @Inject
    private ServerNodes(Node.Factory nodeFactory, @Named("Initial Nodes") URI[] nodeAddresses) {
        for (URI nodeAddress : nodeAddresses) {
            final Node configuredNode = nodeFactory.fromTransportAddress(nodeAddress);
            configuredNodes.put(configuredNode, configuredNode);
        }

        log.debug("Creating ServerNodes with initial nodes {}", configuredNodes.keySet());
        // resolve the configured nodes:
        // we only know a transport address where we can reach them, but we don't know any node ids yet.
        // thus we do not know anything about them, and cannot even match them to node information coming
        // back from /system/cluster -> those all have node ids
        // ServerNodesRefreshService will do this for us, this class only deals with picking nodes from a list,
        // but does not update itself from external sources, this makes testing much easier
    }

    /**
     * Retrieves all currently active nodes.
     *
     * @return list of currently active nodes
     */
    public List all() {
        return all(false);
    }

    public List all(boolean allowInactive) {
        final Iterator nodeIterator;
        if (allowInactive) {
            nodeIterator = serverNodes.iterator();
        }
        else {
            nodeIterator = skipInactive(serverNodes);
        }
        final ImmutableList nodes = ImmutableList.copyOf(nodeIterator);
        if (!allowInactive && nodes.isEmpty()) {
            throw new Graylog2ServerUnavailableException();
        }
        return nodes;
    }

    public Node master() {
        final List all = all(false);

        if (all.isEmpty()) {
            throw new Graylog2ServerUnavailableException();
        }

        for (Node node : all) {
            if (node.isMaster()) {
                return node;
            }
        }

        // No active master node was found.
        throw new Graylog2MasterUnavailableException();
    }

    /**
     * Retrieve a random single active node.
     *
     * @return an active node
     */
    public Node any() {
        return any(false);
    }

    public Node any(boolean allowInactive) {
        final List all = all(allowInactive);
        if (all.isEmpty()) {
            throw new Graylog2ServerUnavailableException();
        }
        final int i = random.nextInt(all.size());
        return all.get(i);
    }

    /**
     * Register nodes in the list of active nodes.
     *
     * The passed nodes are taken to be active, until this process knows it cannot reach them.
     *
     * @param nodes Nodes known to exist in the cluster
     */
    public void put(Collection nodes) {
        HashSet existingNodes = Sets.newHashSet(serverNodes);
        for (Node newNode : nodes) {
            for (Node serverNode : existingNodes) {
                log.debug("Checking new node {} against existing node {}", newNode, serverNode);
                if (newNode.equals(serverNode)) {
                    serverNode.merge(newNode);
                    existingNodes.remove(serverNode);
                    break;
                }
            }
        }

        serverNodes.addAllAbsent(nodes);
        logServerNodesState();
    }

    private void logServerNodesState() {
        if (log.isDebugEnabled()) {
            StringBuilder b = new StringBuilder();
            b.append("Node List").append('\n');
            for (Node serverNode : serverNodes) {
                b.append(' ');
                if (serverNode.isMaster()) {
                    b.append("* ");
                } else {
                    b.append("  ");
                }
                b.append(serverNode.getNodeId())
                        .append('\t')
                        .append(serverNode.getTransportAddress())
                        .append('\t')
                        .append(serverNode.isActive() ? "active" : "inactive");
                if (serverNode.getFailureCount() > 0) {
                    b.append('\t').append("failures: ").append(serverNode.getFailureCount());
                }
                final Node linkedNode = configuredNodes.inverse().get(serverNode);
                if (linkedNode != null) {
                    b.append('\t').append("via config node ").append(linkedNode.getTransportAddress());
                }
                b.append('\n');
            }
            log.debug(b.toString());
        }
    }

    public Map asMap() {
        Map map = Maps.newHashMap();
        for (Node serverNode : ImmutableList.copyOf(skipInactive(serverNodes))) {
            map.put(serverNode.getNodeId(), serverNode);
        }

        return map;
    }

    private Iterator skipInactive(final Iterable iterable) {
        return new AbstractIterator() {
            Iterator in = iterable.iterator();
            @Override
            protected Node computeNext() {
                while (in.hasNext()) {
                    final Node next = in.next();
                    if (next.isActive()) {
                        return next;
                    }
                }
                return endOfData();
            }
        };
    }

    public List getConfiguredNodes() {
        return ImmutableList.copyOf(configuredNodes.keySet());
    }

    public void linkConfiguredNode(Node configuredNode, Node resolvedNode) {
        configuredNodes.put(configuredNode, resolvedNode);
    }

    public Node getDiscoveredNodeVia(Node configuredNode) {
        final Node node = configuredNodes.get(configuredNode);
        return node;
    }

    public Node getConfigNodeOf(Node serverNode) {
        return configuredNodes.inverse().get(serverNode);
    }

    public int connectedNodesCount() {
        return Iterators.size(skipInactive(serverNodes));
    }

    public int totalNodesCount() {
        return serverNodes.size();
    }

    public boolean isConnected() {
        return skipInactive(serverNodes).hasNext();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy