private Object authenticate(
     ClientConnection connection,
     Credentials credentials,
     ClientPrincipal principal,
     boolean firstConnection)
     throws IOException {
   final SerializationService ss = getSerializationService();
   AuthenticationRequest auth = new AuthenticationRequest(credentials, principal);
   connection.init();
   auth.setOwnerConnection(firstConnection);
   // contains remoteAddress and principal
   SerializableCollection collectionWrapper;
   try {
     collectionWrapper = (SerializableCollection) sendAndReceive(auth, connection);
   } catch (Exception e) {
     throw new RetryableIOException(e);
   }
   final Iterator<Data> iter = collectionWrapper.iterator();
   if (iter.hasNext()) {
     final Data addressData = iter.next();
     final Address address = ss.toObject(addressData);
     connection.setRemoteEndpoint(address);
     if (iter.hasNext()) {
       final Data principalData = iter.next();
       return ss.toObject(principalData);
     }
   }
   throw new AuthenticationException();
 }
 void shutdown() {
   interrupt();
   final ClientConnection c = conn;
   if (c != null) {
     c.close();
   }
 }
 @Override
 public void onConnectionClose(ClientConnection clientConnection) {
   Address endpoint = clientConnection.getRemoteEndpoint();
   if (endpoint != null) {
     connections.remove(clientConnection.getRemoteEndpoint());
     ownerConnectionFuture.closeIfAddressMatches(endpoint);
   }
 }
 private void closeIfAddressMatches(Address address) {
   final ClientConnection currentOwnerConnection = ownerConnection;
   if (currentOwnerConnection == null || !currentOwnerConnection.live()) {
     return;
   }
   if (address.equals(currentOwnerConnection.getRemoteEndpoint())) {
     close();
   }
 }
 private void process(ClientPacket packet) {
   final ClientConnection conn = packet.getClientConnection();
   try {
     handleClientMessage(packet.getClientMessage());
   } catch (Exception e) {
     logger.severe("Failed to process task: " + packet + " on responseThread :" + getName(), e);
   } finally {
     conn.decrementPacketCount();
   }
 }
 @Override
 public boolean removeEventHandler(Integer callId) {
   if (callId != null) {
     for (ClientConnection clientConnection : connections.values()) {
       if (clientConnection.deRegisterEventHandler(callId) != null) {
         return true;
       }
     }
   }
   return false;
 }
 @Override
 public void handlePacket(Packet packet) {
   final ClientConnection conn = (ClientConnection) packet.getConn();
   conn.incrementPacketCount();
   if (packet.isHeaderSet(Packet.HEADER_EVENT)) {
     final ClientListenerServiceImpl listenerService =
         (ClientListenerServiceImpl) client.getListenerService();
     listenerService.handleEventPacket(packet);
   } else {
     invocationService.handlePacket(packet);
   }
 }
 @Override
 public ClientConnection call() throws Exception {
   if (!live) {
     throw new HazelcastException("ConnectionManager is not active!!!");
   }
   SocketChannel socketChannel = null;
   try {
     socketChannel = SocketChannel.open();
     Socket socket = socketChannel.socket();
     socket.setKeepAlive(socketOptions.isKeepAlive());
     socket.setTcpNoDelay(socketOptions.isTcpNoDelay());
     socket.setReuseAddress(socketOptions.isReuseAddress());
     if (socketOptions.getLingerSeconds() > 0) {
       socket.setSoLinger(true, socketOptions.getLingerSeconds());
     }
     int bufferSize = socketOptions.getBufferSize() * KILO_BYTE;
     if (bufferSize < 0) {
       bufferSize = DEFAULT_BUFFER_SIZE_BYTE;
     }
     socket.setSendBufferSize(bufferSize);
     socket.setReceiveBufferSize(bufferSize);
     socketChannel.socket().connect(address.getInetSocketAddress(), connectionTimeout);
     SocketChannelWrapper socketChannelWrapper =
         socketChannelWrapperFactory.wrapSocketChannel(socketChannel, true);
     final ClientConnection clientConnection =
         new ClientConnection(
             ClientConnectionManagerImpl.this,
             inSelector,
             outSelector,
             connectionIdGen.incrementAndGet(),
             socketChannelWrapper,
             executionService,
             invocationService,
             client.getSerializationService());
     socketChannel.configureBlocking(true);
     if (socketInterceptor != null) {
       socketInterceptor.onConnect(socket);
     }
     authenticator.auth(clientConnection);
     socketChannel.configureBlocking(isBlock);
     socket.setSoTimeout(0);
     if (!isBlock) {
       clientConnection.getReadHandler().register();
     }
     return clientConnection;
   } catch (Exception e) {
     if (socketChannel != null) {
       socketChannel.close();
     }
     throw ExceptionUtil.rethrow(e);
   }
 }
 @Override
 public synchronized void shutdown() {
   if (!live) {
     return;
   }
   live = false;
   for (ClientConnection connection : connections.values()) {
     connection.close();
   }
   inSelector.shutdown();
   outSelector.shutdown();
   connectionLockMap.clear();
 }
 @Override
 public Object sendAndReceive(ClientRequest request, ClientConnection connection)
     throws Exception {
   final SerializationService ss = client.getSerializationService();
   connection.write(ss.toData(request));
   final Data data = connection.read();
   ClientResponse clientResponse = ss.toObject(data);
   Object response = ss.toObject(clientResponse.getResponse());
   if (response instanceof Throwable) {
     Throwable t = (Throwable) response;
     ExceptionUtil.fixRemoteStackTrace(t, Thread.currentThread().getStackTrace());
     throw new Exception(t);
   }
   return response;
 }
 public void run() {
   if (!live) {
     return;
   }
   final long now = Clock.currentTimeMillis();
   for (ClientConnection connection : connections.values()) {
     if (now - connection.lastReadTime() > heartBeatTimeout) {
       connection.heartBeatingFailed();
     }
     if (now - connection.lastReadTime() > heartBeatInterval) {
       final ClientPingRequest request = new ClientPingRequest();
       invocationService.send(request, connection);
     } else {
       connection.heartBeatingSucceed();
     }
   }
 }
 private void waitForPacketsProcessed() {
   final long begin = System.currentTimeMillis();
   int count = connection.getPacketCount();
   while (count != 0) {
     try {
       Thread.sleep(WAIT_TIME_FOR_PACKETS_TO_BE_CONSUMED);
     } catch (InterruptedException e) {
       logger.warning(e);
       break;
     }
     long elapsed = System.currentTimeMillis() - begin;
     if (elapsed > WAIT_TIME_FOR_PACKETS_TO_BE_CONSUMED_THRESHOLD) {
       logger.warning("There are packets which are not processed " + count);
       break;
     }
     count = connection.getPacketCount();
   }
 }
 boolean isConnectionHealthy(long elapsed) {
   if (elapsed >= heartBeatInterval) {
     if (sendConnection != null) {
       return sendConnection.isHeartBeating();
     } else {
       return true;
     }
   }
   return true;
 }
 public void cleanResources(
     ConstructorFunction<Object, Throwable> responseCtor, ClientConnection connection) {
   final Iterator<Map.Entry<Integer, ClientInvocation>> iter = callIdMap.entrySet().iterator();
   while (iter.hasNext()) {
     final Map.Entry<Integer, ClientInvocation> entry = iter.next();
     final ClientInvocation invocation = entry.getValue();
     if (connection.equals(invocation.getSendConnection())) {
       iter.remove();
       invocation.notifyException(responseCtor.createNew(null));
       eventHandlerMap.remove(entry.getKey());
     }
   }
   final Iterator<ClientListenerInvocation> iterator = eventHandlerMap.values().iterator();
   while (iterator.hasNext()) {
     final ClientInvocation invocation = iterator.next();
     if (connection.equals(invocation.getSendConnection())) {
       iterator.remove();
       invocation.notifyException(responseCtor.createNew(null));
     }
   }
 }
  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;
  }
  private void listenMembershipEvents() throws IOException {
    final SerializationService serializationService = clusterService.getSerializationService();
    while (!Thread.currentThread().isInterrupted()) {
      final Data clientResponseData = conn.read();
      final ClientResponse clientResponse = serializationService.toObject(clientResponseData);
      final Object eventObject = serializationService.toObject(clientResponse.getResponse());
      final ClientMembershipEvent event = (ClientMembershipEvent) eventObject;
      final MemberImpl member = (MemberImpl) event.getMember();
      boolean membersUpdated = false;
      if (event.getEventType() == MembershipEvent.MEMBER_ADDED) {
        members.add(member);
        membersUpdated = true;
      } else if (event.getEventType() == ClientMembershipEvent.MEMBER_REMOVED) {
        members.remove(member);
        membersUpdated = true;
        //                    getConnectionManager().removeConnectionPool(member.getAddress());
        // //TODO
      } else if (event.getEventType() == ClientMembershipEvent.MEMBER_ATTRIBUTE_CHANGED) {
        MemberAttributeChange memberAttributeChange = event.getMemberAttributeChange();
        Map<Address, MemberImpl> memberMap = clusterService.getMembersRef();
        if (memberMap != null) {
          for (MemberImpl target : memberMap.values()) {
            if (target.getUuid().equals(memberAttributeChange.getUuid())) {
              final MemberAttributeOperationType operationType =
                  memberAttributeChange.getOperationType();
              final String key = memberAttributeChange.getKey();
              final Object value = memberAttributeChange.getValue();
              target.updateAttribute(operationType, key, value);
              MemberAttributeEvent memberAttributeEvent =
                  new MemberAttributeEvent(client.getCluster(), target, operationType, key, value);
              clusterService.fireMemberAttributeEvent(memberAttributeEvent);
              break;
            }
          }
        }
      }

      if (membersUpdated) {
        ((ClientPartitionServiceImpl) client.getClientPartitionService()).refreshPartitions();
        updateMembersRef();
        LOGGER.info(clusterService.membersString());
        clusterService.fireMembershipEvent(
            new MembershipEvent(
                client.getCluster(),
                member,
                event.getEventType(),
                Collections.unmodifiableSet(new LinkedHashSet<Member>(members))));
      }
    }
  }
  @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);
  }
  protected void send(ClientInvocation invocation, ClientConnection connection) throws IOException {
    if (isShutdown) {
      throw new HazelcastClientNotActiveException("Client is shut down");
    }
    registerInvocation(invocation);

    ClientMessage clientMessage = invocation.getClientMessage();
    if (!isAllowedToSendRequest(connection, invocation)
        || !writeToConnection(connection, clientMessage)) {
      final int callId = clientMessage.getCorrelationId();
      deRegisterCallId(callId);
      deRegisterEventHandler(callId);
      throw new IOException("Packet not send to " + connection.getRemoteEndpoint());
    }
    invocation.setSendConnection(connection);
  }
    @Override
    public void run() {
      try {
        int correlationId = clientMessage.getCorrelationId();
        final EventHandler eventHandler = eventHandlerMap.get(correlationId);
        if (eventHandler == null) {
          logger.warning(
              "No eventHandler for callId: " + correlationId + ", event: " + clientMessage);
          return;
        }

        eventHandler.handle(clientMessage);
      } finally {
        connection.decrementPendingPacketCount();
      }
    }
  private boolean isAllowedToSendRequest(ClientConnection connection, ClientInvocation invocation) {
    if (!connection.isHeartBeating()) {
      if (invocation.shouldBypassHeartbeatCheck()) {
        // ping and removeAllListeners should be send even though heart is not beating
        return true;
      }

      if (logger.isFinestEnabled()) {
        logger.warning(
            "Connection is not heart-beating, won't write client message -> "
                + invocation.getClientMessage());
      }
      return false;
    }
    return true;
  }
  protected void send(ClientInvocation invocation, ClientConnection connection) throws IOException {
    if (isShutdown) {
      throw new HazelcastClientNotActiveException("Client is shut down");
    }
    registerInvocation(invocation);

    ClientMessage clientMessage = invocation.getClientMessage();
    if (!isAllowedToSendRequest(connection, invocation)
        || !writeToConnection(connection, clientMessage)) {
      final int callId = clientMessage.getCorrelationId();
      ClientInvocation clientInvocation = deRegisterCallId(callId);
      deRegisterEventHandler(callId);
      if (clientInvocation != null) {
        throw new IOException("Packet not send to " + connection.getRemoteEndpoint());
      } else {
        if (logger.isFinestEnabled()) {
          logger.finest("Invocation not found to deregister for call id " + callId);
        }
      }
    }

    invocation.setSendConnection(connection);
  }
 public void removeEndpoint(Address address) {
   final ClientConnection clientConnection = connections.get(address);
   if (clientConnection != null) {
     clientConnection.close();
   }
 }
 private boolean writeToConnection(ClientConnection connection, ClientMessage clientMessage) {
   clientMessage.addFlag(ClientMessage.BEGIN_AND_END_FLAGS);
   return connection.write(clientMessage);
 }