private boolean sendView(GMSMembershipView<ID> view, boolean preparing,
      ViewReplyProcessor viewReplyProcessor)
      throws InterruptedException {

    int id = view.getViewId();
    InstallViewMessage<ID> msg = new InstallViewMessage<>(view,
        services.getAuthenticator().getCredentials(localAddress), preparing);
    List<ID> recips = new ArrayList<>(view.getMembers());

    // a recent member was seen not to receive a new view - I think this is why
    // recips.removeAll(newMembers); // new members get the view in a JoinResponseMessage
    recips.remove(localAddress); // no need to send it to ourselves

    List<ID> responders = recips;
    if (!view.getCrashedMembers().isEmpty()) {
      recips = new ArrayList<>(recips);
      recips.addAll(view.getCrashedMembers());
    }

    if (preparing) {
      preparedView = view;
    } else {
      // Added a check in the view processor to turn off the ViewCreator
      // if another server is the coordinator - GEODE-870
      ViewCreator thread = viewCreator;
      if (isCoordinator && !localAddress.equals(view.getCoordinator())
          && !localAddress.equals(view.getCreator())
          && thread != null) {
        thread.markViewCreatorForShutdown(view.getCoordinator());
        isCoordinator = false;
      }
      installView(new GMSMembershipView<>(view, view.getViewId()));
    }

    if (recips.isEmpty()) {
      if (!preparing) {
        logger.info("no recipients for new view aside from myself");
      }
      return true;
    }

    logger.info((preparing ? "preparing" : "sending") + " new view " + view);

    msg.setRecipients(recips);

    Set<ID> pendingLeaves = getPendingRequestIDs(LEAVE_REQUEST_MESSAGE);
    Set<ID> pendingRemovals = getPendingRequestIDs(REMOVE_MEMBER_REQUEST);
    pendingRemovals.removeAll(view.getCrashedMembers());
    viewReplyProcessor.initialize(id, new HashSet<>(responders));
    viewReplyProcessor.processPendingRequests(pendingLeaves, pendingRemovals);
    addPublicKeysToView(view);
    services.getMessenger().send(msg, view);

    // only wait for responses during preparation
    if (preparing) {
      logger.debug("waiting for view responses");

      Set<ID> failedToRespond = viewReplyProcessor.waitForResponses();

      logger.info("finished waiting for responses to view preparation");

      ID conflictingViewSender =
          viewReplyProcessor.getConflictingViewSender();
      GMSMembershipView<ID> conflictingView = viewReplyProcessor.getConflictingView();
      if (conflictingView != null) {
        logger.warn("received a conflicting membership view from " + conflictingViewSender
            + " during preparation: " + conflictingView);
        return false;
      }

      if (!failedToRespond.isEmpty() && (!services.getCancelCriterion().isCancelInProgress())) {
        logger.warn("these members failed to respond to the view change: " + failedToRespond);
        return false;
      }
    }

    return true;
  }
Transitions this member into the coordinator role. This must be invoked under a synch on
viewInstallationLock that was held at the time the decision was made to become coordinator so
that the decision is atomic with actually becoming coordinator.

@param oldCoordinator may be null
geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java