void createAndSendView(List<AbstractGMSMessage<ID>> requests)
        throws InterruptedException, ViewAbandonedException {
      List<ID> joinReqs = new ArrayList<>(10);
      Map<ID, Integer> joinPorts = new HashMap<>(10);
      Set<ID> leaveReqs = new HashSet<>(10);
      List<ID> removalReqs = new ArrayList<>(10);
      List<String> removalReasons = new ArrayList<>(10);

      GMSMembershipView<ID> oldView = currentView;
      List<ID> oldMembers;
      if (oldView != null) {
        oldMembers = new ArrayList<>(oldView.getMembers());
      } else {
        oldMembers = Collections.emptyList();
      }
      Set<ID> oldIDs = new HashSet<>();

      for (AbstractGMSMessage<ID> msg : requests) {
        logger.debug("processing request {}", msg);

        ID mbr;
        switch (msg.getDSFID()) {
          case JOIN_REQUEST:
            JoinRequestMessage<ID> jmsg = (JoinRequestMessage<ID>) msg;
            mbr = jmsg.getMemberID();
            int port = jmsg.getFailureDetectionPort();
            if (!joinReqs.contains(mbr)) {
              if (mbr.getVmViewId() >= 0 && oldMembers.contains(mbr)) {
                // already joined in a previous view
                logger.info("Ignoring join request from member {} who has already joined", mbr);
              } else {
                joinReqs.add(mbr);
                joinPorts.put(mbr, port);
                if (services.getConfig().isUDPSecurityEnabled() ||
                    services.getConfig().isMulticastEnabled()) {
                  // send a join response so the new member can get the multicast messaging digest
                  // and cluster key
                  JoinResponseMessage<ID> response = new JoinResponseMessage<>(jmsg.getSender(),
                      services.getMessenger().getClusterSecretKey(), jmsg.getRequestId());
                  services.getMessenger().send(response);
                }
              }
            }
            break;
          case LEAVE_REQUEST_MESSAGE:
            mbr = ((LeaveRequestMessage<ID>) msg).getMemberID();
            if (oldMembers.contains(mbr)) {
              leaveReqs.add(mbr);
            }
            break;
          case REMOVE_MEMBER_REQUEST:
            // process these after gathering all leave-requests so that
            // we don't kick out a member that's shutting down
            break;
          default:
            logger.warn("Unknown membership request encountered: {}", msg);
            break;
        }
      }

      for (AbstractGMSMessage<ID> msg : requests) {
        switch (msg.getDSFID()) {
          case REMOVE_MEMBER_REQUEST:
            ID mbr = ((RemoveMemberMessage<ID>) msg).getMemberID();
            if (!leaveReqs.contains(mbr)) {
              if (oldMembers.contains(mbr) && !removalReqs.contains(mbr)) {
                removalReqs.add(mbr);
                removalReasons.add(((RemoveMemberMessage<ID>) msg).getReason());
              } else {
                // unknown, probably rogue, process - send it a removal message
                sendRemoveMessages(Collections.singletonList(mbr),
                    Collections.singletonList(((RemoveMemberMessage<ID>) msg).getReason()),
                    new HashSet<>());
              }
            }
            break;
          default:
            break;
        }
      }

      for (ID mbr : oldIDs) {
        if (!leaveReqs.contains(mbr) && !removalReqs.contains(mbr)) {
          removalReqs.add(mbr);
          removalReasons.add("Removal of old ID that has been reused");
        }
      }

      if (removalReqs.isEmpty() && leaveReqs.isEmpty() && joinReqs.isEmpty()) {
        return;
      }

      GMSMembershipView<ID> newView;
      synchronized (viewInstallationLock) {
        int viewNumber = 0;
        List<ID> mbrs;
        if (currentView == null) {
          mbrs = new ArrayList<>();
        } else {
          viewNumber = currentView.getViewId() + 1;
          mbrs = new ArrayList<>(oldMembers);
        }
        mbrs.removeAll(leaveReqs);
        mbrs.removeAll(removalReqs);
        // add joinReqs after removing old members because an ID may
        // be reused in an auto-reconnect and get a new vmViewID
        mbrs.addAll(joinReqs);
        newView = new GMSMembershipView<>(localAddress, viewNumber, mbrs, leaveReqs,
            new HashSet<>(removalReqs));
        for (ID mbr : joinReqs) {
          if (mbrs.contains(mbr)) {
            newView.setFailureDetectionPort(mbr, joinPorts.get(mbr));
          }
        }
        if (currentView != null) {
          newView.setFailureDetectionPorts(currentView);
          newView.setPublicKeys(currentView);
        }
      }

      // if there are no membership changes then abort creation of
      // the new view
      if (joinReqs.isEmpty() && newView.getMembers().equals(currentView.getMembers())) {
        logger.info("membership hasn't changed - aborting new view {}", newView);
        return;
      }

      for (ID mbr : joinReqs) {
        if (mbr.getVmViewId() < 0) {
          mbr.setVmViewId(newView.getViewId());
        }
      }

      if (isShutdown()) {
        return;
      }

      // send removal messages before installing the view so we stop
      // getting messages from members that have been kicked out
      sendRemoveMessages(removalReqs, removalReasons, oldIDs);

      prepareAndSendView(newView, joinReqs, leaveReqs, newView.getCrashedMembers());

      return;
    }
Create a new membership view and send it to members (including crashed members). Returns
false if the view cannot be prepared successfully, true otherwise
geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java