Builds and executes an HTTP Post request. @param path the path to the endpoint @param body the request body @param respCreator object specifying the response structure @return a response deserialized into type T @throws ChainException
(String path, Object body, ResponseCreator<T> respCreator)
| 338 | * @throws ChainException |
| 339 | */ |
| 340 | private <T> T post(String path, Object body, ResponseCreator<T> respCreator) |
| 341 | throws ChainException { |
| 342 | RequestBody requestBody = RequestBody.create(this.JSON, Utils.serializer.toJson(body)); |
| 343 | Request req; |
| 344 | |
| 345 | ChainException exception = null; |
| 346 | for (int attempt = 1; attempt - 1 <= MAX_RETRIES; attempt++) { |
| 347 | |
| 348 | int idx = this.urlIndex.get(); |
| 349 | URL endpointURL; |
| 350 | try { |
| 351 | URI u = new URI(this.urls.get(idx % this.urls.size()).toString() + "/" + path); |
| 352 | u = u.normalize(); |
| 353 | endpointURL = new URL(u.toString()); |
| 354 | } catch (MalformedURLException ex) { |
| 355 | throw new BadURLException(ex.getMessage()); |
| 356 | } catch (URISyntaxException ex) { |
| 357 | throw new BadURLException(ex.getMessage()); |
| 358 | } |
| 359 | |
| 360 | Request.Builder builder = |
| 361 | new Request.Builder() |
| 362 | .header("User-Agent", "chain-sdk-java/" + version) |
| 363 | .url(endpointURL) |
| 364 | .method("POST", requestBody); |
| 365 | if (hasAccessToken()) { |
| 366 | builder = builder.header("Authorization", buildCredentials()); |
| 367 | } |
| 368 | req = builder.build(); |
| 369 | |
| 370 | // Wait between retrys. The first attempt will not wait at all. |
| 371 | if (attempt > 1) { |
| 372 | int delayMillis = retryDelayMillis(attempt - 1); |
| 373 | try { |
| 374 | TimeUnit.MILLISECONDS.sleep(delayMillis); |
| 375 | } catch (InterruptedException e) { |
| 376 | } |
| 377 | } |
| 378 | |
| 379 | try { |
| 380 | Response resp = this.checkError(this.httpClient.newCall(req).execute()); |
| 381 | return respCreator.create(resp, Utils.serializer); |
| 382 | } catch (IOException ex) { |
| 383 | // This URL's process might be unhealthy; move to the next. |
| 384 | this.nextURL(idx); |
| 385 | |
| 386 | // The OkHttp library already performs retries for some |
| 387 | // I/O-related errors, but we've hit this case in a leader |
| 388 | // failover, so do our own retries too. |
| 389 | exception = new ConfigurationException(ex.getMessage()); |
| 390 | } catch (ConnectivityException ex) { |
| 391 | // This URL's process might be unhealthy; move to the next. |
| 392 | this.nextURL(idx); |
| 393 | |
| 394 | // ConnectivityExceptions are always retriable. |
| 395 | exception = ex; |
| 396 | } catch (APIException ex) { |
| 397 | // Check if this error is retriable (either it's a status code that's |
no test coverage detected