org.ovirt.engine.sdk.web.ConnectionsPoolBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.ovirt.engine.sdk.web.ConnectionsPoolBuilder.java

Source

//
// Copyright (c) 2012 Red Hat, 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 org.ovirt.engine.sdk.web;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.PlainSocketFactory;
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.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.ovirt.engine.sdk.exceptions.ProtocolException;
import org.ovirt.engine.sdk.exceptions.SocketFactoryException;
import org.ovirt.engine.sdk.utils.StringUtils;

/**
 * Provides ConnectionsPool building services
 */
public class ConnectionsPoolBuilder {

    private static final String DEFAULT_KEYSTORE_TRUSTSTORE = "ovirtsdk-keystore.truststore";
    private static final String BAD_PROTOCOL_ERROR = "Unsupported protocol ";
    private static final String BAD_KEY_ERROR = "SSL context initiation has failed because of key error.";
    private static final String NO_TLS_ERROR = "SSL context initiation has failed locating TLS slgorithm.";
    private static final String KEY_STORE_ERROR = "CA certeficate keysotore initiation has failed.";
    private static final String KEY_STORE_FILE_NOT_FOUND_ERROR = "CA certeficate keysotore was not found.";
    private static final String CERTEFICATE_ERROR = "CA certeficate error.";
    private static final String IO_ERROR = "I/O error occured, is your keysotore password correct?";
    private static final String UNRECOVERABLE_KEY_ERROR = "Unrecoverable key error has occured.";

    private static int MAX_CONNECTIONS = 20;
    private static int MAX_CONNECTIONS_PER_HOST = 50;
    private static int MAX_CONNECTIONS_PER_ROUTE = 5;

    private static long WAIT_IDLE_CHECK_TTL = 5000;
    private static long WAIT_IDLE_CLOSE_TTL = 30;

    private static String HTTP_PROTOCOL = "http";
    private static String HTTPS_PROTOCOL = "https";

    private String url;
    private String username;
    private String password;
    private String key_file;
    private String cert_file;
    private String ca_file;
    private int port = -1;
    private Integer requestTimeout;
    private Integer sessionTimeout;
    private boolean noHostVerification = false;
    private String keyStorePath;
    private String keyStorePassword;

    private URL urlobj = null;

    /**
     * @param url
     *            oVirt API url
     * @param username
     *            oVirt API user name
     * @param password
     *            oVirt API password
     * 
     * @throws MalformedURLException
     */
    public ConnectionsPoolBuilder(String url, String username, String password) throws MalformedURLException {
        url(url);
        username(username);
        password(password);
    }

    /**
     * @param url
     *            oVirt API url
     * 
     * @throws MalformedURLException
     */
    public ConnectionsPoolBuilder(String url) throws MalformedURLException {
        url(url);
    }

    /**
     * 
     * @param url
     *            oVirt API url
     * 
     * @throws MalformedURLException
     */
    private ConnectionsPoolBuilder url(String url) throws MalformedURLException {
        this.url = url;
        this.urlobj = createURL(url);
        return this;
    }

    /**
     * @param username
     *            oVirt API user name
     */
    private ConnectionsPoolBuilder username(String username) {
        this.username = username;
        return this;
    }

    /**
     * @param password
     *            oVirt API password
     */
    private ConnectionsPoolBuilder password(String password) {
        this.password = password;
        return this;
    }

    /**
     * @param key_file
     *            client key
     */
    public ConnectionsPoolBuilder key_file(String key_file) {
        this.key_file = key_file;
        return this;
    }

    /**
     * @param cert_file
     *            client cert file
     */
    public ConnectionsPoolBuilder cert_file(String cert_file) {
        this.cert_file = cert_file;
        return this;
    }

    /**
     * @param ca_file
     *            server CA cert.
     */
    public ConnectionsPoolBuilder ca_file(String ca_file) {
        this.ca_file = ca_file;
        return this;
    }

    /**
     * @param keyStorePath
     *            path to server CA KeyStore
     */
    public ConnectionsPoolBuilder keyStorePath(String keyStorePath) {
        this.keyStorePath = keyStorePath;
        return this;
    }

    /**
     * @param keyStorePassword
     *            server CA KeyStore password
     */
    public ConnectionsPoolBuilder keyStorePassword(String keyStorePassword) {
        this.keyStorePassword = keyStorePassword;
        return this;
    }

    /**
     * @param port
     *            oVirt API port
     * 
     */
    public ConnectionsPoolBuilder port(Integer port) {
        if (port != null) {
            this.port = port.intValue();
        }
        return this;
    }

    /**
     * @param requestTimeout
     *            request timeout
     */
    public ConnectionsPoolBuilder requestTimeout(Integer requestTimeout) {
        if (requestTimeout != null) {
            this.requestTimeout = requestTimeout;
        }
        return this;
    }

    /**
     * @param sessionTimeout
     *            authentication session inactivity timeout
     */
    public ConnectionsPoolBuilder sessionTimeout(Integer sessionTimeout) {
        if (sessionTimeout != null) {
            this.sessionTimeout = sessionTimeout;
        }
        return this;
    }

    /**
     * @param noHostVerification
     *            flag
     */
    public ConnectionsPoolBuilder noHostVerification(Boolean noHostVerification) {
        if (noHostVerification != null) {
            this.noHostVerification = noHostVerification.booleanValue();
        }
        return this;
    }

    /**
     * Creates DefaultHttpClient
     *
     * @param url
     * @param username
     * @param password
     * @param key_file
     * @param cert_file
     * @param ca_file
     * @param port
     * @param requestTimeout
     *
     * @return {@link DefaultHttpClient}
     */
    private DefaultHttpClient createDefaultHttpClient(String url, String username, String password, String key_file,
            String cert_file, String ca_file, Integer port, Integer requestTimeout) {

        int port_ = getPort(url, port);

        DefaultHttpClient client = new DefaultHttpClient(createPoolingClientConnectionManager(url, port_));

        if (requestTimeout != null && requestTimeout.intValue() != -1) {
            HttpParams httpParams = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParams, requestTimeout.intValue());
            DefaultHttpClient.setDefaultHttpParams(httpParams);
        }

        if (!StringUtils.isNulOrEmpty(username))
            client.getCredentialsProvider().setCredentials(new AuthScope(getHost(url), port_),
                    new UsernamePasswordCredentials(username, password));

        // FIXME: use all .ctr params

        return client;
    }

    /**
     * Creates PoolingClientConnectionManager
     *
     * @param url
     * @param port
     *
     * @return {@link ClientConnectionManager}
     */
    private ClientConnectionManager createPoolingClientConnectionManager(String url, int port) {
        SchemeRegistry schemeRegistry = createSchemeRegistry(url, port);

        PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
        cm.setMaxTotal(MAX_CONNECTIONS);
        cm.setDefaultMaxPerRoute(MAX_CONNECTIONS_PER_ROUTE);
        cm.setMaxPerRoute(new HttpRoute(new HttpHost(getHost(url), getPort(url, port))), MAX_CONNECTIONS_PER_HOST);

        return cm;
    }

    /**
     * Creates SchemeRegistry
     *
     * @param url
     * @param port
     *
     * @return {@link SchemeRegistry}
     */
    private SchemeRegistry createSchemeRegistry(String url, int port) {
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        String protocol = getProtocol(url);
        SSLSocketFactory sf;

        if (HTTP_PROTOCOL.equals(protocol)) {
            schemeRegistry.register(new Scheme(HTTP_PROTOCOL, port, PlainSocketFactory.getSocketFactory()));
        } else if (HTTPS_PROTOCOL.equals(protocol)) {
            try {
                if (this.noHostVerification) {
                    SSLContext sslcontext = SSLContext.getInstance("TLS");
                    sslcontext.init(null, new TrustManager[] { noCaTrustManager }, null);
                    sf = new SSLSocketFactory(sslcontext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                } else {
                    KeyStore truststore = null;
                    InputStream in = null;

                    if (this.keyStorePath != null) {
                        truststore = KeyStore.getInstance(KeyStore.getDefaultType());
                        try {
                            in = new FileInputStream(this.keyStorePath);
                            truststore.load(in,
                                    this.keyStorePassword != null ? this.keyStorePassword.toCharArray() : null);

                        } finally {
                            if (in != null) {
                                in.close();
                            }
                        }
                    }
                    sf = new SSLSocketFactory(SSLSocketFactory.TLS, null, null, truststore, null, null,
                            SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
                }

                schemeRegistry.register(new Scheme(HTTPS_PROTOCOL, port, sf));

            } catch (NoSuchAlgorithmException e) {
                throw new SocketFactoryException(NO_TLS_ERROR, e);
            } catch (KeyManagementException e) {
                throw new SocketFactoryException(BAD_KEY_ERROR, e);
            } catch (KeyStoreException e) {
                throw new SocketFactoryException(KEY_STORE_ERROR, e);
            } catch (FileNotFoundException e) {
                throw new SocketFactoryException(KEY_STORE_FILE_NOT_FOUND_ERROR, e);
            } catch (CertificateException e) {
                throw new SocketFactoryException(CERTEFICATE_ERROR, e);
            } catch (IOException e) {
                throw new SocketFactoryException(IO_ERROR, e);
            } catch (UnrecoverableKeyException e) {
                throw new SocketFactoryException(UNRECOVERABLE_KEY_ERROR, e);
            }
        } else {
            throw new ProtocolException(BAD_PROTOCOL_ERROR + protocol);
        }

        return schemeRegistry;
    }

    private int getPort(String url, Integer port) {
        return port == null || port == -1 ? this.urlobj.getPort() : port;
    }

    private String getHost(String url) {
        return this.urlobj.getHost();
    }

    private String getProtocol(String url) {
        return this.urlobj.getProtocol();
    }

    /**
     * @return entry point URI
     */
    public String getUrl() {
        return this.url.toString();
    }

    private URL createURL(String url) throws MalformedURLException {
        return new URL(url);
    }

    /**
     * Builds ConnectionPool
     *
     * @return ConnectionsPool
     */
    public ConnectionsPool build() {
        this.keyStorePath = resolveKeyStorePath();
        return new ConnectionsPool(
                createDefaultHttpClient(url, username, password, key_file, cert_file, ca_file, port,
                        requestTimeout),
                this.urlobj, this.sessionTimeout, WAIT_IDLE_CHECK_TTL, WAIT_IDLE_CLOSE_TTL);
    }

    /**
     * Trying to resolve keyStorePath if it's not defined
     * according to the DEFAULT_KEYSTORE_TRUSTSTORE
     *
     * on NX environment it may look like:
     * /home/mpastern/.ovirtsdk/ovirtsdk-keystore.truststore
     *
     * @return keyStorePath or original this.keyStorePath content
     */
    private String resolveKeyStorePath() {
        if (this.keyStorePath == null) {
            String keyStorePathCandidate = System.getProperty("user.home") + File.separator + ".ovirtsdk"
                    + File.separator + DEFAULT_KEYSTORE_TRUSTSTORE;

            try {
                if (new File(keyStorePathCandidate).exists()) {
                    return keyStorePathCandidate;
                }
            } catch (SecurityException ex) {
                ex.printStackTrace();
                // TODO: log error when exposed logger
            }
        }
        return this.keyStorePath;
    }

    /**
     * This TrustManager used to ignore CA cert validation
     * and should not be used unless user explicitly asks to ignore
     * host identity validation.
     */
    X509TrustManager noCaTrustManager = new X509TrustManager() {

        @Override
        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType)
                throws java.security.cert.CertificateException {
            // do nothing
        }

        @Override
        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType)
                throws java.security.cert.CertificateException {
            // do nothing

        }

        @Override
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };
}