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 }