Package com.netflix.discovery.shared

Source Code of com.netflix.discovery.shared.EurekaJerseyClient$JerseyClient$ConnectionCleanerTask

/*
* Copyright 2012 Netflix, Inc.
*
*    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.netflix.discovery.shared;

import com.google.common.base.Preconditions;
import com.netflix.discovery.provider.DiscoveryJerseyProvider;
import com.netflix.http4.MonitoredConnectionManager;
import com.netflix.servo.monitor.BasicCounter;
import com.netflix.servo.monitor.BasicTimer;
import com.netflix.servo.monitor.Counter;
import com.netflix.servo.monitor.MonitorConfig;
import com.netflix.servo.monitor.Monitors;
import com.netflix.servo.monitor.Stopwatch;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.client.apache4.ApacheHttpClient4;
import com.sun.jersey.client.apache4.config.ApacheHttpClient4Config;
import com.sun.jersey.client.apache4.config.DefaultApacheHttpClient4Config;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
* A wrapper for Jersey Apache Client to set the necessary configurations.
*
* @author Karthik Ranganathan
*
*/
public final class EurekaJerseyClient {

    private EurekaJerseyClient() {
    }

    /**
     * Creates a Jersey client with the given configuration parameters.
     *
     *
     * @param clientName
     * @param connectionTimeout
     *            - The connection timeout of the connection in milliseconds
     * @param readTimeout
     *            - The read timeout of the connection in milliseconds
     * @param maxConnectionsPerHost
     *            - The maximum number of connections to a particular host
     * @param maxTotalConnections
     *            - The maximum number of total connections across all hosts
     * @param connectionIdleTimeout
     *            - The idle timeout after which the connections will be cleaned
     *            up in seconds
     * @return - The jersey client object encapsulating the connection
     */
    public static JerseyClient createJerseyClient(String clientName, int connectionTimeout,
                                                  int readTimeout, int maxConnectionsPerHost,
                                                  int maxTotalConnections, int connectionIdleTimeout) {
        Preconditions.checkNotNull(clientName, "Client name can not be null.");
        try {
            ClientConfig jerseyClientConfig = new CustomApacheHttpClientConfig(clientName, maxConnectionsPerHost,
                                                                               maxTotalConnections);

            return new JerseyClient(connectionTimeout, readTimeout,
                                    connectionIdleTimeout, jerseyClientConfig);
        } catch (Throwable e) {
            throw new RuntimeException("Cannot create Jersey client ", e);
        }
    }

    /**
     * Creates a Jersey client with the given configuration parameters.
     *
     *
     * @param clientName
     * @param connectionTimeout
     *            - The connection timeout of the connection in milliseconds
     * @param readTimeout
     *            - The read timeout of the connection in milliseconds
     * @param maxConnectionsPerHost
     *            - The maximum number of connections to a particular host
     * @param maxTotalConnections
     *            - The maximum number of total connections across all hosts
     * @param connectionIdleTimeout
     *            - The idle timeout after which the connections will be cleaned
     *            up in seconds
     * @param proxyHost
     *            - The hostname of the proxy
     * @param proxyPort
     *            - The port number the proxy is listening on
     * @param proxyUserName
     *            - The username to use to authenticate to the proxy
     * @param proxyPassword
     *            - The password to use to authenticate to the proxy
     * @return - The jersey client object encapsulating the connection
     */
    public static JerseyClient createProxyJerseyClient(String clientName, int connectionTimeout,
            int readTimeout, int maxConnectionsPerHost, int maxTotalConnections, int connectionIdleTimeout,
            String proxyHost, String proxyPort, String proxyUserName, String proxyPassword) {
      Preconditions.checkNotNull(clientName, "Client name can not be null.");
      try {
          ClientConfig jerseyClientConfig = new ProxyCustomApacheHttpClientConfig(clientName, maxConnectionsPerHost,
                  maxTotalConnections, proxyHost, proxyPort, proxyUserName, proxyPassword);
         
          return new JerseyClient(connectionTimeout, readTimeout,
                                  connectionIdleTimeout, jerseyClientConfig);
      } catch (Throwable e) {
          throw new RuntimeException("Cannot create Jersey client ", e);
      }
    }
   
    /**
     * Creates the SSL based Jersey client with the given configuration
     * parameters.
     *
     *
     *
     * @param clientName
     * @param connectionTimeout
     *            - The connection timeout of the connection in milliseconds
     * @param readTimeout
     *            - The read timeout of the connection in milliseconds
     * @param maxConnectionsPerHost
     *            - The maximum number of connections to a particular host
     * @param maxTotalConnections
     *            - The maximum number of total connections across all hosts
     * @param connectionIdleTimeout
     *            - The idle timeout after which the connections will be cleaned
     *            up in seconds
     * @param trustStoreFileName
     *            - The full path to the trust store file
     * @param trustStorePassword
     *            - The password of the trust store file
     * @return - The jersey client object encapsulating the connection
     */

    public static JerseyClient createSSLJerseyClient(String clientName, int connectionTimeout,
                                                     int readTimeout, int maxConnectionsPerHost,
                                                     int maxTotalConnections, int connectionIdleTimeout,
                                                     String trustStoreFileName, String trustStorePassword) {
        Preconditions.checkNotNull(clientName, "Client name can not be null.");
        try {
            ClientConfig jerseyClientConfig = new SSLCustomApacheHttpClientConfig(
                    clientName, maxConnectionsPerHost, maxTotalConnections,
                    trustStoreFileName, trustStorePassword);

            return new JerseyClient(connectionTimeout, readTimeout,
                                    connectionIdleTimeout, jerseyClientConfig);
        } catch (Throwable e) {
            throw new RuntimeException("Cannot create SSL Jersey client ", e);
        }
    }

    /**
     * Creates the SSL based Jersey client with the given configuration
     * parameters and using a SystemSocketFactory to support standard keystore/truststore
     * system properties.
     *
     * @param clientName
     * @param connectionTimeout
     *            - The connection timeout of the connection in milliseconds
     * @param readTimeout
     *            - The read timeout of the connection in milliseconds
     * @param maxConnectionsPerHost
     *            - The maximum number of connections to a particular host
     * @param maxTotalConnections
     *            - The maximum number of total connections across all hosts
     * @param connectionIdleTimeout
     *            - The idle timeout after which the connections will be cleaned
     *            up in seconds
     * @return - The jersey client object encapsulating the connection
     */
   
    public static JerseyClient createSystemSSLJerseyClient(String clientName, int connectionTimeout,
        int readTimeout, int maxConnectionsPerHost,
        int maxTotalConnections, int connectionIdleTimeout) {
      Preconditions.checkNotNull(clientName, "Client name can not be null.")
       try {
        ClientConfig jerseyClientConfig = new SystemSSLCustomApacheHttpClientConfig(
            clientName, maxConnectionsPerHost, maxTotalConnections);
       
        return new JerseyClient(connectionTimeout, readTimeout,
            connectionIdleTimeout, jerseyClientConfig);
      } catch (Throwable e) {
        throw new RuntimeException("Cannot create System SSL Jersey client ", e);
      }
    }

    private static class CustomApacheHttpClientConfig extends DefaultApacheHttpClient4Config {

        public CustomApacheHttpClientConfig(String clientName, int maxConnectionsPerHost, int maxTotalConnections)
                throws Throwable {
            MonitoredConnectionManager cm = new MonitoredConnectionManager(clientName);
            cm.setDefaultMaxPerRoute(maxConnectionsPerHost);
            cm.setMaxTotal(maxTotalConnections);
            getProperties().put(ApacheHttpClient4Config.PROPERTY_CONNECTION_MANAGER, cm);
        }
    }

    private static class ProxyCustomApacheHttpClientConfig extends DefaultApacheHttpClient4Config {
     
      public ProxyCustomApacheHttpClientConfig(String clientName, int maxConnectionsPerHost, int maxTotalConnections,
              String proxyHost, String proxyPort, String proxyUserName, String proxyPassword)
          throws Throwable {
        MonitoredConnectionManager cm = new MonitoredConnectionManager(clientName);
        cm.setDefaultMaxPerRoute(maxConnectionsPerHost);
        cm.setMaxTotal(maxTotalConnections);
        getProperties().put(ApacheHttpClient4Config.PROPERTY_CONNECTION_MANAGER, cm);
       
        if (proxyUserName != null && proxyPassword != null) {
          getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_USERNAME, proxyUserName);
          getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_PASSWORD, proxyPassword);
        } else {
          // Due to bug in apache client, user name/password must always be set.
          // Otherwise proxy configuration is ignored.
          getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_USERNAME, "guest");
          getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_PASSWORD, "guest");
        }
        getProperties().put(
                DefaultApacheHttpClient4Config.PROPERTY_PROXY_URI,
                "http://" + proxyHost + ":" + proxyPort);
      }
    }
   
    private static class SSLCustomApacheHttpClientConfig extends DefaultApacheHttpClient4Config {
        private static final String PROTOCOL_SCHEME = "SSL";
        private static final int HTTPS_PORT = 443;
        private static final String PROTOCOL = "https";
        private static final String KEYSTORE_TYPE = "JKS";

        public SSLCustomApacheHttpClientConfig(String clientName, int maxConnectionsPerHost,
                                               int maxTotalConnections, String trustStoreFileName,
                                               String trustStorePassword) throws Throwable {

            SSLContext sslContext = SSLContext.getInstance(PROTOCOL_SCHEME);
            TrustManagerFactory tmf = TrustManagerFactory
            .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            KeyStore sslKeyStore = KeyStore.getInstance(KEYSTORE_TYPE);
            FileInputStream fin = null;
            try {
                fin = new FileInputStream(trustStoreFileName);
                sslKeyStore.load(fin, trustStorePassword.toCharArray());
                tmf.init(sslKeyStore);
                sslContext.init(null, createTrustManagers(sslKeyStore), null);
                SSLSocketFactory sslSocketFactory = new SSLSocketFactory(
                        sslContext);
                sslSocketFactory
                .setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                SchemeRegistry sslSchemeRegistry = new SchemeRegistry();
                sslSchemeRegistry.register(new Scheme(PROTOCOL, HTTPS_PORT, sslSocketFactory));

                MonitoredConnectionManager cm = new MonitoredConnectionManager(clientName, sslSchemeRegistry);
                cm.setDefaultMaxPerRoute(maxConnectionsPerHost);
                cm.setMaxTotal(maxTotalConnections);
                getProperties()
                .put(ApacheHttpClient4Config.PROPERTY_CONNECTION_MANAGER, cm);
            } finally {
                if (fin != null) {
                    fin.close();
                }
            }

        }

        private static TrustManager[] createTrustManagers(KeyStore trustStore) {
            TrustManagerFactory factory;
            try {
                factory = TrustManagerFactory.getInstance(TrustManagerFactory
                                                                  .getDefaultAlgorithm());
                factory.init(trustStore);
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }

            final TrustManager[] managers = factory.getTrustManagers();

            return managers;

        }
    }
   
    private static class SystemSSLCustomApacheHttpClientConfig extends DefaultApacheHttpClient4Config {
      private static final int HTTPS_PORT = 443;
      private static final String PROTOCOL = "https";
     
      public SystemSSLCustomApacheHttpClientConfig(String clientName, int maxConnectionsPerHost,
          int maxTotalConnections) throws Throwable {
       
        SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSystemSocketFactory();
        SchemeRegistry sslSchemeRegistry = new SchemeRegistry();
        sslSchemeRegistry.register(new Scheme(PROTOCOL, HTTPS_PORT, sslSocketFactory));
       
        MonitoredConnectionManager cm = new MonitoredConnectionManager(clientName, sslSchemeRegistry);
        cm.setDefaultMaxPerRoute(maxConnectionsPerHost);
        cm.setMaxTotal(maxTotalConnections);
        getProperties().put(ApacheHttpClient4Config.PROPERTY_CONNECTION_MANAGER, cm);
       
      }
    }

    public static class JerseyClient {

        private static final int HTTP_CONNECTION_CLEANER_INTERVAL_MS = 30 * 1000;

        private ApacheHttpClient4 apacheHttpClient;

        ClientConfig jerseyClientConfig;

        private ScheduledExecutorService eurekaConnCleaner =
                Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {

            private final AtomicInteger threadNumber = new AtomicInteger(1);

            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r, "Eureka-JerseyClient-Conn-Cleaner" + threadNumber.incrementAndGet());
                thread.setDaemon(true);
                return thread;
            }
        });

        private static final Logger s_logger = LoggerFactory.getLogger(JerseyClient.class);

        public ApacheHttpClient4 getClient() {
            return apacheHttpClient;
        }

        public ClientConfig getClientconfig() {
            return jerseyClientConfig;
        }

        public JerseyClient(int connectionTimeout, int readTimeout, final int connectionIdleTimeout,
                            ClientConfig clientConfig) {
            try {
                jerseyClientConfig = clientConfig;
                jerseyClientConfig.getClasses().add(DiscoveryJerseyProvider.class);
                apacheHttpClient = ApacheHttpClient4.create(jerseyClientConfig);
                HttpParams params = apacheHttpClient.getClientHandler().getHttpClient().getParams();

                HttpConnectionParams.setConnectionTimeout(params, connectionTimeout);
                HttpConnectionParams.setSoTimeout(params, readTimeout);

                eurekaConnCleaner.scheduleWithFixedDelay(
                        new ConnectionCleanerTask(connectionIdleTimeout), HTTP_CONNECTION_CLEANER_INTERVAL_MS,
                        HTTP_CONNECTION_CLEANER_INTERVAL_MS,
                        TimeUnit.MILLISECONDS);
            } catch (Throwable e) {
                throw new RuntimeException("Cannot create Jersey client", e);
            }

        }

        /**
         * Clean up resources.
         */
        public void destroyResources() {
            if (eurekaConnCleaner != null) {
                eurekaConnCleaner.shutdown();
            }
            if (apacheHttpClient != null) {
                apacheHttpClient.destroy();
            }
        }

        private class ConnectionCleanerTask implements Runnable {

            private final int connectionIdleTimeout;
            private final BasicTimer executionTimeStats;
            private final Counter cleanupFailed;

            public ConnectionCleanerTask(int connectionIdleTimeout) {
                this.connectionIdleTimeout = connectionIdleTimeout;
                MonitorConfig.Builder monitorConfigBuilder = MonitorConfig.builder("Eureka-Connection-Cleaner-Time");
                executionTimeStats = new BasicTimer(monitorConfigBuilder.build());
                cleanupFailed = new BasicCounter(MonitorConfig.builder("Eureka-Connection-Cleaner-Failure").build());
                try {
                    Monitors.registerObject(this);
                } catch (Exception e) {
                    s_logger.error("Unable to register with servo.", e);
                }
            }

            @Override
            public void run() {
                Stopwatch start = executionTimeStats.start();
                try {
                    apacheHttpClient
                    .getClientHandler()
                    .getHttpClient()
                    .getConnectionManager()
                    .closeIdleConnections(connectionIdleTimeout, TimeUnit.SECONDS);
                } catch (Throwable e) {
                    s_logger.error("Cannot clean connections", e);
                    cleanupFailed.increment();
                } finally {
                    if (null != start) {
                        start.stop();
                    }
                }

            }

        }
    }

}
TOP

Related Classes of com.netflix.discovery.shared.EurekaJerseyClient$JerseyClient$ConnectionCleanerTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.