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