From 7e2924d780c6fbe7fe1f1e1a0bbff168b055e72e Mon Sep 17 00:00:00 2001 From: 0xb00bface <0xboobface@gmail.com> Date: Wed, 19 Aug 2020 12:45:47 +0200 Subject: [PATCH] Add confirmation dialog for shutdown Show confirmation dialog when a shutdown is requested and there are recordings in progress. The user now can decide to shutdown immediately, shutdown gracefully or leave the app running --- CHANGELOG.md | 1 + .../java/ctbrec/ui/CamrecApplication.java | 21 +++- .../main/java/ctbrec/ui/controls/Dialogs.java | 16 ++++ .../ctbrec/recorder/NextGenLocalRecorder.java | 96 ++++++++++--------- .../main/java/ctbrec/recorder/Recorder.java | 4 +- .../java/ctbrec/recorder/RemoteRecorder.java | 2 +- .../ctbrec/recorder/server/HttpServer.java | 2 +- 7 files changed, 90 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc2ad4ce..57c53cf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * media player isn't working because of their authetication mechanism * Fixed bug in recorder servlet. Actions for unpin and notes were mixed up * Recordings now start immediately for newly added models +* Added confirmation dialog for "Pause All" and "Resume All" 3.8.6 ======================== diff --git a/client/src/main/java/ctbrec/ui/CamrecApplication.java b/client/src/main/java/ctbrec/ui/CamrecApplication.java index 8557ae93..6dde753e 100644 --- a/client/src/main/java/ctbrec/ui/CamrecApplication.java +++ b/client/src/main/java/ctbrec/ui/CamrecApplication.java @@ -8,6 +8,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Type; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -70,6 +72,7 @@ import javafx.beans.value.ChangeListener; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; import javafx.scene.control.Label; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; @@ -249,18 +252,34 @@ public class CamrecApplication extends Application { } } + // check for active recordings + boolean shutdownNow = false; + try { + if (!recorder.getCurrentlyRecording().isEmpty()) { + ButtonType result = Dialogs.showShutdownDialog(primaryStage.getScene()); + if(result == ButtonType.NO) { + return; + } else if(result == ButtonType.YES) { + shutdownNow = true; + } + } + } catch (InvalidKeyException | NoSuchAlgorithmException | IOException ex) { + LOG.warn("Couldn't check, if recordings are running"); + } + Alert shutdownInfo = new AutosizeAlert(Alert.AlertType.INFORMATION, primaryStage.getScene()); shutdownInfo.setTitle("Shutdown"); shutdownInfo.setContentText("Shutting down. Please wait while recordings are finished..."); shutdownInfo.show(); + final boolean immediately = shutdownNow; new Thread() { @Override public void run() { modelsTab.saveState(); recordingsTab.saveState(); onlineMonitor.shutdown(); - recorder.shutdown(); + recorder.shutdown(immediately); for (Site site : sites) { if(site.isEnabled()) { site.shutdown(); diff --git a/client/src/main/java/ctbrec/ui/controls/Dialogs.java b/client/src/main/java/ctbrec/ui/controls/Dialogs.java index fec5c51b..886e33dd 100644 --- a/client/src/main/java/ctbrec/ui/controls/Dialogs.java +++ b/client/src/main/java/ctbrec/ui/controls/Dialogs.java @@ -11,6 +11,7 @@ import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.Dialog; import javafx.scene.control.TextArea; @@ -112,4 +113,19 @@ public class Dialogs { confirm.showAndWait(); return confirm.getResult() == ButtonType.YES; } + + public static ButtonType showShutdownDialog(Scene parent) { + String message = "There are recordings in progress"; + AutosizeAlert confirm = new AutosizeAlert(AlertType.CONFIRMATION, "", parent, YES, FINISH, NO); + confirm.setTitle("Shutdown"); + confirm.setHeaderText(message); + ((Button) confirm.getDialogPane().lookupButton(ButtonType.YES)).setText("Shutdown Now"); + ((Button) confirm.getDialogPane().lookupButton(ButtonType.YES)).setDefaultButton(false); + ((Button) confirm.getDialogPane().lookupButton(ButtonType.FINISH)).setText("Shutdown Gracefully"); + ((Button) confirm.getDialogPane().lookupButton(ButtonType.FINISH)).setDefaultButton(true); + ((Button) confirm.getDialogPane().lookupButton(ButtonType.NO)).setText("Keep Running"); + ((Button) confirm.getDialogPane().lookupButton(ButtonType.NO)).setDefaultButton(false); + confirm.showAndWait(); + return confirm.getResult(); + } } diff --git a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java index 4b0ff994..cb22fe2e 100644 --- a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java +++ b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java @@ -410,63 +410,65 @@ public class NextGenLocalRecorder implements Recorder { } @Override - public void shutdown() { + public void shutdown(boolean immediately) { // TODO add a config flag for waitign or stopping immediately LOG.info("Shutting down"); recording = false; - LOG.debug("Stopping all recording processes"); - recorderLock.lock(); - try { - // make a copy to avoid ConcurrentModificationException - List toStop = new ArrayList<>(recordingProcesses.values()); - if (!toStop.isEmpty()) { - ExecutorService shutdownPool = Executors.newFixedThreadPool(toStop.size()); - List> shutdownFutures = new ArrayList<>(toStop.size()); - for (Recording rec : toStop) { - Optional.ofNullable(rec.getDownload()).ifPresent(d -> { - shutdownFutures.add(shutdownPool.submit(() -> d.stop())); - }); + if (!immediately) { + LOG.debug("Stopping all recording processes"); + recorderLock.lock(); + try { + // make a copy to avoid ConcurrentModificationException + List toStop = new ArrayList<>(recordingProcesses.values()); + if (!toStop.isEmpty()) { + ExecutorService shutdownPool = Executors.newFixedThreadPool(toStop.size()); + List> shutdownFutures = new ArrayList<>(toStop.size()); + for (Recording rec : toStop) { + Optional.ofNullable(rec.getDownload()).ifPresent(d -> { + shutdownFutures.add(shutdownPool.submit(() -> d.stop())); + }); + } + shutdownPool.shutdown(); + try { + shutdownPool.awaitTermination(10, TimeUnit.MINUTES); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } } - shutdownPool.shutdown(); - try { - shutdownPool.awaitTermination(10, TimeUnit.MINUTES); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); + } finally { + recorderLock.unlock(); + } + + // wait for downloads to finish + LOG.info("Waiting for downloads to finish"); + for (int i = 0; i < 60; i++) { + if (!recordingProcesses.isEmpty()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOG.error("Error while waiting for downloads to finish", e); + } } } - } finally { - recorderLock.unlock(); - } - // wait for downloads to finish - LOG.info("Waiting for downloads to finish"); - for (int i = 0; i < 60; i++) { - if (!recordingProcesses.isEmpty()) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Error while waiting for downloads to finish", e); - } + // shutdown threadpools + try { + LOG.info("Shutting down download pool"); + downloadPool.shutdown(); + client.shutdown(); + downloadPool.awaitTermination(1, TimeUnit.MINUTES); + LOG.info("Shutting down post-processing pool"); + ppPool.shutdown(); + int minutesToWait = 10; + LOG.info("Waiting {} minutes (max) for post-processing to finish", minutesToWait); + ppPool.awaitTermination(minutesToWait, TimeUnit.MINUTES); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOG.error("Error while waiting for pools to finish", e); } } - - // shutdown threadpools - try { - LOG.info("Shutting down download pool"); - downloadPool.shutdown(); - client.shutdown(); - downloadPool.awaitTermination(1, TimeUnit.MINUTES); - LOG.info("Shutting down post-processing pool"); - ppPool.shutdown(); - int minutesToWait = 10; - LOG.info("Waiting {} minutes (max) for post-processing to finish", minutesToWait); - ppPool.awaitTermination(minutesToWait, TimeUnit.MINUTES); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Error while waiting for pools to finish", e); - } } @Override diff --git a/common/src/main/java/ctbrec/recorder/Recorder.java b/common/src/main/java/ctbrec/recorder/Recorder.java index dd8238a0..7b87a107 100644 --- a/common/src/main/java/ctbrec/recorder/Recorder.java +++ b/common/src/main/java/ctbrec/recorder/Recorder.java @@ -52,7 +52,7 @@ public interface Recorder { */ public void unpin(Recording recording) throws IOException, InvalidKeyException, NoSuchAlgorithmException; - public void shutdown(); + public void shutdown(boolean immediately); public void suspendRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException; public void resumeRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException; @@ -66,7 +66,7 @@ public interface Recorder { public List getOnlineModels(); /** - * Returns only the models from getModels(), which are actually recorded right now + * Returns only the models from getModels(), which are actually recorded right now (a recording process is currently running). * @return * @throws IOException * @throws IllegalStateException diff --git a/common/src/main/java/ctbrec/recorder/RemoteRecorder.java b/common/src/main/java/ctbrec/recorder/RemoteRecorder.java index 10fae6b5..f331439e 100644 --- a/common/src/main/java/ctbrec/recorder/RemoteRecorder.java +++ b/common/src/main/java/ctbrec/recorder/RemoteRecorder.java @@ -175,7 +175,7 @@ public class RemoteRecorder implements Recorder { } @Override - public void shutdown() { + public void shutdown(boolean immediately) { syncThread.stopThread(); } diff --git a/server/src/main/java/ctbrec/recorder/server/HttpServer.java b/server/src/main/java/ctbrec/recorder/server/HttpServer.java index 48f79391..56126c9b 100644 --- a/server/src/main/java/ctbrec/recorder/server/HttpServer.java +++ b/server/src/main/java/ctbrec/recorder/server/HttpServer.java @@ -151,7 +151,7 @@ public class HttpServer { onlineMonitor.shutdown(); } if (recorder != null) { - recorder.shutdown(); + recorder.shutdown(false); } try { server.stop();