/**
   * Connect to a remote node if appropriate
   *
   * @param bootstrap the client bootstrap object
   * @param n the node to connect to
   */
  protected void doNodeConnect(ClusterNode n) {
    if (!shutDown && n.getNodeId() < syncManager.getLocalNodeId()) {
      Short nodeId = n.getNodeId();

      synchronized (connections) {
        NodeConnection c = connections.get(n.getNodeId());
        if (c == null) {
          connections.put(nodeId, c = new NodeConnection());
        }

        if (logger.isTraceEnabled()) {
          logger.trace(
              "[{}->{}] Connection state: {}",
              new Object[] {syncManager.getLocalNodeId(), nodeId, c.state});
        }
        if (c.state.equals(NodeConnectionState.NONE)) {
          if (logger.isDebugEnabled()) {
            logger.debug(
                "[{}->{}] Attempting connection {} {}",
                new Object[] {syncManager.getLocalNodeId(), nodeId, n.getHostname(), n.getPort()});
          }
          SocketAddress sa = new InetSocketAddress(n.getHostname(), n.getPort());
          c.pendingFuture = clientBootstrap.connect(sa);
          c.pendingFuture.addListener(new ConnectCFListener(n));
          c.state = NodeConnectionState.PENDING;
        }
      }
    }
  }
 /**
  * Add the node connection to the node connection map
  *
  * @param nodeId the node ID for the channel
  * @param channel the new channel
  */
 protected void nodeConnected(short nodeId, Channel channel) {
   logger.debug("[{}->{}] Connection established", syncManager.getLocalNodeId(), nodeId);
   synchronized (connections) {
     NodeConnection c = connections.get(nodeId);
     if (c == null) {
       connections.put(nodeId, c = new NodeConnection());
     }
     c.nodeChannel = channel;
     c.state = NodeConnectionState.CONNECTED;
   }
   clusterManager.connectionStateChange();
 }
    @Override
    public void operationComplete(ChannelFuture cf) throws Exception {
      if (!cf.isSuccess()) {
        synchronized (connections) {
          NodeConnection c = connections.remove(node.getNodeId());
          if (c != null) c.nuke();
          cf.getChannel().close();
        }

        String message = "[unknown error]";
        if (cf.isCancelled()) message = "Timed out on connect";
        if (cf.getCause() != null) message = cf.getCause().getMessage();
        logger.debug(
            "[{}->{}] Could not connect to RPC " + "node: {}",
            new Object[] {syncManager.getLocalNodeId(), node.getNodeId(), message});
      } else {
        logger.trace(
            "[{}->{}] Channel future successful", syncManager.getLocalNodeId(), node.getNodeId());
      }
    }
  /**
   * Remove the connection from the connection registry and clean up any remaining shrapnel
   *
   * @param nodeId
   */
  public void disconnectNode(short nodeId) {
    synchronized (connections) {
      Short n = Short.valueOf(nodeId);
      MessageWindow mw = messageWindows.get(n);
      if (mw != null) {
        mw.lock.lock();
        mw.disconnected = true;
        try {
          mw.full.signalAll();
          messageWindows.remove(n);
        } finally {
          mw.lock.unlock();
        }
      }

      NodeConnection nc = connections.get(nodeId);
      if (nc != null) {
        nc.nuke();
      }
      connections.remove(nodeId);
    }
    clusterManager.connectionStateChange();
  }