001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 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.*;
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 public String execute(Query<?> query) {
073 return executeRequest(newGetRequest(query));
074 }
075
076 public String execute(CreateQuery<?> query) {
077 return executeRequest(newPostRequest(query));
078 }
079
080 public String execute(UpdateQuery<?> query) {
081 return executeRequest(newPutRequest(query));
082 }
083
084 public String execute(DeleteQuery query) {
085 return executeRequest(newDeleteRequest(query));
086 }
087
088 private String executeRequest(HttpMethodBase method) {
089 String json = null;
090 try {
091 httpClient.executeMethod(method);
092
093 if (method.getStatusCode() == HttpStatus.SC_OK) {
094 json = getResponseBodyAsString(method);
095
096 } else if (method.getStatusCode() != HttpStatus.SC_NOT_FOUND) {
097 throw new ConnectionException("HTTP error: " + method.getStatusCode() + ", msg: " + method.getStatusText() + ", query: " + method);
098 }
099
100 } catch (HttpException e) {
101 throw new ConnectionException("Query: " + method, e);
102
103 } catch (IOException e) {
104 throw new ConnectionException("Query: " + method, e);
105
106 } finally {
107 if (method != null) {
108 method.releaseConnection();
109 }
110 }
111 return json;
112 }
113
114 private HttpMethodBase newGetRequest(Query<?> query) {
115 HttpMethodBase method = new GetMethod(server.getHost() + query.getUrl());
116 initRequest(method, query);
117 return method;
118 }
119
120 private HttpMethodBase newDeleteRequest(DeleteQuery query) {
121 HttpMethodBase method = new DeleteMethod(server.getHost() + query.getUrl());
122 initRequest(method, query);
123 return method;
124 }
125
126 private HttpMethodBase newPostRequest(CreateQuery<?> query) {
127 PostMethod method = new PostMethod(server.getHost() + query.getUrl());
128 initRequest(method, query);
129 setRequestEntity(method, query);
130 return method;
131 }
132
133 private HttpMethodBase newPutRequest(UpdateQuery<?> query) {
134 PutMethod method = new PutMethod(server.getHost() + query.getUrl());
135 initRequest(method, query);
136 setRequestEntity(method, query);
137 return method;
138 }
139
140 private void setRequestEntity(EntityEnclosingMethod request, AbstractQuery<?> query) {
141 if (query.getBody() != null) {
142 try {
143 request.setRequestEntity(new StringRequestEntity(query.getBody(), "text/plain; charset=UTF-8", "UTF-8"));
144 } catch (UnsupportedEncodingException e) {
145 throw new ConnectionException("Unsupported encoding", e);
146 }
147 }
148 }
149
150 private void initRequest(HttpMethodBase request, AbstractQuery query) {
151 request.setRequestHeader("Accept", "application/json");
152 if (query.getLocale() != null) {
153 request.setRequestHeader("Accept-Language", query.getLocale());
154 }
155 request.getParams().setSoTimeout(query.getTimeoutMilliseconds());
156 }
157
158 private String getResponseBodyAsString(HttpMethod method) {
159 BufferedReader reader = null;
160 try {
161 final InputStream inputStream = method.getResponseBodyAsStream();
162 reader = new BufferedReader(new InputStreamReader(inputStream));
163 final StringBuilder sb = new StringBuilder();
164 String line;
165
166 while ((line = reader.readLine()) != null) {
167 sb.append(line).append("\n");
168 }
169 return sb.toString();
170
171 } catch (IOException e) {
172 throw new ConnectionException("Can not read response", e);
173
174 } finally {
175 if (reader != null) {
176 try {
177 reader.close();
178 } catch (Exception e) {
179 throw new RuntimeException("Fail to close HTTP stream", e);
180 }
181 }
182 }
183 }
184 }