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

io.dropwizard.discovery.core.CuratorAdvertiser Maven / Gradle / Ivy

package io.dropwizard.discovery.core;

import static com.google.common.base.Preconditions.checkNotNull;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Collection;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.framework.state.ConnectionStateListener;
import org.apache.curator.x.discovery.ServiceDiscovery;
import org.apache.curator.x.discovery.ServiceInstance;
import org.apache.curator.x.discovery.ServiceInstanceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Strings;
import io.dropwizard.discovery.DiscoveryFactory;

@ThreadSafe
public class CuratorAdvertiser implements ConnectionStateListener {
    private static final Logger LOGGER = LoggerFactory
            .getLogger(CuratorAdvertiser.class);

    private static final UUID instanceId = UUID.randomUUID();
    private final ServiceDiscovery discovery;
    private final DiscoveryFactory configuration;
    private final ServiceInstanceFactory serviceInstanceFactory;

    @Nullable
    @GuardedBy("this")
    private String listenAddress = null;

    @GuardedBy("this")
    private int listenPort = 0;

    @Nullable
    @GuardedBy("this")
    private Integer adminPort = null;

    @Nullable
    @GuardedBy("this")
    private ServiceInstance instance;

    /**
     * Constructor
     * 
     * @param configuration
     *            {@link DiscoveryFactory}
     * @param discovery
     *            {@link ServiceDiscovery}
     */
    public CuratorAdvertiser(@Nonnull final DiscoveryFactory configuration,
            @Nonnull final ServiceDiscovery discovery,
            @Nonnull final ServiceInstanceFactory serviceInstanceFactory) {
        this.configuration = checkNotNull(configuration);
        this.discovery = checkNotNull(discovery);
        this.serviceInstanceFactory = checkNotNull(serviceInstanceFactory);
    }

    /**
     * Set the listen port and set the listen address from the configuration
     * file or attempt to auto-detect the first IPv4 address that is found.
     * 
     * @param port
     *            port this instance is listening on
     * @param adminPort
     *            optional admin port this instance is listening on
     */
    public synchronized void initListenInfo(final int port,
            @Nullable final Integer adminPort) {
        this.listenPort = port;
        this.adminPort = adminPort;

        if (!Strings.isNullOrEmpty(configuration.getListenAddress())) {
            LOGGER.info("Using '{}' as listenAddress from configuration file",
                    configuration.getListenAddress());
            listenAddress = configuration.getListenAddress();
            return;
        }

        LOGGER.warn(
                "listenAddress not found in configuration file, attempting to auto-detect");

        try {
            final Collection ips = ServiceInstanceBuilder
                    .getAllLocalIPs();
            for (final InetAddress ip : ips) {
                String ipAddr = String.valueOf(ip);
                // crude hack to look for IPv6 addresses
                if (ipAddr.indexOf(":") != -1) {
                    continue;
                }
                if (ipAddr.startsWith("/")) {
                    ipAddr = ipAddr.substring(1);
                }
                listenAddress = ipAddr;
                LOGGER.info(
                        "Using '{}' as listenAddress from found addresses: {}",
                        listenAddress, ips);
                break;
            }
        } catch (final SocketException e) {
            LOGGER.error("Error getting local IP addresses", e);
        }
    }

    /**
     * Register the instance in Zookeeper
     * 
     * @throws Exception
     */
    public synchronized void registerAvailability() throws Exception {
        registerAvailability(getInstance());
    }

    /**
     * Register a specific instance in Zookeeper
     * 
     * @param instance
     *            Service Instance
     * @throws Exception
     */
    public synchronized void registerAvailability(
            @Nonnull final ServiceInstance instance) throws Exception {
        checkInitialized();
        LOGGER.info("Registering service ({}) at <{}:{}>",
                configuration.getServiceName(), listenAddress, listenPort);

        discovery.registerService(instance);
        LOGGER.debug("Successfully registered service ({}) in ZK",
                configuration.getServiceName());
    }

    /**
     * Remove the instance from Zookeeper
     * 
     * @throws Exception
     */
    public synchronized void unregisterAvailability() throws Exception {
        unregisterAvailability(getInstance());
    }

    /**
     * Remove the specific instance from Zookeeper
     * 
     * @param instance
     *            Service Instance
     * @throws Exception
     */
    public synchronized void unregisterAvailability(
            @Nonnull final ServiceInstance instance) throws Exception {
        checkInitialized();
        LOGGER.info("Unregistering service ({}) at <{}:{}>",
                configuration.getServiceName(), listenAddress, listenPort);

        discovery.unregisterService(instance);
        LOGGER.debug("Successfully unregistered service ({}) from ZK",
                configuration.getServiceName());
    }

    /**
     * Return the instance ID
     * 
     * @return {@link UUID}
     */
    public UUID getInstanceId() {
        return instanceId;
    }

    /**
     * Return the listening port
     * 
     * @return port number
     */
    public synchronized int getListenPort() {
        return listenPort;
    }

    /**
     * Return the admin port
     *
     * @return port number
     */
    public synchronized Optional getAdminPort() {
        return Optional.ofNullable(adminPort);
    }

    /**
     * Return the listening IP address
     * 
     * @return IP address
     */
    @Nullable
    public synchronized String getListenAddress() {
        return listenAddress;
    }

    /**
     * Return the {@link ServiceInstance} that will be registered with the
     * {@link ServiceDiscovery} instance.
     * 
     * @return {@link ServiceInstance}
     * @throws Exception
     */
    public synchronized ServiceInstance getInstance() throws Exception {
        if (instance != null) {
            return instance;
        }
        instance = serviceInstanceFactory.build(configuration.getServiceName(),
                this);
        return instance;
    }

    /**
     * Check that the {@link #initListenInfo} method has been called by
     * validating that the listenPort is greater than 1.
     * 
     * @throws IllegalStateException
     */
    public synchronized void checkInitialized() {
        if (Strings.isNullOrEmpty(listenAddress) || listenPort < 1) {
            throw new IllegalStateException("Not initialized");
        }
    }

    /**
     * TODO - figure out how to register this listener
     */
    @Override
    public void stateChanged(final CuratorFramework client,
            final ConnectionState newState) {
        if (newState == ConnectionState.RECONNECTED) {
            try {
                registerAvailability();
            } catch (final Exception e) {
                LOGGER.error("Unable to register service", e);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy