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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -31,8 +32,7 @@ public interface VotingBoothController {
|
|||
* set the voting questions
|
||||
* @param questions
|
||||
*/
|
||||
public void setBallotChannelChoiceQuestions(BallotQuestion[] questions);
|
||||
public void setBallotChannelChoiceQuestions(ArrayList<BallotQuestion> questions);
|
||||
public void setBallotChannelChoiceQuestions(List<BallotQuestion> questions);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param questions
|
||||
*/
|
||||
public void setBallotRaceQuestions(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 ();
|
||||
public void setBallotRaceQuestions(List<BallotQuestion> questions);
|
||||
|
||||
/**
|
||||
* 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.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* Created by hai on 28/03/16.
|
||||
*/
|
||||
public class VotingBoothImpl implements VotingBoothController, Runnable {
|
||||
public class VotingBoothImpl implements VotingBoothController {
|
||||
|
||||
private BallotOutputDevice outputDevice;
|
||||
private VotingBoothEncryptor encryptor;
|
||||
private VotingBoothUI ui;
|
||||
private StorageManager storageManager;
|
||||
private BallotQuestion[] questionsForChoosingChannel;
|
||||
private BallotQuestion[] questions;
|
||||
private List<BallotQuestion> questionsForChoosingChannel;
|
||||
private List<BallotQuestion> questions;
|
||||
private QuestionSelector questionSelector;
|
||||
|
||||
private LinkedBlockingQueue<ControllerCommand> queue;
|
||||
|
@ -33,38 +33,18 @@ public class VotingBoothImpl implements VotingBoothController, Runnable {
|
|||
private Logger logger;
|
||||
|
||||
private ControllerState state;
|
||||
private boolean shutDownHasBeenCalled;
|
||||
private volatile boolean shutDownHasBeenCalled;
|
||||
|
||||
protected final int MAX_REQUEST_IDENTIFIER = 100000;
|
||||
private static int requestCounter = 0;
|
||||
|
||||
private UIElement waitForCommitMessage;
|
||||
private UIElement waitForAuditMessage;
|
||||
private UIElement waitForCastMessage;
|
||||
|
||||
|
||||
|
||||
public VotingBoothImpl () {
|
||||
logger = LoggerFactory.getLogger(VotingBoothImpl.class);
|
||||
logger.info("A VotingBoothImpl is constructed");
|
||||
shutDownHasBeenCalled = false;
|
||||
queue = new LinkedBlockingQueue<>();
|
||||
|
||||
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();
|
||||
|
||||
state = new ControllerState();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,42 +60,22 @@ public class VotingBoothImpl implements VotingBoothController, Runnable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setBallotChannelChoiceQuestions(BallotQuestion[] questions) {
|
||||
public void setBallotChannelChoiceQuestions(List<BallotQuestion> questions) {
|
||||
logger.info("setting 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
|
||||
public void setChannelQuestionSelector(QuestionSelector selector) {
|
||||
this.questionSelector = selector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBallotRaceQuestions(BallotQuestion[] questions) {
|
||||
public void setBallotRaceQuestions(List<BallotQuestion> questions) {
|
||||
logger.info("setting 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
|
||||
public void run() {
|
||||
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 () {
|
||||
logger.info("entered the voting flow");
|
||||
|
||||
|
@ -151,64 +100,70 @@ public class VotingBoothImpl implements VotingBoothController, Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
private void doShutDown () {
|
||||
logger.info("running shutDown");
|
||||
@Override
|
||||
public void callShutDown() {
|
||||
logger.info("callShutDown command has been called");
|
||||
shutDownHasBeenCalled = true;
|
||||
queue.clear();
|
||||
queue.add(new ShutDownCommand());
|
||||
}
|
||||
|
||||
private void handleSingleTask (ControllerCommand task) {
|
||||
if (task instanceof RestartVotingCommand) {
|
||||
doRestartVoting ();
|
||||
return;
|
||||
}
|
||||
if (task.getBallotSerialNumber() != state.currentBallotSerialNumber) {
|
||||
if (task.getBallotSerialNumber() != state.currentBallotSerialNumber && !(task instanceof RestartVotingCommand)) {
|
||||
// probably an old command relating to some old ballot serial number. Simply log it and ignore it.
|
||||
String errorMessage = "handleSingleTask: received a task too old. " +
|
||||
task.getBallotSerialNumber() + " " + state.currentBallotSerialNumber;
|
||||
logger.warn (errorMessage);
|
||||
logger.debug(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (task instanceof CastCommand) {
|
||||
doCast();
|
||||
return;
|
||||
if (task instanceof RestartVotingCommand) {
|
||||
doRestartVoting ();
|
||||
}
|
||||
else if (task instanceof CastCommand) {
|
||||
doFinalize(false);
|
||||
}
|
||||
else if (task instanceof AuditCommand) {
|
||||
doAudit();
|
||||
return;
|
||||
doFinalize(true);
|
||||
}
|
||||
else if (task instanceof ChannelChoiceCommand) {
|
||||
doChooseChannel();
|
||||
return;
|
||||
}
|
||||
else if (task instanceof ChannelDeterminedCommand) {
|
||||
doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task);
|
||||
return;
|
||||
}
|
||||
else if (task instanceof EncryptAndCommitBallotCommand) {
|
||||
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 {
|
||||
String errorMessage = "handleSingleTask: unknown type of ControllerCommand received: " +
|
||||
task.getClass().getName();
|
||||
logger.error(errorMessage);
|
||||
throw new RuntimeException(errorMessage);
|
||||
logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName());
|
||||
doReportErrorAndForceRestart(SystemMessages.getSomethingWrongMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Map<string, funcImpl> taskHandlers = new Map<>() {
|
||||
CaskTask.getClass().getName() : doCast(),
|
||||
ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
|
||||
}
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
private synchronized boolean wasShutDownCalled () {
|
||||
private boolean wasShutDownCalled () {
|
||||
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 () {
|
||||
queue.clear();
|
||||
state.clearPlaintext();
|
||||
|
@ -216,7 +171,22 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
|
|||
state.stateIdentifier = VBState.NEW_VOTER;
|
||||
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 () {
|
||||
|
@ -227,7 +197,7 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
|
|||
new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
}
|
||||
else {
|
||||
logger.warn("doChooseChannel: current state is " + state.stateIdentifier);
|
||||
logger.debug("doChooseChannel: current state is " + state.stateIdentifier);
|
||||
// ignore this request
|
||||
}
|
||||
}
|
||||
|
@ -236,15 +206,14 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
|
|||
if (state.stateIdentifier == VBState.CHOOSE_CHANNEL) {
|
||||
logger.debug("doing set channel and ask questions");
|
||||
state.stateIdentifier = VBState.ANSWER_QUESTIONS;
|
||||
BallotAnswer[] channelChoiceAnswers = task.channelChoiceAnswers;
|
||||
List<BallotAnswer> channelChoiceAnswers = task.channelChoiceAnswers;
|
||||
state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers);
|
||||
state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(channelChoiceAnswers);
|
||||
state.stateIdentifier = VBState.ANSWER_QUESTIONS;
|
||||
ui.askVoterQuestions(state.channelSpecificQuestions,
|
||||
new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
}
|
||||
else {
|
||||
logger.warn("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier);
|
||||
logger.debug("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier);
|
||||
// ignore this request
|
||||
}
|
||||
}
|
||||
|
@ -254,10 +223,8 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
|
|||
if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) {
|
||||
logger.debug("doing commit");
|
||||
state.stateIdentifier = VBState.COMMITTING_TO_BALLOT;
|
||||
VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot);
|
||||
state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot();
|
||||
state.secrets = encryptionAndSecrets.getSecrets();
|
||||
ui.notifyVoterToWaitForFinish(waitForCommitMessage,
|
||||
setBallotData (task);
|
||||
ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCommitMessage(),
|
||||
new WaitForFinishCallback(generateRequestIdentifier(),
|
||||
state.currentBallotSerialNumber,
|
||||
this.queue));
|
||||
|
@ -266,38 +233,38 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
|
|||
new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
}
|
||||
else {
|
||||
logger.warn("doCommit: current state is " + state.stateIdentifier);
|
||||
logger.debug("doCommit: current state is " + state.stateIdentifier);
|
||||
// ignore this request
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void doAudit () {
|
||||
if (state.stateIdentifier == VBState.CAST_OR_AUDIT) {
|
||||
logger.debug("doing audit");
|
||||
state.stateIdentifier = VBState.FINALIZING;
|
||||
outputDevice.audit(state.secrets,
|
||||
new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
ui.notifyVoterToWaitForFinish(waitForAuditMessage,
|
||||
new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
}
|
||||
else {
|
||||
logger.warn("doAudit: current state is " + state.stateIdentifier);
|
||||
// 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 doCast () {
|
||||
private void doFinalize (boolean auditRequested) {
|
||||
if (state.stateIdentifier == VBState.CAST_OR_AUDIT) {
|
||||
logger.debug("casting ballot");
|
||||
logger.debug("finalizing");
|
||||
state.stateIdentifier = VBState.FINALIZING;
|
||||
outputDevice.castBallot(
|
||||
new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
ui.notifyVoterToWaitForFinish(waitForCastMessage,
|
||||
ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(),
|
||||
new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
if (auditRequested) {
|
||||
outputDevice.audit(state.secrets,
|
||||
new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
}
|
||||
else {
|
||||
outputDevice.castBallot(
|
||||
new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.warn("doCast: current state is " + state.stateIdentifier);
|
||||
logger.debug("doFinalize: current state is " + state.stateIdentifier);
|
||||
// ignore this request
|
||||
}
|
||||
}
|
||||
|
@ -312,14 +279,16 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
|
|||
ANSWER_QUESTIONS,
|
||||
COMMITTING_TO_BALLOT,
|
||||
CAST_OR_AUDIT,
|
||||
FINALIZING
|
||||
FINALIZING,
|
||||
FATAL_ERROR_FORCE_NEW_VOTER,
|
||||
SHUT_DOWN
|
||||
}
|
||||
|
||||
|
||||
private class ControllerState {
|
||||
public VotingBoothImpl.VBState stateIdentifier;
|
||||
public VBState stateIdentifier;
|
||||
public int channelIdentifier;
|
||||
public BallotQuestion[] channelSpecificQuestions;
|
||||
public List<BallotQuestion> channelSpecificQuestions;
|
||||
public PlaintextBallot plaintextBallot;
|
||||
public EncryptedBallot encryptedBallot;
|
||||
public BallotSecrets secrets;
|
||||
|
@ -338,12 +307,10 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(),
|
|||
|
||||
|
||||
public void clearPlaintext () {
|
||||
//TODO: Do we need safe erasure?
|
||||
plaintextBallot = null;
|
||||
}
|
||||
|
||||
public void clearCiphertext () {
|
||||
//TODO: Do we need safe erasure?
|
||||
encryptedBallot = null;
|
||||
secrets = null;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.voting.controller.callbacks;
|
||||
|
||||
|
||||
import meerkat.voting.controller.SystemMessages;
|
||||
import meerkat.voting.controller.commands.*;
|
||||
import meerkat.voting.controller.commands.ControllerCommand;
|
||||
import meerkat.voting.controller.commands.RestartVotingCommand;
|
||||
|
@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
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);
|
||||
|
||||
public CastOrAuditCallback(int requestId,
|
||||
|
@ -20,18 +20,18 @@ public class CastOrAuditCallback extends ControllerCallback {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Object result) {
|
||||
assert (result instanceof FinalizeBallotChoice);
|
||||
|
||||
public void onSuccess(FinalizeBallotChoice result) {
|
||||
if (result == FinalizeBallotChoice.CAST) {
|
||||
controllerQueue.add(new CastCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
enqueueCommand(new CastCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
}
|
||||
else if (result == FinalizeBallotChoice.AUDIT) {
|
||||
controllerQueue.add(new AuditCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
enqueueCommand(new AuditCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
}
|
||||
else {
|
||||
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
|
||||
public void onFailure(Throwable 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;
|
||||
|
||||
import meerkat.protobuf.Voting;
|
||||
import meerkat.voting.controller.commands.ChannelDeterminedCommand;
|
||||
import meerkat.voting.controller.commands.ControllerCommand;
|
||||
import meerkat.voting.controller.commands.RestartVotingCommand;
|
||||
import meerkat.protobuf.Voting.*;
|
||||
import meerkat.voting.controller.SystemMessages;
|
||||
import meerkat.voting.controller.commands.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
public ChannelChoiceCallback(int requestId,
|
||||
|
@ -22,22 +22,22 @@ public class ChannelChoiceCallback extends ControllerCallback {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Object result) {
|
||||
assert (result instanceof Voting.BallotAnswer[]);
|
||||
if (((Voting.BallotAnswer[])result).length != 0) {
|
||||
public void onSuccess(List<BallotAnswer> result) {
|
||||
if (result.size() != 0) {
|
||||
logger.debug("callback for channel choice returned success");
|
||||
controllerQueue.add(
|
||||
new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result));
|
||||
enqueueCommand(new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), result));
|
||||
}
|
||||
else {
|
||||
logger.debug("ChannelChoiceCallback got a cancellation response: " + result);
|
||||
controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable 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;
|
||||
|
||||
/**
|
||||
* Created by hai on 18/05/16.
|
||||
*/
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import meerkat.voting.controller.commands.ControllerCommand;
|
||||
|
||||
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 long ballotSerialNumber;
|
||||
protected LinkedBlockingQueue<ControllerCommand> controllerQueue;
|
||||
private LinkedBlockingQueue<ControllerCommand> controllerQueue;
|
||||
|
||||
protected ControllerCallback (int requestId,
|
||||
long ballotSerialNumber,
|
||||
|
@ -21,7 +25,13 @@ public abstract class ControllerCallback implements FutureCallback {
|
|||
protected int getRequestIdentifier () {
|
||||
return requestIdentifier;
|
||||
}
|
||||
|
||||
protected long getBallotSerialNumber () {
|
||||
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;
|
||||
|
||||
public class NewVoterCallback extends ControllerCallback {
|
||||
public class NewVoterCallback extends ControllerCallback<Void> {
|
||||
protected final static Logger logger = LoggerFactory.getLogger(NewVoterCallback.class);
|
||||
|
||||
public NewVoterCallback(int requestId,
|
||||
|
@ -18,15 +18,14 @@ public class NewVoterCallback extends ControllerCallback {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Object v) {
|
||||
public void onSuccess(Void v) {
|
||||
logger.debug("callback for new voting returned success");
|
||||
assert v==null;
|
||||
controllerQueue.add(new ChannelChoiceCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
enqueueCommand(new ChannelChoiceCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable 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;
|
||||
|
||||
import meerkat.voting.controller.SystemMessages;
|
||||
import meerkat.voting.controller.commands.ControllerCommand;
|
||||
import meerkat.voting.controller.commands.ReportErrorCommand;
|
||||
import meerkat.voting.controller.commands.RestartVotingCommand;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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);
|
||||
|
||||
public OutputDeviceCallback(int requestId,
|
||||
|
@ -17,13 +19,14 @@ public class OutputDeviceCallback extends ControllerCallback {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Object v) {
|
||||
assert v instanceof Void;
|
||||
public void onSuccess(Void v) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable 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;
|
||||
|
||||
import meerkat.protobuf.Voting;
|
||||
import meerkat.protobuf.Voting.*;
|
||||
import meerkat.voting.controller.SystemMessages;
|
||||
import meerkat.voting.controller.commands.ControllerCommand;
|
||||
import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand;
|
||||
import meerkat.voting.controller.commands.ReportErrorCommand;
|
||||
import meerkat.voting.controller.commands.RestartVotingCommand;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
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);
|
||||
|
||||
public VotingCallback(int requestId,
|
||||
|
@ -19,22 +22,22 @@ public class VotingCallback extends ControllerCallback {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Object result) {
|
||||
assert result instanceof Voting.BallotAnswer[];
|
||||
if (((Voting.BallotAnswer[])result).length != 0) {
|
||||
public void onSuccess(List<BallotAnswer> result) {
|
||||
if (result.size() != 0) {
|
||||
logger.debug("callback for voting returned success");
|
||||
controllerQueue.add(
|
||||
new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result));
|
||||
enqueueCommand(new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), result));
|
||||
}
|
||||
else {
|
||||
logger.debug("VotingCallback got a cancellation response: " + result);
|
||||
controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable 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;
|
||||
|
||||
import meerkat.voting.controller.SystemMessages;
|
||||
import meerkat.voting.controller.commands.ControllerCommand;
|
||||
import meerkat.voting.controller.commands.ReportErrorCommand;
|
||||
import meerkat.voting.controller.commands.RestartVotingCommand;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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);
|
||||
|
||||
public WaitForFinishCallback(int requestId,
|
||||
|
@ -17,13 +19,14 @@ public class WaitForFinishCallback extends ControllerCallback {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Object v) {
|
||||
assert v instanceof Void;
|
||||
public void onSuccess(Void v) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable 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;
|
||||
|
||||
import meerkat.protobuf.Voting;
|
||||
import meerkat.protobuf.Voting.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by hai on 11/04/16.
|
||||
*/
|
||||
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);
|
||||
channelChoiceAnswers = answers;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
package meerkat.voting.controller.commands;
|
||||
|
||||
import meerkat.protobuf.Voting;
|
||||
import meerkat.protobuf.Voting.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
import meerkat.protobuf.Voting.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by hai on 02/05/16.
|
||||
*/
|
||||
public abstract class QuestionSelector {
|
||||
public interface QuestionSelector {
|
||||
|
||||
protected Object selectionData;
|
||||
protected BallotQuestion[] allBallotQuestions;
|
||||
public void setAllBallotQuestions (List<BallotQuestion> allBallotQuestions);
|
||||
|
||||
public QuestionSelector(Object selectionData, BallotQuestion[] allBallotQuestions) {
|
||||
this.selectionData = selectionData;
|
||||
this.allBallotQuestions = allBallotQuestions;
|
||||
}
|
||||
public void setSelectionData(SelectionData data);
|
||||
|
||||
public abstract int getChannelIdentifier (BallotAnswer[] channelChoiceAnswers);
|
||||
public abstract BallotQuestion[] selectQuestionsForVoter (BallotAnswer[] channelChoiceAnswers);
|
||||
public int getChannelIdentifier (List<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;
|
||||
|
||||
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 HashMap<SingleChosenAnswer, int[]> questionsSelections;
|
||||
private int[] sharedDefaults; // a category of questions to include for every voter
|
||||
// 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;
|
||||
|
||||
public SimpleCategoriesData() {
|
||||
sharedDefaults = new int[0];
|
||||
questionsSelections = new HashMap();
|
||||
questionSelectionsByAnswer = new int[0][][];
|
||||
maxQuestionNumber = -1;
|
||||
}
|
||||
|
||||
public void setSharedDefaults(int[] sharedDefaultsIndices) {
|
||||
this.sharedDefaults = sharedDefaultsIndices;
|
||||
maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(sharedDefaultsIndices));
|
||||
this.sharedDefaults = sharedDefaultsIndices.clone();
|
||||
maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(sharedDefaultsIndices));
|
||||
}
|
||||
|
||||
public int[] getSharedDefaults() {
|
||||
return sharedDefaults;
|
||||
}
|
||||
|
||||
public void setItem(SingleChosenAnswer key, int[] questionIndices) {
|
||||
questionsSelections.put(key, questionIndices);
|
||||
maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(questionIndices));
|
||||
public void setItem(int questionNumber, int answerNumber, int[] questionIndices) {
|
||||
if (questionNumber >= questionSelectionsByAnswer.length) {
|
||||
int[][][] tmp = new int[questionNumber+1][][];
|
||||
System.arraycopy(questionSelectionsByAnswer, 0, tmp, 0, questionSelectionsByAnswer.length);
|
||||
tmp[questionNumber] = new int[0][];
|
||||
questionSelectionsByAnswer = tmp;
|
||||
}
|
||||
|
||||
if (answerNumber >= questionSelectionsByAnswer[questionNumber].length) {
|
||||
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(SingleChosenAnswer key) {
|
||||
return questionsSelections.get(key);
|
||||
public int[] getItem(int questionNumber, int answerNumber) {
|
||||
return questionSelectionsByAnswer[questionNumber][answerNumber];
|
||||
}
|
||||
|
||||
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;
|
||||
for (int i: arr) {
|
||||
m = Math.max(i , m);
|
||||
|
@ -53,8 +74,11 @@ public class SimpleCategoriesData {
|
|||
String s = "SimpleCategoriesData:\n";
|
||||
s += "shared : " + arrayToString(sharedDefaults) + "\n";
|
||||
s += "map : \n";
|
||||
for (SingleChosenAnswer key : questionsSelections.keySet()) {
|
||||
s += key + " : " + arrayToString(questionsSelections.get(key)) + "\n";
|
||||
for (int questionNumber = 0; questionNumber < questionSelectionsByAnswer.length; ++questionNumber) {
|
||||
for (int answerNumber = 0; answerNumber < questionSelectionsByAnswer[questionNumber].length; ++answerNumber) {
|
||||
s += "(" + questionNumber + ", " + answerNumber + ") -> " +
|
||||
arrayToString(questionSelectionsByAnswer[questionNumber][answerNumber]) + "\n";
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -1,75 +1,88 @@
|
|||
package meerkat.voting.controller.selector;
|
||||
|
||||
import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException;
|
||||
import meerkat.protobuf.Voting.*;
|
||||
import meerkat.protobuf.Voting.BallotAnswer;
|
||||
import meerkat.protobuf.Voting.BallotQuestion;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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);
|
||||
private BallotQuestion[] allBallotQuestions;
|
||||
private SimpleCategoriesData selectionData;
|
||||
private boolean[] isSelected;
|
||||
|
||||
public SimpleListCategoriesSelector(Object selectionData, BallotQuestion[] allBallotQuestions) {
|
||||
super(selectionData, allBallotQuestions);
|
||||
initializeAttributes (allBallotQuestions);
|
||||
}
|
||||
|
||||
public SimpleListCategoriesSelector(Object selectionData, ArrayList<BallotQuestion> allBallotQuestions) {
|
||||
super(selectionData, null);
|
||||
BallotQuestion[] questionsArr = new BallotQuestion[allBallotQuestions.size()];
|
||||
for (int i = 0; i < questionsArr.length; ++i) {
|
||||
questionsArr[i] = allBallotQuestions.get(i);
|
||||
}
|
||||
initializeAttributes (questionsArr);
|
||||
public SimpleListCategoriesSelector() {
|
||||
this.allBallotQuestions = null;
|
||||
this.selectionData = null;
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BallotQuestion[] selectQuestionsForVoter(BallotAnswer[] channelChoiceAnswers) {
|
||||
SimpleCategoriesData data = (SimpleCategoriesData)selectionData;
|
||||
public List<BallotQuestion> selectQuestionsForVoter(List<BallotAnswer> channelChoiceAnswers) {
|
||||
java.util.Arrays.fill(isSelected, false);
|
||||
markSelected(data.getSharedDefaults());
|
||||
markSelectionsOfVoterChannelChoice (channelChoiceAnswers);
|
||||
markSelected(selectionData.getSharedDefaults());
|
||||
markSelectionsOfVoterChannelChoice ((BallotAnswer[])channelChoiceAnswers.toArray());
|
||||
int[] questionIndices = extractSelectedIndices();
|
||||
BallotQuestion[] selectedQuestions = new BallotQuestion[questionIndices.length];
|
||||
for (int i = 0; i < questionIndices.length; ++i) {
|
||||
selectedQuestions[i] = allBallotQuestions[questionIndices[i]];
|
||||
List<BallotQuestion> selectedQuestions = new ArrayList<>();
|
||||
for (int questionIndex: questionIndices) {
|
||||
selectedQuestions.add(allBallotQuestions[questionIndex]);
|
||||
}
|
||||
return selectedQuestions;
|
||||
}
|
||||
|
||||
private void markSelectionsOfVoterChannelChoice(BallotAnswer[] channelChoiceAnswers) {
|
||||
SimpleCategoriesData data = (SimpleCategoriesData)selectionData;
|
||||
for (int q = 0; q < channelChoiceAnswers.length; ++q) {
|
||||
BallotAnswer ballotAnswer = channelChoiceAnswers[q];
|
||||
assertAnswerLengthIsOne(ballotAnswer, q);
|
||||
SingleChosenAnswer key = new SingleChosenAnswer(q, ballotAnswer.getAnswer(0));
|
||||
assertKeyInSelectionData(key);
|
||||
markSelected(data.getItem(key));
|
||||
assertKeyInSelectionData(q, (int)ballotAnswer.getAnswer(0));
|
||||
markSelected(selectionData.getItem(q, (int)ballotAnswer.getAnswer(0)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,17 +94,16 @@ public class SimpleListCategoriesSelector extends QuestionSelector {
|
|||
errorMessage += " " + i;
|
||||
}
|
||||
logger.error(errorMessage);
|
||||
throw new ValueException(errorMessage);
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertKeyInSelectionData(SingleChosenAnswer key) {
|
||||
SimpleCategoriesData data = (SimpleCategoriesData)selectionData;
|
||||
int[] questionListToAdd = data.getItem(key);
|
||||
private void assertKeyInSelectionData(int questionNumber, int answerNumber) {
|
||||
int[] questionListToAdd = selectionData.getItem(questionNumber, answerNumber);
|
||||
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);
|
||||
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.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Date;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Timer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import meerkat.voting.controller.callbacks.*;
|
||||
|
@ -45,54 +43,47 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
|
|||
logger.info("entered the voting flow");
|
||||
while (true) {
|
||||
try {
|
||||
UICommand task = queue.take();
|
||||
handleSingleTask (task);
|
||||
UICommand command = queue.take();
|
||||
handleSingleCommand(command);
|
||||
}
|
||||
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) {
|
||||
if (!(task instanceof TickCommand)) {
|
||||
private void handleSingleCommand(UICommand command) {
|
||||
if (!(command instanceof TickCommand)) {
|
||||
if (startWaitingTime != null) {
|
||||
stopWaiting();
|
||||
}
|
||||
}
|
||||
|
||||
if (task instanceof StartSessionUICommand) {
|
||||
doShowWelcomeScreen((StartSessionUICommand)task);
|
||||
return;
|
||||
if (command instanceof StartSessionUICommand) {
|
||||
doShowWelcomeScreen((StartSessionUICommand)command);
|
||||
}
|
||||
else if (task instanceof ChannelChoiceUICommand) {
|
||||
doAskChannelChoiceQuestions((ChannelChoiceUICommand)task);
|
||||
return;
|
||||
else if (command instanceof ChannelChoiceUICommand) {
|
||||
doAskChannelChoiceQuestions((ChannelChoiceUICommand)command);
|
||||
}
|
||||
else if (task instanceof RaceVotingUICommand) {
|
||||
doAskVotingQuestions((RaceVotingUICommand)task);
|
||||
return;
|
||||
else if (command instanceof RaceVotingUICommand) {
|
||||
doAskVotingQuestions((RaceVotingUICommand)command);
|
||||
}
|
||||
else if (task instanceof CastOrAuditUICommand) {
|
||||
doCastOrAudit ((CastOrAuditUICommand)task);
|
||||
return;
|
||||
else if (command instanceof CastOrAuditUICommand) {
|
||||
doCastOrAudit ((CastOrAuditUICommand)command);
|
||||
}
|
||||
else if (task instanceof HaltCommand) {
|
||||
doHalt((HaltCommand)task);
|
||||
return;
|
||||
else if (command instanceof FatalErrorUICommand) {
|
||||
doFatalError((FatalErrorUICommand)command);
|
||||
}
|
||||
else if (task instanceof WaitForFinishCommand) {
|
||||
doWaitForFinish((WaitForFinishCommand)task);
|
||||
return;
|
||||
else if (command instanceof WaitForFinishUICommand) {
|
||||
doWaitForFinish((WaitForFinishUICommand)command);
|
||||
}
|
||||
else if (task instanceof TickCommand) {
|
||||
else if (command instanceof TickCommand) {
|
||||
doTick ();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
String errorMessage = "handleSingleTask: unknown type of UICommand received: " +
|
||||
task.getClass().getName();
|
||||
String errorMessage = "handleSingleCommand: unknown type of UICommand received: " +
|
||||
command.getClass().getName();
|
||||
logger.error(errorMessage);
|
||||
throw new RuntimeException(errorMessage);
|
||||
}
|
||||
|
@ -105,13 +96,13 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
|
|||
queue.add(new StartSessionUICommand((ControllerCallback)callback));
|
||||
}
|
||||
|
||||
private void doShowWelcomeScreen(StartSessionUICommand task) {
|
||||
private void doShowWelcomeScreen(StartSessionUICommand command) {
|
||||
logger.debug("UI entered doShowWelcomeScreen");
|
||||
System.out.println("Welcome, new voter!");
|
||||
waitForEnter(null);
|
||||
ControllerCallback callback = task.getCallback();
|
||||
ControllerCallback callback = command.getCallback();
|
||||
assert (callback instanceof NewVoterCallback);
|
||||
((NewVoterCallback)callback).onSuccess(null);
|
||||
callback.onSuccess(null);
|
||||
}
|
||||
|
||||
private void stopWaiting () {
|
||||
|
@ -138,45 +129,45 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
|
|||
}
|
||||
|
||||
@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");
|
||||
ChannelChoiceUICommand task = new ChannelChoiceUICommand(questions, (ControllerCallback)callback);
|
||||
queue.add(task);
|
||||
ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ControllerCallback)callback);
|
||||
queue.add(command);
|
||||
}
|
||||
|
||||
private void doAskChannelChoiceQuestions (ChannelChoiceUICommand task) {
|
||||
private void doAskChannelChoiceQuestions (ChannelChoiceUICommand command) {
|
||||
logger.debug("UI: doAskChannelChoiceQuestions");
|
||||
System.out.println("Showing questions for choosing channel:\n");
|
||||
try {
|
||||
BallotAnswer[] answers = askVoterForAnswers(task.getQuestions());
|
||||
task.getCallback().onSuccess(answers);
|
||||
List<BallotAnswer> answers = askVoterForAnswers(command.getQuestions());
|
||||
command.getCallback().onSuccess(answers);
|
||||
}
|
||||
catch (IOException e) {
|
||||
String errorMessage = "Channel choice failed due to IOException: " + e;
|
||||
logger.error (errorMessage);
|
||||
System.err.println(errorMessage);
|
||||
task.getCallback().onFailure(e);
|
||||
command.getCallback().onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@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");
|
||||
queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback));
|
||||
}
|
||||
|
||||
private void doAskVotingQuestions (RaceVotingUICommand task) {
|
||||
private void doAskVotingQuestions (RaceVotingUICommand command) {
|
||||
logger.debug("UI: doAskVotingQuestions");
|
||||
System.out.println("Showing questions for race voting:\n");
|
||||
try {
|
||||
BallotAnswer[] answers = askVoterForAnswers(task.getQuestions());
|
||||
task.getCallback().onSuccess(answers);
|
||||
List<BallotAnswer> answers = askVoterForAnswers(command.getQuestions());
|
||||
command.getCallback().onSuccess(answers);
|
||||
}
|
||||
catch (IOException e) {
|
||||
String errorMessage = "Asking voting questions failed due to IOException: " + e;
|
||||
logger.error (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));
|
||||
}
|
||||
|
||||
private void doCastOrAudit(CastOrAuditUICommand task) {
|
||||
private void doCastOrAudit(CastOrAuditUICommand command) {
|
||||
logger.debug("UI entered doCastOrAudit");
|
||||
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 {
|
||||
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);
|
||||
((CastOrAuditCallback)callback).onSuccess(fChoice);
|
||||
}
|
||||
catch (IllegalArgumentException|IOException e) {
|
||||
String errorMessage = "doCastOrAudit: some error with reading input from console. details: " + e;
|
||||
logger.error(errorMessage);
|
||||
task.getCallback().onFailure(e);
|
||||
command.getCallback().onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void notifyVoterToWaitForFinish(UIElement message, FutureCallback<Boolean> callback) {
|
||||
public void notifyVoterToWaitForFinish(UIElement message, FutureCallback<Void> callback) {
|
||||
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");
|
||||
|
||||
startWaitingTime = new Date();
|
||||
|
||||
UIElement message = task.getMessage();
|
||||
UIElement message = command.getMessage();
|
||||
String messageString;
|
||||
if (message.getType() != UIElementDataType.TEXT) {
|
||||
messageString = "Default message: encountered an error. System halting";
|
||||
|
@ -240,39 +231,57 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
|
|||
@Override
|
||||
public void showErrorMessageAndHalt(UIElement errorMessage, FutureCallback<Boolean> callback) {
|
||||
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;
|
||||
if (errorMessage.getType() != UIElementDataType.TEXT) {
|
||||
errorMessageString = "Default message: encountered an error. System halting";
|
||||
} else {
|
||||
errorMessageString = bytesToString(errorMessage.getData());
|
||||
}
|
||||
System.out.println(errorMessageString);
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("UI halt has been interrupted. Details: " + e);
|
||||
ControllerCallback callback = task.getCallback();
|
||||
assert callback instanceof HaltCallback;
|
||||
((HaltCallback) callback).onFailure(e);
|
||||
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);
|
||||
for (int i = 0; i < buttonLabelStrings.length; ++i) {
|
||||
System.out.println("" + i + " - " + buttonLabelStrings[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
String s = readInputLine();
|
||||
Integer chosenButton = new Integer(s);
|
||||
command.getCallback().onSuccess(chosenButton);
|
||||
}
|
||||
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 () {
|
||||
if (startWaitingTime != null) {
|
||||
System.out.print ("."); // still waiting
|
||||
|
@ -295,9 +304,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
|
|||
}
|
||||
|
||||
|
||||
private void assertQuestionsAreValid (BallotQuestion[] questions) {
|
||||
for (int index = 0; index < questions.length; ++index) {
|
||||
BallotQuestion question = questions[index];
|
||||
private void assertQuestionsAreValid (List<BallotQuestion> questions) {
|
||||
for (int index = 0; index < questions.size(); ++index) {
|
||||
BallotQuestion question = questions.get(index);
|
||||
if (question.getIsMandatory()) {
|
||||
String errorMessage = "askVoterQuestions: question number " + index + " is marked as mandatory";
|
||||
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);
|
||||
|
||||
BallotAnswer answers[] = new BallotAnswer[questions.length];
|
||||
List<BallotAnswer> answers = new ArrayList<>();
|
||||
int index = 0;
|
||||
while (index < questions.length) {
|
||||
BallotQuestion question = questions[index];
|
||||
while (index < questions.size()) {
|
||||
BallotQuestion question = questions.get(index);
|
||||
System.out.println("Question number " + index);
|
||||
showQuestionOnScreen(question);
|
||||
|
||||
|
@ -330,13 +339,14 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
|
|||
}
|
||||
else if (s.equals("back") || s.equals("b")) {
|
||||
--index;
|
||||
answers.remove(index);
|
||||
}
|
||||
else if (s.equals("skip") || s.equals("s")) {
|
||||
answers[index] = translateStringAnswerToProtoBufMessageAnswer("");
|
||||
answers.add(translateStringAnswerToProtoBufMessageAnswer(""));
|
||||
++index;
|
||||
}
|
||||
else {
|
||||
answers[index] = translateStringAnswerToProtoBufMessageAnswer(s);
|
||||
answers.add(translateStringAnswerToProtoBufMessageAnswer(s));
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package meerkat.voting.ui;
|
|||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import meerkat.protobuf.Voting.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 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 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.
|
||||
* @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
|
||||
*/
|
||||
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.
|
||||
|
@ -51,7 +53,7 @@ public interface VotingBoothUI {
|
|||
* @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)
|
||||
*/
|
||||
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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.voting.ui.uicommands;
|
||||
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
import meerkat.voting.controller.callbacks.*;
|
||||
|
||||
/**
|
||||
* Created by hai on 21/04/16.
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
package meerkat.voting.ui.uicommands;
|
||||
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
this.questions = questions;
|
||||
}
|
||||
|
||||
public BallotQuestion[] getQuestions () {
|
||||
public List<BallotQuestion> getQuestions () {
|
||||
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;
|
||||
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
this.questions = questions;
|
||||
}
|
||||
|
||||
public BallotQuestion[] getQuestions () {
|
||||
public List<BallotQuestion> getQuestions () {
|
||||
return this.questions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.voting.ui.uicommands;
|
||||
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
import meerkat.voting.controller.callbacks.*;
|
||||
|
||||
/**
|
||||
* Created by hai on 18/04/16.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.voting.ui.uicommands;
|
||||
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
import meerkat.voting.controller.callbacks.*;
|
||||
|
||||
/**
|
||||
* Created by hai on 18/04/16.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.voting.ui.uicommands;
|
||||
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
import meerkat.voting.controller.callbacks.*;
|
||||
|
||||
//TODO: make this class generic
|
||||
public abstract class UICommand {
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
package meerkat.voting.ui.uicommands;
|
||||
|
||||
import meerkat.protobuf.Voting.*;
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
import meerkat.voting.controller.callbacks.*;
|
||||
|
||||
/**
|
||||
* Created by hai on 18/04/16.
|
||||
*/
|
||||
|
||||
public class WaitForFinishCommand extends UICommand {
|
||||
public class WaitForFinishUICommand extends UICommand {
|
||||
|
||||
private final UIElement message;
|
||||
|
||||
public WaitForFinishCommand(UIElement message, ControllerCallback callback)
|
||||
public WaitForFinishUICommand(UIElement message, ControllerCallback callback)
|
||||
{
|
||||
super(callback);
|
||||
this.message = message;
|
Loading…
Reference in New Issue