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 }