@Override
  public void onDetectingUnresponsiveConnection(ClientConnection connection) {
    if (smartRouting) {
      // closing the owner connection if unresponsive so that it can be switched to a healthy one.
      ownerConnectionFuture.closeIfAddressMatches(connection.getEndPoint());
      // we do not close connection itself since we will continue to send heartbeat ping to this
      // connection.
      // IOUtil.closeResource(connection);
      return;
    }

    // close both owner and operation connection
    ownerConnectionFuture.close();
    IOUtil.closeResource(connection);
  }
 @Override
 public void onConnectionClose(ClientConnection clientConnection) {
   Address endpoint = clientConnection.getRemoteEndpoint();
   if (endpoint != null) {
     connections.remove(clientConnection.getRemoteEndpoint());
     ownerConnectionFuture.closeIfAddressMatches(endpoint);
   }
 }
 @Override
 public ClientConnection ownerConnection(Address address) throws Exception {
   final Address translatedAddress = addressTranslator.translate(address);
   if (translatedAddress == null) {
     throw new RetryableIOException(address + " can not be translated! ");
   }
   return ownerConnectionFuture.createNew(translatedAddress);
 }
  private ClientConnection getOrConnect(Address target, Authenticator authenticator)
      throws Exception {
    if (!smartRouting) {
      target = ownerConnectionFuture.getOrWaitForCreation().getEndPoint();
    }

    Address address = addressTranslator.translate(target);

    if (address == null) {
      throw new IOException("Address is required!");
    }

    ClientConnection clientConnection = connections.get(address);
    if (clientConnection == null) {
      final Object lock = getLock(address);
      synchronized (lock) {
        clientConnection = connections.get(address);
        if (clientConnection == null) {
          final ConnectionProcessor connectionProcessor =
              new ConnectionProcessor(address, authenticator, false);
          final ICompletableFuture<ClientConnection> future =
              executionService.submitInternal(connectionProcessor);
          try {
            clientConnection = future.get(connectionTimeout, TimeUnit.MILLISECONDS);
          } catch (Exception e) {
            future.cancel(true);
            throw new RetryableIOException(e);
          }
          ClientConnection current = connections.putIfAbsent(address, clientConnection);
          if (current != null) {
            clientConnection.close();
            clientConnection = current;
          }
        }
      }
    }
    return clientConnection;
  }
 @Override
 public void onCloseOwnerConnection() {
   // mark the owner connection as closed so that operations requiring owner connection can be
   // waited.
   ownerConnectionFuture.markAsClosed();
 }