/**
   * Copy constructor.
   *
   * @param cfg Configuration to be copied.
   */
  public GridClientConfiguration(GridClientConfiguration cfg) {
    // Preserve alphabetical order for maintenance;
    autoFetchAttrs = cfg.isAutoFetchAttributes();
    autoFetchMetrics = cfg.isAutoFetchMetrics();
    balancer = cfg.getBalancer();
    connectTimeout = cfg.getConnectTimeout();
    credProvider = cfg.getSecurityCredentialsProvider();
    enableAttrsCache = cfg.isEnableAttributesCache();
    enableMetricsCache = cfg.isEnableMetricsCache();
    executor = cfg.getExecutorService();
    marshaller = cfg.getMarshaller();
    maxConnIdleTime = cfg.getMaxConnectionIdleTime();
    pingInterval = cfg.getPingInterval();
    pingTimeout = cfg.getPingTimeout();
    proto = cfg.getProtocol();
    routers = cfg.getRouters();
    srvs = cfg.getServers();
    sslCtxFactory = cfg.getSslContextFactory();
    tcpNoDelay = cfg.isTcpNoDelay();
    topRefreshFreq = cfg.getTopologyRefreshFrequency();
    daemon = cfg.isDaemon();
    marshaller = cfg.getMarshaller();

    setDataConfigurations(cfg.getDataConfigurations());
  }
  /**
   * Create new connection to specified server.
   *
   * @param nodeId {@code UUID} of node for mapping with connection. {@code null} if no need of
   *     mapping.
   * @param addr Remote socket to connect.
   * @return Established connection.
   * @throws IOException If connection failed.
   * @throws GridClientException If protocol error happened.
   * @throws InterruptedException If thread was interrupted before connection was established.
   */
  protected GridClientConnection connect(@Nullable UUID nodeId, InetSocketAddress addr)
      throws IOException, GridClientException, InterruptedException {
    endpointStripedLock.lock(addr);

    try {
      GridClientConnection old = conns.get(addr);

      if (old != null) {
        if (old.isClosed()) {
          conns.remove(addr, old);

          if (nodeId != null) nodeConns.remove(nodeId, old);
        } else {
          if (nodeId != null) nodeConns.put(nodeId, old);

          return old;
        }
      }

      SecurityCredentials cred = null;

      try {
        if (cfg.getSecurityCredentialsProvider() != null)
          cred = cfg.getSecurityCredentialsProvider().credentials();
      } catch (IgniteCheckedException e) {
        throw new GridClientException("Failed to obtain client credentials.", e);
      }

      GridClientConnection conn;

      if (cfg.getProtocol() == GridClientProtocol.TCP) {
        conn =
            new GridClientNioTcpConnection(
                srv,
                clientId,
                addr,
                sslCtx,
                pingExecutor,
                cfg.getConnectTimeout(),
                cfg.getPingInterval(),
                cfg.getPingTimeout(),
                cfg.isTcpNoDelay(),
                cfg.getMarshaller(),
                marshId,
                top,
                cred,
                keepPortablesThreadLocal());
      } else
        throw new GridServerUnreachableException(
            "Failed to create client (protocol is not supported): " + cfg.getProtocol());

      old = conns.putIfAbsent(addr, conn);

      assert old == null;

      if (nodeId != null) nodeConns.put(nodeId, conn);

      return conn;
    } finally {
      endpointStripedLock.unlock(addr);
    }
  }