//----------------------------------------------------------------
// Example 1: class embeds knowledge of every possible subclass
//----------------------------------------------------------------

public abstract class BaseMessage implements Serializable {
    ...
    
    /**
     * Note: If you define a new Message type, you must add a corresponding
     * entry to the MessageType enum.
     */
    public enum MessageType {
        APPEND_ENTRIES, APPEND_ENTRIES_RESPONSE,
        REQUEST_VOTE, REQUEST_VOTE_RESPONSE
    }
}

//----------------------------------------------------------------
// Example 2: pull related things together
//----------------------------------------------------------------

    // Value indicating that the vote for the current term is null.
    public static final int NOT_YET_VOTED = -1;

    // The filename that currentTerm and votedFor are persisted to
    private static final String TERM_VOTE_FILENAME = "term_vote.txt";

    // Latest term server has seen
    private int currentTerm;

    // Which serverId if any, the server voted for in currentTerm.
    private int votedFor;

//----------------------------------------------------------------
// Example 2': a better version
//----------------------------------------------------------------

    // The filename that currentTerm and votedFor are persisted to
    private static final String TERM_VOTE_FILENAME = "term_vote.txt";

    // Latest term server has seen
    private int currentTerm;

    // The serverId we voted for in currentTerm, or NOT_YET_VOTED if none.
    private int votedFor;
    public static final int NOT_YET_VOTED = -1;

//----------------------------------------------------------------
// Example 3: related things brought together
//----------------------------------------------------------------

public class Server {
    // The three types of states defined in Section 5.1 of the Raft paper
    private enum Role {
        LEADER, CANDIDATE, FOLLOWER
    }
    private Role role;

//----------------------------------------------------------------
// Example 4: argument parsing info spread out
//----------------------------------------------------------------


public class RaftMain {
    
    /**
     * Which command-line argument contains the local server's configuration
     * information.
     */
    private static final int SERVER_ARGUMENT_INDEX = 0;
    
    /**
     * The first command-line argument containing a remote server's
     * configuration information. All subsequent arguments also configure
     * remote servers.
     */
    private static final int PEER_ARGUMENTS_START_INDEX = 1;

...

    public static void main(String[] args) {
        ...
        
        Pair<Integer, Pair<InetAddress, Integer>> serverConfig =
                parseConfig(args[SERVER_ARGUMENT_INDEX]);
        ...
        ArrayList<RaftPeer> peers = createPeers(args);

...

    private static ArrayList<RaftPeer> createPeers(String[] args) {
        ArrayList<RaftPeer> peers = new ArrayList<RaftPeer>();
        for (int i = PEER_ARGUMENTS_START_INDEX; i < args.length; i++) {

//----------------------------------------------------------------
// Example 5: symbolic definition makes things obscure
//----------------------------------------------------------------
    
    /**
     *  Printed when command line arguments are incorrect.
     */
    private static final String USAGE = "Usage Error: Please invoke RaftServer"
            + " with the following arguments: "
            + "<IP_ADDRESS> <PORT> <CONFIG_FILE_PATH>.";

    ... much later ...

    public static void main(String[] args) {
        
        if(args.length != 3) {
            logger.log(Level.SEVERE, "Usage Error: " + USAGE);
            System.exit(1);
        }

//----------------------------------------------------------------
// Example T1: synchronization too granular
//----------------------------------------------------------------

    synchronized(this.status) {
        /* ensures that other reads of status, e.g. in requestVote,
         * would be blocked until we update status */
        this.status = citizenStatus.CANDIDATE;
    }
    synchronized(this.curTerm) {
        this.curTerm += 1;
        this.votedFor = this.myId; // voted for self
        this.updatePersistentStorage();
    }

//----------------------------------------------------------------
// Example T2: document synchronization strategy
//----------------------------------------------------------------

    //--------------------------------------------------------------------
    // Synchronization strategy:
    //
    // This class involves numerous threads and lots of opportunities for
    // concurrency and races. To simplify this, we use the RaftServer object
    // for synchronization, locking it at a very high level in top-level
    // handlers for RPC requests and responses. Thus, lower-level methods
    // can assume they have exclusive access. This works because all of the
    // request and response handlers complete fairly quickly.
    //--------------------------------------------------------------------

//----------------------------------------------------------------
// Example T3: timers add lots of code
//----------------------------------------------------------------
    stopHeartbeatTimer();
    stopElectionTimer();
    startElectionTimer();

//----------------------------------------------------------------
// Example E1: continuing after failure to write state
//----------------------------------------------------------------

    public static void store(ServerTermInfo info) {
        /* Opens a new BufferedWriter to filePath using charset and 
         * StandardOpenOptions create, write, and truncate. Writes info 
         * to file in one line, overwriting last line due to truncate 
         * existing open option.
         */
            try {
                    BufferedWriter writer = Files.newBufferedWriter(filePath, 
                            charset, 
                                    StandardOpenOption.CREATE,
                                    StandardOpenOption.WRITE,
                                    StandardOpenOption.TRUNCATE_EXISTING);
                    writer.write(info.toString());
                    writer.close();
            } catch (IOException e) {
                    logger.log(Level.SEVERE, "Error in writing to file "
                            + filePath + ". " + e.getMessage());
                    e.printStackTrace();
            }
    }

//----------------------------------------------------------------
// Example D1: Unnecessary info in interface documentation
//----------------------------------------------------------------

    /**
     * AppendEntriesRequest subclasses RPCMessage.
     * It includes the parameters: term, leaderId, and leaderCommit.
     */
    public class AppendEntriesRequest extends RPCMessage {

---------------------

    /**
     * Request should contain term and candidateId (the raftServerId) of 
     * the server that sent request.
     * Returns response with currentTerm and voteGranted boolean.
     * If term in request is less than currentTerm, voteGranted is false.
     * If term in request is greater than currentTerm, voteGranted is 
     * true and currentTerm is updated to match request.
     * Otherwise, if votedFor is null or equal to candidateId,
     * voteGranted is true.
     * 
     * @param  request  RequestVote request that was received
     */
    private void handleRequestVoteReq(RequestVoteRequest request) {

---------------------

    /**
     * Takes in a <code>Message</code> and performs updates and
     * sends messages related to leader election. Possible outcomes are:
     * 
     * <li>If the incoming message is a <code>RequestVoteResponse</code>,
     * update our state tracking whether we have won the election. If we have,
     * assume leadership and start sending heartbeats.</li>
     * 
     * <li>If the incoming message is a <code>RequestVoteRequest</code>, then
     * send a <code>RequestVoteResponse</code> with our vote.</li>
     * 
     * <li>If the incoming message is an <code>AppendEntriesRequest</code>
     * representing a heartbeat, send an <code>AppendEntriesResponse</code>.
     */
    public synchronized void handleMessage(Message message) {...

//----------------------------------------------------------------
// Example D2: does caller need to know all of this?
//----------------------------------------------------------------
    
    /**
     * Starts a timer on a separate thread that runs for a random time 
     * between MIN_ELECTION_TIME and MAX_ELECTION_TIME seconds.
     * Timer is reset if RaftServer has received a valid AppendEntries
     * request or granted vote to another RaftServer. Once time elapses,
     * RaftServer converts to candidate state and starts election.
     */
    private void startElectionTimer() {

//----------------------------------------------------------------
// Example D3: interface documentation too vague
//----------------------------------------------------------------

    **
     * Tries to send a buffer of data to a remote host.
     * 
     * @param receiver The remote host to send data to.
     * @param id The identifier to send with this message.
     * @param data The raw bytes to be sent.
     */
     public void trySendData(
             Pair<InetAddress, Integer> receiver,
             int id,
             ByteBuffer data
     ) {

//----------------------------------------------------------------
// Example D4: describes how used, not what it means
//----------------------------------------------------------------

    /* FOLLOWER VARIABLE: indicator variable that allows the Receiver and the 
     * PeriodicTasks thread to communicate about whether a heartbeat has been
     * received within the follower's election timeout window.
     * Toggled to TRUE when a valid heartbeat is received.
     * Toggled to FALSE when the election timeout window is reset. */
    private boolean receivedValidHeartbeat;

//----------------------------------------------------------------
// Example D5: not enough info (missing units, not precise enough)
//----------------------------------------------------------------

    /* Interval to retry sending RPCs. */
    private static final int RETRY_TIMEOUT = 10000;

//----------------------------------------------------------------
// Example D6: useless comments (obvious, duplicate code)
//----------------------------------------------------------------

    public ServerState(String ipString,
                       int port,
                       List<InetSocketAddress> clusterAddresses) {
        // This constructor is responsible for initializing each of the fields
        // in this ServerState class. See the documentation on each field for
        // what each is meant to do.

---------------------------

      /* The current role of the raft node (see RaftRole enum). */
      private RaftRole role;

---------------------------

    public Raft(Config config) throws StableStorageException {

        /* Initialization. */
        rpcManager = new RpcManager();
        timer = new Timer(true);
        timerHasExpired = new AtomicBoolean();
        logger = Logger.getLogger(Raft.class.getName());

---------------------------

    /* They are equal if they have the same hostname and port */
    NetworkAddress otherAddress = (NetworkAddress) obj;
    return otherAddress.getPort() == getPort() 
            && otherAddress.getHostname().equals(getHostname());

----------------------------

    // If channel is open, attempt write.
    if (channel.isOpen()) {
            // catch pending write exception and add to queue instead
            try {
                    channel.write(buffer, WRITE_TIMEOUT_SECONDS,
                            TimeUnit.SECONDS, attachment, writeHandler);

//----------------------------------------------------------------
// Example D7: documentation doesn't give good feel for class
//----------------------------------------------------------------

/**
 * RaftServer is a multi-threaded program that listens for incoming Raft RPCs.
 * For each incoming RPC, the thread passes the RPC to each logic module to
 * handle, and sends any messages back in parallel that those modules require
 * to be sent.  It also retries sending message requests until it receives
 * a response.
 * 
 * Thanks to http://cs.lmu.edu/~ray/notes/javanetexamples/ for code examples of
 * Java servers.
 */
public class RaftServer implements MessageSender {

//----------------------------------------------------------------
// Example M1: Pairs not a good idea (no abstraction)
//----------------------------------------------------------------

    /**
     * Associates a network address to an open socket channel so that multiple
     * channels are not opened for sending to the same end host.
     */
    private Map<Pair<InetAddress, Integer>, SocketChannel> sendingChannels;

    ...
    public RaftNetworkManager(
                Pair<InetAddress, Integer> serverNetworkAddress, 
                HashMap<Integer, RaftNetworkListener> networkListeners
        ) throws IOException {
        ...

        this.serverSocketChannel.socket().bind(
                new InetSocketAddress(
                        serverNetworkAddress.getKey(), 
                        serverNetworkAddress.getValue()
                )
        );

//----------------------------------------------------------------
// Example M2: ByteBuffer API: what does "flip" do? nb
//----------------------------------------------------------------

    SocketChannel connectionReadyForReading = 
            (SocketChannel)selectedChannel.channel();
    ByteBuffer readBuffer = buffers.get(connectionReadyForReading);
    connectionReadyForReading.read(
            readBuffer
    );
    // Resets the position in the buffer to zero.
    readBuffer.flip();
    // We need to have the message size and sender ID
    // before we can even see if this is a whole message.
    int bytesInBuffer = readBuffer.remaining();
    if (bytesInBuffer >= HEADER_SIZE) {
        int messageSize = readBuffer.getInt();
        int remoteID = readBuffer.getInt();
        if ((bytesInBuffer - HEADER_SIZE) < messageSize) {
            // Whole message isn't here yet, reset the buffer
            // and skip for now.
            int resetPosition = 
                    readBuffer.position() - HEADER_SIZE;
            readBuffer.position(resetPosition);
        } else {
            byte[] message = new byte[messageSize];
            readBuffer.get(message, 0, messageSize);
            ByteBuffer messageBuffer = ByteBuffer.wrap(
                    message
            );
            RaftNetworkListener peer = 
                    networkListeners.get(remoteID);
            peer.onNetworkDataReceived(messageBuffer);
            readBuffer.compact();
        }
    }