001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.wsclient.connectors;
021    
022    import org.apache.commons.httpclient.*;
023    import org.apache.commons.httpclient.auth.AuthScope;
024    import org.apache.commons.httpclient.methods.DeleteMethod;
025    import org.apache.commons.httpclient.methods.GetMethod;
026    import org.apache.commons.httpclient.methods.PostMethod;
027    import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
028    import org.apache.commons.httpclient.util.URIUtil;
029    import org.sonar.wsclient.Host;
030    import org.sonar.wsclient.services.CreateQuery;
031    import org.sonar.wsclient.services.DeleteQuery;
032    import org.sonar.wsclient.services.Query;
033    
034    import java.io.BufferedReader;
035    import java.io.IOException;
036    import java.io.InputStream;
037    import java.io.InputStreamReader;
038    
039    /**
040     * @since 2.1
041     */
042    public class HttpClient3Connector extends Connector {
043    
044      private static final int MAX_TOTAL_CONNECTIONS = 40;
045      private static final int MAX_HOST_CONNECTIONS = 4;
046    
047      private final Host server;
048      private HttpClient httpClient;
049    
050      public HttpClient3Connector(final Host server) {
051        this.server = server;
052        createClient();
053      }
054    
055      public HttpClient3Connector(Host server, HttpClient httpClient) {
056        this.httpClient = httpClient;
057        this.server = server;
058      }
059    
060      private void createClient() {
061        final HttpConnectionManagerParams params = new HttpConnectionManagerParams();
062        params.setConnectionTimeout(TIMEOUT_MS);
063        params.setSoTimeout(TIMEOUT_MS);
064        params.setDefaultMaxConnectionsPerHost(MAX_HOST_CONNECTIONS);
065        params.setMaxTotalConnections(MAX_TOTAL_CONNECTIONS);
066        final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
067        connectionManager.setParams(params);
068        this.httpClient = new HttpClient(connectionManager);
069        configureCredentials();
070      }
071    
072      private void configureCredentials() {
073        if (server.getUsername() != null) {
074          httpClient.getParams().setAuthenticationPreemptive(true);
075          Credentials defaultcreds = new UsernamePasswordCredentials(server.getUsername(), server.getPassword());
076          httpClient.getState().setCredentials(AuthScope.ANY, defaultcreds);
077        }
078      }
079    
080      public String execute(Query query) {
081        return executeRequest(newGetRequest(query));
082      }
083    
084      public String execute(CreateQuery query) {
085        return executeRequest(newPostRequest(query));
086      }
087    
088      public String execute(DeleteQuery query) {
089        return executeRequest(newDeleteRequest(query));
090      }
091    
092      private String executeRequest(HttpMethodBase method) {
093        String json = null;
094        try {
095          httpClient.executeMethod(method);
096          if (method.getStatusCode() == HttpStatus.SC_OK) {
097            json = getResponseBodyAsString(method);
098    
099          } else if (method.getStatusCode() != HttpStatus.SC_NOT_FOUND) {
100            throw new ConnectionException("HTTP error: " + method.getStatusCode() + ", msg: " + method.getStatusText() + ", query: " + method);
101          }
102    
103        } catch (HttpException e) {
104          throw new ConnectionException("Query: " + method, e);
105    
106        } catch (IOException e) {
107          throw new ConnectionException("Query: " + method, e);
108    
109        } finally {
110          if (method != null) {
111            method.releaseConnection();
112          }
113        }
114        return json;
115      }
116    
117      private HttpMethodBase newGetRequest(Query query) {
118        try {
119          String url = server.getHost() + URIUtil.encodeQuery(query.getUrl());
120          HttpMethodBase method = new GetMethod(url);
121          method.setRequestHeader("Accept", "application/json");
122          return method;
123    
124        } catch (URIException e) {
125          throw new ConnectionException("Query: " + query, e);
126        }
127      }
128    
129      private HttpMethodBase newPostRequest(CreateQuery query) {
130        try {
131          String url = server.getHost() + URIUtil.encodeQuery(query.getUrl());
132          HttpMethodBase method = new PostMethod(url);
133          method.setRequestHeader("Accept", "application/json");
134          return method;
135    
136        } catch (URIException e) {
137          throw new ConnectionException("Query: " + query, e);
138        }
139      }
140    
141      private HttpMethodBase newDeleteRequest(DeleteQuery query) {
142        try {
143          String url = server.getHost() + URIUtil.encodeQuery(query.getUrl());
144          HttpMethodBase method = new DeleteMethod(url);
145          method.setRequestHeader("Accept", "application/json");
146          return method;
147    
148        } catch (URIException e) {
149          throw new ConnectionException("Query: " + query, e);
150        }
151      }
152    
153      private String getResponseBodyAsString(HttpMethod method) {
154        BufferedReader reader = null;
155        try {
156          final InputStream inputStream = method.getResponseBodyAsStream();
157          reader = new BufferedReader(new InputStreamReader(inputStream));
158          final StringBuilder sb = new StringBuilder();
159          String line;
160    
161          while ((line = reader.readLine()) != null) {
162            sb.append(line).append("\n");
163          }
164          return sb.toString();
165    
166        } catch (IOException e) {
167          throw new ConnectionException("Can not read response", e);
168    
169        } finally {
170          if (reader != null) {
171            try {
172              reader.close();
173    
174            } catch (Exception e) {
175              // TODO
176            }
177          }
178        }
179      }
180    }