diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index 7619b48..ef89f86 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -40,6 +40,7 @@ version += "${isSnapshot ? '-SNAPSHOT' : ''}" dependencies { // Meerkat common compile project(':meerkat-common') + compile project(':restful-api-common') // Logging compile 'org.slf4j:slf4j-api:1.7.7' diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelThrowable.java similarity index 76% rename from voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java rename to voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelThrowable.java index 2844fc1..38c2c8b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelThrowable.java @@ -3,6 +3,6 @@ package meerkat.voting.controller.callbacks; /** * Just a simple unique exception to throw when a voter aborts/cancels the voting during the voting process */ -public class VoterCancelException extends Exception { +public class VoterCancelThrowable extends Throwable { // } diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java new file mode 100644 index 0000000..50bd6d5 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -0,0 +1,161 @@ +package meerkat.voting.output; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.BoolValue; +import meerkat.protobuf.PollingStation.ScannedData; +import meerkat.protobuf.Voting.*; +import meerkat.rest.*; +import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.output.outputcommands.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.client.*; +import javax.ws.rs.core.Response; + +import java.io.IOException; +import java.util.concurrent.LinkedBlockingQueue; + +import static meerkat.pollingstation.PollingStationConstants.*; + +/** + * Created by hai on 27/06/16. + */ +public class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { + + private Logger logger; + private LinkedBlockingQueue queue; + private volatile boolean shutDownHasBeenCalled; + + private SignedEncryptedBallot signedEncryptedBallot; + + private final WebTarget successfulPrintTarget; + + public AsyncRunnableOutputDevice(String address) { + logger = LoggerFactory.getLogger(AsyncRunnableOutputDevice.class); + logger.info("A NetworkVirtualPrinter is constructed"); + queue = new LinkedBlockingQueue<>(); + shutDownHasBeenCalled = false; + + Client client = ClientBuilder.newClient(); + client.register(ProtobufMessageBodyReader.class); + client.register(ProtobufMessageBodyWriter.class); + successfulPrintTarget = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); + } + + @Override + public void run () { + logger.info("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 callback) { + logger.debug("Output interface call to commit to ballot"); + queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback)); + } + + @Override + public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { + logger.debug("an interface call to audit"); + queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback)); + } + + @Override + public void castBallot(FutureCallback callback) { + logger.debug("an interface call to cast ballot"); + queue.add(new CastOutputCommand((ControllerCallback)callback)); + } + + @Override + public void cancelBallot(FutureCallback callback) { + logger.debug("an interface call to cancel the output"); + queue.add(new CancelOutputCommand((ControllerCallback)callback)); + } + + + public void doCommitToBallot(CommitOutputCommand command) { + logger.debug("entered method doCommitToBallot"); + signedEncryptedBallot = command.getSignedEncryptedBallot(); + command.getCallback().onSuccess(null); + } + + + public void doAudit(AuditOutputCommand command) { + logger.debug("entered method doAudit"); + signedEncryptedBallot = null; + command.getCallback().onSuccess(null); + } + + + public void doCastBallot(CastOutputCommand command) { + logger.debug("entered method doCastBallot"); + ScannedData scannedData = ScannedData.newBuilder() + .setChannel(null) //TODO: fill the details for the channel to be able to send here + .setSignedEncryptedBallot(this.signedEncryptedBallot) + .build(); + + Response response = successfulPrintTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF)); + BoolValue b = response.readEntity(BoolValue.class); + response.close(); + + if (b.getValue()) { + command.getCallback().onSuccess(null); + } + else { + command.getCallback().onFailure(new IOException()); + } + } + + + public void doCancel(CancelOutputCommand command) { + logger.debug("entered method doCancel"); + signedEncryptedBallot = null; + command.getCallback().onSuccess(null); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java new file mode 100644 index 0000000..d3e3625 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -0,0 +1,37 @@ +package meerkat.voting.output; + +import com.google.protobuf.BoolValue; +import meerkat.pollingstation.PollingStationScanner; +import meerkat.protobuf.PollingStation.*; +import meerkat.rest.*; + +import javax.ws.rs.client.*; + +import static meerkat.pollingstation.PollingStationConstants.*; + +/** + * Created by hai on 27/06/16. + */ +public class NetworkVirtualPrinter implements PollingStationScanner.Producer { + + WebTarget successfulScanPath; + WebTarget errorPath; + + public NetworkVirtualPrinter(String address) { + Client client = ClientBuilder.newClient(); + client.register(ProtobufMessageBodyReader.class); + client.register(ProtobufMessageBodyWriter.class); + successfulScanPath = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); + errorPath = client.target(address).path(POLLING_STATION_WEB_SCANNER_ERROR_PATH); + } + + @Override + public BoolValue newScan(ScannedData scannedData) { + return null; + } + + @Override + public BoolValue reportScanError(ErrorMsg errorMsg) { + return null; + } +}