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