com.clarolab.bamboo.client.HttpClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bamboo-rest-api-client Show documentation
Show all versions of bamboo-rest-api-client Show documentation
This library allows to extract information from projects, plans and builds on Bamboo
/*
* Copyright (c) 2019, Clarolab. All rights reserved.
*/
package com.clarolab.bamboo.client;
import com.clarolab.bamboo.utils.Constants;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.Builder;
import lombok.Data;
import lombok.extern.java.Log;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.TruncatedChunkException;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.json.XML;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
@Data
@Log
public class HttpClient {
//TODO: Make improvements using https://www.baeldung.com/httpclient-connection-management
private String baseUrl;
private String userName;
private String userPassword;
private CloseableHttpClient client;
private HttpGet get;
private CloseableHttpResponse response;
@Builder
public HttpClient(String baseUrl, String userName, String userPassword) {
this.baseUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl+"/";
this.userName = userName;
this.userPassword = userPassword;
client = HttpClients.custom()
.setRetryHandler(this.retryHandler())
.setSSLContext(baseUrl.startsWith("https") ? this.getSslContext() : null)
.setSSLHostnameVerifier(baseUrl.startsWith("https") ? new NoopHostnameVerifier() : null)
.build();
}
private SSLContext getSslContext(){
SSLContext sslContext = null;
try {
sslContext = new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true).build();
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
log.log(Level.SEVERE, "Error getting: " + baseUrl, e);
}
return sslContext;
}
private HttpRequestRetryHandler retryHandler(){
return (exception, executionCount, context) -> {
log.info("Try request: " + executionCount);
if (executionCount >= Constants.DEFAULT_HTTP_MAX_RETRY) {
// Do not retry if over max retry count
return false;
}
if (exception instanceof InterruptedIOException ||
exception instanceof UnknownHostException ||
exception instanceof SSLException ||
exception instanceof ConnectException ||
// exception instanceof ConnectorServiceException ||
// exception instanceof ContainerServiceException ||
// exception instanceof ExecutorServiceException ||
// exception instanceof BuildServiceException ||
// exception instanceof ReportServiceException ||
exception instanceof TruncatedChunkException) {
// Timeout || Unknown host || SSL handshake || Services
return false;
}
if (!(HttpClientContext.adapt(context).getRequest() instanceof HttpEntityEnclosingRequest)) {
// Retry if the request is considered idempotent
return true;
}
return false;
};
}
public String get(String baseUrl, String getRequest) throws Exception {
this.prepareRequest(baseUrl, getRequest);
return this.executeRequest();
}
public T get(String request, Class classOfT) throws Exception {
return this.get(null, request, classOfT);
}
public T get(GsonBuilder builder, String request, Class classOfT) throws Exception {
if (builder == null)
return new Gson().fromJson(this.get(request), classOfT);
else
return builder.create().fromJson(this.get(request), classOfT);
}
public String get(String getRequest) throws IOException, AuthenticationException, URISyntaxException {
this.prepareRequest(this.baseUrl, getRequest);
return this.executeRequest();
}
private String executeRequest() throws IOException {
HttpEntity entity = null;
String entityStr;
try {
log.info("Curl to execute: "+generateCurlSentence(this.get));
this.performRequest();
this.validateResponse();
entity = this.getEntity(this.response);
entityStr = EntityUtils.toString(entity);
//entityStr = this.convertEntityToString(entity);
} finally {
EntityUtils.consume(entity);
this.clean();
//client.close();
}
return entityStr;
}
public void prepareRequest(String getRequest) throws Exception {
this.prepareRequest(this.baseUrl, getRequest);
}
public void prepareRequest(String baseUrl, String getRequest) throws AuthenticationException, URISyntaxException {
String requestURL = this.normalizeRequest(baseUrl, getRequest);
HttpGet httpGetRequest = new HttpGet(new URI(requestURL));
httpGetRequest.addHeader(new BasicScheme(StandardCharsets.UTF_8).authenticate(new UsernamePasswordCredentials(userName, userPassword), httpGetRequest, null));
httpGetRequest.addHeader("Accept", "application/json");
this.get = httpGetRequest;
}
public void performRequest() throws IOException {
this.response = client.execute(get);
}
public void validateResponse() throws HttpResponseException {
int status = this.response.getStatusLine().getStatusCode();
if (status < 200 || status >= 400) {
throw new HttpResponseException(status, this.response.getStatusLine().getReasonPhrase());
}
}
public HttpEntity getEntity(CloseableHttpResponse response){
HttpEntity entity = this.response.getEntity();
return entity;
}
public void clean() throws IOException {
if(this.response != null)
this.response.close();
if(this.get != null)
this.get.releaseConnection();
}
public String getJson(String baseUrl, String request) throws Exception {
String json = null;
for(int i = 0; i<5; i++) {
json = XML.toJSONObject(this.get(baseUrl, request)).toString(4);
if(!Strings.isNullOrEmpty(json))
break;
}
return json;
}
/**
* Return an equivalent curl sentence of the Http request
*/
private String generateCurlSentence(HttpUriRequest request) {
StringBuilder curlSentence = generateString(request);
String url = request.getURI().toString();
String method = request.getMethod();
curlSentence.append(" -X ").append(method).append(" ");
curlSentence.append("\"").append(url).append("\"").append(" --insecure");
return curlSentence.toString();
}
private StringBuilder generateString(HttpUriRequest request) {
StringBuilder curlSentence = new StringBuilder();
curlSentence.append("curl");
Header authHeader = request.getFirstHeader("Authorization");
if (authHeader != null) {
try {
String credentials = new String(Base64.decodeBase64(authHeader.getValue().replace("Basic ", "")),"UTF-8");
curlSentence.append(" -u ");
curlSentence.append(credentials);
}
catch (UnsupportedEncodingException e) {
}
}
Header[] allHeaders = request.getAllHeaders();
curlSentence.append(" --header '");
for (Header h : allHeaders) {
if (!h.getName().contains("Authorization")) {
curlSentence.append(h.toString()).append(";");
}
}
curlSentence.append("'");
return curlSentence;
}
public void close(){
try {
this.client.close();
} catch (IOException e) {
log.log(Level.WARNING, "I/O exception closing client", e);
}
}
private String normalizeRequest(String baseUrl, String getRequest){
String retUrl;
if(!baseUrl.endsWith("/") && !getRequest.startsWith("/"))
retUrl = baseUrl + "/" + getRequest;
else if(baseUrl.endsWith("/") && getRequest.startsWith("/"))
retUrl = baseUrl + getRequest.substring(1);
else
retUrl = baseUrl + getRequest;
return retUrl.replace(" ", "%20");
}
// private String convertEntityToString(HttpEntity entity) throws IOException {
// String out = null;
// if (entity != null) {
// InputStream inStream = entity.getContent();
// byte[] bytes = IOUtils.toByteArray(inStream);
// out = new String(bytes, "UTF-8");
// inStream.close();
// }
// return out;
// }
}