diff --git a/voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java b/voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java new file mode 100644 index 0000000..a12d3ac --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java @@ -0,0 +1,53 @@ +package meerkat.voting.ui; + +import java.util.concurrent.ArrayBlockingQueue; + +/** + * A special kind of an ArrayBlockingQueue. + * It is only of size 1, meaning it keeps only one element at most at every point of time. + * The trample function is similar to put/add except that it overrides the previously kept element. + * Other functions are similar to the matching functions in ArrayBlockingQueue. + * For instance, the offer function only "recommends" another element to keep, but if there is a stored element + * already, than this recommendation is ignored. + */ +public class CommandPend { + + private ArrayBlockingQueue queue; + + public CommandPend () { + queue = new ArrayBlockingQueue<>(1); + } + + /** + * overrides the current kept command + * @param cmd a command to override the previous one (if existed) + */ + synchronized public void trample (T cmd) { + queue.clear(); + queue.add(cmd); + } + + /** + * keeps the offered command, but only if there is no other command to handle right now + * @param cmd a command to keep if we currently do not have another + */ + synchronized public void offer (T cmd) { + queue.offer(cmd); + } + + /** + * Retrieves and removes the kept command, waiting if necessary until a command becomes available. + * @return the kept command + * @throws InterruptedException + */ + public T take() throws InterruptedException { + return queue.take(); + } + + /** + * removes the kept command + */ + synchronized public void clear () { + queue.clear(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index e35c527..3b34da8 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -8,7 +8,6 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.*; -import java.util.concurrent.LinkedBlockingQueue; import meerkat.voting.controller.callbacks.*; import meerkat.voting.ui.uicommands.*; @@ -27,7 +26,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { private static final Logger logger = LoggerFactory.getLogger(SystemConsoleUI.class); private BufferedReader bufferedReader; - private LinkedBlockingQueue queue; + private CommandPend cmdPend; private Date startWaitingTime; private volatile boolean shutDownHasBeenCalled; @@ -37,30 +36,30 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { final int tickDurationInMillisec = 10; // period between view update calls logger.info("A VB UI console is constructed"); - queue = new LinkedBlockingQueue<>(); + cmdPend = new CommandPend<>(); bufferedReader = new BufferedReader(new InputStreamReader(in)); startWaitingTime = null; Timer timer = new Timer(); - timer.scheduleAtFixedRate(new TickerTimerTask(queue), new Date(), tickDurationInMillisec); + timer.scheduleAtFixedRate(new TickerTimerTask(cmdPend), new Date(), tickDurationInMillisec); shutDownHasBeenCalled = false; } /** - * the run() method. Simply loops and takes commands from the UI's queue and handles them accordingly + * the run() method. Simply loops and takes the UI's pending command and handles it accordingly */ @Override public void run () { logger.info("UI starts running"); while (! wasShutDownCalled()) { try { - UICommand command = queue.take(); + UICommand command = cmdPend.take(); handleSingleCommand(command); } catch (InterruptedException e) { - logger.warn ("Interrupted while reading from command queue " + e); + logger.warn ("Interrupted while reading the pending command " + e); } } } @@ -70,7 +69,8 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { public void callShutDown() { logger.info("callShutDown command has been called"); shutDownHasBeenCalled = true; - queue.clear(); + stopWaiting(); + cmdPend.clear(); } /** @@ -124,7 +124,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void startNewVoterSession(FutureCallback callback) { logger.debug("UI interface call to startNewVoterSession"); - queue.add(new StartSessionUICommand((NewVoterCallback)callback)); + cmdPend.trample(new StartSessionUICommand((NewVoterCallback)callback)); } /** @@ -178,8 +178,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void chooseChannel(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ChannelChoiceCallback)callback); - queue.add(command); + cmdPend.trample(new ChannelChoiceUICommand(questions, (ChannelChoiceCallback)callback)); } /** @@ -212,7 +211,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void askVoterQuestions(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - queue.add(new RaceVotingUICommand(questions, (VotingCallback)callback)); + cmdPend.trample(new RaceVotingUICommand(questions, (VotingCallback)callback)); } /** @@ -244,7 +243,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void castOrAudit(FutureCallback callback) { logger.debug("UI interface call to castOrAudit"); - queue.add(new CastOrAuditUICommand((CastOrAuditCallback)callback)); + cmdPend.trample(new CastOrAuditUICommand((CastOrAuditCallback)callback)); } /** @@ -288,7 +287,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { logger.debug("UI interface call to notifyVoterToWaitForFinish"); - queue.add(new WaitForFinishUICommand(message, (WaitForFinishCallback)callback)); + cmdPend.trample(new WaitForFinishUICommand(message, (WaitForFinishCallback)callback)); } /** @@ -331,8 +330,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageWithButtons"); - queue.clear(); - queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); + cmdPend.trample(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); } /** diff --git a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java index 594fb6e..42924c2 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java @@ -4,22 +4,18 @@ import meerkat.voting.ui.uicommands.TickCommand; import meerkat.voting.ui.uicommands.UICommand; import java.util.TimerTask; -import java.util.concurrent.LinkedBlockingQueue; /** * A thread that sends the UI clock TickCommands in a given constant frequency */ class TickerTimerTask extends TimerTask { - private LinkedBlockingQueue uiQueue; - public TickerTimerTask (LinkedBlockingQueue uiQueue) { - this.uiQueue = uiQueue; + private CommandPend cmdPend; + public TickerTimerTask (CommandPend cmdPend) { + this.cmdPend = cmdPend; } @Override public void run() { - UICommand t = uiQueue.peek(); - if ((t != null) && !(t instanceof TickCommand)) { - uiQueue.add(new TickCommand(null)); - } + cmdPend.offer(new TickCommand(null)); } }