class GridClientRoundRobinBalancer extends GridClientBalancerAdapter implements GridClientTopologyListener {
    /** Lock. */
    private Lock lock = new ReentrantLock();

    /** Nodes to share load. */
    private LinkedList<UUID> nodeQueue = new LinkedList<>();

    /** {@inheritDoc} */
    @Override public GridClientNode balancedNode(Collection<? extends GridClientNode> nodes)
        throws GridClientException {
        assert !nodes.isEmpty();

        if (isPreferDirectNodes()) {
            Collection<GridClientNode> direct = selectDirectNodes(nodes);

            int directSize = direct.size();

            // If set of direct nodes is not empty and differ from original one
            // replace original set of nodes with directly available.
            if (directSize > 0 && directSize < nodes.size())
                nodes = direct;
        }

        Map<UUID, GridClientNode> lookup = U.newHashMap(nodes.size());

        for (GridClientNode node : nodes)
            lookup.put(node.nodeId(), node);

        lock.lock();

        try {
            GridClientNode balanced = null;

            for (Iterator<UUID> iter = nodeQueue.iterator(); iter.hasNext();) {
                UUID nodeId = iter.next();

                balanced = lookup.get(nodeId);

                if (balanced != null) {
                    iter.remove();

                    break;
                }
            }

            if (balanced != null) {
                nodeQueue.addLast(balanced.nodeId());

                return balanced;
            }

            throw new GridClientException("Passed nodes doesn't present in topology " +
                "[nodes=" + nodes + ", top=" + nodeQueue);
        }
        finally {
            lock.unlock();
        }
    }

    /** {@inheritDoc} */
    @Override public void onNodeAdded(GridClientNode node) {<FILL_FUNCTION_BODY>}

    /** {@inheritDoc} */
    @Override public void onNodeRemoved(GridClientNode node) {
        lock.lock();

        try {
            nodeQueue.remove(node.nodeId());
        }
        finally {
            lock.unlock();
        }
    }
}

        lock.lock();

        try {
            nodeQueue.addFirst(node.nodeId());
        }
        finally {
            lock.unlock();
        }
    
<methods>public non-sealed void <init>() ,public boolean isPreferDirectNodes() ,public org.apache.ignite.internal.client.balancer.GridClientBalancerAdapter setPreferDirectNodes(boolean) <variables>private static final IgnitePredicate<org.apache.ignite.internal.client.GridClientNode> CONNECTABLE,private boolean preferDirectNodes