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 }