private ClientConnection getOrWaitForCreation() throws IOException {
      ClientNetworkConfig networkConfig = client.getClientConfig().getNetworkConfig();
      long connectionAttemptLimit = networkConfig.getConnectionAttemptLimit();
      long connectionAttemptPeriod = networkConfig.getConnectionAttemptPeriod();
      long waitTime = connectionAttemptLimit * connectionAttemptPeriod * 2;
      if (waitTime < 0) {
        waitTime = Long.MAX_VALUE;
      }

      final ClientConnection currentOwnerConnection = ownerConnection;
      if (currentOwnerConnection != null) {
        return currentOwnerConnection;
      }

      long remainingWait = waitTime;
      synchronized (ownerConnectionLock) {
        long waitStart = System.currentTimeMillis();
        while (ownerConnection == null && remainingWait > 0) {
          try {
            ownerConnectionLock.wait(remainingWait);
            remainingWait = waitTime - (System.currentTimeMillis() - waitStart);
          } catch (InterruptedException e) {
            throw new IOException(e);
          }
        }
        if (ownerConnection == null) {
          LOGGER.warning("Wait for owner connection is timed out");
          throw new IOException("Wait for owner connection is timed out");
        }
        return ownerConnection;
      }
    }
  @Test
  public void testParsing() throws Exception {
    String xmlFileName = "hazelcast-client-discovery-spi-test.xml";
    InputStream xmlResource =
        ClientDiscoverySpiTest.class.getClassLoader().getResourceAsStream(xmlFileName);
    ClientConfig clientConfig = new XmlClientConfigBuilder(xmlResource).build();

    ClientNetworkConfig networkConfig = clientConfig.getNetworkConfig();

    AwsConfig awsConfig = networkConfig.getAwsConfig();
    assertNull(awsConfig);

    DiscoveryStrategiesConfig discoveryStrategiesConfig =
        networkConfig.getDiscoveryStrategiesConfig();
    assertTrue(discoveryStrategiesConfig.isEnabled());

    assertEquals(1, discoveryStrategiesConfig.getDiscoveryStrategyConfigs().size());

    DiscoveryStrategyConfig providerConfig =
        discoveryStrategiesConfig.getDiscoveryStrategyConfigs().iterator().next();

    assertEquals(3, providerConfig.getProperties().size());
    assertEquals("foo", providerConfig.getProperties().get("key-string"));
    assertEquals("123", providerConfig.getProperties().get("key-int"));
    assertEquals("true", providerConfig.getProperties().get("key-boolean"));
  }
  @Test
  public void testNodeFilter_from_xml() throws Exception {
    String xmlFileName = "hazelcast-client-discovery-spi-test.xml";
    InputStream xmlResource =
        ClientDiscoverySpiTest.class.getClassLoader().getResourceAsStream(xmlFileName);
    ClientConfig clientConfig = new XmlClientConfigBuilder(xmlResource).build();

    ClientNetworkConfig networkConfig = clientConfig.getNetworkConfig();

    DiscoveryStrategiesConfig discoveryStrategiesConfig =
        networkConfig.getDiscoveryStrategiesConfig();
    assertNotNull(discoveryStrategiesConfig);
    assertNotNull(discoveryStrategiesConfig.getNodeFilterClass());

    DiscoveryServiceProvider provider = new DefaultDiscoveryServiceProvider();
    DiscoveryService discoveryService =
        provider.newDiscoveryService(
            DiscoveryMode.Client,
            discoveryStrategiesConfig,
            ClientDiscoverySpiTest.class.getClassLoader());

    discoveryService.start();
    discoveryService.discoverNodes();
    discoveryService.destroy();

    Field nodeFilterField = DefaultDiscoveryService.class.getDeclaredField("nodeFilter");
    nodeFilterField.setAccessible(true);

    TestNodeFilter nodeFilter = (TestNodeFilter) nodeFilterField.get(discoveryService);

    assertEquals(4, nodeFilter.getNodes().size());
  }
  private ClientConnection connectToOne() throws Exception {
    final ClientNetworkConfig networkConfig = client.getClientConfig().getNetworkConfig();
    final int connectionAttemptLimit = networkConfig.getConnectionAttemptLimit();
    final int connectionAttemptPeriod = networkConfig.getConnectionAttemptPeriod();
    int attempt = 0;
    Throwable lastError = null;
    while (true) {
      final long nextTry = Clock.currentTimeMillis() + connectionAttemptPeriod;
      final Collection<InetSocketAddress> socketAddresses = getSocketAddresses();
      for (InetSocketAddress isa : socketAddresses) {
        Address address = new Address(isa);
        try {
          final ClientConnection connection = connectionManager.ownerConnection(address);
          clusterService.fireConnectionEvent(false);
          return connection;
        } catch (IOException e) {
          lastError = e;
          LOGGER.finest("IO error during initial connection...", e);
        } catch (AuthenticationException e) {
          lastError = e;
          LOGGER.warning("Authentication error on " + address, e);
        }
      }
      if (attempt++ >= connectionAttemptLimit) {
        break;
      }
      final long remainingTime = nextTry - Clock.currentTimeMillis();
      LOGGER.warning(
          String.format(
              "Unable to get alive cluster connection," + " try in %d ms later, attempt %d of %d.",
              Math.max(0, remainingTime), attempt, connectionAttemptLimit));

      if (remainingTime > 0) {
        try {
          Thread.sleep(remainingTime);
        } catch (InterruptedException e) {
          break;
        }
      }
    }
    throw new IllegalStateException("Unable to connect to any address in the config!", lastError);
  }
  private SocketChannelWrapperFactory initSocketChannel(ClientNetworkConfig networkConfig) {
    // ioService.getSSLConfig(); TODO
    SSLConfig sslConfig = networkConfig.getSSLConfig();

    if (sslConfig != null && sslConfig.isEnabled()) {
      LOGGER.info("SSL is enabled");
      return new SSLSocketChannelWrapperFactory(sslConfig);
    } else {
      return new DefaultSocketChannelWrapperFactory();
    }
  }
  public ClientConnectionManagerImpl(
      HazelcastClient client, LoadBalancer loadBalancer, AddressTranslator addressTranslator) {
    this.client = client;
    this.addressTranslator = addressTranslator;
    final ClientConfig config = client.getClientConfig();
    final ClientNetworkConfig networkConfig = config.getNetworkConfig();

    final int connTimeout = networkConfig.getConnectionTimeout();
    connectionTimeout = connTimeout == 0 ? Integer.MAX_VALUE : connTimeout;

    final ClientProperties clientProperties = client.getClientProperties();
    int timeout = clientProperties.getHeartbeatTimeout().getInteger();
    this.heartBeatTimeout =
        timeout > 0 ? timeout : Integer.parseInt(PROP_HEARTBEAT_TIMEOUT_DEFAULT);

    int interval = clientProperties.getHeartbeatInterval().getInteger();
    heartBeatInterval = interval > 0 ? interval : Integer.parseInt(PROP_HEARTBEAT_INTERVAL_DEFAULT);

    smartRouting = networkConfig.isSmartRouting();
    executionService = (ClientExecutionServiceImpl) client.getClientExecutionService();
    credentials = initCredentials(config);
    router = new Router(loadBalancer);

    inSelector =
        new InSelectorImpl(
            client.getThreadGroup(),
            "InSelector",
            Logger.getLogger(InSelectorImpl.class),
            OUT_OF_MEMORY_HANDLER);
    outSelector =
        new OutSelectorImpl(
            client.getThreadGroup(),
            "OutSelector",
            Logger.getLogger(OutSelectorImpl.class),
            OUT_OF_MEMORY_HANDLER);

    socketInterceptor = initSocketInterceptor(networkConfig.getSocketInterceptorConfig());
    socketOptions = networkConfig.getSocketOptions();
    socketChannelWrapperFactory = initSocketChannel(networkConfig);
  }