Skip to content

Commit 42117f8

Browse files
author
danf
committed
Fully configurable timeouts and thread pool
1 parent 85e93c3 commit 42117f8

File tree

6 files changed

+65
-43
lines changed

6 files changed

+65
-43
lines changed

api/src/main/java/com/jfrog/bintray/client/api/BintrayCallException.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,21 @@ public BintrayCallException(HttpResponse response) {
3232
super(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
3333
String message = " ";
3434
String entity = null;
35-
try {
36-
entity = IOUtils.toString(response.getEntity().getContent());
37-
ObjectMapper mapper = ObjectMapperHelper.objectMapper;
38-
JsonNode node = mapper.readTree(entity);
39-
message = node.get("message").getTextValue();
40-
} catch (IOException | NullPointerException e) {
41-
//Null entity?
42-
if (entity != null) {
43-
message = entity;
35+
int statusCode = response.getStatusLine().getStatusCode();
36+
if (response.getEntity() != null && statusCode != 405 && statusCode != 500) {
37+
try {
38+
entity = IOUtils.toString(response.getEntity().getContent());
39+
ObjectMapper mapper = ObjectMapperHelper.objectMapper;
40+
JsonNode node = mapper.readTree(entity);
41+
message = node.get("message").getTextValue();
42+
} catch (IOException | NullPointerException e) {
43+
//Null entity?
44+
if (entity != null) {
45+
message = entity;
46+
}
4447
}
4548
}
46-
this.statusCode = response.getStatusLine().getStatusCode();
49+
this.statusCode = statusCode;
4750
this.reason = response.getStatusLine().getReasonPhrase();
4851
this.message = message;
4952
}

api/src/main/java/com/jfrog/bintray/client/api/handle/VersionHandle.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ public interface VersionHandle extends Handle<Version> {
4242

4343
VersionHandle discard() throws BintrayCallException;
4444

45-
VersionHandle sign(String passphrase) throws BintrayCallException;
45+
VersionHandle sign(String passphrase, int fileCount) throws BintrayCallException;
4646

47-
VersionHandle sign() throws BintrayCallException;
47+
VersionHandle sign(int fileCount) throws BintrayCallException;
4848

4949
String getVersionUri();
5050
}

impl/src/main/java/com/jfrog/bintray/client/impl/BintrayClient.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,33 +18,38 @@ public class BintrayClient {
1818
public static final String BINTRAY_API_URL = "https://api.bintray.com";
1919
public static final String USER_AGENT = "BintrayJavaClient/0.5"; // TODO: make dynamic
2020
private static final int DEFAULT_THREAD_POOL_SIZE = 5; //Don't mess with this - its here for a reason
21+
private static final int DEFAULT_SIGN_REQUEST_TIMEOUT_PER_FILE = 90000; //1.5 min per file
2122

2223
//Mainly used by Artifactory to avoid all of the configuration, but you can specify your own too
23-
static public Bintray create(CloseableHttpClient preConfiguredClient, String url, int threadPoolSize) {
24-
return new BintrayImpl(preConfiguredClient, url, threadPoolSize);
24+
static public Bintray create(CloseableHttpClient preConfiguredClient, String url, int threadPoolSize,
25+
int signRequestTimeoutPerFile) {
26+
return new BintrayImpl(preConfiguredClient, url, threadPoolSize, signRequestTimeoutPerFile);
2527
}
2628

2729
/**
2830
* Username and API key, no proxy
2931
*/
3032
static public Bintray create(String userName, String apiKey) {
3133
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, apiKey);
32-
return new BintrayImpl(createClient(creds, null, BINTRAY_API_URL), BINTRAY_API_URL, DEFAULT_THREAD_POOL_SIZE);
34+
return new BintrayImpl(createClient(creds, null, BINTRAY_API_URL), BINTRAY_API_URL, DEFAULT_THREAD_POOL_SIZE,
35+
DEFAULT_SIGN_REQUEST_TIMEOUT_PER_FILE);
3336
}
3437

3538
/**
3639
* Username, API key, and custom url
3740
*/
3841
static public Bintray create(String url, String userName, String apiKey) {
3942
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, apiKey);
40-
return new BintrayImpl(createClient(creds, null, BINTRAY_API_URL), BINTRAY_API_URL, DEFAULT_THREAD_POOL_SIZE);
43+
return new BintrayImpl(createClient(creds, null, BINTRAY_API_URL), BINTRAY_API_URL, DEFAULT_THREAD_POOL_SIZE,
44+
DEFAULT_SIGN_REQUEST_TIMEOUT_PER_FILE);
4145
}
4246

4347
/**
4448
* Credentials with proxy
4549
*/
4650
static public Bintray create(UsernamePasswordCredentials creds, HttpClientConfigurator.ProxyConfig proxyConfig) {
47-
return new BintrayImpl(createClient(creds, proxyConfig, BINTRAY_API_URL), BINTRAY_API_URL, DEFAULT_THREAD_POOL_SIZE);
51+
return new BintrayImpl(createClient(creds, proxyConfig, BINTRAY_API_URL), BINTRAY_API_URL,
52+
DEFAULT_THREAD_POOL_SIZE, DEFAULT_SIGN_REQUEST_TIMEOUT_PER_FILE);
4853
}
4954

5055
/**
@@ -53,7 +58,8 @@ static public Bintray create(UsernamePasswordCredentials creds, HttpClientConfig
5358
static public Bintray create(String bintrayUserName, String bintrayApiKey,
5459
HttpClientConfigurator.ProxyConfig proxyConfig, String url) {
5560
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(bintrayUserName, bintrayApiKey);
56-
return new BintrayImpl(createClient(creds, proxyConfig, url), url, DEFAULT_THREAD_POOL_SIZE);
61+
return new BintrayImpl(createClient(creds, proxyConfig, url), url, DEFAULT_THREAD_POOL_SIZE,
62+
DEFAULT_SIGN_REQUEST_TIMEOUT_PER_FILE);
5763
}
5864

5965

impl/src/main/java/com/jfrog/bintray/client/impl/handle/BintrayImpl.java

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.apache.commons.io.IOUtils;
88
import org.apache.http.*;
99
import org.apache.http.client.ResponseHandler;
10+
import org.apache.http.client.config.RequestConfig;
1011
import org.apache.http.client.methods.*;
1112
import org.apache.http.client.protocol.HttpClientContext;
1213
import org.apache.http.client.utils.HttpClientUtils;
@@ -22,7 +23,10 @@
2223
import java.io.InputStream;
2324
import java.nio.charset.Charset;
2425
import java.util.*;
25-
import java.util.concurrent.*;
26+
import java.util.concurrent.Callable;
27+
import java.util.concurrent.ExecutorService;
28+
import java.util.concurrent.Executors;
29+
import java.util.concurrent.Future;
2630

2731

2832
/**
@@ -34,12 +38,14 @@ public class BintrayImpl implements Bintray {
3438
private CloseableHttpClient client;
3539
private ResponseHandler<HttpResponse> responseHandler = new BintrayResponseHandler();
3640
private String baseUrl;
41+
private int signRequestTimeoutPerFile;
3742

3843

39-
public BintrayImpl(CloseableHttpClient client, String baseUrl, int threadPoolSize) {
44+
public BintrayImpl(CloseableHttpClient client, String baseUrl, int threadPoolSize, int signRequestTimeoutPerFile) {
4045
this.client = client;
4146
this.baseUrl = (baseUrl == null || baseUrl.isEmpty()) ? BintrayClient.BINTRAY_API_URL : baseUrl;
4247
this.executorService = Executors.newFixedThreadPool(threadPoolSize);
48+
this.signRequestTimeoutPerFile = signRequestTimeoutPerFile;
4349
}
4450

4551
static public void addContentTypeJsonHeader(Map<String, String> headers) {
@@ -96,27 +102,32 @@ public HttpResponse head(String uri, Map<String, String> headers) throws Bintray
96102
}
97103

98104
/**
99-
* Executes a sign request using the ExecutorService to avoid timing out
105+
* Executes a sign request using the ExecutorService and uses the file count to set a timeout to avoid timing out
106+
* on long requests
100107
*
101108
* @throws BintrayCallException
102109
*/
103-
public HttpResponse sign(String uri, Map<String, String> headers) throws BintrayCallException {
110+
public HttpResponse sign(String uri, Map<String, String> headers, int fileCount) throws BintrayCallException {
104111
HttpPost signRequest = new HttpPost(createUrl(uri));
105112
setHeaders(signRequest, headers);
113+
//Set signRequestTimeoutPerFile * fileCount timeout on request
114+
signRequest.setConfig(RequestConfig.custom().setSocketTimeout(signRequestTimeoutPerFile * fileCount)
115+
.setConnectionRequestTimeout(signRequestTimeoutPerFile * fileCount)
116+
.setConnectTimeout(signRequestTimeoutPerFile * fileCount).build());
106117
RequestRunner runner = new RequestRunner(signRequest, client, responseHandler);
107118
Future<String> signResponse = executorService.submit(runner);
108-
109119
try {
110120
signResponse.get();
111121
} catch (Exception e) {
112122
BintrayCallException bce;
113123
if (e.getCause() instanceof BintrayCallException) {
114124
bce = (BintrayCallException) e.getCause();
115125
} else {
116-
bce = new BintrayCallException(400, e.getMessage(), (e.getCause() == null) ? "" : e.getCause().getMessage());
126+
bce = new BintrayCallException(409, e.getMessage(), (e.getCause() == null) ? ""
127+
: ", " + e.getCause().toString() + " : " + e.getCause().getMessage());
117128
}
118129
log.error(bce.toString());
119-
log.debug("{}", e);
130+
log.debug("{}", e.getMessage(), e);
120131
throw bce;
121132
}
122133

@@ -203,11 +214,12 @@ private HttpResponse put(List<HttpPut> requests) throws MultipleBintrayCallExcep
203214
runners.add(runner);
204215
}
205216
try {
206-
executions = executorService.invokeAll(runners, 10, TimeUnit.MINUTES);
217+
executions = executorService.invokeAll(runners);
207218
} catch (InterruptedException e) {
208-
BintrayCallException bce = new BintrayCallException(400, e.getMessage(), (e.getCause() == null) ? "" : e.getCause().getMessage());
219+
BintrayCallException bce = new BintrayCallException(409, e.getMessage(), (e.getCause() == null) ? ""
220+
: e.getCause().toString() + " : " + e.getCause().getMessage());
209221
log.error(bce.toString());
210-
log.debug("{}", e);
222+
log.debug("{}", e.getMessage(), e);
211223
errors.add(bce);
212224
}
213225

@@ -272,12 +284,12 @@ private HttpResponse execute(HttpUriRequest request, HttpClientContext context)
272284
return client.execute(request, responseHandler);
273285
}
274286
} catch (BintrayCallException bce) {
275-
log.debug("{}", bce);
287+
log.debug("{}", bce.toString(), bce);
276288
throw bce;
277289
} catch (IOException ioe) {
278290
//Underlying IOException form the client
279-
String underlyingCause = (ioe.getCause() == null) ? "" : ioe.getCause().getMessage();
280-
log.debug("{}", ioe);
291+
String underlyingCause = (ioe.getCause() == null) ? "" : ioe.toString() + " : " + ioe.getCause().getMessage();
292+
log.debug("{}", ioe.getMessage(), ioe);
281293
throw new BintrayCallException(400, ioe.getMessage(), underlyingCause);
282294
}
283295
}
@@ -307,7 +319,7 @@ public String call() throws BintrayCallException {
307319
log.info("Pushing " + pushPath);
308320
errorResultBuilder = new StringBuilder(" Pushing " + pushPath + " failed: ");
309321
} else {
310-
errorResultBuilder = new StringBuilder(request.getMethod() + " " + request.getURI().getPath() + " failed:");
322+
errorResultBuilder = new StringBuilder(request.getMethod() + " " + request.getURI().getPath() + " failed: ");
311323
}
312324
HttpResponse response;
313325
try {
@@ -319,9 +331,9 @@ public String call() throws BintrayCallException {
319331
throw bce;
320332
} catch (IOException ioe) {
321333
log.debug("IOException occured: '{}'", ioe.getMessage(), ioe);
322-
String cause = (ioe.getCause() == null) ? ((ioe.getMessage() != null && !ioe.getMessage().equals("")) ? ioe.getMessage() : ioe.toString())
323-
: " : " + ((ioe.getCause().getMessage() != null && !ioe.getCause().getMessage().equals("")) ? ioe.getCause().getMessage() : ioe.getCause().toString());
324-
errorResultBuilder.append(ioe.getMessage()).append(cause);
334+
String cause = (ioe.getCause() != null) ? (", caused by: " + ioe.getCause().toString() + " : "
335+
+ ioe.getCause().getMessage()) : "";
336+
errorResultBuilder.append(ioe.toString()).append(" : ").append(ioe.getMessage()).append(cause);
325337
throw new BintrayCallException(HttpStatus.SC_BAD_REQUEST, ioe.getMessage(), errorResultBuilder.toString());
326338
} finally {
327339
request.releaseConnection();
@@ -366,7 +378,8 @@ public HttpResponse handleResponse(HttpResponse response) throws BintrayCallExce
366378
}
367379
}
368380

369-
HttpResponse newResponse = DefaultHttpResponseFactory.INSTANCE.newHttpResponse(response.getStatusLine(), new HttpClientContext());
381+
HttpResponse newResponse = DefaultHttpResponseFactory.INSTANCE.newHttpResponse(response.getStatusLine(),
382+
new HttpClientContext());
370383
newResponse.setEntity(new StringEntity(entity, Charset.forName("UTF-8")));
371384
newResponse.setHeaders(response.getAllHeaders());
372385
return newResponse;

impl/src/main/java/com/jfrog/bintray/client/impl/handle/VersionHandleImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,17 +163,17 @@ public VersionHandle discard() throws BintrayCallException {
163163

164164

165165
@Override
166-
public VersionHandle sign() throws BintrayCallException {
167-
return sign(null);
166+
public VersionHandle sign(int fileCount) throws BintrayCallException {
167+
return sign(null, fileCount);
168168
}
169169

170170
@Override
171-
public VersionHandle sign(String passphrase) throws BintrayCallException {
171+
public VersionHandle sign(String passphrase, int fileCount) throws BintrayCallException {
172172
Map<String, String> headers = new HashMap<>();
173173
if (!(passphrase == null) && !passphrase.equals("")) {
174174
headers.put(GPG_SIGN_HEADER, passphrase);
175175
}
176-
bintrayHandle.sign(getCurrentVersionGpgUri(), headers);
176+
bintrayHandle.sign(getCurrentVersionGpgUri(), headers, fileCount);
177177
return null;
178178
}
179179

impl/src/test/groovy/com/jfrog/bintray/client/impl/BintrayClientSpec.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ class BintrayClientSpec extends Specification {
146146
private BintrayImpl createClient(String url = "https://api.bintray.com") {
147147
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(connectionProperties.username as String, connectionProperties.apiKey as String)
148148
HttpClientConfigurator conf = new HttpClientConfigurator()
149-
return new BintrayImpl(conf.hostFromUrl(url).noRetry().authentication(creds).getClient(), url, 5)
149+
return new BintrayImpl(conf.hostFromUrl(url).noRetry().authentication(creds).getClient(), url, 5, 90000)
150150
}
151151

152152
def 'Connection is successful and subject has correct username and avatar'() {
@@ -369,7 +369,7 @@ class BintrayClientSpec extends Specification {
369369
sleep(10000) //wait for previous deletions to propagate
370370
def ver = bintray.subject(connectionProperties.username).repository(REPO_NAME).createPkg(pkgBuilder).createVersion(versionBuilder)
371371
HttpClientConfigurator conf = new HttpClientConfigurator();
372-
def anonymousDownloadServerClient = new BintrayImpl(conf.hostFromUrl("https://dl.bintray.com").noRetry().noCookies().getClient(), "https://dl.bintray.com", 5)
372+
def anonymousDownloadServerClient = new BintrayImpl(conf.hostFromUrl("https://dl.bintray.com").noRetry().noCookies().getClient(), "https://dl.bintray.com", 5, 90000)
373373

374374
when:
375375
sleep(6000)
@@ -386,7 +386,7 @@ class BintrayClientSpec extends Specification {
386386
setup:
387387
VersionHandle ver = bintray.subject(connectionProperties.username).repository(REPO_NAME).createPkg(pkgBuilder).createVersion(versionBuilder).upload(this.files)
388388
HttpClientConfigurator conf = new HttpClientConfigurator();
389-
def anonymousDownloadServerClient = new BintrayImpl(conf.hostFromUrl("https://dl.bintray.com").noRetry().getClient(), "https://dl.bintray.com", 5)
389+
def anonymousDownloadServerClient = new BintrayImpl(conf.hostFromUrl("https://dl.bintray.com").noRetry().getClient(), "https://dl.bintray.com", 5, 90000)
390390

391391
when:
392392
sleep(2000)

0 commit comments

Comments
 (0)