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 */ 020package org.sonar.wsclient.connectors; 021 022import org.apache.commons.httpclient.*; 023import org.apache.commons.httpclient.auth.AuthScope; 024import org.apache.commons.httpclient.methods.*; 025import org.apache.commons.httpclient.params.HttpConnectionManagerParams; 026import org.sonar.wsclient.Host; 027import org.sonar.wsclient.services.*; 028 029import java.io.*; 030 031/** 032 * @since 2.1 033 */ 034public 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}