docs: public <T extends AbstractBceResponse> T execute(InternalRequest request, Class<T> responseClass,
              HttpResponseHandler[] responseHandlers) {
          // Apply whatever request options we know how to handle, such as user-agent.
          request.addHeader(Headers.USER_AGENT, this.config.getUserAgent());
          BceCredentials credentials = config.getCredentials();
          if (request.getCredentials() != null) {
              credentials = request.getCredentials();
          }
          long delayForNextRetryInMillis = 0;
          for (int attempt = 1; ; ++attempt) {
              HttpRequestBase httpRequest = null;
              CloseableHttpResponse httpResponse = null;
              CloseableHttpAsyncClient httpAsyncClient = null;
              try {
                  // Sign the request if credentials were provided
                  if (credentials != null) {
                      this.signer.sign(request, credentials);
                  }
  
                  requestLogger.debug("Sending Request: {}", request);
  
                  httpRequest = this.createHttpRequest(request);
  
                  HttpContext httpContext = this.createHttpContext(request);
  
                  if (this.isHttpAsyncPutEnabled && httpRequest.getMethod().equals("PUT")) {
                      httpAsyncClient = this.createHttpAsyncClient(this.createNHttpClientConnectionManager());
                      httpAsyncClient.start();
                      Future<HttpResponse> future = httpAsyncClient.execute(HttpAsyncMethods.create(httpRequest),
                              new BasicAsyncResponseConsumer(),
                              httpContext, null);
                      httpResponse = new BceCloseableHttpResponse(future.get());
                  } else {
                      httpResponse = this.httpClient.execute(httpRequest, httpContext);
                  }
                  HttpUtils.printRequest(httpRequest);
                  BceHttpResponse bceHttpResponse = new BceHttpResponse(httpResponse);
  
                  T response = responseClass.newInstance();
                  for (HttpResponseHandler handler : responseHandlers) {
                      if (handler.handle(bceHttpResponse, response)) {
                          break;
                      }
                  }
  
                  // everything is ok
                  return response;
              } catch (Exception e) {
                  if (logger.isInfoEnabled()) {
                      logger.info("Unable to execute HTTP request", e);
                  }
  
                  BceClientException bce;
                  if (e instanceof BceClientException) {
                      bce = (BceClientException) e;
                  } else {
                      bce = new BceClientException("Unable to execute HTTP request", e);
                  }
                  delayForNextRetryInMillis =
                          this.getDelayBeforeNextRetryInMillis(httpRequest, bce, attempt, this.config.getRetryPolicy());
                  if (delayForNextRetryInMillis < 0) {
                      throw bce;
                  }
  
                  logger.debug("Retriable error detected, will retry in {} ms, attempt number: {}",
                          delayForNextRetryInMillis, attempt);
                  try {
                      Thread.sleep(delayForNextRetryInMillis);
                  } catch (InterruptedException e1) {
                      throw new BceClientException("Delay interrupted", e1);
                  }
                  if (request.getContent() != null) {
                      request.getContent().restart();
                  }
                  if (httpResponse != null) {
                      try {
                          HttpEntity entity = httpResponse.getEntity();
                          if (entity != null && entity.isStreaming()) {
                              final InputStream instream = entity.getContent();
                              if (instream != null) {
                                  instream.close();
                              }
                          }
                      } catch (IOException e1) {
                          logger.debug("Fail to consume entity.", e1);
                          try {
                              httpResponse.close();
                          } catch (IOException e2) {
                              logger.debug("Fail to close connection.", e2);
                          }
                      }
                  }
              } finally {
                  try {
                      if (httpAsyncClient != null) {
                          httpAsyncClient.close();
                      }
                  } catch (IOException e) {
                      logger.debug("Fail to close HttpAsyncClient", e);
                  }
              }
          }
      }