@Override
  public void handleAccepted(PaxosMessage proposal) {
    ensureSize(chosen, proposal.getInstanceNum() + 1); // Prevent NPE

    if (chosen.get(proposal.getInstanceNum()) != null)
      return; // Something has already been chosen so I dont care anymore.

    List<PaxosMessage> acceptedVotes = proposalAcceptedVotes.get(proposal.getInstanceNum());
    if (acceptedVotes == null) {
      acceptedVotes = new ArrayList<PaxosMessage>();
      acceptedVotes.add(proposal);
      proposalAcceptedVotes.put(proposal.getInstanceNum(), acceptedVotes);
    } else {
      for (PaxosMessage acceptedVote : acceptedVotes) {
        if (proposal.getProposerId() == acceptedVote.getProposerId())
          return; // This person is reaffirming their acceptance of this instances proposal.
      }
      acceptedVotes.add(proposal);
      proposalAcceptedVotes.put(proposal.getInstanceNum(), acceptedVotes);
    }
    // handle being chosen
    if (proposalAcceptedVotes.get(proposal.getInstanceNum()).size() >= serverSet.getQuorumSize()) {
      onChosen(proposal);
    }
  }
 public void messageReceived(IoSession ioSession, Object message) throws Exception {
   if (message instanceof DefaultPaxosMessage) {
     PaxosMessage paxosMessage = (DefaultPaxosMessage) message;
     switch (paxosMessage.getType()) {
       case PROPOSE:
         handlePropose(paxosMessage);
         break;
       case ACCEPTED:
         handleAccepted(paxosMessage);
         break;
       case PREPARE:
         handlePrepare(
             (Integer) paxosMessage.getValue(),
             paxosMessage.getProposerId()); // PSN and consensus instance dont matter
         break;
       case PREPARE_RESP:
         handlePrepareResponse(paxosMessage);
         break;
       case RECOVERY:
         handleRecovery(paxosMessage);
         break;
       case RECOVERY_RESP:
         handleRecoveryResponse(paxosMessage);
         break;
       case PING:
         if (paxosMessage.getProposerId() == getLeader()) // Leaders HeartBeat
         leaderLastHeard = new Date();
         else if (((Integer) paxosMessage.getValue())
             > preparedFor) { // I came alive and the leader is not who I thought.
           preparedFor = ((Integer) paxosMessage.getValue());
           handlePrepare(preparedFor, getLeader());
           sendRecovery();
         }
         break;
       default:
         throw new Exception(
             "received PaxosMessage of unknown type" + paxosMessage.getType().name());
     }
   } else if (message instanceof ChatMessage) { // Some client sent or some server forwarded.
     if (nodeIsLeader()) {
       propose(
           new DefaultPaxosMessage(
               nextInstance, nextPropose, id, PaxosMessageType.PROPOSE, (ChatMessage) message));
       nextInstance++;
     } else {
       sendToLeader((ChatMessage) message);
     }
   } else {
     throw new Exception("Unknown message type:" + message.getClass().getSimpleName());
   }
 }
  @Override
  public void handlePrepareResponse(PaxosMessage response) {
    if (!prepareResponseFrom.contains(response.getProposerId()))
      prepareResponseFrom.add(
          response.getProposerId()); // This is a new server accepted our prepare request.

    List<ChatMessage> remoteAccepted = (List<ChatMessage>) response.getValue();
    for (int i = 0; i < remoteAccepted.size(); i++) {
      if (chosen.size() > i && chosen.get(i) != null) continue;
      if (remoteAccepted.get(i) != null) {
        propose(
            new DefaultPaxosMessage(
                i, nextPropose, id, PaxosMessageType.PROPOSE, remoteAccepted.get(i)));
        if (i > nextInstance) nextInstance = i;
      }
    }
  }
 private void handleRecovery(PaxosMessage recoveryRequest) {
   PaxosMessage recoveryResponse =
       new DefaultPaxosMessage(-1, -1, id, PaxosMessageType.RECOVERY_RESP, chosen);
   sendMessage(recoveryResponse, recoveryRequest.getProposerId());
 }