Many fixes, some are still only in temporary phase, according to what Arbel told me to do so far.
							parent
							
								
									c04ed42dca
								
							
						
					
					
						commit
						94f3920e6d
					
				| 
						 | 
					@ -0,0 +1,84 @@
 | 
				
			||||||
 | 
					package meerkat.voting.controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.protobuf.ByteString;
 | 
				
			||||||
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Created by hai on 18/05/16.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					final public class SystemMessages {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private SystemMessages() {
 | 
				
			||||||
 | 
					        // This is a static class. No instantiation of this is needed.
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static UIElement getWaitForCommitMessage() {
 | 
				
			||||||
 | 
					        return UIElement.newBuilder()
 | 
				
			||||||
 | 
					                .setType(UIElementDataType.TEXT)
 | 
				
			||||||
 | 
					                .setData(ByteString.copyFromUtf8("Please wait while committing to ballot"))
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static UIElement getWaitForAuditMessage() {
 | 
				
			||||||
 | 
					        return UIElement.newBuilder()
 | 
				
			||||||
 | 
					                .setType(UIElementDataType.TEXT)
 | 
				
			||||||
 | 
					                .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot"))
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static UIElement getWaitForCastMessage() {
 | 
				
			||||||
 | 
					        return UIElement.newBuilder()
 | 
				
			||||||
 | 
					                .setType(UIElementDataType.TEXT)
 | 
				
			||||||
 | 
					                .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting"))
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static UIElement getFatalForceRestartMessage() {
 | 
				
			||||||
 | 
					        return UIElement.newBuilder()
 | 
				
			||||||
 | 
					                .setType(UIElementDataType.TEXT)
 | 
				
			||||||
 | 
					                .setData(ByteString.copyFromUtf8("Fatal error: Internal controller queue received unrecognized command. Force restarting the voting process."))
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static UIElement getRestartVotingButton() {
 | 
				
			||||||
 | 
					        return UIElement.newBuilder()
 | 
				
			||||||
 | 
					                .setType(UIElementDataType.TEXT)
 | 
				
			||||||
 | 
					                .setData(ByteString.copyFromUtf8("Restart voting"))
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static UIElement getUnrecognizedFinalizeResponseMessage() {
 | 
				
			||||||
 | 
					        return UIElement.newBuilder()
 | 
				
			||||||
 | 
					                .setType(UIElementDataType.TEXT)
 | 
				
			||||||
 | 
					                .setData(ByteString.copyFromUtf8("Could not understand response for Cast or Audit. Force restarting."))
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static UIElement getUnsuccessfulChannelChoiceMessage() {
 | 
				
			||||||
 | 
					        return UIElement.newBuilder()
 | 
				
			||||||
 | 
					                .setType(UIElementDataType.TEXT)
 | 
				
			||||||
 | 
					                .setData(ByteString.copyFromUtf8("Choice of channel was unsuccessful. Force restarting."))
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static UIElement getOutputDeviceFailureMessage() {
 | 
				
			||||||
 | 
					        return UIElement.newBuilder()
 | 
				
			||||||
 | 
					                .setType(UIElementDataType.TEXT)
 | 
				
			||||||
 | 
					                .setData(ByteString.copyFromUtf8("Ballot output device failure. Force restarting."))
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static UIElement getUnsuccessfulVotingMessage() {
 | 
				
			||||||
 | 
					        return UIElement.newBuilder()
 | 
				
			||||||
 | 
					                .setType(UIElementDataType.TEXT)
 | 
				
			||||||
 | 
					                .setData(ByteString.copyFromUtf8("Voting was unsuccessful. Force restarting."))
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static UIElement getSomethingWrongMessage() {
 | 
				
			||||||
 | 
					        return UIElement.newBuilder()
 | 
				
			||||||
 | 
					                .setType(UIElementDataType.TEXT)
 | 
				
			||||||
 | 
					                .setData(ByteString.copyFromUtf8("Something was terribly wrong. Force restarting."))
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -8,12 +8,13 @@ import meerkat.voting.output.BallotOutputDevice;
 | 
				
			||||||
import meerkat.voting.storage.StorageManager;
 | 
					import meerkat.voting.storage.StorageManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * An interface for the controller component of the voting booth
 | 
					 * An interface for the controller component of the voting booth
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public interface VotingBoothController {
 | 
					public interface VotingBoothController extends Runnable{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * initialize by setting all the different components of the Voting Booth to be recognized by this controller
 | 
					     * initialize by setting all the different components of the Voting Booth to be recognized by this controller
 | 
				
			||||||
| 
						 | 
					@ -31,8 +32,7 @@ public interface VotingBoothController {
 | 
				
			||||||
     * set the voting questions
 | 
					     * set the voting questions
 | 
				
			||||||
     * @param questions
 | 
					     * @param questions
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void setBallotChannelChoiceQuestions(BallotQuestion[] questions);
 | 
					    public void setBallotChannelChoiceQuestions(List<BallotQuestion> questions);
 | 
				
			||||||
    public void setBallotChannelChoiceQuestions(ArrayList<BallotQuestion> questions);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Set the channel question-selector (the component which matches the ballot questions to each user)
 | 
					     * Set the channel question-selector (the component which matches the ballot questions to each user)
 | 
				
			||||||
| 
						 | 
					@ -44,18 +44,12 @@ public interface VotingBoothController {
 | 
				
			||||||
     * set the voting race questions
 | 
					     * set the voting race questions
 | 
				
			||||||
     * @param questions
 | 
					     * @param questions
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void setBallotRaceQuestions(BallotQuestion[] questions);
 | 
					    public void setBallotRaceQuestions(List<BallotQuestion> questions);
 | 
				
			||||||
    public void setBallotRaceQuestions(ArrayList<BallotQuestion> questions);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * a synchronous function. Starts running the controller component, and basically run the whole system for voting
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
    public void run ();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system
 | 
					     * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void shutDown();
 | 
					    public void callShutDown();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,20 +12,20 @@ import meerkat.voting.ui.VotingBoothUI;
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
					import java.util.concurrent.LinkedBlockingQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 28/03/16.
 | 
					 * Created by hai on 28/03/16.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class VotingBoothImpl implements VotingBoothController, Runnable {
 | 
					public class VotingBoothImpl implements VotingBoothController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private BallotOutputDevice outputDevice;
 | 
					    private BallotOutputDevice outputDevice;
 | 
				
			||||||
    private VotingBoothEncryptor encryptor;
 | 
					    private VotingBoothEncryptor encryptor;
 | 
				
			||||||
    private VotingBoothUI ui;
 | 
					    private VotingBoothUI ui;
 | 
				
			||||||
    private StorageManager storageManager;
 | 
					    private StorageManager storageManager;
 | 
				
			||||||
    private BallotQuestion[] questionsForChoosingChannel;
 | 
					    private List<BallotQuestion> questionsForChoosingChannel;
 | 
				
			||||||
    private BallotQuestion[] questions;
 | 
					    private List<BallotQuestion> questions;
 | 
				
			||||||
    private QuestionSelector questionSelector;
 | 
					    private QuestionSelector questionSelector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private LinkedBlockingQueue<ControllerCommand> queue;
 | 
					    private LinkedBlockingQueue<ControllerCommand> queue;
 | 
				
			||||||
| 
						 | 
					@ -33,38 +33,18 @@ public class VotingBoothImpl implements VotingBoothController, Runnable {
 | 
				
			||||||
    private Logger logger;
 | 
					    private Logger logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ControllerState state;
 | 
					    private ControllerState state;
 | 
				
			||||||
    private boolean shutDownHasBeenCalled;
 | 
					    private volatile boolean shutDownHasBeenCalled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected final int MAX_REQUEST_IDENTIFIER = 100000;
 | 
					    protected final int MAX_REQUEST_IDENTIFIER = 100000;
 | 
				
			||||||
    private static int requestCounter = 0;
 | 
					    private static int requestCounter = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private UIElement waitForCommitMessage;
 | 
					 | 
				
			||||||
    private UIElement waitForAuditMessage;
 | 
					 | 
				
			||||||
    private UIElement waitForCastMessage;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public VotingBoothImpl () {
 | 
					    public VotingBoothImpl () {
 | 
				
			||||||
        logger = LoggerFactory.getLogger(VotingBoothImpl.class);
 | 
					        logger = LoggerFactory.getLogger(VotingBoothImpl.class);
 | 
				
			||||||
        logger.info("A VotingBoothImpl is constructed");
 | 
					        logger.info("A VotingBoothImpl is constructed");
 | 
				
			||||||
        shutDownHasBeenCalled = false;
 | 
					        shutDownHasBeenCalled = false;
 | 
				
			||||||
        queue = new LinkedBlockingQueue<>();
 | 
					        queue = new LinkedBlockingQueue<>();
 | 
				
			||||||
 | 
					        state = new ControllerState();
 | 
				
			||||||
        waitForCommitMessage = UIElement.newBuilder()
 | 
					 | 
				
			||||||
                .setType(UIElementDataType.TEXT)
 | 
					 | 
				
			||||||
                .setData(ByteString.copyFromUtf8("Please wait while committing to ballot"))
 | 
					 | 
				
			||||||
                .build();
 | 
					 | 
				
			||||||
        waitForAuditMessage = UIElement.newBuilder()
 | 
					 | 
				
			||||||
                .setType(UIElementDataType.TEXT)
 | 
					 | 
				
			||||||
                .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot"))
 | 
					 | 
				
			||||||
                .build();
 | 
					 | 
				
			||||||
        waitForCastMessage = UIElement.newBuilder()
 | 
					 | 
				
			||||||
                .setType(UIElementDataType.TEXT)
 | 
					 | 
				
			||||||
                .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting"))
 | 
					 | 
				
			||||||
                .build();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        state = new VotingBoothImpl.ControllerState();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
| 
						 | 
					@ -80,42 +60,22 @@ public class VotingBoothImpl implements VotingBoothController, Runnable {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void setBallotChannelChoiceQuestions(BallotQuestion[] questions) {
 | 
					    public void setBallotChannelChoiceQuestions(List<BallotQuestion> questions) {
 | 
				
			||||||
        logger.info("setting questions");
 | 
					        logger.info("setting questions");
 | 
				
			||||||
        this.questionsForChoosingChannel = questions;
 | 
					        this.questionsForChoosingChannel = questions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void setBallotChannelChoiceQuestions(ArrayList<BallotQuestion> questions) {
 | 
					 | 
				
			||||||
        BallotQuestion[] bqArr = new BallotQuestion[questions.size()];
 | 
					 | 
				
			||||||
        for (int i = 0; i < bqArr.length; ++i) {
 | 
					 | 
				
			||||||
            bqArr[i] = questions.get(i);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        setBallotChannelChoiceQuestions(bqArr);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void setChannelQuestionSelector(QuestionSelector selector) {
 | 
					    public void setChannelQuestionSelector(QuestionSelector selector) {
 | 
				
			||||||
        this.questionSelector = selector;
 | 
					        this.questionSelector = selector;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void setBallotRaceQuestions(BallotQuestion[] questions) {
 | 
					    public void setBallotRaceQuestions(List<BallotQuestion> questions) {
 | 
				
			||||||
        logger.info("setting questions");
 | 
					        logger.info("setting questions");
 | 
				
			||||||
        this.questions = questions;
 | 
					        this.questions = questions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void setBallotRaceQuestions(ArrayList<BallotQuestion> questions) {
 | 
					 | 
				
			||||||
        // TODO: why does the toArray method not work??
 | 
					 | 
				
			||||||
        //BallotQuestion[] bqArr = (BallotQuestion[])(questions.toArray());
 | 
					 | 
				
			||||||
        BallotQuestion[] bqArr = new BallotQuestion[questions.size()];
 | 
					 | 
				
			||||||
        for (int i = 0; i < bqArr.length; ++i) {
 | 
					 | 
				
			||||||
            bqArr[i] = questions.get(i);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        setBallotRaceQuestions(bqArr);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void run() {
 | 
					    public void run() {
 | 
				
			||||||
        logger.info("run command has been called");
 | 
					        logger.info("run command has been called");
 | 
				
			||||||
| 
						 | 
					@ -124,17 +84,6 @@ public class VotingBoothImpl implements VotingBoothController, Runnable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void shutDown() {
 | 
					 | 
				
			||||||
        logger.info("shutDown command has been called");
 | 
					 | 
				
			||||||
        synchronized (this) {
 | 
					 | 
				
			||||||
            shutDownHasBeenCalled = true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void runVotingFlow () {
 | 
					    private void runVotingFlow () {
 | 
				
			||||||
        logger.info("entered the voting flow");
 | 
					        logger.info("entered the voting flow");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -151,64 +100,70 @@ public class VotingBoothImpl implements VotingBoothController, Runnable {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void doShutDown () {
 | 
					    @Override
 | 
				
			||||||
        logger.info("running shutDown");
 | 
					    public void callShutDown() {
 | 
				
			||||||
 | 
					        logger.info("callShutDown command has been called");
 | 
				
			||||||
 | 
					        shutDownHasBeenCalled = true;
 | 
				
			||||||
 | 
					        queue.clear();
 | 
				
			||||||
 | 
					        queue.add(new ShutDownCommand());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void handleSingleTask (ControllerCommand task) {
 | 
					    private void handleSingleTask (ControllerCommand task) {
 | 
				
			||||||
        if (task instanceof RestartVotingCommand) {
 | 
					        if (task.getBallotSerialNumber() != state.currentBallotSerialNumber && !(task instanceof RestartVotingCommand)) {
 | 
				
			||||||
            doRestartVoting ();
 | 
					            // probably an old command relating to some old ballot serial number. Simply log it and ignore it.
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (task.getBallotSerialNumber() != state.currentBallotSerialNumber) {
 | 
					 | 
				
			||||||
            String errorMessage = "handleSingleTask: received a task too old. " +
 | 
					            String errorMessage = "handleSingleTask: received a task too old. " +
 | 
				
			||||||
                    task.getBallotSerialNumber() + " " + state.currentBallotSerialNumber;
 | 
					                    task.getBallotSerialNumber() + " " + state.currentBallotSerialNumber;
 | 
				
			||||||
            logger.warn (errorMessage);
 | 
					            logger.debug(errorMessage);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (task instanceof CastCommand) {
 | 
					        if (task instanceof RestartVotingCommand) {
 | 
				
			||||||
            doCast();
 | 
					            doRestartVoting ();
 | 
				
			||||||
            return;
 | 
					        }
 | 
				
			||||||
 | 
					        else if (task instanceof CastCommand) {
 | 
				
			||||||
 | 
					            doFinalize(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (task instanceof AuditCommand) {
 | 
					        else if (task instanceof AuditCommand) {
 | 
				
			||||||
            doAudit();
 | 
					            doFinalize(true);
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (task instanceof ChannelChoiceCommand) {
 | 
					        else if (task instanceof ChannelChoiceCommand) {
 | 
				
			||||||
            doChooseChannel();
 | 
					            doChooseChannel();
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (task instanceof ChannelDeterminedCommand) {
 | 
					        else if (task instanceof ChannelDeterminedCommand) {
 | 
				
			||||||
            doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task);
 | 
					            doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task);
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (task instanceof EncryptAndCommitBallotCommand) {
 | 
					        else if (task instanceof EncryptAndCommitBallotCommand) {
 | 
				
			||||||
            doCommit ((EncryptAndCommitBallotCommand)task);
 | 
					            doCommit ((EncryptAndCommitBallotCommand)task);
 | 
				
			||||||
            return;
 | 
					        }
 | 
				
			||||||
 | 
					        else if (task instanceof ReportErrorCommand) {
 | 
				
			||||||
 | 
					            doReportErrorAndForceRestart((ReportErrorCommand)task);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (task instanceof ShutDownCommand) {
 | 
				
			||||||
 | 
					            // wasShutDownCalled is now true. Do nothing.
 | 
				
			||||||
 | 
					            // The program will not access the command queue anymore, and will exit normally
 | 
				
			||||||
 | 
					            if (!wasShutDownCalled()) {
 | 
				
			||||||
 | 
					                logger.warn("Received a ShutDownCommand command. At this point shutDownHasBeenCalled flag should have been True, but it's not...");
 | 
				
			||||||
 | 
					                shutDownHasBeenCalled = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            String errorMessage = "handleSingleTask: unknown type of ControllerCommand received: " +
 | 
					            logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName());
 | 
				
			||||||
                    task.getClass().getName();
 | 
					            doReportErrorAndForceRestart(SystemMessages.getSomethingWrongMessage());
 | 
				
			||||||
            logger.error(errorMessage);
 | 
					 | 
				
			||||||
            throw new RuntimeException(errorMessage);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    private boolean wasShutDownCalled () {
 | 
				
			||||||
    Map<string, funcImpl> taskHandlers = new Map<>() {
 | 
					 | 
				
			||||||
CaskTask.getClass().getName() : doCast(),
 | 
					 | 
				
			||||||
ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private synchronized boolean wasShutDownCalled () {
 | 
					 | 
				
			||||||
        return shutDownHasBeenCalled;
 | 
					        return shutDownHasBeenCalled;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void doShutDown () {
 | 
				
			||||||
 | 
					        logger.info("running callShutDown");
 | 
				
			||||||
 | 
					        state.clearPlaintext();
 | 
				
			||||||
 | 
					        state.clearCiphertext();
 | 
				
			||||||
 | 
					        state.stateIdentifier = VBState.SHUT_DOWN;
 | 
				
			||||||
 | 
					        //TODO: add commands to actually shut down the machine
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void doRestartVoting () {
 | 
					    private void doRestartVoting () {
 | 
				
			||||||
        queue.clear();
 | 
					        queue.clear();
 | 
				
			||||||
        state.clearPlaintext();
 | 
					        state.clearPlaintext();
 | 
				
			||||||
| 
						 | 
					@ -216,7 +171,22 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
 | 
				
			||||||
        state.stateIdentifier = VBState.NEW_VOTER;
 | 
					        state.stateIdentifier = VBState.NEW_VOTER;
 | 
				
			||||||
        state.currentBallotSerialNumber += 1;
 | 
					        state.currentBallotSerialNumber += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber , this.queue));
 | 
					        ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void doReportErrorAndForceRestart(ReportErrorCommand task) {
 | 
				
			||||||
 | 
					        doReportErrorAndForceRestart(task.getErrorMessage());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void doReportErrorAndForceRestart(UIElement errorMessage) {
 | 
				
			||||||
 | 
					        queue.clear();
 | 
				
			||||||
 | 
					        state.clearPlaintext();
 | 
				
			||||||
 | 
					        state.clearCiphertext();
 | 
				
			||||||
 | 
					        state.stateIdentifier = VBState.FATAL_ERROR_FORCE_NEW_VOTER;
 | 
				
			||||||
 | 
					        state.currentBallotSerialNumber += 1;
 | 
				
			||||||
 | 
					        ui.showErrorMessageWithButtons(errorMessage,
 | 
				
			||||||
 | 
					                new UIElement[]{SystemMessages.getRestartVotingButton()},
 | 
				
			||||||
 | 
					                new ErrorMessageRestartCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void doChooseChannel () {
 | 
					    private void doChooseChannel () {
 | 
				
			||||||
| 
						 | 
					@ -227,7 +197,7 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
 | 
				
			||||||
                    new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
					                    new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            logger.warn("doChooseChannel: current state is " + state.stateIdentifier);
 | 
					            logger.debug("doChooseChannel: current state is " + state.stateIdentifier);
 | 
				
			||||||
            // ignore this request
 | 
					            // ignore this request
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -236,15 +206,14 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
 | 
				
			||||||
        if (state.stateIdentifier == VBState.CHOOSE_CHANNEL) {
 | 
					        if (state.stateIdentifier == VBState.CHOOSE_CHANNEL) {
 | 
				
			||||||
            logger.debug("doing set channel and ask questions");
 | 
					            logger.debug("doing set channel and ask questions");
 | 
				
			||||||
            state.stateIdentifier = VBState.ANSWER_QUESTIONS;
 | 
					            state.stateIdentifier = VBState.ANSWER_QUESTIONS;
 | 
				
			||||||
            BallotAnswer[] channelChoiceAnswers = task.channelChoiceAnswers;
 | 
					            List<BallotAnswer> channelChoiceAnswers = task.channelChoiceAnswers;
 | 
				
			||||||
            state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers);
 | 
					            state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers);
 | 
				
			||||||
            state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(channelChoiceAnswers);
 | 
					            state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(channelChoiceAnswers);
 | 
				
			||||||
            state.stateIdentifier = VBState.ANSWER_QUESTIONS;
 | 
					 | 
				
			||||||
            ui.askVoterQuestions(state.channelSpecificQuestions,
 | 
					            ui.askVoterQuestions(state.channelSpecificQuestions,
 | 
				
			||||||
                    new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
					                    new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            logger.warn("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier);
 | 
					            logger.debug("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier);
 | 
				
			||||||
            // ignore this request
 | 
					            // ignore this request
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -254,10 +223,8 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
 | 
				
			||||||
        if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) {
 | 
					        if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) {
 | 
				
			||||||
            logger.debug("doing commit");
 | 
					            logger.debug("doing commit");
 | 
				
			||||||
            state.stateIdentifier = VBState.COMMITTING_TO_BALLOT;
 | 
					            state.stateIdentifier = VBState.COMMITTING_TO_BALLOT;
 | 
				
			||||||
            VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot);
 | 
					            setBallotData (task);
 | 
				
			||||||
            state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot();
 | 
					            ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCommitMessage(),
 | 
				
			||||||
            state.secrets = encryptionAndSecrets.getSecrets();
 | 
					 | 
				
			||||||
            ui.notifyVoterToWaitForFinish(waitForCommitMessage,
 | 
					 | 
				
			||||||
                    new WaitForFinishCallback(generateRequestIdentifier(),
 | 
					                    new WaitForFinishCallback(generateRequestIdentifier(),
 | 
				
			||||||
                            state.currentBallotSerialNumber,
 | 
					                            state.currentBallotSerialNumber,
 | 
				
			||||||
                            this.queue));
 | 
					                            this.queue));
 | 
				
			||||||
| 
						 | 
					@ -266,38 +233,38 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
 | 
				
			||||||
                    new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
					                    new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            logger.warn("doCommit: current state is " + state.stateIdentifier);
 | 
					            logger.debug("doCommit: current state is " + state.stateIdentifier);
 | 
				
			||||||
            // ignore this request
 | 
					            // ignore this request
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void setBallotData (EncryptAndCommitBallotCommand task) {
 | 
				
			||||||
 | 
					        state.plaintextBallot = PlaintextBallot.newBuilder()
 | 
				
			||||||
 | 
					                .setSerialNumber(task.getBallotSerialNumber())
 | 
				
			||||||
 | 
					                .addAllAnswers(task.getVotingAnswers())
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
 | 
					        VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot);
 | 
				
			||||||
 | 
					        state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot();
 | 
				
			||||||
 | 
					        state.secrets = encryptionAndSecrets.getSecrets();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void doAudit () {
 | 
					    private void doFinalize (boolean auditRequested) {
 | 
				
			||||||
        if (state.stateIdentifier == VBState.CAST_OR_AUDIT) {
 | 
					        if (state.stateIdentifier == VBState.CAST_OR_AUDIT) {
 | 
				
			||||||
            logger.debug("doing audit");
 | 
					            logger.debug("finalizing");
 | 
				
			||||||
            state.stateIdentifier = VBState.FINALIZING;
 | 
					            state.stateIdentifier = VBState.FINALIZING;
 | 
				
			||||||
 | 
					            ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(),
 | 
				
			||||||
 | 
					                    new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
				
			||||||
 | 
					            if (auditRequested) {
 | 
				
			||||||
                outputDevice.audit(state.secrets,
 | 
					                outputDevice.audit(state.secrets,
 | 
				
			||||||
                        new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
					                        new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
				
			||||||
            ui.notifyVoterToWaitForFinish(waitForAuditMessage,
 | 
					 | 
				
			||||||
                    new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else {
 | 
					            else {
 | 
				
			||||||
            logger.warn("doAudit: current state is " + state.stateIdentifier);
 | 
					 | 
				
			||||||
            // ignore this request
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void doCast () {
 | 
					 | 
				
			||||||
        if (state.stateIdentifier == VBState.CAST_OR_AUDIT) {
 | 
					 | 
				
			||||||
            logger.debug("casting ballot");
 | 
					 | 
				
			||||||
            state.stateIdentifier = VBState.FINALIZING;
 | 
					 | 
				
			||||||
                outputDevice.castBallot(
 | 
					                outputDevice.castBallot(
 | 
				
			||||||
                        new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
					                        new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
				
			||||||
            ui.notifyVoterToWaitForFinish(waitForCastMessage,
 | 
					            }
 | 
				
			||||||
                    new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            logger.warn("doCast: current state is " + state.stateIdentifier);
 | 
					            logger.debug("doFinalize: current state is " + state.stateIdentifier);
 | 
				
			||||||
            // ignore this request
 | 
					            // ignore this request
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -312,14 +279,16 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
 | 
				
			||||||
        ANSWER_QUESTIONS,
 | 
					        ANSWER_QUESTIONS,
 | 
				
			||||||
        COMMITTING_TO_BALLOT,
 | 
					        COMMITTING_TO_BALLOT,
 | 
				
			||||||
        CAST_OR_AUDIT,
 | 
					        CAST_OR_AUDIT,
 | 
				
			||||||
        FINALIZING
 | 
					        FINALIZING,
 | 
				
			||||||
 | 
					        FATAL_ERROR_FORCE_NEW_VOTER,
 | 
				
			||||||
 | 
					        SHUT_DOWN
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private class ControllerState {
 | 
					    private class ControllerState {
 | 
				
			||||||
        public VotingBoothImpl.VBState stateIdentifier;
 | 
					        public VBState stateIdentifier;
 | 
				
			||||||
        public int channelIdentifier;
 | 
					        public int channelIdentifier;
 | 
				
			||||||
        public BallotQuestion[] channelSpecificQuestions;
 | 
					        public List<BallotQuestion> channelSpecificQuestions;
 | 
				
			||||||
        public PlaintextBallot plaintextBallot;
 | 
					        public PlaintextBallot plaintextBallot;
 | 
				
			||||||
        public EncryptedBallot encryptedBallot;
 | 
					        public EncryptedBallot encryptedBallot;
 | 
				
			||||||
        public BallotSecrets secrets;
 | 
					        public BallotSecrets secrets;
 | 
				
			||||||
| 
						 | 
					@ -338,12 +307,10 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void clearPlaintext () {
 | 
					        public void clearPlaintext () {
 | 
				
			||||||
            //TODO: Do we need safe erasure?
 | 
					 | 
				
			||||||
            plaintextBallot = null;
 | 
					            plaintextBallot = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void clearCiphertext () {
 | 
					        public void clearCiphertext () {
 | 
				
			||||||
            //TODO: Do we need safe erasure?
 | 
					 | 
				
			||||||
            encryptedBallot = null;
 | 
					            encryptedBallot = null;
 | 
				
			||||||
            secrets = null;
 | 
					            secrets = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
package meerkat.voting.controller.callbacks;
 | 
					package meerkat.voting.controller.callbacks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import meerkat.voting.controller.SystemMessages;
 | 
				
			||||||
import meerkat.voting.controller.commands.*;
 | 
					import meerkat.voting.controller.commands.*;
 | 
				
			||||||
import meerkat.voting.controller.commands.ControllerCommand;
 | 
					import meerkat.voting.controller.commands.ControllerCommand;
 | 
				
			||||||
import meerkat.voting.controller.commands.RestartVotingCommand;
 | 
					import meerkat.voting.controller.commands.RestartVotingCommand;
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
					import java.util.concurrent.LinkedBlockingQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class CastOrAuditCallback extends ControllerCallback {
 | 
					public class CastOrAuditCallback extends ControllerCallback<FinalizeBallotChoice> {
 | 
				
			||||||
    protected final static Logger logger = LoggerFactory.getLogger(CastOrAuditCallback.class);
 | 
					    protected final static Logger logger = LoggerFactory.getLogger(CastOrAuditCallback.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public CastOrAuditCallback(int requestId,
 | 
					    public CastOrAuditCallback(int requestId,
 | 
				
			||||||
| 
						 | 
					@ -20,18 +20,18 @@ public class CastOrAuditCallback extends ControllerCallback {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onSuccess(Object result) {
 | 
					    public void onSuccess(FinalizeBallotChoice result) {
 | 
				
			||||||
        assert (result instanceof FinalizeBallotChoice);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (result == FinalizeBallotChoice.CAST) {
 | 
					        if (result == FinalizeBallotChoice.CAST) {
 | 
				
			||||||
            controllerQueue.add(new CastCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					            enqueueCommand(new CastCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (result == FinalizeBallotChoice.AUDIT) {
 | 
					        else if (result == FinalizeBallotChoice.AUDIT) {
 | 
				
			||||||
            controllerQueue.add(new AuditCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					            enqueueCommand(new AuditCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            logger.error("CastOrAuditCallback got an unrecognized response: " + result);
 | 
					            logger.error("CastOrAuditCallback got an unrecognized response: " + result);
 | 
				
			||||||
            controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					            enqueueCommand(new ReportErrorCommand(getRequestIdentifier(),
 | 
				
			||||||
 | 
					                    getBallotSerialNumber(),
 | 
				
			||||||
 | 
					                    SystemMessages.getUnrecognizedFinalizeResponseMessage()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,9 @@ public class CastOrAuditCallback extends ControllerCallback {
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onFailure(Throwable t) {
 | 
					    public void onFailure(Throwable t) {
 | 
				
			||||||
        logger.error("CastOrAuditCallback got a failure: " + t);
 | 
					        logger.error("CastOrAuditCallback got a failure: " + t);
 | 
				
			||||||
        controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					        enqueueCommand(new ReportErrorCommand(getRequestIdentifier(),
 | 
				
			||||||
 | 
					                getBallotSerialNumber(),
 | 
				
			||||||
 | 
					                SystemMessages.getUnrecognizedFinalizeResponseMessage()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,18 +1,18 @@
 | 
				
			||||||
package meerkat.voting.controller.callbacks;
 | 
					package meerkat.voting.controller.callbacks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.protobuf.Voting;
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
import meerkat.voting.controller.commands.ChannelDeterminedCommand;
 | 
					import meerkat.voting.controller.SystemMessages;
 | 
				
			||||||
import meerkat.voting.controller.commands.ControllerCommand;
 | 
					import meerkat.voting.controller.commands.*;
 | 
				
			||||||
import meerkat.voting.controller.commands.RestartVotingCommand;
 | 
					 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
					import java.util.concurrent.LinkedBlockingQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 11/04/16.
 | 
					 * Created by hai on 11/04/16.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class ChannelChoiceCallback extends ControllerCallback {
 | 
					public class ChannelChoiceCallback extends ControllerCallback<List<BallotAnswer>> {
 | 
				
			||||||
    protected final static Logger logger = LoggerFactory.getLogger(ChannelChoiceCallback.class);
 | 
					    protected final static Logger logger = LoggerFactory.getLogger(ChannelChoiceCallback.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ChannelChoiceCallback(int requestId,
 | 
					    public ChannelChoiceCallback(int requestId,
 | 
				
			||||||
| 
						 | 
					@ -22,22 +22,22 @@ public class ChannelChoiceCallback extends ControllerCallback {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onSuccess(Object result) {
 | 
					    public void onSuccess(List<BallotAnswer> result) {
 | 
				
			||||||
        assert (result instanceof Voting.BallotAnswer[]);
 | 
					        if (result.size() != 0) {
 | 
				
			||||||
        if (((Voting.BallotAnswer[])result).length != 0) {
 | 
					 | 
				
			||||||
            logger.debug("callback for channel choice returned success");
 | 
					            logger.debug("callback for channel choice returned success");
 | 
				
			||||||
            controllerQueue.add(
 | 
					            enqueueCommand(new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), result));
 | 
				
			||||||
                    new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result));
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            logger.debug("ChannelChoiceCallback got a cancellation response: " + result);
 | 
					            logger.debug("ChannelChoiceCallback got a cancellation response: " + result);
 | 
				
			||||||
            controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					            enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onFailure(Throwable t) {
 | 
					    public void onFailure(Throwable t) {
 | 
				
			||||||
        logger.error("channel choice initiated a failure: " + t);
 | 
					        logger.error("channel choice initiated a failure: " + t);
 | 
				
			||||||
        controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					        enqueueCommand(new ReportErrorCommand(getRequestIdentifier(),
 | 
				
			||||||
 | 
					                getBallotSerialNumber(),
 | 
				
			||||||
 | 
					                SystemMessages.getUnsuccessfulChannelChoiceMessage()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,18 @@
 | 
				
			||||||
package meerkat.voting.controller.callbacks;
 | 
					package meerkat.voting.controller.callbacks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Created by hai on 18/05/16.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
import com.google.common.util.concurrent.FutureCallback;
 | 
					import com.google.common.util.concurrent.FutureCallback;
 | 
				
			||||||
import meerkat.voting.controller.commands.ControllerCommand;
 | 
					import meerkat.voting.controller.commands.ControllerCommand;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
					import java.util.concurrent.LinkedBlockingQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public abstract class ControllerCallback implements FutureCallback {
 | 
					public abstract class ControllerCallback<T> implements FutureCallback<T> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final int requestIdentifier;
 | 
					    private final int requestIdentifier;
 | 
				
			||||||
    private final long ballotSerialNumber;
 | 
					    private final long ballotSerialNumber;
 | 
				
			||||||
    protected LinkedBlockingQueue<ControllerCommand> controllerQueue;
 | 
					    private LinkedBlockingQueue<ControllerCommand> controllerQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected ControllerCallback (int requestId,
 | 
					    protected ControllerCallback (int requestId,
 | 
				
			||||||
                                  long ballotSerialNumber,
 | 
					                                  long ballotSerialNumber,
 | 
				
			||||||
| 
						 | 
					@ -21,7 +25,13 @@ public abstract class ControllerCallback implements FutureCallback {
 | 
				
			||||||
    protected int getRequestIdentifier () {
 | 
					    protected int getRequestIdentifier () {
 | 
				
			||||||
        return requestIdentifier;
 | 
					        return requestIdentifier;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected long getBallotSerialNumber () {
 | 
					    protected long getBallotSerialNumber () {
 | 
				
			||||||
        return ballotSerialNumber;
 | 
					        return ballotSerialNumber;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected void enqueueCommand (ControllerCommand command) {
 | 
				
			||||||
 | 
					        controllerQueue.add(command);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					package meerkat.voting.controller.callbacks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import meerkat.voting.controller.commands.ControllerCommand;
 | 
				
			||||||
 | 
					import meerkat.voting.controller.commands.RestartVotingCommand;
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.concurrent.LinkedBlockingQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ErrorMessageRestartCallback extends ControllerCallback<Integer> {
 | 
				
			||||||
 | 
					    protected final static Logger logger = LoggerFactory.getLogger(ErrorMessageRestartCallback.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ErrorMessageRestartCallback(int requestId,
 | 
				
			||||||
 | 
					                                       long ballotSerialNumber,
 | 
				
			||||||
 | 
					                                       LinkedBlockingQueue<ControllerCommand> controllerQueue) {
 | 
				
			||||||
 | 
					        super(requestId, ballotSerialNumber, controllerQueue);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onSuccess(Integer result) {
 | 
				
			||||||
 | 
					        enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onFailure(Throwable t) {
 | 
				
			||||||
 | 
					        logger.error("Error message execution initiated a failure: " + t);
 | 
				
			||||||
 | 
					        enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,32 +0,0 @@
 | 
				
			||||||
package meerkat.voting.controller.callbacks;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import meerkat.voting.controller.commands.ControllerCommand;
 | 
					 | 
				
			||||||
import org.slf4j.Logger;
 | 
					 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Created by hai on 21/04/16.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class HaltCallback extends ControllerCallback{
 | 
					 | 
				
			||||||
    protected final static Logger logger = LoggerFactory.getLogger(HaltCallback.class);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public HaltCallback(int requestId,
 | 
					 | 
				
			||||||
                        long ballotSerialNumber,
 | 
					 | 
				
			||||||
                        LinkedBlockingQueue<ControllerCommand> controllerQueue) {
 | 
					 | 
				
			||||||
        super(requestId, ballotSerialNumber, controllerQueue);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void onSuccess(Object result) {
 | 
					 | 
				
			||||||
        throw new UnsupportedOperationException("HaltCallback: onSuccess: There cannot be a successful return for this task. Returned value is " + result);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void onFailure(Throwable t) {
 | 
					 | 
				
			||||||
        logger.error("Halting initiated a failure: " + t);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
					import java.util.concurrent.LinkedBlockingQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class NewVoterCallback extends ControllerCallback {
 | 
					public class NewVoterCallback extends ControllerCallback<Void> {
 | 
				
			||||||
    protected final static Logger logger = LoggerFactory.getLogger(NewVoterCallback.class);
 | 
					    protected final static Logger logger = LoggerFactory.getLogger(NewVoterCallback.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public NewVoterCallback(int requestId,
 | 
					    public NewVoterCallback(int requestId,
 | 
				
			||||||
| 
						 | 
					@ -18,15 +18,14 @@ public class NewVoterCallback extends ControllerCallback {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onSuccess(Object v) {
 | 
					    public void onSuccess(Void v) {
 | 
				
			||||||
        logger.debug("callback for new voting returned success");
 | 
					        logger.debug("callback for new voting returned success");
 | 
				
			||||||
        assert v==null;
 | 
					        enqueueCommand(new ChannelChoiceCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
				
			||||||
        controllerQueue.add(new ChannelChoiceCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onFailure(Throwable t) {
 | 
					    public void onFailure(Throwable t) {
 | 
				
			||||||
        logger.error("New voting session got a failure: " + t);
 | 
					        logger.error("New voting session got a failure: " + t);
 | 
				
			||||||
        controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					        enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,15 @@
 | 
				
			||||||
package meerkat.voting.controller.callbacks;
 | 
					package meerkat.voting.controller.callbacks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import meerkat.voting.controller.SystemMessages;
 | 
				
			||||||
import meerkat.voting.controller.commands.ControllerCommand;
 | 
					import meerkat.voting.controller.commands.ControllerCommand;
 | 
				
			||||||
 | 
					import meerkat.voting.controller.commands.ReportErrorCommand;
 | 
				
			||||||
import meerkat.voting.controller.commands.RestartVotingCommand;
 | 
					import meerkat.voting.controller.commands.RestartVotingCommand;
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
					import java.util.concurrent.LinkedBlockingQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class OutputDeviceCallback extends ControllerCallback {
 | 
					public class OutputDeviceCallback extends ControllerCallback<Void> {
 | 
				
			||||||
    protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCallback.class);
 | 
					    protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCallback.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public OutputDeviceCallback(int requestId,
 | 
					    public OutputDeviceCallback(int requestId,
 | 
				
			||||||
| 
						 | 
					@ -17,13 +19,14 @@ public class OutputDeviceCallback extends ControllerCallback {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onSuccess(Object v) {
 | 
					    public void onSuccess(Void v) {
 | 
				
			||||||
        assert v instanceof Void;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onFailure(Throwable t) {
 | 
					    public void onFailure(Throwable t) {
 | 
				
			||||||
        logger.error("WaitForFinishCallback got a failure: " + t);
 | 
					        logger.error("WaitForFinishCallback got a failure: " + t);
 | 
				
			||||||
        controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					        enqueueCommand(new ReportErrorCommand(getRequestIdentifier(),
 | 
				
			||||||
 | 
					                getBallotSerialNumber(),
 | 
				
			||||||
 | 
					                SystemMessages.getOutputDeviceFailureMessage()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,18 @@
 | 
				
			||||||
package meerkat.voting.controller.callbacks;
 | 
					package meerkat.voting.controller.callbacks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.protobuf.Voting;
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
 | 
					import meerkat.voting.controller.SystemMessages;
 | 
				
			||||||
import meerkat.voting.controller.commands.ControllerCommand;
 | 
					import meerkat.voting.controller.commands.ControllerCommand;
 | 
				
			||||||
import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand;
 | 
					import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand;
 | 
				
			||||||
 | 
					import meerkat.voting.controller.commands.ReportErrorCommand;
 | 
				
			||||||
import meerkat.voting.controller.commands.RestartVotingCommand;
 | 
					import meerkat.voting.controller.commands.RestartVotingCommand;
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
					import java.util.concurrent.LinkedBlockingQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class VotingCallback extends ControllerCallback {
 | 
					public class VotingCallback extends ControllerCallback<List<BallotAnswer>> {
 | 
				
			||||||
    protected final static Logger logger = LoggerFactory.getLogger(VotingCallback.class);
 | 
					    protected final static Logger logger = LoggerFactory.getLogger(VotingCallback.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public VotingCallback(int requestId,
 | 
					    public VotingCallback(int requestId,
 | 
				
			||||||
| 
						 | 
					@ -19,22 +22,22 @@ public class VotingCallback extends ControllerCallback {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onSuccess(Object result) {
 | 
					    public void onSuccess(List<BallotAnswer> result) {
 | 
				
			||||||
        assert result instanceof Voting.BallotAnswer[];
 | 
					        if (result.size() != 0) {
 | 
				
			||||||
        if (((Voting.BallotAnswer[])result).length != 0) {
 | 
					 | 
				
			||||||
            logger.debug("callback for voting returned success");
 | 
					            logger.debug("callback for voting returned success");
 | 
				
			||||||
            controllerQueue.add(
 | 
					            enqueueCommand(new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), result));
 | 
				
			||||||
                    new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result));
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            logger.debug("VotingCallback got a cancellation response: " + result);
 | 
					            logger.debug("VotingCallback got a cancellation response: " + result);
 | 
				
			||||||
            controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					            enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onFailure(Throwable t) {
 | 
					    public void onFailure(Throwable t) {
 | 
				
			||||||
        logger.error("voting initiated a failure: " + t);
 | 
					        logger.error("voting initiated a failure: " + t);
 | 
				
			||||||
        controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					        enqueueCommand(new ReportErrorCommand(getRequestIdentifier(),
 | 
				
			||||||
 | 
					                getBallotSerialNumber(),
 | 
				
			||||||
 | 
					                SystemMessages.getUnsuccessfulVotingMessage()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,15 @@
 | 
				
			||||||
package meerkat.voting.controller.callbacks;
 | 
					package meerkat.voting.controller.callbacks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import meerkat.voting.controller.SystemMessages;
 | 
				
			||||||
import meerkat.voting.controller.commands.ControllerCommand;
 | 
					import meerkat.voting.controller.commands.ControllerCommand;
 | 
				
			||||||
 | 
					import meerkat.voting.controller.commands.ReportErrorCommand;
 | 
				
			||||||
import meerkat.voting.controller.commands.RestartVotingCommand;
 | 
					import meerkat.voting.controller.commands.RestartVotingCommand;
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
					import java.util.concurrent.LinkedBlockingQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class WaitForFinishCallback extends ControllerCallback {
 | 
					public class WaitForFinishCallback extends ControllerCallback<Void> {
 | 
				
			||||||
    protected final static Logger logger = LoggerFactory.getLogger(WaitForFinishCallback.class);
 | 
					    protected final static Logger logger = LoggerFactory.getLogger(WaitForFinishCallback.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public WaitForFinishCallback(int requestId,
 | 
					    public WaitForFinishCallback(int requestId,
 | 
				
			||||||
| 
						 | 
					@ -17,13 +19,14 @@ public class WaitForFinishCallback extends ControllerCallback {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onSuccess(Object v) {
 | 
					    public void onSuccess(Void v) {
 | 
				
			||||||
        assert v instanceof Void;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onFailure(Throwable t) {
 | 
					    public void onFailure(Throwable t) {
 | 
				
			||||||
        logger.error("WaitForFinishCallback got a failure: " + t);
 | 
					        logger.error("WaitForFinishCallback got a failure: " + t);
 | 
				
			||||||
        controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
 | 
					        enqueueCommand(new ReportErrorCommand(getRequestIdentifier(),
 | 
				
			||||||
 | 
					                getBallotSerialNumber(),
 | 
				
			||||||
 | 
					                SystemMessages.getSomethingWrongMessage()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,15 @@
 | 
				
			||||||
package meerkat.voting.controller.commands;
 | 
					package meerkat.voting.controller.commands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.protobuf.Voting;
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 11/04/16.
 | 
					 * Created by hai on 11/04/16.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class ChannelDeterminedCommand extends ControllerCommand {
 | 
					public class ChannelDeterminedCommand extends ControllerCommand {
 | 
				
			||||||
    public Voting.BallotAnswer[] channelChoiceAnswers;
 | 
					    public List<BallotAnswer> channelChoiceAnswers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ChannelDeterminedCommand(int requestIdentifier, long ballotSerialNumber, Voting.BallotAnswer[] answers) {
 | 
					    public ChannelDeterminedCommand(int requestIdentifier, long ballotSerialNumber, List<BallotAnswer> answers) {
 | 
				
			||||||
        super(requestIdentifier, ballotSerialNumber);
 | 
					        super(requestIdentifier, ballotSerialNumber);
 | 
				
			||||||
        channelChoiceAnswers = answers;
 | 
					        channelChoiceAnswers = answers;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,18 @@
 | 
				
			||||||
package meerkat.voting.controller.commands;
 | 
					package meerkat.voting.controller.commands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.protobuf.Voting;
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class EncryptAndCommitBallotCommand extends ControllerCommand {
 | 
					public class EncryptAndCommitBallotCommand extends ControllerCommand {
 | 
				
			||||||
    public Voting.BallotAnswer[] votingAnswers;
 | 
					    private final List<BallotAnswer> votingAnswers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public EncryptAndCommitBallotCommand(int requestIdentifier, long ballotSerialNumber, Voting.BallotAnswer[] answers) {
 | 
					    public EncryptAndCommitBallotCommand(int requestIdentifier, long ballotSerialNumber, List<BallotAnswer> answers) {
 | 
				
			||||||
        super(requestIdentifier, ballotSerialNumber);
 | 
					        super(requestIdentifier, ballotSerialNumber);
 | 
				
			||||||
        votingAnswers = answers;
 | 
					        votingAnswers = answers;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public List<BallotAnswer> getVotingAnswers() {
 | 
				
			||||||
 | 
					        return votingAnswers;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					package meerkat.voting.controller.commands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ReportErrorCommand extends ControllerCommand {
 | 
				
			||||||
 | 
					    private final UIElement errorMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ReportErrorCommand(int requestIdentifier, long ballotSerialNumber, UIElement errorMessage) {
 | 
				
			||||||
 | 
					        super(requestIdentifier, ballotSerialNumber);
 | 
				
			||||||
 | 
					        this.errorMessage = errorMessage;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UIElement getErrorMessage() {
 | 
				
			||||||
 | 
					        return errorMessage;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					package meerkat.voting.controller.commands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Created by hai on 11/04/16.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ShutDownCommand extends ControllerCommand {
 | 
				
			||||||
 | 
					    public ShutDownCommand() {
 | 
				
			||||||
 | 
					        super(0, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,20 +1,18 @@
 | 
				
			||||||
package meerkat.voting.controller.selector;
 | 
					package meerkat.voting.controller.selector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.protobuf.Voting.*;
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 02/05/16.
 | 
					 * Created by hai on 02/05/16.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract class QuestionSelector {
 | 
					public interface QuestionSelector {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected Object selectionData;
 | 
					    public void setAllBallotQuestions (List<BallotQuestion> allBallotQuestions);
 | 
				
			||||||
    protected BallotQuestion[] allBallotQuestions;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public QuestionSelector(Object selectionData, BallotQuestion[] allBallotQuestions) {
 | 
					    public void setSelectionData(SelectionData data);
 | 
				
			||||||
        this.selectionData = selectionData;
 | 
					 | 
				
			||||||
        this.allBallotQuestions = allBallotQuestions;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public abstract int getChannelIdentifier (BallotAnswer[] channelChoiceAnswers);
 | 
					    public int getChannelIdentifier (List<BallotAnswer> channelChoiceAnswers);
 | 
				
			||||||
    public abstract BallotQuestion[] selectQuestionsForVoter (BallotAnswer[] channelChoiceAnswers);
 | 
					
 | 
				
			||||||
 | 
					    public List<BallotQuestion> selectQuestionsForVoter (List<BallotAnswer> channelChoiceAnswers);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					package meerkat.voting.controller.selector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Created by hai on 11/05/16.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SelectionData {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,39 +1,60 @@
 | 
				
			||||||
package meerkat.voting.controller.selector;
 | 
					package meerkat.voting.controller.selector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.HashMap;
 | 
					 | 
				
			||||||
import java.lang.Math;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 02/05/16.
 | 
					 * This class is the SelectionData used to initialize a SimpleListCategoriesSelector.
 | 
				
			||||||
 | 
					 * It holds a table of question categories.
 | 
				
			||||||
 | 
					 * Every answer in the channel choice phase dictates a category of questions to include in the ballot.
 | 
				
			||||||
 | 
					 * This class is simply only the data class of these categories.
 | 
				
			||||||
 | 
					 * Specifically the questionSelectionsByAnswer member is this categories table:
 | 
				
			||||||
 | 
					 * questionSelectionsByAnswer[questionNumber][answerNumber] is an array of question indices to include in ballot
 | 
				
			||||||
 | 
					 * whenever the voter answered answerNumber on question questionNumber in the channel choice phase.
 | 
				
			||||||
 | 
					 * Also the sharedDefaults member is a category of question indices to include for EVERY voter,
 | 
				
			||||||
 | 
					 * regardless of his channel choice answers
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class SimpleCategoriesData {
 | 
					public class SimpleCategoriesData extends SelectionData{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private int[] sharedDefaults;
 | 
					    private int[] sharedDefaults;  // a category of questions to include for every voter
 | 
				
			||||||
    private HashMap<SingleChosenAnswer, int[]> questionsSelections;
 | 
					    // the categories
 | 
				
			||||||
 | 
					    // first index is the question number, the second is the answer number. the value is an array of question indices in this category
 | 
				
			||||||
 | 
					    private int[][][] questionSelectionsByAnswer;
 | 
				
			||||||
    private int maxQuestionNumber;
 | 
					    private int maxQuestionNumber;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public SimpleCategoriesData() {
 | 
					    public SimpleCategoriesData() {
 | 
				
			||||||
        sharedDefaults = new int[0];
 | 
					        sharedDefaults = new int[0];
 | 
				
			||||||
        questionsSelections = new HashMap();
 | 
					        questionSelectionsByAnswer = new int[0][][];
 | 
				
			||||||
        maxQuestionNumber = -1;
 | 
					        maxQuestionNumber = -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setSharedDefaults(int[] sharedDefaultsIndices) {
 | 
					    public void setSharedDefaults(int[] sharedDefaultsIndices) {
 | 
				
			||||||
        this.sharedDefaults = sharedDefaultsIndices;
 | 
					        this.sharedDefaults = sharedDefaultsIndices.clone();
 | 
				
			||||||
        maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(sharedDefaultsIndices));
 | 
					        maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(sharedDefaultsIndices));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public int[] getSharedDefaults() {
 | 
					    public int[] getSharedDefaults() {
 | 
				
			||||||
        return sharedDefaults;
 | 
					        return sharedDefaults;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setItem(SingleChosenAnswer key, int[] questionIndices) {
 | 
					    public void setItem(int questionNumber, int answerNumber, int[] questionIndices) {
 | 
				
			||||||
        questionsSelections.put(key, questionIndices);
 | 
					        if (questionNumber >= questionSelectionsByAnswer.length) {
 | 
				
			||||||
        maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(questionIndices));
 | 
					            int[][][] tmp = new int[questionNumber+1][][];
 | 
				
			||||||
 | 
					            System.arraycopy(questionSelectionsByAnswer, 0, tmp, 0, questionSelectionsByAnswer.length);
 | 
				
			||||||
 | 
					            tmp[questionNumber] = new int[0][];
 | 
				
			||||||
 | 
					            questionSelectionsByAnswer = tmp;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public int[] getItem(SingleChosenAnswer key) {
 | 
					        if (answerNumber >= questionSelectionsByAnswer[questionNumber].length) {
 | 
				
			||||||
        return questionsSelections.get(key);
 | 
					            int[][] tmp = new int[answerNumber+1][];
 | 
				
			||||||
 | 
					            System.arraycopy(questionSelectionsByAnswer[questionNumber], 0,
 | 
				
			||||||
 | 
					                    tmp, 0, questionSelectionsByAnswer[questionNumber].length);
 | 
				
			||||||
 | 
					            questionSelectionsByAnswer[questionNumber] = tmp;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        questionSelectionsByAnswer[questionNumber][answerNumber] = questionIndices.clone();
 | 
				
			||||||
 | 
					        maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(questionIndices));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int[] getItem(int questionNumber, int answerNumber) {
 | 
				
			||||||
 | 
					        return questionSelectionsByAnswer[questionNumber][answerNumber];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public int getMaxQuestionNumber() {
 | 
					    public int getMaxQuestionNumber() {
 | 
				
			||||||
| 
						 | 
					@ -41,7 +62,7 @@ public class SimpleCategoriesData {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static int maxInt(int[] arr) {
 | 
					    private static int maxIntInArray(int[] arr) {
 | 
				
			||||||
        int m = -1;
 | 
					        int m = -1;
 | 
				
			||||||
        for (int i: arr) {
 | 
					        for (int i: arr) {
 | 
				
			||||||
            m = Math.max(i , m);
 | 
					            m = Math.max(i , m);
 | 
				
			||||||
| 
						 | 
					@ -53,8 +74,11 @@ public class SimpleCategoriesData {
 | 
				
			||||||
        String s = "SimpleCategoriesData:\n";
 | 
					        String s = "SimpleCategoriesData:\n";
 | 
				
			||||||
        s += "shared : " + arrayToString(sharedDefaults) + "\n";
 | 
					        s += "shared : " + arrayToString(sharedDefaults) + "\n";
 | 
				
			||||||
        s += "map : \n";
 | 
					        s += "map : \n";
 | 
				
			||||||
        for (SingleChosenAnswer key : questionsSelections.keySet()) {
 | 
					        for (int questionNumber = 0; questionNumber < questionSelectionsByAnswer.length; ++questionNumber) {
 | 
				
			||||||
            s += key + " : " + arrayToString(questionsSelections.get(key)) + "\n";
 | 
					            for (int answerNumber = 0; answerNumber < questionSelectionsByAnswer[questionNumber].length; ++answerNumber) {
 | 
				
			||||||
 | 
					                s += "(" + questionNumber + ", " + answerNumber + ") -> " +
 | 
				
			||||||
 | 
					                        arrayToString(questionSelectionsByAnswer[questionNumber][answerNumber]) + "\n";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return s;
 | 
					        return s;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,75 +1,88 @@
 | 
				
			||||||
package meerkat.voting.controller.selector;
 | 
					package meerkat.voting.controller.selector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException;
 | 
					import meerkat.protobuf.Voting.BallotAnswer;
 | 
				
			||||||
import meerkat.protobuf.Voting.*;
 | 
					import meerkat.protobuf.Voting.BallotQuestion;
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 02/05/16.
 | 
					 * A simple implementation of a QuestionSelector.
 | 
				
			||||||
 | 
					 * This implementation simply regards every single answer in the channel choice phase as an identifier of a category
 | 
				
			||||||
 | 
					 * Every category is an array of ballot questions.
 | 
				
			||||||
 | 
					 * Data of categories is initialized and stored by a SimpleCategoriesData object.
 | 
				
			||||||
 | 
					 * After receiving the answers from a channel choice phase, this class simply gathers all the categories
 | 
				
			||||||
 | 
					 * chosen and compiles the list of ballot questions to include in the ballot for this voter (a question
 | 
				
			||||||
 | 
					 * is included if its index appears in any chosen category, or in the default category shared by all voters)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class SimpleListCategoriesSelector extends QuestionSelector {
 | 
					public class SimpleListCategoriesSelector implements QuestionSelector {
 | 
				
			||||||
    protected final static Logger logger = LoggerFactory.getLogger(SimpleListCategoriesSelector.class);
 | 
					    protected final static Logger logger = LoggerFactory.getLogger(SimpleListCategoriesSelector.class);
 | 
				
			||||||
 | 
					    private BallotQuestion[] allBallotQuestions;
 | 
				
			||||||
 | 
					    private SimpleCategoriesData selectionData;
 | 
				
			||||||
    private boolean[] isSelected;
 | 
					    private boolean[] isSelected;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public SimpleListCategoriesSelector(Object selectionData, BallotQuestion[] allBallotQuestions) {
 | 
					 | 
				
			||||||
        super(selectionData, allBallotQuestions);
 | 
					 | 
				
			||||||
        initializeAttributes (allBallotQuestions);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public SimpleListCategoriesSelector(Object selectionData, ArrayList<BallotQuestion> allBallotQuestions) {
 | 
					    public SimpleListCategoriesSelector() {
 | 
				
			||||||
        super(selectionData, null);
 | 
					        this.allBallotQuestions = null;
 | 
				
			||||||
        BallotQuestion[] questionsArr = new BallotQuestion[allBallotQuestions.size()];
 | 
					        this.selectionData = null;
 | 
				
			||||||
        for (int i = 0; i < questionsArr.length; ++i) {
 | 
					 | 
				
			||||||
            questionsArr[i] = allBallotQuestions.get(i);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        initializeAttributes (questionsArr);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void initializeAttributes (BallotQuestion[] allBallotQuestions) {
 | 
					 | 
				
			||||||
        assert selectionData instanceof SimpleCategoriesData;
 | 
					 | 
				
			||||||
        this.allBallotQuestions = allBallotQuestions;
 | 
					 | 
				
			||||||
        SimpleCategoriesData data = (SimpleCategoriesData) selectionData;
 | 
					 | 
				
			||||||
        int maxQuestionNumber = data.getMaxQuestionNumber();
 | 
					 | 
				
			||||||
        int length = allBallotQuestions.length;
 | 
					 | 
				
			||||||
        if (maxQuestionNumber >= length) {
 | 
					 | 
				
			||||||
            String errorMessage = "Selection data refers to question index " + maxQuestionNumber + " while we have only " + length + " questions totally";
 | 
					 | 
				
			||||||
            logger.error(errorMessage);
 | 
					 | 
				
			||||||
            throw new ValueException(errorMessage);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        isSelected = new boolean[allBallotQuestions.length];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public int getChannelIdentifier(BallotAnswer[] channelChoiceAnswers) {
 | 
					    public void setAllBallotQuestions(List<BallotQuestion> allBallotQuestions) {
 | 
				
			||||||
 | 
					        this.allBallotQuestions = (BallotQuestion[])allBallotQuestions.toArray();
 | 
				
			||||||
 | 
					        isSelected = new boolean[this.allBallotQuestions.length];
 | 
				
			||||||
 | 
					        assertDataValid();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setSelectionData(SelectionData data) {
 | 
				
			||||||
 | 
					        if (! (data instanceof SimpleCategoriesData)) {
 | 
				
			||||||
 | 
					            String errorMessage = "Initialization of SimpleListCategoriesSelector with wrong object type";
 | 
				
			||||||
 | 
					            logger.error(errorMessage);
 | 
				
			||||||
 | 
					            throw new RuntimeException(errorMessage);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.selectionData = (SimpleCategoriesData)data;
 | 
				
			||||||
 | 
					        assertDataValid();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void assertDataValid () {
 | 
				
			||||||
 | 
					        if (selectionData != null && allBallotQuestions != null) {
 | 
				
			||||||
 | 
					            int questionsLength = allBallotQuestions.length;
 | 
				
			||||||
 | 
					            int maxQuestionNumber = selectionData.getMaxQuestionNumber();
 | 
				
			||||||
 | 
					            if (maxQuestionNumber >= questionsLength) {
 | 
				
			||||||
 | 
					                String errorMessage = "Selection data refers to question index " + maxQuestionNumber + " while we have only " + questionsLength + " questions totally";
 | 
				
			||||||
 | 
					                logger.error(errorMessage);
 | 
				
			||||||
 | 
					                throw new IndexOutOfBoundsException(errorMessage);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public int getChannelIdentifier(List<BallotAnswer> channelChoiceAnswers) {
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public BallotQuestion[] selectQuestionsForVoter(BallotAnswer[] channelChoiceAnswers) {
 | 
					    public List<BallotQuestion> selectQuestionsForVoter(List<BallotAnswer> channelChoiceAnswers) {
 | 
				
			||||||
        SimpleCategoriesData data = (SimpleCategoriesData)selectionData;
 | 
					 | 
				
			||||||
        java.util.Arrays.fill(isSelected, false);
 | 
					        java.util.Arrays.fill(isSelected, false);
 | 
				
			||||||
        markSelected(data.getSharedDefaults());
 | 
					        markSelected(selectionData.getSharedDefaults());
 | 
				
			||||||
        markSelectionsOfVoterChannelChoice (channelChoiceAnswers);
 | 
					        markSelectionsOfVoterChannelChoice ((BallotAnswer[])channelChoiceAnswers.toArray());
 | 
				
			||||||
        int[] questionIndices = extractSelectedIndices();
 | 
					        int[] questionIndices = extractSelectedIndices();
 | 
				
			||||||
        BallotQuestion[] selectedQuestions = new BallotQuestion[questionIndices.length];
 | 
					        List<BallotQuestion> selectedQuestions = new ArrayList<>();
 | 
				
			||||||
        for (int i = 0; i < questionIndices.length; ++i) {
 | 
					        for (int questionIndex: questionIndices) {
 | 
				
			||||||
            selectedQuestions[i] = allBallotQuestions[questionIndices[i]];
 | 
					            selectedQuestions.add(allBallotQuestions[questionIndex]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return selectedQuestions;
 | 
					        return selectedQuestions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void markSelectionsOfVoterChannelChoice(BallotAnswer[] channelChoiceAnswers) {
 | 
					    private void markSelectionsOfVoterChannelChoice(BallotAnswer[] channelChoiceAnswers) {
 | 
				
			||||||
        SimpleCategoriesData data = (SimpleCategoriesData)selectionData;
 | 
					 | 
				
			||||||
        for (int q = 0; q < channelChoiceAnswers.length; ++q) {
 | 
					        for (int q = 0; q < channelChoiceAnswers.length; ++q) {
 | 
				
			||||||
            BallotAnswer ballotAnswer = channelChoiceAnswers[q];
 | 
					            BallotAnswer ballotAnswer = channelChoiceAnswers[q];
 | 
				
			||||||
            assertAnswerLengthIsOne(ballotAnswer, q);
 | 
					            assertAnswerLengthIsOne(ballotAnswer, q);
 | 
				
			||||||
            SingleChosenAnswer key = new SingleChosenAnswer(q, ballotAnswer.getAnswer(0));
 | 
					            assertKeyInSelectionData(q, (int)ballotAnswer.getAnswer(0));
 | 
				
			||||||
            assertKeyInSelectionData(key);
 | 
					            markSelected(selectionData.getItem(q, (int)ballotAnswer.getAnswer(0)));
 | 
				
			||||||
            markSelected(data.getItem(key));
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,17 +94,16 @@ public class SimpleListCategoriesSelector extends QuestionSelector {
 | 
				
			||||||
                errorMessage += " " + i;
 | 
					                errorMessage += " " + i;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            logger.error(errorMessage);
 | 
					            logger.error(errorMessage);
 | 
				
			||||||
            throw new ValueException(errorMessage);
 | 
					            throw new IllegalArgumentException(errorMessage);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void assertKeyInSelectionData(SingleChosenAnswer key) {
 | 
					    private void assertKeyInSelectionData(int questionNumber, int answerNumber) {
 | 
				
			||||||
        SimpleCategoriesData data = (SimpleCategoriesData)selectionData;
 | 
					        int[] questionListToAdd = selectionData.getItem(questionNumber, answerNumber);
 | 
				
			||||||
        int[] questionListToAdd = data.getItem(key);
 | 
					 | 
				
			||||||
        if (null == questionListToAdd) {
 | 
					        if (null == questionListToAdd) {
 | 
				
			||||||
            String errorMessage = "SimpleListCategoriesSelector could not resolve answer number " + key.answerNumber + " for question number " + key.questionNumber;
 | 
					            String errorMessage = "SimpleListCategoriesSelector could not resolve answer number " + answerNumber + " for question number " + questionNumber;
 | 
				
			||||||
            logger.error(errorMessage);
 | 
					            logger.error(errorMessage);
 | 
				
			||||||
            throw new ValueException(errorMessage);
 | 
					            throw new IllegalArgumentException(errorMessage);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,31 +0,0 @@
 | 
				
			||||||
package meerkat.voting.controller.selector;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Created by hai on 02/05/16.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class SingleChosenAnswer {
 | 
					 | 
				
			||||||
    public int questionNumber;
 | 
					 | 
				
			||||||
    public long answerNumber;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public SingleChosenAnswer(int questionNumber, long answerNumber) {
 | 
					 | 
				
			||||||
        this.questionNumber = questionNumber;
 | 
					 | 
				
			||||||
        this.answerNumber = answerNumber;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public String toString() {
 | 
					 | 
				
			||||||
        return "SingleChosenAnswer(" + questionNumber + ", " + answerNumber + ")";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public boolean equals (Object other) {
 | 
					 | 
				
			||||||
        if (!(other instanceof SingleChosenAnswer)) {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        SingleChosenAnswer o = (SingleChosenAnswer)other;
 | 
					 | 
				
			||||||
        return (o.questionNumber == this.questionNumber) && (o.answerNumber == this.answerNumber);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public int hashCode () {
 | 
					 | 
				
			||||||
        return questionNumber*1000 + (int)answerNumber;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -7,9 +7,7 @@ import meerkat.protobuf.Voting.*;
 | 
				
			||||||
import java.io.BufferedReader;
 | 
					import java.io.BufferedReader;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.io.InputStreamReader;
 | 
					import java.io.InputStreamReader;
 | 
				
			||||||
import java.util.Date;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.StringTokenizer;
 | 
					 | 
				
			||||||
import java.util.Timer;
 | 
					 | 
				
			||||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
					import java.util.concurrent.LinkedBlockingQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.voting.controller.callbacks.*;
 | 
					import meerkat.voting.controller.callbacks.*;
 | 
				
			||||||
| 
						 | 
					@ -45,54 +43,47 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
 | 
				
			||||||
        logger.info("entered the voting flow");
 | 
					        logger.info("entered the voting flow");
 | 
				
			||||||
        while (true) {
 | 
					        while (true) {
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                UICommand task = queue.take();
 | 
					                UICommand command = queue.take();
 | 
				
			||||||
                handleSingleTask (task);
 | 
					                handleSingleCommand(command);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (InterruptedException e) {
 | 
					            catch (InterruptedException e) {
 | 
				
			||||||
                logger.warn ("Interrupted while reading from task queue " + e);
 | 
					                logger.warn ("Interrupted while reading from command queue " + e);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void handleSingleTask (UICommand task) {
 | 
					    private void handleSingleCommand(UICommand command) {
 | 
				
			||||||
        if (!(task instanceof TickCommand)) {
 | 
					        if (!(command instanceof TickCommand)) {
 | 
				
			||||||
            if (startWaitingTime != null) {
 | 
					            if (startWaitingTime != null) {
 | 
				
			||||||
                stopWaiting();
 | 
					                stopWaiting();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (task instanceof StartSessionUICommand) {
 | 
					        if (command instanceof StartSessionUICommand) {
 | 
				
			||||||
            doShowWelcomeScreen((StartSessionUICommand)task);
 | 
					            doShowWelcomeScreen((StartSessionUICommand)command);
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (task instanceof ChannelChoiceUICommand) {
 | 
					        else if (command instanceof ChannelChoiceUICommand) {
 | 
				
			||||||
            doAskChannelChoiceQuestions((ChannelChoiceUICommand)task);
 | 
					            doAskChannelChoiceQuestions((ChannelChoiceUICommand)command);
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (task instanceof RaceVotingUICommand) {
 | 
					        else if (command instanceof RaceVotingUICommand) {
 | 
				
			||||||
            doAskVotingQuestions((RaceVotingUICommand)task);
 | 
					            doAskVotingQuestions((RaceVotingUICommand)command);
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (task instanceof CastOrAuditUICommand) {
 | 
					        else if (command instanceof CastOrAuditUICommand) {
 | 
				
			||||||
            doCastOrAudit ((CastOrAuditUICommand)task);
 | 
					            doCastOrAudit ((CastOrAuditUICommand)command);
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (task instanceof HaltCommand) {
 | 
					        else if (command instanceof FatalErrorUICommand) {
 | 
				
			||||||
            doHalt((HaltCommand)task);
 | 
					            doFatalError((FatalErrorUICommand)command);
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (task instanceof WaitForFinishCommand) {
 | 
					        else if (command instanceof WaitForFinishUICommand) {
 | 
				
			||||||
            doWaitForFinish((WaitForFinishCommand)task);
 | 
					            doWaitForFinish((WaitForFinishUICommand)command);
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (task instanceof TickCommand) {
 | 
					        else if (command instanceof TickCommand) {
 | 
				
			||||||
            doTick ();
 | 
					            doTick ();
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            String errorMessage = "handleSingleTask: unknown type of UICommand received: " +
 | 
					            String errorMessage = "handleSingleCommand: unknown type of UICommand received: " +
 | 
				
			||||||
                    task.getClass().getName();
 | 
					                    command.getClass().getName();
 | 
				
			||||||
            logger.error(errorMessage);
 | 
					            logger.error(errorMessage);
 | 
				
			||||||
            throw new RuntimeException(errorMessage);
 | 
					            throw new RuntimeException(errorMessage);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -105,13 +96,13 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
 | 
				
			||||||
        queue.add(new StartSessionUICommand((ControllerCallback)callback));
 | 
					        queue.add(new StartSessionUICommand((ControllerCallback)callback));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void doShowWelcomeScreen(StartSessionUICommand task) {
 | 
					    private void doShowWelcomeScreen(StartSessionUICommand command) {
 | 
				
			||||||
        logger.debug("UI entered doShowWelcomeScreen");
 | 
					        logger.debug("UI entered doShowWelcomeScreen");
 | 
				
			||||||
        System.out.println("Welcome, new voter!");
 | 
					        System.out.println("Welcome, new voter!");
 | 
				
			||||||
        waitForEnter(null);
 | 
					        waitForEnter(null);
 | 
				
			||||||
        ControllerCallback callback = task.getCallback();
 | 
					        ControllerCallback callback = command.getCallback();
 | 
				
			||||||
        assert (callback instanceof NewVoterCallback);
 | 
					        assert (callback instanceof NewVoterCallback);
 | 
				
			||||||
        ((NewVoterCallback)callback).onSuccess(null);
 | 
					        callback.onSuccess(null);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void stopWaiting () {
 | 
					    private void stopWaiting () {
 | 
				
			||||||
| 
						 | 
					@ -138,45 +129,45 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void chooseChannel(BallotQuestion[] questions, FutureCallback<BallotAnswer[]> callback) {
 | 
					    public void chooseChannel(List<BallotQuestion> questions, FutureCallback<List<BallotAnswer>> callback) {
 | 
				
			||||||
        logger.debug("UI interface call to chooseChannel");
 | 
					        logger.debug("UI interface call to chooseChannel");
 | 
				
			||||||
        ChannelChoiceUICommand task = new ChannelChoiceUICommand(questions, (ControllerCallback)callback);
 | 
					        ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ControllerCallback)callback);
 | 
				
			||||||
        queue.add(task);
 | 
					        queue.add(command);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void doAskChannelChoiceQuestions (ChannelChoiceUICommand task) {
 | 
					    private void doAskChannelChoiceQuestions (ChannelChoiceUICommand command) {
 | 
				
			||||||
        logger.debug("UI: doAskChannelChoiceQuestions");
 | 
					        logger.debug("UI: doAskChannelChoiceQuestions");
 | 
				
			||||||
        System.out.println("Showing questions for choosing channel:\n");
 | 
					        System.out.println("Showing questions for choosing channel:\n");
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            BallotAnswer[] answers = askVoterForAnswers(task.getQuestions());
 | 
					            List<BallotAnswer> answers = askVoterForAnswers(command.getQuestions());
 | 
				
			||||||
            task.getCallback().onSuccess(answers);
 | 
					            command.getCallback().onSuccess(answers);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (IOException e) {
 | 
					        catch (IOException e) {
 | 
				
			||||||
            String errorMessage = "Channel choice failed due to IOException: " + e;
 | 
					            String errorMessage = "Channel choice failed due to IOException: " + e;
 | 
				
			||||||
            logger.error (errorMessage);
 | 
					            logger.error (errorMessage);
 | 
				
			||||||
            System.err.println(errorMessage);
 | 
					            System.err.println(errorMessage);
 | 
				
			||||||
            task.getCallback().onFailure(e);
 | 
					            command.getCallback().onFailure(e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void askVoterQuestions(BallotQuestion[] questions, FutureCallback<BallotAnswer[]> callback) {
 | 
					    public void askVoterQuestions(List<BallotQuestion> questions, FutureCallback<List<BallotAnswer>> callback) {
 | 
				
			||||||
        logger.debug("UI interface call to chooseChannel");
 | 
					        logger.debug("UI interface call to chooseChannel");
 | 
				
			||||||
        queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback));
 | 
					        queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void doAskVotingQuestions (RaceVotingUICommand task) {
 | 
					    private void doAskVotingQuestions (RaceVotingUICommand command) {
 | 
				
			||||||
        logger.debug("UI: doAskVotingQuestions");
 | 
					        logger.debug("UI: doAskVotingQuestions");
 | 
				
			||||||
        System.out.println("Showing questions for race voting:\n");
 | 
					        System.out.println("Showing questions for race voting:\n");
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            BallotAnswer[] answers = askVoterForAnswers(task.getQuestions());
 | 
					            List<BallotAnswer> answers = askVoterForAnswers(command.getQuestions());
 | 
				
			||||||
            task.getCallback().onSuccess(answers);
 | 
					            command.getCallback().onSuccess(answers);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (IOException e) {
 | 
					        catch (IOException e) {
 | 
				
			||||||
            String errorMessage = "Asking voting questions failed due to IOException: " + e;
 | 
					            String errorMessage = "Asking voting questions failed due to IOException: " + e;
 | 
				
			||||||
            logger.error (errorMessage);
 | 
					            logger.error (errorMessage);
 | 
				
			||||||
            System.err.println(errorMessage);
 | 
					            System.err.println(errorMessage);
 | 
				
			||||||
            task.getCallback().onFailure(e);
 | 
					            command.getCallback().onFailure(e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -186,7 +177,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
 | 
				
			||||||
        queue.add(new CastOrAuditUICommand((ControllerCallback)callback));
 | 
					        queue.add(new CastOrAuditUICommand((ControllerCallback)callback));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void doCastOrAudit(CastOrAuditUICommand task) {
 | 
					    private void doCastOrAudit(CastOrAuditUICommand command) {
 | 
				
			||||||
        logger.debug("UI entered doCastOrAudit");
 | 
					        logger.debug("UI entered doCastOrAudit");
 | 
				
			||||||
        System.out.println ("Finalizing your vote. Do you wish to (C)ast or (A)udit?");
 | 
					        System.out.println ("Finalizing your vote. Do you wish to (C)ast or (A)udit?");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,30 +194,30 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
 | 
				
			||||||
            else {
 | 
					            else {
 | 
				
			||||||
                throw new IllegalArgumentException("UI could not understand the answer for cast/audit question '" + s + "'");
 | 
					                throw new IllegalArgumentException("UI could not understand the answer for cast/audit question '" + s + "'");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ControllerCallback callback = task.getCallback();
 | 
					            ControllerCallback callback = command.getCallback();
 | 
				
			||||||
            assert (callback instanceof CastOrAuditCallback);
 | 
					            assert (callback instanceof CastOrAuditCallback);
 | 
				
			||||||
            ((CastOrAuditCallback)callback).onSuccess(fChoice);
 | 
					            ((CastOrAuditCallback)callback).onSuccess(fChoice);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (IllegalArgumentException|IOException e) {
 | 
					        catch (IllegalArgumentException|IOException e) {
 | 
				
			||||||
            String errorMessage = "doCastOrAudit: some error with reading input from console. details: " + e;
 | 
					            String errorMessage = "doCastOrAudit: some error with reading input from console. details: " + e;
 | 
				
			||||||
            logger.error(errorMessage);
 | 
					            logger.error(errorMessage);
 | 
				
			||||||
            task.getCallback().onFailure(e);
 | 
					            command.getCallback().onFailure(e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void notifyVoterToWaitForFinish(UIElement message, FutureCallback<Boolean> callback) {
 | 
					    public void notifyVoterToWaitForFinish(UIElement message, FutureCallback<Void> callback) {
 | 
				
			||||||
        logger.debug("UI interface call to notifyVoterToWaitForFinish");
 | 
					        logger.debug("UI interface call to notifyVoterToWaitForFinish");
 | 
				
			||||||
        queue.add(new WaitForFinishCommand(message, (ControllerCallback)callback));
 | 
					        queue.add(new WaitForFinishUICommand(message, (ControllerCallback)callback));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void doWaitForFinish (WaitForFinishCommand task) {
 | 
					    public void doWaitForFinish (WaitForFinishUICommand command) {
 | 
				
			||||||
        logger.debug("UI entered doWaitForFinish");
 | 
					        logger.debug("UI entered doWaitForFinish");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        startWaitingTime = new Date();
 | 
					        startWaitingTime = new Date();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        UIElement message = task.getMessage();
 | 
					        UIElement message = command.getMessage();
 | 
				
			||||||
        String messageString;
 | 
					        String messageString;
 | 
				
			||||||
        if (message.getType() != UIElementDataType.TEXT) {
 | 
					        if (message.getType() != UIElementDataType.TEXT) {
 | 
				
			||||||
            messageString = "Default message: encountered an error. System halting";
 | 
					            messageString = "Default message: encountered an error. System halting";
 | 
				
			||||||
| 
						 | 
					@ -240,39 +231,57 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void showErrorMessageAndHalt(UIElement errorMessage, FutureCallback<Boolean> callback) {
 | 
					    public void showErrorMessageAndHalt(UIElement errorMessage, FutureCallback<Boolean> callback) {
 | 
				
			||||||
        logger.debug("UI interface call to showErrorMessageAndHalt");
 | 
					        logger.debug("UI interface call to showErrorMessageAndHalt");
 | 
				
			||||||
        queue.add(new HaltCommand(errorMessage, (ControllerCallback)callback));
 | 
					        throw new UnsupportedOperationException("Not implemented becuase currently not sure if we ever use it.");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void doHalt (HaltCommand task) {
 | 
					 | 
				
			||||||
        logger.debug("UI entered doHalt");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        UIElement errorMessage = task.getErrorMessage();
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback<Integer> callback) {
 | 
				
			||||||
 | 
					        logger.debug("UI interface call to showErrorMessageWithButtons");
 | 
				
			||||||
 | 
					        queue.clear();
 | 
				
			||||||
 | 
					        queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void doFatalError (FatalErrorUICommand command) {
 | 
				
			||||||
 | 
					        logger.debug("UI entered doFatalError");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        UIElement errorMessage = command.getErrorMessage();
 | 
				
			||||||
        String errorMessageString;
 | 
					        String errorMessageString;
 | 
				
			||||||
        if (errorMessage.getType() != UIElementDataType.TEXT) {
 | 
					        if (errorMessage.getType() != UIElementDataType.TEXT) {
 | 
				
			||||||
            errorMessageString = "Default message: encountered an error. System halting";
 | 
					            errorMessageString = "Default message: encountered an error. System halting";
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            errorMessageString = bytesToString(errorMessage.getData());
 | 
					            errorMessageString = bytesToString(errorMessage.getData());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        UIElement[] buttonLabels = command.getButtonLabels();
 | 
				
			||||||
 | 
					        String[] buttonLabelStrings = new String[buttonLabels.length];
 | 
				
			||||||
 | 
					        for (int i = 0; i < buttonLabels.length; ++i) {
 | 
				
			||||||
 | 
					            if (buttonLabels[i].getType() != UIElementDataType.TEXT) {
 | 
				
			||||||
 | 
					                buttonLabelStrings[i] = "<NON_TEXT>";
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                buttonLabelStrings[i] = bytesToString(errorMessage.getData());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        System.out.println(errorMessageString);
 | 
					        System.out.println(errorMessageString);
 | 
				
			||||||
 | 
					        for (int i = 0; i < buttonLabelStrings.length; ++i) {
 | 
				
			||||||
 | 
					            System.out.println("" + i + " - " + buttonLabelStrings[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (true) {
 | 
					 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
                wait();
 | 
					            String s = readInputLine();
 | 
				
			||||||
            } catch (InterruptedException e) {
 | 
					            Integer chosenButton = new Integer(s);
 | 
				
			||||||
                logger.error("UI halt has been interrupted. Details: " + e);
 | 
					            command.getCallback().onSuccess(chosenButton);
 | 
				
			||||||
                ControllerCallback callback = task.getCallback();
 | 
					 | 
				
			||||||
                assert callback instanceof HaltCallback;
 | 
					 | 
				
			||||||
                ((HaltCallback) callback).onFailure(e);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        catch (IOException e) {
 | 
				
			||||||
 | 
					            String err = "doFatalError: some error with reading input from console. details: " + e;
 | 
				
			||||||
 | 
					            logger.error(err);
 | 
				
			||||||
 | 
					            command.getCallback().onFailure(e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback<Integer> callback) {
 | 
					 | 
				
			||||||
        throw new UnsupportedOperationException();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void doTick () {
 | 
					    private void doTick () {
 | 
				
			||||||
        if (startWaitingTime != null) {
 | 
					        if (startWaitingTime != null) {
 | 
				
			||||||
            System.out.print (".");  // still waiting
 | 
					            System.out.print (".");  // still waiting
 | 
				
			||||||
| 
						 | 
					@ -295,9 +304,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void assertQuestionsAreValid (BallotQuestion[] questions) {
 | 
					    private void assertQuestionsAreValid (List<BallotQuestion> questions) {
 | 
				
			||||||
        for (int index = 0; index < questions.length; ++index) {
 | 
					        for (int index = 0; index < questions.size(); ++index) {
 | 
				
			||||||
            BallotQuestion question = questions[index];
 | 
					            BallotQuestion question = questions.get(index);
 | 
				
			||||||
            if (question.getIsMandatory()) {
 | 
					            if (question.getIsMandatory()) {
 | 
				
			||||||
                String errorMessage = "askVoterQuestions: question number " + index + " is marked as mandatory";
 | 
					                String errorMessage = "askVoterQuestions: question number " + index + " is marked as mandatory";
 | 
				
			||||||
                logger.error(errorMessage);
 | 
					                logger.error(errorMessage);
 | 
				
			||||||
| 
						 | 
					@ -311,14 +320,14 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private BallotAnswer[] askVoterForAnswers(BallotQuestion[] questions) throws IOException {
 | 
					    private List<BallotAnswer> askVoterForAnswers(List<BallotQuestion> questions) throws IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assertQuestionsAreValid (questions);
 | 
					        assertQuestionsAreValid (questions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        BallotAnswer answers[] = new BallotAnswer[questions.length];
 | 
					        List<BallotAnswer> answers = new ArrayList<>();
 | 
				
			||||||
        int index = 0;
 | 
					        int index = 0;
 | 
				
			||||||
        while (index < questions.length) {
 | 
					        while (index < questions.size()) {
 | 
				
			||||||
            BallotQuestion question = questions[index];
 | 
					            BallotQuestion question = questions.get(index);
 | 
				
			||||||
            System.out.println("Question number " + index);
 | 
					            System.out.println("Question number " + index);
 | 
				
			||||||
            showQuestionOnScreen(question);
 | 
					            showQuestionOnScreen(question);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -330,13 +339,14 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (s.equals("back") || s.equals("b")) {
 | 
					            else if (s.equals("back") || s.equals("b")) {
 | 
				
			||||||
                --index;
 | 
					                --index;
 | 
				
			||||||
 | 
					                answers.remove(index);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (s.equals("skip") || s.equals("s")) {
 | 
					            else if (s.equals("skip") || s.equals("s")) {
 | 
				
			||||||
                answers[index] = translateStringAnswerToProtoBufMessageAnswer("");
 | 
					                answers.add(translateStringAnswerToProtoBufMessageAnswer(""));
 | 
				
			||||||
                ++index;
 | 
					                ++index;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else {
 | 
					            else {
 | 
				
			||||||
                answers[index] = translateStringAnswerToProtoBufMessageAnswer(s);
 | 
					                answers.add(translateStringAnswerToProtoBufMessageAnswer(s));
 | 
				
			||||||
                ++index;
 | 
					                ++index;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,8 @@ package meerkat.voting.ui;
 | 
				
			||||||
import com.google.common.util.concurrent.FutureCallback;
 | 
					import com.google.common.util.concurrent.FutureCallback;
 | 
				
			||||||
import meerkat.protobuf.Voting.*;
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * An interface for the user interface component of the voting booth
 | 
					 * An interface for the user interface component of the voting booth
 | 
				
			||||||
| 
						 | 
					@ -25,14 +27,14 @@ public interface VotingBoothUI {
 | 
				
			||||||
     * @param questions questions to determine the right voting channel for this voter
 | 
					     * @param questions questions to determine the right voting channel for this voter
 | 
				
			||||||
     * @param callback that's where we store the answers to decide channel upon for the current voter
 | 
					     * @param callback that's where we store the answers to decide channel upon for the current voter
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void chooseChannel (BallotQuestion[] questions, FutureCallback<BallotAnswer[]> callback);
 | 
					    public void chooseChannel (List<BallotQuestion> questions, FutureCallback<List<BallotAnswer>> callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Presents the set of questions to the voter. Collect all his responses.
 | 
					     * Presents the set of questions to the voter. Collect all his responses.
 | 
				
			||||||
     * @param questions all ballot questions to present to the voter
 | 
					     * @param questions all ballot questions to present to the voter
 | 
				
			||||||
     * @param callback the responses to the questions collected by the UI, to send back to the controller. Responses are null if voter chose to cancel session
 | 
					     * @param callback the responses to the questions collected by the UI, to send back to the controller. Responses are null if voter chose to cancel session
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void askVoterQuestions (BallotQuestion[] questions, FutureCallback<BallotAnswer[]> callback);
 | 
					    public void askVoterQuestions (List<BallotQuestion> questions, FutureCallback<List<BallotAnswer>> callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get a response from the voter on how to finalize the ballot.
 | 
					     * Get a response from the voter on how to finalize the ballot.
 | 
				
			||||||
| 
						 | 
					@ -51,7 +53,7 @@ public interface VotingBoothUI {
 | 
				
			||||||
     * @param message a message to show the user on the UI device while waiting
 | 
					     * @param message a message to show the user on the UI device while waiting
 | 
				
			||||||
     * @param callback a success return value of the wait (cancelling returns false)
 | 
					     * @param callback a success return value of the wait (cancelling returns false)
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void notifyVoterToWaitForFinish (UIElement message, FutureCallback<Boolean> callback);
 | 
					    public void notifyVoterToWaitForFinish (UIElement message, FutureCallback<Void> callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * show a fatal error message in the UI. Halts system. Waits for administrator interrupt or reset
 | 
					     * show a fatal error message in the UI. Halts system. Waits for administrator interrupt or reset
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
package meerkat.voting.ui.uicommands;
 | 
					package meerkat.voting.ui.uicommands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.voting.controller.callbacks.ControllerCallback;
 | 
					import meerkat.voting.controller.callbacks.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 21/04/16.
 | 
					 * Created by hai on 21/04/16.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,22 +1,24 @@
 | 
				
			||||||
package meerkat.voting.ui.uicommands;
 | 
					package meerkat.voting.ui.uicommands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.protobuf.Voting.*;
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
import meerkat.voting.controller.callbacks.ControllerCallback;
 | 
					import meerkat.voting.controller.callbacks.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 18/04/16.
 | 
					 * Created by hai on 18/04/16.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class ChannelChoiceUICommand extends UICommand {
 | 
					public class ChannelChoiceUICommand extends UICommand {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final BallotQuestion[] questions;
 | 
					    private final List<BallotQuestion> questions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ChannelChoiceUICommand(BallotQuestion[] questions, ControllerCallback callback)
 | 
					    public ChannelChoiceUICommand(List<BallotQuestion> questions, ControllerCallback callback)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        super(callback);
 | 
					        super(callback);
 | 
				
			||||||
        this.questions = questions;
 | 
					        this.questions = questions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public BallotQuestion[] getQuestions () {
 | 
					    public List<BallotQuestion> getQuestions () {
 | 
				
			||||||
        return this.questions;
 | 
					        return this.questions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					package meerkat.voting.ui.uicommands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import meerkat.protobuf.Voting.UIElement;
 | 
				
			||||||
 | 
					import meerkat.voting.controller.callbacks.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Created by hai on 18/04/16.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class FatalErrorUICommand extends UICommand {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final UIElement errorMessage;
 | 
				
			||||||
 | 
					    private final UIElement[] buttonLabels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public FatalErrorUICommand(UIElement errorMessage, UIElement[] buttonLabels, ControllerCallback callback)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        super(callback);
 | 
				
			||||||
 | 
					        this.errorMessage = errorMessage;
 | 
				
			||||||
 | 
					        this.buttonLabels = buttonLabels;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UIElement getErrorMessage() {
 | 
				
			||||||
 | 
					        return this.errorMessage;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UIElement[] getButtonLabels() {
 | 
				
			||||||
 | 
					        return this.getButtonLabels();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,22 +0,0 @@
 | 
				
			||||||
package meerkat.voting.ui.uicommands;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import meerkat.protobuf.Voting.*;
 | 
					 | 
				
			||||||
import meerkat.voting.controller.callbacks.ControllerCallback;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Created by hai on 18/04/16.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class HaltCommand extends UICommand {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private final UIElement errorMessage;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public HaltCommand(UIElement errorMessage, ControllerCallback callback)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        super(callback);
 | 
					 | 
				
			||||||
        this.errorMessage = errorMessage;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public UIElement getErrorMessage () {
 | 
					 | 
				
			||||||
        return this.errorMessage;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,22 +1,24 @@
 | 
				
			||||||
package meerkat.voting.ui.uicommands;
 | 
					package meerkat.voting.ui.uicommands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.protobuf.Voting.*;
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
import meerkat.voting.controller.callbacks.ControllerCallback;
 | 
					import meerkat.voting.controller.callbacks.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 18/04/16.
 | 
					 * Created by hai on 18/04/16.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class RaceVotingUICommand extends UICommand {
 | 
					public class RaceVotingUICommand extends UICommand {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final BallotQuestion[] questions;
 | 
					    private final List<BallotQuestion> questions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public RaceVotingUICommand(BallotQuestion[] questions, ControllerCallback callback)
 | 
					    public RaceVotingUICommand(List<BallotQuestion> questions, ControllerCallback callback)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        super(callback);
 | 
					        super(callback);
 | 
				
			||||||
        this.questions = questions;
 | 
					        this.questions = questions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public BallotQuestion[] getQuestions () {
 | 
					    public List<BallotQuestion> getQuestions () {
 | 
				
			||||||
        return this.questions;
 | 
					        return this.questions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
package meerkat.voting.ui.uicommands;
 | 
					package meerkat.voting.ui.uicommands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.voting.controller.callbacks.ControllerCallback;
 | 
					import meerkat.voting.controller.callbacks.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 18/04/16.
 | 
					 * Created by hai on 18/04/16.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
package meerkat.voting.ui.uicommands;
 | 
					package meerkat.voting.ui.uicommands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.voting.controller.callbacks.ControllerCallback;
 | 
					import meerkat.voting.controller.callbacks.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 18/04/16.
 | 
					 * Created by hai on 18/04/16.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
package meerkat.voting.ui.uicommands;
 | 
					package meerkat.voting.ui.uicommands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.voting.controller.callbacks.ControllerCallback;
 | 
					import meerkat.voting.controller.callbacks.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//TODO: make this class generic
 | 
					//TODO: make this class generic
 | 
				
			||||||
public abstract class UICommand {
 | 
					public abstract class UICommand {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,17 @@
 | 
				
			||||||
package meerkat.voting.ui.uicommands;
 | 
					package meerkat.voting.ui.uicommands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import meerkat.protobuf.Voting.*;
 | 
					import meerkat.protobuf.Voting.*;
 | 
				
			||||||
import meerkat.voting.controller.callbacks.ControllerCallback;
 | 
					import meerkat.voting.controller.callbacks.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by hai on 18/04/16.
 | 
					 * Created by hai on 18/04/16.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class WaitForFinishCommand extends UICommand {
 | 
					public class WaitForFinishUICommand extends UICommand {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final UIElement message;
 | 
					    private final UIElement message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public WaitForFinishCommand(UIElement message, ControllerCallback callback)
 | 
					    public WaitForFinishUICommand(UIElement message, ControllerCallback callback)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        super(callback);
 | 
					        super(callback);
 | 
				
			||||||
        this.message = message;
 | 
					        this.message = message;
 | 
				
			||||||
		Loading…
	
		Reference in New Issue