class Candidate extends AbstractRaftActorBehavior {

    @Override
    public RaftActorBehavior handleMessage(final ActorRef sender, final Object message) {
        if (message instanceof ElectionTimeout) {
            log.debug("{}: Received ElectionTimeout", logName());

            if (votesRequired == 0) {
                // If there are no peers then we should be a Leader
                // We wait for the election timeout to occur before declare
                // ourselves the leader. This gives enough time for a leader
                // who we do not know about (as a peer)
                // to send a message to the candidate

                return internalSwitchBehavior(RaftState.Leader);
            }

            startNewTerm();
            scheduleElection(electionDuration());
            return this;
        }

        if (message instanceof RaftRPC) {

            RaftRPC rpc = (RaftRPC) message;

            log.debug("{}: RaftRPC message received {}, my term is {}", logName(), rpc,
                        context.getTermInformation().getCurrentTerm());

            // If RPC request or response contains term T > currentTerm:
            // set currentTerm = T, convert to follower (§5.1)
            // This applies to all RPC messages and responses
            if (rpc.getTerm() > context.getTermInformation().getCurrentTerm()) {
                log.info("{}: Term {} in \"{}\" message is greater than Candidate's term {} - switching to Follower",
                        logName(), rpc.getTerm(), rpc, context.getTermInformation().getCurrentTerm());

                context.getTermInformation().updateAndPersist(rpc.getTerm(), null);

                // The raft paper does not say whether or not a Candidate can/should process a RequestVote in
                // this case but doing so gains quicker convergence when the sender's log is more up-to-date.
                if (message instanceof RequestVote) {
                    super.handleMessage(sender, message);
                }

                return internalSwitchBehavior(RaftState.Follower);
            }
        }

        return super.handleMessage(sender, message);
    }

    public  Candidate(final RaftActorContext context);

}