001    package org.sonar.ide.wsclient;
002    
003    import java.net.Authenticator;
004    import java.net.InetAddress;
005    import java.net.InetSocketAddress;
006    import java.net.PasswordAuthentication;
007    import java.net.Proxy;
008    import java.net.ProxySelector;
009    import java.net.URI;
010    import java.util.List;
011    
012    import org.apache.commons.httpclient.Credentials;
013    import org.apache.commons.httpclient.HttpClient;
014    import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
015    import org.apache.commons.httpclient.UsernamePasswordCredentials;
016    import org.apache.commons.httpclient.auth.AuthScope;
017    import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
018    import org.sonar.wsclient.Host;
019    import org.sonar.wsclient.connectors.HttpClient3Connector;
020    
021    /**
022     * @author Evgeny Mandrikov
023     */
024    public final class HttpClient3ConnectorFactory {
025      protected static final int TIMEOUT_MS = 30000;
026      private static final int MAX_TOTAL_CONNECTIONS = 40;
027      private static final int MAX_HOST_CONNECTIONS = 4;
028    
029      /**
030       * Hide utility-class constructor.
031       */
032      private HttpClient3ConnectorFactory() {
033      }
034    
035      /**
036       * Workaround for <a href="http://jira.codehaus.org/browse/SONAR-1715">SONAR-1715</a> and
037       * for <a href="http://jira.codehaus.org/browse/SONAR-1586">SONAR-1586</a>.
038       * <p>
039       * TODO Godin: I suppose that call of method {@link HttpClient3Connector#configureCredentials()} should be added to constructor
040       * {@link HttpClient3Connector#HttpClient3Connector(Host, HttpClient)}
041       * </p>
042       * 
043       * @param server Sonar server
044       * @return configured {@link HttpClient3Connector}
045       * @see org.sonar.wsclient.connectors.HttpClient3Connector#createClient()
046       * @see org.sonar.wsclient.connectors.HttpClient3Connector#configureCredentials()
047       */
048      public static HttpClient3Connector createConnector(Host server) {
049        // createClient
050        final HttpConnectionManagerParams params = new HttpConnectionManagerParams();
051        params.setConnectionTimeout(TIMEOUT_MS);
052        params.setSoTimeout(TIMEOUT_MS);
053        params.setDefaultMaxConnectionsPerHost(MAX_HOST_CONNECTIONS);
054        params.setMaxTotalConnections(MAX_TOTAL_CONNECTIONS);
055        final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
056        connectionManager.setParams(params);
057        HttpClient httpClient = new HttpClient(connectionManager);
058    
059        // configureCredentials
060        if (server.getUsername() != null) {
061          httpClient.getParams().setAuthenticationPreemptive(true);
062          Credentials defaultcreds = new UsernamePasswordCredentials(server.getUsername(), server.getPassword());
063          httpClient.getState().setCredentials(AuthScope.ANY, defaultcreds);
064        }
065    
066        // TODO Godin: ugly hack to use ProxySelector with commons-httpclient 3.1
067        try {
068          List<Proxy> list = ProxySelector.getDefault().select(new URI(server.getHost()));
069          for (Proxy proxy : list) {
070            if (proxy.type() == Proxy.Type.HTTP) {
071              // Proxy
072              InetSocketAddress addr = (InetSocketAddress) proxy.address();
073              httpClient.getHostConfiguration().setProxy(addr.getHostName(), addr.getPort());
074              // Proxy auth
075              InetAddress proxyInetAddress = InetAddress.getByName(addr.getHostName());
076              PasswordAuthentication auth = Authenticator.requestPasswordAuthentication(proxyInetAddress, addr.getPort(), null, null, null);
077              if (auth != null) {
078                Credentials defaultcreds = new UsernamePasswordCredentials(auth.getUserName(), new String(auth.getPassword()));
079                httpClient.getState().setProxyCredentials(AuthScope.ANY, defaultcreds);
080              }
081            }
082          }
083        } catch (Exception e) {
084          e.printStackTrace();
085        }
086    
087        return new HttpClient3Connector(server, httpClient);
088      }
089    }