/* * Copyright © 2016 - 2020 VMware, Inc. All Rights Reserved. * * 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.vrg.standalone; import com.google.common.net.HostAndPort; import com.google.protobuf.ByteString; import com.vrg.rapid.Cluster; import com.vrg.rapid.messaging.impl.NettyClientServer; import com.vrg.rapid.pb.Endpoint; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nullable; import java.io.IOException; /** * An example to demonstrate how to plugin a custom messaging implementation to Rapid. * */ public class AgentWithNettyMessaging extends StandaloneAgent { private static final Logger LOG = LoggerFactory.getLogger(AgentWithNettyMessaging.class); private static final int SLEEP_INTERVAL_MS = 1000; private static final int MAX_TRIES = 400; @Nullable private Cluster cluster = null; private AgentWithNettyMessaging(final HostAndPort listenAddress, final HostAndPort seedAddress) { super(listenAddress, seedAddress); } @Override public void startCluster() throws IOException, InterruptedException { final Endpoint endpoint = Endpoint.newBuilder() .setHostname(ByteString.copyFromUtf8(listenAddress.getHost())) .setPort(listenAddress.getPort()).build(); // To use your own messaging implementation with Rapid, supply an instance each of IMessagingClient // and IMessagingServer to Cluster.Builder.setMessagingClientServer(). // // In this example, we use an object NettyClientServer which implements both the IMessagingClient // and IMessagingServer interfaces. final NettyClientServer nettyMessaging = new NettyClientServer(endpoint); if (listenAddress.equals(seedAddress)) { cluster = new Cluster.Builder(listenAddress) .setMessagingClientAndServer(nettyMessaging, nettyMessaging) .start(); } else { cluster = new Cluster.Builder(listenAddress) .setMessagingClientAndServer(nettyMessaging, nettyMessaging) .join(seedAddress); } cluster.registerSubscription(com.vrg.rapid.ClusterEvents.VIEW_CHANGE_PROPOSAL, this::onViewChangeProposal); cluster.registerSubscription(com.vrg.rapid.ClusterEvents.VIEW_CHANGE, this::onViewChange); cluster.registerSubscription(com.vrg.rapid.ClusterEvents.KICKED, this::onKicked); } /** * Prints the current membership */ private void printClusterMembership() { LOG.info("Node {} -- cluster size {}", listenAddress, cluster.getMembershipSize()); } public static void main(final String[] args) throws ParseException { final Options options = new Options(); options.addRequiredOption("l", "listenAddress", true, "The listening addresses Rapid Cluster instances"); options.addRequiredOption("s", "seedAddress", true, "The seed node's address for the bootstrap protocol"); final CommandLineParser parser = new DefaultParser(); final CommandLine cmd = parser.parse(options, args); // Get CLI options final HostAndPort listenAddress = HostAndPort.fromString(cmd.getOptionValue("listenAddress")); final HostAndPort seedAddress = HostAndPort.fromString(cmd.getOptionValue("seedAddress")); // Bring up Rapid node try { final AgentWithNettyMessaging agent = new AgentWithNettyMessaging(listenAddress, seedAddress); agent.startCluster(); for (int i = 0; i < MAX_TRIES; i++) { agent.printClusterMembership(); Thread.sleep(SLEEP_INTERVAL_MS); } } catch (final IOException | InterruptedException e) { LOG.error("Exception thrown by StandaloneAgent {}", e); Thread.currentThread().interrupt(); } } }