Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.jfrog.bintray.client.impl.handle.BintrayImpl Maven / Gradle / Ivy
package com.jfrog.bintray.client.impl.handle;
import com.jfrog.bintray.client.api.BintrayCallException;
import com.jfrog.bintray.client.api.MultipleBintrayCallException;
import com.jfrog.bintray.client.api.handle.*;
import com.jfrog.bintray.client.impl.util.URIUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.*;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* @author Dan Feldman
*/
public class BintrayImpl implements Bintray {
private static final Logger log = LoggerFactory.getLogger(BintrayImpl.class);
ExecutorService executorService;
private CloseableHttpClient client;
private ResponseHandler responseHandler = new BintrayResponseHandler();
private String baseUrl;
private int signRequestTimeoutPerFile;
public BintrayImpl(CloseableHttpClient client, String baseUrl, int threadPoolSize, int signRequestTimeoutPerFile) {
this.client = client;
this.baseUrl = baseUrl;
this.executorService = Executors.newFixedThreadPool(threadPoolSize);
this.signRequestTimeoutPerFile = signRequestTimeoutPerFile;
}
static public void addContentTypeJsonHeader(Map headers) {
headers.put(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
}
static public void addContentTypeBinaryHeader(Map headers) {
headers.put(HttpHeaders.CONTENT_TYPE, ContentType.DEFAULT_BINARY.getMimeType());
}
private static boolean statusNotOk(int statusCode) {
return statusCode != HttpStatus.SC_OK
&& statusCode != HttpStatus.SC_CREATED
&& statusCode != HttpStatus.SC_ACCEPTED
&& statusCode != HttpStatus.SC_NO_CONTENT;
}
@Override
public SubjectHandle subject(String subject) {
return new SubjectHandleImpl(this, subject);
}
@Override
public RepositoryHandle repository(String repositoryPath) {
// TODO: implement full path resolution that receives /subject/repo/
throw new UnsupportedOperationException("Not yet supported");
}
@Override
public PackageHandle pkg(String packagePath) {
// TODO: implement full path resolution that receives /subject/repo/pkg
throw new UnsupportedOperationException("Not yet supported");
}
@Override
public VersionHandle version(String versionPath) {
// TODO: implement full path resolution that receives /subject/repo/pkg/version
throw new UnsupportedOperationException("Not yet supported");
}
@Override
public void close() {
executorService.shutdown();
HttpClientUtils.closeQuietly(client);
}
public HttpResponse get(String uri, Map headers) throws BintrayCallException {
HttpGet getRequest = new HttpGet(createUrl(uri));
return setHeadersAndExecute(getRequest, headers);
}
public HttpResponse head(String uri, Map headers) throws BintrayCallException {
HttpHead headRequest = new HttpHead(createUrl(uri));
return setHeadersAndExecute(headRequest, headers);
}
/**
* Executes a sign request using the ExecutorService and uses the file count to set a timeout to avoid timing out
* on long requests
*
* @throws BintrayCallException
*/
public HttpResponse sign(String uri, Map headers, int fileCount) throws BintrayCallException {
HttpPost signRequest = new HttpPost(createUrl(uri));
setHeaders(signRequest, headers);
signRequest.setConfig(RequestConfig.custom().setSocketTimeout(signRequestTimeoutPerFile * fileCount)
.setConnectionRequestTimeout(signRequestTimeoutPerFile * fileCount)
.setConnectTimeout(signRequestTimeoutPerFile * fileCount).build());
RequestRunner runner = new RequestRunner(signRequest, client, responseHandler);
Future signResponse = executorService.submit(runner);
try {
signResponse.get();
} catch (Exception e) {
BintrayCallException bce;
if (e.getCause() instanceof BintrayCallException) {
bce = (BintrayCallException) e.getCause();
} else {
bce = new BintrayCallException(409, e.getMessage(), (e.getCause() == null) ? ""
: ", " + e.getCause().toString() + " : " + e.getCause().getMessage());
}
log.error(bce.toString());
log.debug("{}", e.getMessage(), e);
throw bce;
}
//Return ok
String entity = "Signing the version was successful";
HttpResponse response = DefaultHttpResponseFactory.INSTANCE.newHttpResponse(
new ProtocolVersion("HTTP", 1, 1), HttpStatus.SC_CREATED, new HttpClientContext());
response.setEntity(new StringEntity(entity, Charset.forName("UTF-8")));
return response;
}
public HttpResponse post(String uri, Map headers) throws BintrayCallException {
HttpPost postRequest = new HttpPost(createUrl(uri));
return setHeadersAndExecute(postRequest, headers);
}
public HttpResponse post(String uri, Map headers, InputStream elementInputStream) throws BintrayCallException {
HttpPost postRequest = new HttpPost(createUrl(uri));
HttpEntity requestEntity = new InputStreamEntity(elementInputStream);
postRequest.setEntity(requestEntity);
return setHeadersAndExecute(postRequest, headers);
}
public HttpResponse patch(String uri, Map headers, InputStream elementInputStream) throws BintrayCallException {
HttpPatch patchRequest = new HttpPatch(createUrl(uri));
HttpEntity requestEntity = new InputStreamEntity(elementInputStream);
patchRequest.setEntity(requestEntity);
return setHeadersAndExecute(patchRequest, headers);
}
public HttpResponse delete(String uri, Map headers) throws BintrayCallException {
HttpDelete deleteRequest = new HttpDelete(createUrl(uri));
return setHeadersAndExecute(deleteRequest, headers);
}
public HttpResponse putBinary(String uri, Map headers, InputStream elementInputStream) throws BintrayCallException {
if (headers == null) {
headers = new HashMap<>();
}
addContentTypeBinaryHeader(headers);
return put(uri, headers, elementInputStream);
}
public HttpResponse putBinary(Map uriAndStreamMap, Map headers) throws MultipleBintrayCallException {
if (headers == null) {
headers = new HashMap<>();
}
addContentTypeBinaryHeader(headers);
return put(uriAndStreamMap, headers);
}
public HttpResponse put(String uri, Map headers, InputStream elementInputStream) throws BintrayCallException {
HttpPut putRequest = new HttpPut(createUrl(uri));
HttpEntity requestEntity = new InputStreamEntity(elementInputStream);
putRequest.setEntity(requestEntity);
return setHeadersAndExecute(putRequest, headers);
}
public HttpResponse put(Map uriAndStreamMap, Map headers) throws MultipleBintrayCallException {
List> executions = new ArrayList<>();
List errors = new ArrayList<>();
List runners = createPutRequestRunners(uriAndStreamMap, headers, errors);
try {
executions = executorService.invokeAll(runners);
} catch (InterruptedException e) {
BintrayCallException bce = new BintrayCallException(409, e.getMessage(), (e.getCause() == null) ? ""
: e.getCause().toString() + " : " + e.getCause().getMessage());
log.error(bce.toString());
log.debug("{}", e.getMessage(), e);
errors.add(bce);
}
collectResults(executions, errors);
//Return ok or throw errors
if (errors.isEmpty()) {
String entity = "Operation Successful";
HttpResponse response = DefaultHttpResponseFactory.INSTANCE.newHttpResponse(
new ProtocolVersion("HTTP", 1, 1), HttpStatus.SC_CREATED, new HttpClientContext());
response.setEntity(new StringEntity(entity, Charset.forName("UTF-8")));
return response;
} else {
throw new MultipleBintrayCallException(errors);
}
}
private List createPutRequestRunners(Map uriAndStreamMap, Map headers, List errors) {
List runners = new ArrayList<>();
List requests = new ArrayList<>();
log.debug("Creating PUT requests and RequestRunners for execution");
for (String apiPath : uriAndStreamMap.keySet()) {
HttpPut putRequest;
try {
putRequest = new HttpPut(createUrl(apiPath));
} catch (BintrayCallException bce) {
errors.add(bce);
continue;
}
HttpEntity requestEntity = new InputStreamEntity(uriAndStreamMap.get(apiPath));
putRequest.setEntity(requestEntity);
setHeaders(putRequest, headers);
requests.add(putRequest);
}
for (HttpPut request : requests) {
RequestRunner runner = new RequestRunner(request, client, responseHandler);
runners.add(runner);
}
return runners;
}
private void collectResults(List> executions, List errors) {
//Wait until all executions are done
while (!executions.isEmpty()) {
log.debug("Querying execution Futures for results");
for (Iterator> executionIter = executions.iterator(); executionIter.hasNext(); ) {
Future execution = executionIter.next();
if (execution.isDone()) {
try {
String response = execution.get();
log.debug("Got complete execution: {}", response);
} catch (Exception e) {
BintrayCallException bce;
if (e.getCause() instanceof BintrayCallException) {
bce = (BintrayCallException) e.getCause();
} else {
bce = new BintrayCallException(400, e.getMessage(), (e.getCause() == null) ? ""
: e.getCause().getMessage());
}
log.error(bce.toString());
log.debug("{}", e.getMessage(), e);
errors.add(bce);
} finally {
executionIter.remove(); //Remove completed execution from iteration
}
}
}
}
}
private String createUrl(String queryPath) throws BintrayCallException {
log.debug("Trying to encode uri: '{}' with base url: {}", queryPath, baseUrl);
try {
return URIUtil.encodeQuery(baseUrl + "/" + queryPath);
} catch (HttpException e) {
throw new BintrayCallException(HttpStatus.SC_BAD_REQUEST, "Malformed url, request will not be sent: ",
e.getMessage());
}
}
private void setHeaders(HttpUriRequest request, Map headers) {
if (headers != null && !headers.isEmpty()) {
for (String header : headers.keySet()) {
request.setHeader(header, headers.get(header));
}
}
}
private HttpResponse setHeadersAndExecute(HttpUriRequest request, Map headers) throws BintrayCallException {
setHeaders(request, headers);
return execute(request, null);
}
private HttpResponse execute(HttpUriRequest request, HttpClientContext context) throws BintrayCallException {
log.debug("Executing {} request to path '{}', with headers: {}", request.getMethod(), request.getURI(),
Arrays.toString(request.getAllHeaders()));
try {
if (context != null) {
return client.execute(request, responseHandler, context);
} else {
return client.execute(request, responseHandler);
}
} catch (BintrayCallException bce) {
log.debug("{}", bce.toString(), bce);
throw bce;
} catch (IOException ioe) {
//Underlying IOException form the client
String underlyingCause = (ioe.getCause() == null) ? "" : ioe.toString() + " : " + ioe.getCause().getMessage();
log.debug("{}", ioe.getMessage(), ioe);
throw new BintrayCallException(400, ioe.getClass() + " : " + ioe.getMessage(), underlyingCause);
}
}
/**
* A callable that executes a single put request, returns a String containing an error or '200' if successful
*/
private static class RequestRunner implements Callable {
private final HttpRequestBase request;
private final CloseableHttpClient client;
private final HttpClientContext context;
private final ResponseHandler responseHandler;
public RequestRunner(HttpRequestBase request, CloseableHttpClient client, ResponseHandler responseHandler) {
this.request = request;
this.client = client;
this.context = HttpClientContext.create();
this.responseHandler = responseHandler;
}
@Override
public String call() throws BintrayCallException {
log.debug("Executing {} request to path '{}', with headers: {}", request.getMethod(), request.getURI(),
Arrays.toString(request.getAllHeaders()));
StringBuilder errorResultBuilder;
String requestPath;
if (request instanceof HttpPut) {
requestPath = request.getURI().getPath().substring(9); //Substring cuts the '/content/' part from the URI
log.info("Pushing " + requestPath);
errorResultBuilder = new StringBuilder(" Pushing " + requestPath + " failed: ");
} else {
requestPath = request.getURI().getPath();
errorResultBuilder = new StringBuilder(request.getMethod() + " " + requestPath + " failed: ");
}
HttpResponse response;
try {
response = client.execute(request, responseHandler, context);
} catch (BintrayCallException bce) {
log.debug("{}", bce.getMessage(), bce);
errorResultBuilder.append(bce.getMessage());
bce.setMessage(errorResultBuilder.toString());
throw bce;
} catch (IOException ioe) {
log.debug("IOException occurred: '{}'", ioe.getMessage(), ioe);
String cause = (ioe.getCause() != null) ? (", caused by: " + ioe.getCause().toString() + " : "
+ ioe.getCause().getMessage()) : "";
errorResultBuilder.append(ioe.toString()).append(" : ").append(ioe.getMessage()).append(cause);
throw new BintrayCallException(HttpStatus.SC_BAD_REQUEST, ioe.getMessage(), errorResultBuilder.toString());
} finally {
request.releaseConnection();
}
if (statusNotOk(response.getStatusLine().getStatusCode())) {
BintrayCallException bce = new BintrayCallException(response);
errorResultBuilder.append(bce.getMessage());
bce.setMessage(errorResultBuilder.toString());
throw bce;
}
return request.getMethod() + " " + requestPath + ": " + String.valueOf(response.getStatusLine().getStatusCode());
}
}
/**
* gets responses from the underlying HttpClient and closes them (so you don't have to) the response body is
* buffered in an intermediary byte array.
* Will throw a {@link BintrayCallException} if the request failed.
*/
private class BintrayResponseHandler implements ResponseHandler {
@Override
public HttpResponse handleResponse(HttpResponse response) throws BintrayCallException {
int statusCode = response.getStatusLine().getStatusCode();
if (statusNotOk(statusCode)) {
BintrayCallException bce = new BintrayCallException(response);
//We're using CloseableHttpClient so it's ok
HttpClientUtils.closeQuietly((CloseableHttpResponse) response);
throw bce;
}
//Response entity might be null, 500 and 405 also give the html itself so skip it
byte[] entity = new byte[0];
if (response.getEntity() != null && statusCode != 500 && statusCode != 405) {
try {
entity = IOUtils.toByteArray(response.getEntity().getContent());
} catch (IOException | NullPointerException e) {
//Null entity - Ignore
} finally {
HttpClientUtils.closeQuietly((CloseableHttpResponse) response);
}
}
HttpResponse newResponse = DefaultHttpResponseFactory.INSTANCE.newHttpResponse(response.getStatusLine(),
new HttpClientContext());
newResponse.setEntity(new ByteArrayEntity(entity));
newResponse.setHeaders(response.getAllHeaders());
return newResponse;
}
}
}