/**
   * @param clientId Client ID.
   * @param sslCtx SSL context to enable secured connection or {@code null} to use unsecured one.
   * @param cfg Client configuration.
   * @param routers Routers or empty collection to use endpoints from topology info.
   * @param top Topology.
   * @param marshId Marshaller ID.
   * @throws GridClientException In case of error.
   */
  @SuppressWarnings("unchecked")
  protected GridClientConnectionManagerAdapter(
      UUID clientId,
      SSLContext sslCtx,
      GridClientConfiguration cfg,
      Collection<InetSocketAddress> routers,
      GridClientTopology top,
      @Nullable Byte marshId,
      boolean routerClient)
      throws GridClientException {
    assert clientId != null : "clientId != null";
    assert cfg != null : "cfg != null";
    assert routers != null : "routers != null";
    assert top != null : "top != null";

    this.clientId = clientId;
    this.sslCtx = sslCtx;
    this.cfg = cfg;
    this.routers = new ArrayList<>(routers);
    this.top = top;

    log = Logger.getLogger(getClass().getName());

    executor =
        cfg.getExecutorService() != null
            ? cfg.getExecutorService()
            : Executors.newCachedThreadPool(new GridClientThreadFactory("exec", true));

    pingExecutor =
        cfg.getProtocol() == GridClientProtocol.TCP
            ? Executors.newScheduledThreadPool(
                Runtime.getRuntime().availableProcessors(),
                new GridClientThreadFactory("exec", true))
            : null;

    this.marshId = marshId;

    if (marshId == null && cfg.getMarshaller() == null)
      throw new GridClientException("Failed to start client (marshaller is not configured).");

    if (cfg.getProtocol() == GridClientProtocol.TCP) {
      try {
        IgniteLogger gridLog = new JavaLogger(false);

        GridNioFilter[] filters;

        GridNioFilter codecFilter =
            new GridNioCodecFilter(new GridTcpRestParser(routerClient), gridLog, false);

        if (sslCtx != null) {
          GridNioSslFilter sslFilter =
              new GridNioSslFilter(sslCtx, true, ByteOrder.nativeOrder(), gridLog);

          sslFilter.directMode(false);
          sslFilter.clientMode(true);

          filters = new GridNioFilter[] {codecFilter, sslFilter};
        } else filters = new GridNioFilter[] {codecFilter};

        srv =
            GridNioServer.builder()
                .address(U.getLocalHost())
                .port(-1)
                .listener(new NioListener(log))
                .filters(filters)
                .logger(gridLog)
                .selectorCount(Runtime.getRuntime().availableProcessors())
                .sendQueueLimit(1024)
                .byteOrder(ByteOrder.nativeOrder())
                .tcpNoDelay(cfg.isTcpNoDelay())
                .directBuffer(true)
                .directMode(false)
                .socketReceiveBufferSize(0)
                .socketSendBufferSize(0)
                .idleTimeout(Long.MAX_VALUE)
                .gridName(routerClient ? "routerClient" : "gridClient")
                .daemon(cfg.isDaemon())
                .build();

        srv.start();
      } catch (IOException | IgniteCheckedException e) {
        throw new GridClientException("Failed to start connection server.", e);
      }
    }
  }
  /**
   * Recreates tpcSrvr socket instance.
   *
   * @return Server instance.
   * @throws IgniteCheckedException Thrown if it's not possible to create server.
   */
  private GridNioServer<HadoopMessage> resetNioServer() throws IgniteCheckedException {
    if (boundTcpPort >= 0)
      throw new IgniteCheckedException(
          "Tcp NIO server was already created on port " + boundTcpPort);

    IgniteCheckedException lastEx = null;

    // If configured TCP port is busy, find first available in range.
    for (int port = locPort; port < locPort + locPortRange; port++) {
      try {
        GridNioServer<HadoopMessage> srvr =
            GridNioServer.<HadoopMessage>builder()
                .address(locHost)
                .port(port)
                .listener(srvLsnr)
                .logger(log.getLogger(GridNioServer.class))
                .selectorCount(selectorsCnt)
                .gridName(gridName)
                .tcpNoDelay(tcpNoDelay)
                .directBuffer(directBuf)
                .byteOrder(ByteOrder.nativeOrder())
                .socketSendBufferSize(sockSndBuf)
                .socketReceiveBufferSize(sockRcvBuf)
                .sendQueueLimit(msgQueueLimit)
                .directMode(false)
                .filters(filters())
                .build();

        boundTcpPort = port;

        // Ack Port the TCP server was bound to.
        if (log.isInfoEnabled())
          log.info(
              "Successfully bound to TCP port [port="
                  + boundTcpPort
                  + ", locHost="
                  + locHost
                  + ']');

        return srvr;
      } catch (IgniteCheckedException e) {
        lastEx = e;

        if (log.isDebugEnabled())
          log.debug(
              "Failed to bind to local port (will try next port within range) [port="
                  + port
                  + ", locHost="
                  + locHost
                  + ']');
      }
    }

    // If free port wasn't found.
    throw new IgniteCheckedException(
        "Failed to bind to any port within range [startPort="
            + locPort
            + ", portRange="
            + locPortRange
            + ", locHost="
            + locHost
            + ']',
        lastEx);
  }