001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube 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 * SonarQube 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 License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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.*;
025 import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
026 import org.sonar.wsclient.Host;
027 import org.sonar.wsclient.services.*;
028
029 import java.io.*;
030
031 /**
032 * @since 2.1
033 */
034 public class HttpClient3Connector extends Connector {
035
036 private static final int MAX_TOTAL_CONNECTIONS = 40;
037 private static final int MAX_HOST_CONNECTIONS = 4;
038
039 private final Host server;
040 private HttpClient httpClient;
041
042 public HttpClient3Connector(final Host server) {
043 this.server = server;
044 createClient();
045 }
046
047 public HttpClient3Connector(Host server, HttpClient httpClient) {
048 this.httpClient = httpClient;
049 this.server = server;
050 }
051
052 private void createClient() {
053 final HttpConnectionManagerParams params = new HttpConnectionManagerParams();
054 params.setConnectionTimeout(AbstractQuery.DEFAULT_TIMEOUT_MILLISECONDS);
055 params.setSoTimeout(AbstractQuery.DEFAULT_TIMEOUT_MILLISECONDS);
056 params.setDefaultMaxConnectionsPerHost(MAX_HOST_CONNECTIONS);
057 params.setMaxTotalConnections(MAX_TOTAL_CONNECTIONS);
058 final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
059 connectionManager.setParams(params);
060 this.httpClient = new HttpClient(connectionManager);
061 configureCredentials();
062 }
063
064 private void configureCredentials() {
065 if (server.getUsername() != null) {
066 httpClient.getParams().setAuthenticationPreemptive(true);
067 Credentials defaultcreds = new UsernamePasswordCredentials(server.getUsername(), server.getPassword());
068 httpClient.getState().setCredentials(AuthScope.ANY, defaultcreds);
069 }
070 }
071
072 /**
073 * @since 3.4
074 */
075 public HttpClient getHttpClient() {
076 return httpClient;
077 }
078
079 @Override
080 public String execute(Query<?> query) {
081 return executeRequest(newGetRequest(query));
082 }
083
084 @Override
085 public String execute(CreateQuery<?> query) {
086 return executeRequest(newPostRequest(query));
087 }
088
089 @Override
090 public String execute(UpdateQuery<?> query) {
091 return executeRequest(newPutRequest(query));
092 }
093
094 @Override
095 public String execute(DeleteQuery query) {
096 return executeRequest(newDeleteRequest(query));
097 }
098
099 private String executeRequest(HttpMethodBase method) {
100 String json = null;
101 try {
102 httpClient.executeMethod(method);
103
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 HttpMethodBase method = new GetMethod(server.getHost() + query.getUrl());
127 initRequest(method, query);
128 return method;
129 }
130
131 private HttpMethodBase newDeleteRequest(DeleteQuery query) {
132 HttpMethodBase method = new DeleteMethod(server.getHost() + query.getUrl());
133 initRequest(method, query);
134 return method;
135 }
136
137 private HttpMethodBase newPostRequest(CreateQuery<?> query) {
138 PostMethod method = new PostMethod(server.getHost() + query.getUrl());
139 initRequest(method, query);
140 setRequestEntity(method, query);
141 return method;
142 }
143
144 private HttpMethodBase newPutRequest(UpdateQuery<?> query) {
145 PutMethod method = new PutMethod(server.getHost() + query.getUrl());
146 initRequest(method, query);
147 setRequestEntity(method, query);
148 return method;
149 }
150
151 private void setRequestEntity(EntityEnclosingMethod request, AbstractQuery<?> query) {
152 if (query.getBody() != null) {
153 try {
154 request.setRequestEntity(new StringRequestEntity(query.getBody(), "text/plain; charset=UTF-8", "UTF-8"));
155 } catch (UnsupportedEncodingException e) {
156 throw new ConnectionException("Unsupported encoding", e);
157 }
158 }
159 }
160
161 private void initRequest(HttpMethodBase request, AbstractQuery query) {
162 request.setRequestHeader("Accept", "application/json");
163 if (query.getLocale() != null) {
164 request.setRequestHeader("Accept-Language", query.getLocale());
165 }
166 request.getParams().setSoTimeout(query.getTimeoutMilliseconds());
167 }
168
169 private String getResponseBodyAsString(HttpMethod method) {
170 BufferedReader reader = null;
171 try {
172 final InputStream inputStream = method.getResponseBodyAsStream();
173 reader = new BufferedReader(new InputStreamReader(inputStream));
174 final StringBuilder sb = new StringBuilder();
175 String line;
176
177 while ((line = reader.readLine()) != null) {
178 sb.append(line).append("\n");
179 }
180 return sb.toString();
181
182 } catch (IOException e) {
183 throw new ConnectionException("Can not read response", e);
184
185 } finally {
186 if (reader != null) {
187 try {
188 reader.close();
189 } catch (Exception e) {
190 // wsclient does not have logging ability -> silently ignore
191 }
192 }
193 }
194 }
195 }