change the output class to run as a thread.
It is now runnable and has its own queue of (also new) OutputCommands, and its own shutdown flag.vbdev2
parent
76d3fdeac2
commit
13f8948cfb
|
@ -73,8 +73,7 @@ message EncryptedBallot {
|
|||
|
||||
message SignedEncryptedBallot {
|
||||
EncryptedBallot encrypted_ballot = 1;
|
||||
bytes signer_id = 2;
|
||||
Signature signature = 3;
|
||||
Signature signature = 2;
|
||||
}
|
||||
|
||||
message BallotSecrets {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package meerkat.voting;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.crypto.Encryption;
|
||||
import meerkat.protobuf.Crypto.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by hai on 07/06/16.
|
||||
*/
|
||||
public class ToyEncryption implements Encryption {
|
||||
|
||||
@Override
|
||||
public RerandomizableEncryptedMessage encrypt(Message plaintext, EncryptionRandomness rnd) throws IOException {
|
||||
ByteString cipher = ByteString.copyFromUtf8("Encryption(")
|
||||
.concat(plaintext.toByteString())
|
||||
.concat(ByteString.copyFromUtf8(", Random("))
|
||||
.concat(rnd.getData())
|
||||
.concat(ByteString.copyFromUtf8("))"));
|
||||
return RerandomizableEncryptedMessage.newBuilder()
|
||||
.setData(cipher)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RerandomizableEncryptedMessage rerandomize
|
||||
(RerandomizableEncryptedMessage msg, EncryptionRandomness rnd) throws InvalidProtocolBufferException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EncryptionRandomness generateRandomness(Random rand) {
|
||||
ByteBuffer b = ByteBuffer.allocate(4);
|
||||
b.putInt(rand.nextInt());
|
||||
byte[] bArr = b.array();
|
||||
ByteString bs = ByteString.copyFrom(bArr);
|
||||
return EncryptionRandomness.newBuilder()
|
||||
.setData(bs)
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package meerkat.voting;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.crypto.DigitalSignature;
|
||||
import meerkat.protobuf.Crypto.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.SignatureException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
/**
|
||||
* Created by hai on 07/06/16.
|
||||
*/
|
||||
public class ToySignature implements DigitalSignature {
|
||||
|
||||
private final ByteString signerID;
|
||||
private ByteString msgByteString;
|
||||
|
||||
|
||||
public ToySignature(String signerID) {
|
||||
this.signerID = ByteString.copyFromUtf8(signerID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteString getSignerID() {
|
||||
return signerID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateContent(Message msg) throws SignatureException {
|
||||
msgByteString = msg.toByteString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Signature sign() throws SignatureException {
|
||||
ByteString signature = ByteString.copyFromUtf8("Signature(")
|
||||
.concat(msgByteString)
|
||||
.concat(ByteString.copyFromUtf8(")"));
|
||||
return Signature.newBuilder()
|
||||
.setType(SignatureType.ECDSA)
|
||||
.setData(signature)
|
||||
.setSignerId(getSignerID())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loadVerificationCertificates(InputStream certStream) throws CertificateException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearVerificationCertificates() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initVerify(Signature sig) throws CertificateException, InvalidKeyException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clearSigningKey() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
package meerkat.voting;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.crypto.DigitalSignature;
|
||||
import meerkat.crypto.Encryption;
|
||||
import meerkat.protobuf.Voting.*;
|
||||
import meerkat.voting.controller.*;
|
||||
import meerkat.voting.controller.selector.SimpleListCategoriesSelector;
|
||||
import meerkat.voting.output.*;
|
||||
import meerkat.voting.storage.*;
|
||||
import meerkat.voting.encryptor.*;
|
||||
import meerkat.voting.ui.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by hai on 26/04/16.
|
||||
*/
|
||||
public class VotingBoothToyRun {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Random rand = new Random();
|
||||
Encryption enc = new ToyEncryption();
|
||||
DigitalSignature sig = new ToySignature("MY_SIGNER_ID");
|
||||
|
||||
StorageManager storageManager = new StorageManagerMockup();
|
||||
SystemConsoleOutputDevice outputDevice = new SystemConsoleOutputDevice();
|
||||
VBCryptoManager cryptoManager = new VBCryptoManagerImpl(rand, enc, sig);
|
||||
SystemConsoleUI ui = new SystemConsoleUI ();
|
||||
|
||||
|
||||
VotingBoothImpl controller = new VotingBoothImpl();
|
||||
controller.init(outputDevice, cryptoManager, ui, storageManager);
|
||||
|
||||
generateDemoQuestions(controller);
|
||||
|
||||
// create threads
|
||||
|
||||
|
||||
Thread controllerThread = new Thread(controller);
|
||||
controllerThread.setName("Meerkat VB-Controller Thread");
|
||||
Thread uiThread = new Thread(ui);
|
||||
uiThread.setName("Meerkat VB-UI Thread");
|
||||
Thread outputThread = new Thread(outputDevice);
|
||||
uiThread.setName("Meerkat VB-Output Thread");
|
||||
|
||||
uiThread.start();
|
||||
controllerThread.start();
|
||||
outputThread.start();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void generateDemoQuestions(VotingBoothController controller) {
|
||||
|
||||
List<BallotQuestion> channelChoiceQuestions = generateCahnnelChoiceQuestions();
|
||||
controller.setBallotChannelChoiceQuestions(channelChoiceQuestions);
|
||||
|
||||
List<BallotQuestion> allBallotQuestions = generateBallotQuestions();
|
||||
controller.setBallotRaceQuestions(allBallotQuestions);
|
||||
|
||||
SimpleCategoriesSelectionData selectionData = generateSelectionData();
|
||||
SimpleListCategoriesSelector selector = new SimpleListCategoriesSelector(allBallotQuestions, selectionData);
|
||||
controller.setChannelQuestionSelector(selector);
|
||||
}
|
||||
|
||||
|
||||
private static List<BallotQuestion> generateCahnnelChoiceQuestions() {
|
||||
ArrayList<BallotQuestion> channelChoiceQuestions = new ArrayList();
|
||||
|
||||
String[] ans1 = {"Red", "Blue", "Green"};
|
||||
BallotQuestion ccquestion1 = generateBallotQuestion("What is your favorite color?", "Pick one answer", ans1);
|
||||
channelChoiceQuestions.add(ccquestion1);
|
||||
|
||||
String[] ans2 = {"Yes", "No"};
|
||||
BallotQuestion ccquestion2 = generateBallotQuestion("Are you a republican?", "Pick one answer", ans2);
|
||||
channelChoiceQuestions.add(ccquestion2);
|
||||
|
||||
return channelChoiceQuestions;
|
||||
}
|
||||
|
||||
|
||||
private static List<BallotQuestion> generateBallotQuestions() {
|
||||
ArrayList<BallotQuestion> allBallotQuestions = new ArrayList();
|
||||
|
||||
String[] answers1 = {"answer 1", "answer 2", "answer 3", "answer 4"};
|
||||
allBallotQuestions.add(generateBallotQuestion("question 1. Asking something...", "Pick one answer", answers1));
|
||||
|
||||
String[] answers2 = {"Miranda Kerr", "Doutzen Kroes", "Moran Atias", "Roslana Rodina", "Adriana Lima"};
|
||||
allBallotQuestions.add(generateBallotQuestion("question 2: Which model do you like", "Mark as many as you want", answers2));
|
||||
|
||||
allBallotQuestions.add(generateBallotQuestion("question 3. Asking something...", "Pick one answer", answers1));
|
||||
allBallotQuestions.add(generateBallotQuestion("question 4. Asking something...", "Pick one answer", answers1));
|
||||
|
||||
String[] answers5 = {"Clint Eastwood", "Ninja", "Sonic", "Tai-chi", "Diablo", "Keanu"};
|
||||
allBallotQuestions.add(generateBallotQuestion("question 5: Good name for a cat", "Pick the best one", answers5));
|
||||
|
||||
allBallotQuestions.add(generateBallotQuestion("question 6. Asking something...", "Pick one answer", answers1));
|
||||
allBallotQuestions.add(generateBallotQuestion("question 7. Asking something...", "Pick one answer", answers1));
|
||||
allBallotQuestions.add(generateBallotQuestion("question 8. Asking something...", "Pick one answer", answers1));
|
||||
allBallotQuestions.add(generateBallotQuestion("question 9. Asking something...", "Pick one answer", answers1));
|
||||
allBallotQuestions.add(generateBallotQuestion("question 10. Asking something...", "Pick one answer", answers1));
|
||||
allBallotQuestions.add(generateBallotQuestion("question 11. Asking something...", "Pick one answer", answers1));
|
||||
allBallotQuestions.add(generateBallotQuestion("question 12. Asking something...", "Pick one answer", answers1));
|
||||
allBallotQuestions.add(generateBallotQuestion("question 13. Asking something...", "Pick one answer", answers1));
|
||||
allBallotQuestions.add(generateBallotQuestion("question 14. Asking something...", "Pick one answer", answers1));
|
||||
|
||||
return allBallotQuestions;
|
||||
}
|
||||
|
||||
|
||||
private static BallotQuestion generateBallotQuestion(String questionStr, String descriptionStr, String[] answers) {
|
||||
UIElement question = UIElement.newBuilder()
|
||||
.setType(UIElementDataType.TEXT)
|
||||
.setData(stringToBytes(questionStr))
|
||||
.build();
|
||||
|
||||
UIElement description = UIElement.newBuilder()
|
||||
.setType(UIElementDataType.TEXT)
|
||||
.setData(stringToBytes(descriptionStr))
|
||||
.build();
|
||||
|
||||
BallotQuestion.Builder bqb = BallotQuestion.newBuilder();
|
||||
bqb.setIsMandatory(false);
|
||||
bqb.setQuestion(question);
|
||||
bqb.setDescription(description);
|
||||
for (String answerStr : answers) {
|
||||
UIElement answer = UIElement.newBuilder()
|
||||
.setType(UIElementDataType.TEXT)
|
||||
.setData(stringToBytes(answerStr))
|
||||
.build();
|
||||
bqb.addAnswer(answer);
|
||||
}
|
||||
|
||||
return bqb.build();
|
||||
}
|
||||
|
||||
|
||||
private static SimpleCategoriesSelectionData generateSelectionData() {
|
||||
Category sharedDefaults = Category.newBuilder()
|
||||
.addQuestionIndex(0)
|
||||
.addQuestionIndex(5)
|
||||
.addQuestionIndex(9)
|
||||
.build();
|
||||
|
||||
Category cat00 = Category.newBuilder()
|
||||
.addQuestionIndex(1)
|
||||
.addQuestionIndex(4)
|
||||
.addQuestionIndex(6)
|
||||
.addQuestionIndex(7)
|
||||
.build();
|
||||
|
||||
Category cat01 = Category.newBuilder()
|
||||
.addQuestionIndex(2)
|
||||
.addQuestionIndex(4)
|
||||
.addQuestionIndex(8)
|
||||
.build();
|
||||
|
||||
Category cat02 = Category.newBuilder()
|
||||
.addQuestionIndex(3)
|
||||
.addQuestionIndex(8)
|
||||
.build();
|
||||
|
||||
Category cat10 = Category.newBuilder()
|
||||
.addQuestionIndex(10)
|
||||
.addQuestionIndex(11)
|
||||
.build();
|
||||
|
||||
Category cat11 = Category.newBuilder()
|
||||
.addQuestionIndex(12)
|
||||
.addQuestionIndex(13)
|
||||
.build();
|
||||
|
||||
CategoryChooser catChooser0 = CategoryChooser.newBuilder()
|
||||
.addCategory(cat00)
|
||||
.addCategory(cat01)
|
||||
.addCategory(cat02)
|
||||
.build();
|
||||
|
||||
CategoryChooser catChooser1 = CategoryChooser.newBuilder()
|
||||
.addCategory(cat10)
|
||||
.addCategory(cat11)
|
||||
.build();
|
||||
|
||||
return SimpleCategoriesSelectionData.newBuilder()
|
||||
.setSharedDefaults(sharedDefaults)
|
||||
.addCategoryChooser(catChooser0)
|
||||
.addCategoryChooser(catChooser1)
|
||||
.build();
|
||||
|
||||
}
|
||||
private static ByteString stringToBytes (String s) {
|
||||
return ByteString.copyFromUtf8(s);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -108,6 +108,7 @@ public class VotingBoothImpl implements VotingBoothController {
|
|||
shutDownHasBeenCalled = true;
|
||||
queue.clear();
|
||||
ui.callShutDown();
|
||||
outputDevice.callShutDown();
|
||||
}
|
||||
|
||||
private void handleSingleTask (ControllerCommand task) {
|
||||
|
@ -122,18 +123,21 @@ public class VotingBoothImpl implements VotingBoothController {
|
|||
if (task instanceof RestartVotingCommand) {
|
||||
doRestartVoting ();
|
||||
}
|
||||
else if (task instanceof CastCommand) {
|
||||
doFinalize(false);
|
||||
}
|
||||
else if (task instanceof AuditCommand) {
|
||||
doFinalize(true);
|
||||
}
|
||||
else if (task instanceof ChannelChoiceCommand) {
|
||||
doChooseChannel();
|
||||
}
|
||||
else if (task instanceof ChannelDeterminedCommand) {
|
||||
doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task);
|
||||
}
|
||||
else if (task instanceof ChooseFinalizeOptionCommand) {
|
||||
doChooseFinalizeOption();
|
||||
}
|
||||
else if (task instanceof CastCommand) {
|
||||
doFinalize(false);
|
||||
}
|
||||
else if (task instanceof AuditCommand) {
|
||||
doFinalize(true);
|
||||
}
|
||||
else if (task instanceof EncryptAndCommitBallotCommand) {
|
||||
doCommit ((EncryptAndCommitBallotCommand)task);
|
||||
}
|
||||
|
@ -213,6 +217,19 @@ public class VotingBoothImpl implements VotingBoothController {
|
|||
}
|
||||
|
||||
|
||||
private void doChooseFinalizeOption() {
|
||||
if (state.stateIdentifier == VBState.COMMITTING_TO_BALLOT) {
|
||||
logger.debug("doChooseFinalizeOption");
|
||||
state.stateIdentifier = VBState.CAST_OR_AUDIT;
|
||||
ui.castOrAudit(new CastOrAuditCallback(generateRequestIdentifier(),
|
||||
state.currentBallotSerialNumber,
|
||||
this.queue));
|
||||
}
|
||||
else {
|
||||
logger.debug("doChooseFinalizeOption: current state is " + state.stateIdentifier);
|
||||
// ignore this request
|
||||
}
|
||||
}
|
||||
private void doCommit (EncryptAndCommitBallotCommand task) {
|
||||
if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) {
|
||||
logger.debug("doing commit");
|
||||
|
@ -224,7 +241,7 @@ public class VotingBoothImpl implements VotingBoothController {
|
|||
this.queue));
|
||||
outputDevice.commitToBallot(state.plaintextBallot,
|
||||
state.signedEncryptedBallot,
|
||||
new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
new OutputDeviceCommitCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
}
|
||||
else {
|
||||
logger.debug("doCommit: current state is " + state.stateIdentifier);
|
||||
|
@ -252,15 +269,17 @@ public class VotingBoothImpl implements VotingBoothController {
|
|||
if (state.stateIdentifier == VBState.CAST_OR_AUDIT) {
|
||||
logger.debug("finalizing");
|
||||
state.stateIdentifier = VBState.FINALIZING;
|
||||
ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(),
|
||||
new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
if (auditRequested) {
|
||||
ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(),
|
||||
new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
outputDevice.audit(state.secrets,
|
||||
new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
}
|
||||
else {
|
||||
ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCastMessage(),
|
||||
new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
outputDevice.castBallot(
|
||||
new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package meerkat.voting.controller.callbacks;
|
||||
|
||||
import meerkat.voting.controller.SystemMessages;
|
||||
import meerkat.voting.controller.commands.ControllerCommand;
|
||||
import meerkat.voting.controller.commands.ChooseFinalizeOptionCommand;
|
||||
import meerkat.voting.controller.commands.ReportErrorCommand;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class OutputDeviceCommitCallback extends ControllerCallback<Void> {
|
||||
protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCommitCallback.class);
|
||||
|
||||
public OutputDeviceCommitCallback(int requestId,
|
||||
long ballotSerialNumber,
|
||||
LinkedBlockingQueue<ControllerCommand> controllerQueue) {
|
||||
super(requestId, ballotSerialNumber, controllerQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void v) {
|
||||
logger.debug("callback for output device commit success");
|
||||
enqueueCommand(new ChooseFinalizeOptionCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
logger.error("OutputDeviceCommitCallback got a failure: " + t);
|
||||
enqueueCommand(new ReportErrorCommand(getRequestIdentifier(),
|
||||
getBallotSerialNumber(),
|
||||
SystemMessages.getOutputDeviceFailureMessage()));
|
||||
}
|
||||
}
|
|
@ -9,22 +9,24 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class OutputDeviceCallback extends ControllerCallback<Void> {
|
||||
protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCallback.class);
|
||||
public class OutputDeviceFinalizeCallback extends ControllerCallback<Void> {
|
||||
protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceFinalizeCallback.class);
|
||||
|
||||
public OutputDeviceCallback(int requestId,
|
||||
long ballotSerialNumber,
|
||||
LinkedBlockingQueue<ControllerCommand> controllerQueue) {
|
||||
public OutputDeviceFinalizeCallback(int requestId,
|
||||
long ballotSerialNumber,
|
||||
LinkedBlockingQueue<ControllerCommand> controllerQueue) {
|
||||
super(requestId, ballotSerialNumber, controllerQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void v) {
|
||||
logger.debug("callback for output device finalize success");
|
||||
enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
logger.error("WaitForFinishCallback got a failure: " + t);
|
||||
logger.error("OutputDeviceFinalizeCallback got a failure: " + t);
|
||||
enqueueCommand(new ReportErrorCommand(getRequestIdentifier(),
|
||||
getBallotSerialNumber(),
|
||||
SystemMessages.getOutputDeviceFailureMessage()));
|
|
@ -0,0 +1,10 @@
|
|||
package meerkat.voting.controller.commands;
|
||||
|
||||
/**
|
||||
* Created by hai on 11/04/16.
|
||||
*/
|
||||
public class ChooseFinalizeOptionCommand extends ControllerCommand {
|
||||
public ChooseFinalizeOptionCommand(int requestIdentifier, long ballotSerialNumber) {
|
||||
super(requestIdentifier, ballotSerialNumber);
|
||||
}
|
||||
}
|
|
@ -49,7 +49,6 @@ public class VBCryptoManagerImpl implements VBCryptoManager {
|
|||
|
||||
SignedEncryptedBallot signedEncryptedBallot = SignedEncryptedBallot.newBuilder()
|
||||
.setEncryptedBallot(encBallot)
|
||||
.setSignerId(digitalSignature.getSignerID())
|
||||
.setSignature(digitalSignature.sign())
|
||||
.build();
|
||||
|
||||
|
|
|
@ -37,4 +37,5 @@ public interface BallotOutputDevice {
|
|||
*/
|
||||
public void cancelBallot(FutureCallback<Void> callback);
|
||||
|
||||
public void callShutDown();
|
||||
}
|
||||
|
|
|
@ -4,22 +4,31 @@ import com.google.common.util.concurrent.FutureCallback;
|
|||
import com.google.protobuf.ByteString;
|
||||
import meerkat.protobuf.Crypto.*;
|
||||
import meerkat.protobuf.Voting.*;
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
import meerkat.voting.output.outputcommands.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* A toy OutputDevice class
|
||||
* outputs everything simply to the System console
|
||||
*/
|
||||
public class SystemConsoleOutputDevice implements BallotOutputDevice {
|
||||
public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable {
|
||||
|
||||
private Logger logger;
|
||||
private LinkedBlockingQueue<OutputCommand> queue;
|
||||
private volatile boolean shutDownHasBeenCalled;
|
||||
|
||||
public SystemConsoleOutputDevice () {
|
||||
logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class);
|
||||
logger.info("A SystemConsoleOutputDevice is constructed");
|
||||
queue = new LinkedBlockingQueue<>();
|
||||
shutDownHasBeenCalled = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns the UTF8 decoding of byte-string data
|
||||
*/
|
||||
|
@ -27,13 +36,69 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice {
|
|||
return data.toStringUtf8();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run () {
|
||||
logger.info("UI starts running");
|
||||
while (! wasShutDownCalled()) {
|
||||
try {
|
||||
OutputCommand command = queue.take();
|
||||
handleSingleCommand(command);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
logger.warn ("Interrupted while reading from command queue " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean wasShutDownCalled () {
|
||||
return shutDownHasBeenCalled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callShutDown() {
|
||||
logger.info("callShutDown command has been called");
|
||||
shutDownHasBeenCalled = true;
|
||||
queue.clear();
|
||||
}
|
||||
|
||||
|
||||
private void handleSingleCommand(OutputCommand command) {
|
||||
if (command instanceof CommitOutputCommand) {
|
||||
doCommitToBallot((CommitOutputCommand)command);
|
||||
}
|
||||
else if (command instanceof AuditOutputCommand) {
|
||||
doAudit((AuditOutputCommand)command);
|
||||
}
|
||||
else if (command instanceof CastOutputCommand) {
|
||||
doCastBallot((CastOutputCommand)command);
|
||||
}
|
||||
else if (command instanceof CancelOutputCommand) {
|
||||
doCancel((CancelOutputCommand)command);
|
||||
}
|
||||
else {
|
||||
String errorMessage = "handleSingleCommand: unknown type of OutputCommand received: " +
|
||||
command.getClass().getName();
|
||||
logger.error(errorMessage);
|
||||
throw new RuntimeException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void commitToBallot(PlaintextBallot plaintextBallot,
|
||||
SignedEncryptedBallot signedEncryptedBallot,
|
||||
FutureCallback<Void> callback) {
|
||||
logger.debug("entered method commitToBallot");
|
||||
logger.debug("Output interface call to commit to ballot");
|
||||
queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback));
|
||||
}
|
||||
|
||||
public void doCommitToBallot(CommitOutputCommand command) {
|
||||
logger.debug("entered method doCommitToBallot");
|
||||
PlaintextBallot plaintextBallot = command.getPlaintext();
|
||||
long plaintextSerialNumber = plaintextBallot.getSerialNumber();
|
||||
System.out.println("Commitment of Ballot #" + plaintextSerialNumber + " (plaintext):");
|
||||
System.out.println(plaintextBallot);
|
||||
SignedEncryptedBallot signedEncryptedBallot = command.getSignedEncryptedBallot();
|
||||
long encryptedSerialNumber = signedEncryptedBallot.getEncryptedBallot().getSerialNumber();
|
||||
System.out.println("Commitment of Ballot #" + encryptedSerialNumber + " (ciphertext):");
|
||||
if (plaintextSerialNumber != encryptedSerialNumber) {
|
||||
|
@ -42,33 +107,52 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice {
|
|||
}
|
||||
ByteString encryptedData = signedEncryptedBallot.getEncryptedBallot().getData().getData();
|
||||
System.out.println(bytesToString(encryptedData));
|
||||
callback.onSuccess(null);
|
||||
command.getCallback().onSuccess(null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void audit(BallotSecrets ballotSecrets, FutureCallback<Void> callback) {
|
||||
logger.debug("entered method audit");
|
||||
logger.debug("an interface call to audit");
|
||||
queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback));
|
||||
}
|
||||
|
||||
public void doAudit(AuditOutputCommand command) {
|
||||
logger.debug("entered method doAudit");
|
||||
System.out.println("Auditing");
|
||||
printPlaintextBallot (ballotSecrets.getPlaintextBallot());
|
||||
BallotSecrets ballotSecrets = command.getBallotSecrets();
|
||||
printEncryptionRandomness (ballotSecrets.getEncryptionRandomness());
|
||||
printRandomnessGenerationProof (ballotSecrets.getProof());
|
||||
callback.onSuccess(null);
|
||||
command.getCallback().onSuccess(null);
|
||||
}
|
||||
|
||||
private void printPlaintextBallot (PlaintextBallot plaintextBallot) {
|
||||
long plaintextSerialNumber = plaintextBallot.getSerialNumber();
|
||||
System.out.println("Plaintext serial number = " + plaintextSerialNumber);
|
||||
|
||||
System.out.println("Answers = ");
|
||||
for (BallotAnswer ballotAnswer : plaintextBallot.getAnswersList()) {
|
||||
String printableAnswer = "";
|
||||
for (long n : ballotAnswer.getAnswerList()) {
|
||||
printableAnswer += n + " ";
|
||||
}
|
||||
System.out.println(printableAnswer);
|
||||
}
|
||||
@Override
|
||||
public void castBallot(FutureCallback<Void> callback) {
|
||||
logger.debug("an interface call to cast ballot");
|
||||
queue.add(new CastOutputCommand((ControllerCallback)callback));
|
||||
}
|
||||
|
||||
public void doCastBallot(CastOutputCommand command) {
|
||||
logger.debug("entered method doCastBallot");
|
||||
System.out.println("Ballot finalized for casting!");
|
||||
command.getCallback().onSuccess(null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void cancelBallot(FutureCallback<Void> callback) {
|
||||
logger.debug("an interface call to cancel the output");
|
||||
queue.add(new CancelOutputCommand((ControllerCallback)callback));
|
||||
}
|
||||
|
||||
public void doCancel(CancelOutputCommand command) {
|
||||
logger.debug("entered method doCancel");
|
||||
System.out.println("Ballot cancelled!");
|
||||
command.getCallback().onSuccess(null);
|
||||
}
|
||||
|
||||
|
||||
private void printEncryptionRandomness (EncryptionRandomness encryptionRandomness) {
|
||||
System.out.println("Encryption Randomness = ");
|
||||
ByteString data = encryptionRandomness.getData();
|
||||
|
@ -81,18 +165,4 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice {
|
|||
System.out.println(bytesToString(data));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void castBallot(FutureCallback<Void> callback) {
|
||||
logger.debug("entered method castBallot");
|
||||
System.out.println("Ballot finalized for casting!");
|
||||
callback.onSuccess(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelBallot(FutureCallback<Void> callback) {
|
||||
logger.debug("entered method cancelBallot");
|
||||
System.out.println("Ballot cancelled!");
|
||||
callback.onSuccess(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package meerkat.voting.output.outputcommands;
|
||||
|
||||
import meerkat.protobuf.Voting.*;
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
|
||||
/**
|
||||
* Created by hai on 15/06/16.
|
||||
*/
|
||||
public class AuditOutputCommand extends OutputCommand {
|
||||
|
||||
private final BallotSecrets ballotSecrets;
|
||||
|
||||
public AuditOutputCommand(BallotSecrets ballotSecrets, ControllerCallback callback) {
|
||||
super(callback);
|
||||
this.ballotSecrets = ballotSecrets;
|
||||
}
|
||||
|
||||
public BallotSecrets getBallotSecrets() {
|
||||
return ballotSecrets;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package meerkat.voting.output.outputcommands;
|
||||
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
|
||||
/**
|
||||
* Created by hai on 15/06/16.
|
||||
*/
|
||||
public class CancelOutputCommand extends OutputCommand {
|
||||
|
||||
public CancelOutputCommand(ControllerCallback callback) {
|
||||
super(callback);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package meerkat.voting.output.outputcommands;
|
||||
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
|
||||
/**
|
||||
* Created by hai on 15/06/16.
|
||||
*/
|
||||
public class CastOutputCommand extends OutputCommand {
|
||||
|
||||
public CastOutputCommand(ControllerCallback callback) {
|
||||
super(callback);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package meerkat.voting.output.outputcommands;
|
||||
|
||||
import meerkat.protobuf.Voting.*;
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
|
||||
/**
|
||||
* Created by hai on 15/06/16.
|
||||
*/
|
||||
public class CommitOutputCommand extends OutputCommand {
|
||||
|
||||
private final PlaintextBallot plaintextBallot;
|
||||
private final SignedEncryptedBallot signedEncryptedBallot;
|
||||
|
||||
public CommitOutputCommand(PlaintextBallot plaintextBallot,
|
||||
SignedEncryptedBallot signedEncryptedBallot,
|
||||
ControllerCallback callback) {
|
||||
super(callback);
|
||||
this.plaintextBallot = plaintextBallot;
|
||||
this.signedEncryptedBallot = signedEncryptedBallot;
|
||||
}
|
||||
|
||||
public PlaintextBallot getPlaintext() {
|
||||
return plaintextBallot;
|
||||
}
|
||||
|
||||
public SignedEncryptedBallot getSignedEncryptedBallot() {
|
||||
return signedEncryptedBallot;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package meerkat.voting.output.outputcommands;
|
||||
|
||||
import meerkat.voting.controller.callbacks.ControllerCallback;
|
||||
|
||||
//TODO: make this class generic
|
||||
public abstract class OutputCommand {
|
||||
protected final ControllerCallback callback;
|
||||
|
||||
protected OutputCommand(ControllerCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public ControllerCallback getCallback () {
|
||||
return this.callback;
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable {
|
|||
|
||||
@Override
|
||||
public void run () {
|
||||
logger.info("entered the voting flow");
|
||||
logger.info("UI starts running");
|
||||
while (! wasShutDownCalled()) {
|
||||
try {
|
||||
UICommand command = queue.take();
|
||||
|
|
Loading…
Reference in New Issue