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

com.ge.snowizard.client.SnowizardClient Maven / Gradle / Ivy

package com.ge.snowizard.client;

import static com.google.common.base.Preconditions.checkNotNull;
import io.dropwizard.jersey.protobuf.ProtocolBufferMediaType;
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
import javax.annotation.Nullable;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.config.SocketConfig;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultBackoffStrategy;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ge.snowizard.api.protos.SnowizardProtos.SnowizardResponse;
import com.ge.snowizard.client.exceptions.SnowizardClientException;

public class SnowizardClient implements Closeable {

    private static final Logger LOGGER = LoggerFactory
            .getLogger(SnowizardClient.class);
    private static final int MAX_HOSTS = 1024;
    private static final int SOCKET_TIMEOUT_MS = 500;
    private static final int CONNECTION_TIMEOUT_MS = 500;
    private static final int MAX_RETRIES = 3;
    private final Iterable hosts;
    private final CloseableHttpClient client;

    /**
     * Constructor
     * 
     * @param hosts
     *            List of host:port pairs to connect to
     */
    public SnowizardClient(final Iterable hosts) {
        this(newHttpClient(), hosts);
    }

    /**
     * Constructor
     * 
     * @param client
     *            {@link HttpClient} to use
     * @param hosts
     *            List of host:port pairs to connect to
     */
    public SnowizardClient(final CloseableHttpClient client,
            final Iterable hosts) {
        checkNotNull(client);
        checkNotNull(hosts);

        this.client = client;
        this.hosts = hosts;
    }

    /**
     * Get a new CloseableHttpClient
     * 
     * @return CloseableHttpClient
     */
    public static CloseableHttpClient newHttpClient() {
        final SocketConfig socketConfig = SocketConfig.custom()
                .setSoKeepAlive(Boolean.TRUE).setTcpNoDelay(Boolean.TRUE)
                .setSoTimeout(SOCKET_TIMEOUT_MS).build();

        final PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
        manager.setDefaultMaxPerRoute(MAX_HOSTS);
        manager.setMaxTotal(MAX_HOSTS);
        manager.setDefaultSocketConfig(socketConfig);

        final RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(CONNECTION_TIMEOUT_MS)
                .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
                .setStaleConnectionCheckEnabled(Boolean.FALSE)
                .setSocketTimeout(SOCKET_TIMEOUT_MS).build();

        final CloseableHttpClient client = HttpClients
                .custom()
                .disableRedirectHandling()
                .setConnectionManager(manager)
                .setDefaultRequestConfig(requestConfig)
                .setConnectionReuseStrategy(
                        new DefaultConnectionReuseStrategy())
                .setConnectionBackoffStrategy(new DefaultBackoffStrategy())
                .setRetryHandler(
                        new DefaultHttpRequestRetryHandler(MAX_RETRIES, false))
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
                .build();
        return client;
    }

    /**
     * Return the internal {@link CloseableHttpClient}
     * 
     * @return CloseableHttpClient
     */
    public CloseableHttpClient getHttpClient() {
        return client;
    }

    /**
     * Execute a request to the Snowizard service URL and return a single ID.
     * 
     * @param host
     *            Host:Port pair to connect to
     * @return SnowizardResponse
     * @throws IOException
     *             Error in communicating with Snowizard
     */
    @Nullable
    public SnowizardResponse executeRequest(final String host)
            throws IOException {
        return executeRequest(host, 1);
    }

    /**
     * Execute a request to the Snowizard service URL
     * 
     * @param host
     *            Host:Port pair to connect to
     * @param count
     *            Number of IDs to generate
     * @return SnowizardResponse
     * @throws IOException
     *             Error in communicating with Snowizard
     */
    @Nullable
    public SnowizardResponse executeRequest(final String host, final int count)
            throws IOException {
        final String uri = String.format("http://%s/?count=%d", host, count);
        final HttpGet request = new HttpGet(uri);
        request.addHeader(HttpHeaders.ACCEPT, ProtocolBufferMediaType.APPLICATION_PROTOBUF);
        request.addHeader(HttpHeaders.USER_AGENT, getUserAgent());

        SnowizardResponse snowizard = null;
        try {
            final BasicHttpContext context = new BasicHttpContext();
            final HttpResponse response = client.execute(request, context);
            final int code = response.getStatusLine().getStatusCode();
            if (code == HttpStatus.SC_OK) {
                final HttpEntity entity = response.getEntity();
                if (entity != null) {
                    snowizard = SnowizardResponse
                            .parseFrom(entity.getContent());
                }
                EntityUtils.consumeQuietly(entity);
            }
        } finally {
            request.releaseConnection();
        }
        return snowizard;
    }

    /**
     * Get a new ID from Snowizard
     * 
     * @return generated ID
     * @throws SnowizardClientException
     *             when unable to get an ID from any host
     */
    public long getId() throws SnowizardClientException {
        for (final String host : hosts) {
            try {
                final SnowizardResponse snowizard = executeRequest(host);
                if (snowizard != null) {
                    return snowizard.getId(0);
                }
            } catch (final Exception ex) {
                LOGGER.warn("Unable to get ID from host ({})", host);
            }
        }
        throw new SnowizardClientException(
                "Unable to generate ID from Snowizard");
    }

    /**
     * Get multiple IDs from Snowizard
     * 
     * @param count
     *            Number of IDs to return
     * @return generated IDs
     * @throws SnowizardClientException
     *             when unable to get an ID from any host
     */
    public List getIds(final int count) throws SnowizardClientException {
        for (final String host : hosts) {
            try {
                final SnowizardResponse snowizard = executeRequest(host, count);
                if (snowizard != null) {
                    return snowizard.getIdList();
                }
            } catch (final Exception ex) {
                LOGGER.warn("Unable to get ID from host ({})", host);
            }
        }
        throw new SnowizardClientException(
                "Unable to generate batch of IDs from Snowizard");
    }

    /**
     * Get the user-agent for the client
     * 
     * @return user-agent for the client
     */
    public static String getUserAgent() {
        return "snowizard-client";
    }

    /**
     * Closes the underlying connection pool used by the internal
     * {@link CloseableHttpClient}.
     */
    @Override
    public void close() {
        if (client != null) {
            try {
                client.close();
            } catch (final IOException e) {
                LOGGER.error("Unable to close HTTP client", e);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy