001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 SonarSource
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.methods.PutMethod;
028    import org.apache.commons.httpclient.methods.StringRequestEntity;
029    import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
030    import org.apache.commons.httpclient.util.URIUtil;
031    import org.sonar.wsclient.Host;
032    import org.sonar.wsclient.services.CreateQuery;
033    import org.sonar.wsclient.services.DeleteQuery;
034    import org.sonar.wsclient.services.Query;
035    import org.sonar.wsclient.services.UpdateQuery;
036    
037    import java.io.BufferedReader;
038    import java.io.IOException;
039    import java.io.InputStream;
040    import java.io.InputStreamReader;
041    import java.io.UnsupportedEncodingException;
042    
043    /**
044     * @since 2.1
045     */
046    public class HttpClient3Connector extends Connector {
047    
048      private static final int MAX_TOTAL_CONNECTIONS = 40;
049      private static final int MAX_HOST_CONNECTIONS = 4;
050    
051      private final Host server;
052      private HttpClient httpClient;
053    
054      public HttpClient3Connector(final Host server) {
055        this.server = server;
056        createClient();
057      }
058    
059      public HttpClient3Connector(Host server, HttpClient httpClient) {
060        this.httpClient = httpClient;
061        this.server = server;
062      }
063    
064      private void createClient() {
065        final HttpConnectionManagerParams params = new HttpConnectionManagerParams();
066        params.setConnectionTimeout(TIMEOUT_MS);
067        params.setSoTimeout(TIMEOUT_MS);
068        params.setDefaultMaxConnectionsPerHost(MAX_HOST_CONNECTIONS);
069        params.setMaxTotalConnections(MAX_TOTAL_CONNECTIONS);
070        final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
071        connectionManager.setParams(params);
072        this.httpClient = new HttpClient(connectionManager);
073        configureCredentials();
074      }
075    
076      private void configureCredentials() {
077        if (server.getUsername() != null) {
078          httpClient.getParams().setAuthenticationPreemptive(true);
079          Credentials defaultcreds = new UsernamePasswordCredentials(server.getUsername(), server.getPassword());
080          httpClient.getState().setCredentials(AuthScope.ANY, defaultcreds);
081        }
082      }
083    
084      public String execute(Query<?> query) {
085        return executeRequest(newGetRequest(query));
086      }
087    
088      public String execute(CreateQuery<?> query) {
089        return executeRequest(newPostRequest(query));
090      }
091    
092      public String execute(UpdateQuery<?> query) {
093        return executeRequest(newPutRequest(query));
094      }
095    
096      public String execute(DeleteQuery<?> query) {
097        return executeRequest(newDeleteRequest(query));
098      }
099    
100      private String executeRequest(HttpMethodBase method) {
101        String json = null;
102        try {
103          httpClient.executeMethod(method);
104          if (method.getStatusCode() == HttpStatus.SC_OK) {
105            json = getResponseBodyAsString(method);
106    
107          } else if (method.getStatusCode() != HttpStatus.SC_NOT_FOUND) {
108            throw new ConnectionException("HTTP error: " + method.getStatusCode() + ", msg: " + method.getStatusText() + ", query: " + method);
109          }
110    
111        } catch (HttpException e) {
112          throw new ConnectionException("Query: " + method, e);
113    
114        } catch (IOException e) {
115          throw new ConnectionException("Query: " + method, e);
116    
117        } finally {
118          if (method != null) {
119            method.releaseConnection();
120          }
121        }
122        return json;
123      }
124    
125      private HttpMethodBase newGetRequest(Query<?> query) {
126        try {
127          String url = server.getHost() + URIUtil.encodeQuery(query.getUrl());
128          HttpMethodBase method = new GetMethod(url);
129          method.setRequestHeader("Accept", "application/json");
130          return method;
131    
132        } catch (URIException e) {
133          throw new ConnectionException("Query: " + query, e);
134        }
135      }
136    
137      private HttpMethodBase newPostRequest(CreateQuery<?> query) {
138        try {
139          String url = server.getHost() + URIUtil.encodeQuery(query.getUrl());
140          PostMethod method = new PostMethod(url);
141          method.setRequestHeader("Accept", "application/json");
142          if (query.getBody() != null) {
143            method.setRequestEntity(new StringRequestEntity(query.getBody(), "text/plain; charset=UTF-8", "UTF-8"));
144          }
145          return method;
146    
147        } catch (URIException e) {
148          throw new ConnectionException("Query: " + query, e);
149        } catch (UnsupportedEncodingException e) {
150          throw new ConnectionException("Unsupported encoding", e);
151        }
152      }
153    
154      private HttpMethodBase newPutRequest(UpdateQuery<?> query) {
155        try {
156          String url = server.getHost() + URIUtil.encodeQuery(query.getUrl());
157          PutMethod method = new PutMethod(url);
158          method.setRequestHeader("Accept", "application/json");
159          if (query.getBody() != null) {
160            method.setRequestEntity(new StringRequestEntity(query.getBody(), "text/plain; charset=UTF-8", "UTF-8"));
161          }
162          return method;
163    
164        } catch (URIException e) {
165          throw new ConnectionException("Query: " + query, e);
166        } catch (UnsupportedEncodingException e) {
167          throw new ConnectionException("Unsupported encoding", e);
168        }
169      }
170    
171      private HttpMethodBase newDeleteRequest(DeleteQuery<?> query) {
172        try {
173          String url = server.getHost() + URIUtil.encodeQuery(query.getUrl());
174          HttpMethodBase method = new DeleteMethod(url);
175          method.setRequestHeader("Accept", "application/json");
176          return method;
177    
178        } catch (URIException e) {
179          throw new ConnectionException("Query: " + query, e);
180        }
181      }
182    
183      private String getResponseBodyAsString(HttpMethod method) {
184        BufferedReader reader = null;
185        try {
186          final InputStream inputStream = method.getResponseBodyAsStream();
187          reader = new BufferedReader(new InputStreamReader(inputStream));
188          final StringBuilder sb = new StringBuilder();
189          String line;
190    
191          while ((line = reader.readLine()) != null) {
192            sb.append(line).append("\n");
193          }
194          return sb.toString();
195    
196        } catch (IOException e) {
197          throw new ConnectionException("Can not read response", e);
198    
199        } finally {
200          if (reader != null) {
201            try {
202              reader.close();
203    
204            } catch (Exception e) {
205              // TODO
206            }
207          }
208        }
209      }
210    }