From 1fc278df9cd04a2769c5fb3b87b52678a9431859 Mon Sep 17 00:00:00 2001
From: Robert Goldmann <deadlocker@gmx.de>
Date: Sun, 10 Dec 2017 15:29:08 +0100
Subject: [PATCH] improved shutdown handling

---
 .../budgetmasterclient/main/Main.java         |  5 +-
 .../budgetmasterclient/ui/RestartHandler.java |  4 +-
 .../ui/ShutdownHandler.java                   | 49 +++++++++++++++++++
 .../ui/controller/Controller.java             | 47 ++++++++----------
 .../ui/controller/SplashScreenController.java |  7 ++-
 .../server/SparkServer.java                   |  3 +-
 .../server/shutdown/Shutdown.java             | 37 +++++++++-----
 7 files changed, 106 insertions(+), 46 deletions(-)
 create mode 100644 BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/ShutdownHandler.java

diff --git a/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/main/Main.java b/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/main/Main.java
index 0931c1111..774cc3c8b 100644
--- a/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/main/Main.java
+++ b/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/main/Main.java
@@ -6,6 +6,7 @@ import java.util.Locale;
 import de.deadlocker8.budgetmaster.logic.Settings;
 import de.deadlocker8.budgetmaster.logic.utils.FileHelper;
 import de.deadlocker8.budgetmaster.logic.utils.Strings;
+import de.deadlocker8.budgetmasterclient.ui.ShutdownHandler;
 import de.deadlocker8.budgetmasterclient.ui.controller.SplashScreenController;
 import javafx.application.Application;
 import javafx.scene.image.Image;
@@ -30,9 +31,11 @@ public class Main extends Application
 		{
 			Localization.loadLanguage(settings.getLanguage().getLocale());
 		}
+		
+		ShutdownHandler shutdownHandler = new ShutdownHandler();
 
 		Image icon = new Image("/de/deadlocker8/budgetmaster/icon.png");
-		new SplashScreenController(stage, icon, getParameters().getNamed().get("update") != null);
+		new SplashScreenController(stage, icon, getParameters().getNamed().get("update") != null, shutdownHandler);
 	}
 
 	@Override
diff --git a/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/RestartHandler.java b/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/RestartHandler.java
index 34db5c8f2..faa92647c 100644
--- a/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/RestartHandler.java
+++ b/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/RestartHandler.java
@@ -62,12 +62,12 @@ public class RestartHandler
 			Optional<ButtonType> result = alert.showAndWait();						
 			if (result.get() == buttonTypeOne)
 			{				
-				controller.getStage().close();				
+				controller.getStage().close();
 				
 				Localization.loadLanguage(controller.getSettings().getLanguage().getLocale());
 				
 			    Image icon = new Image("/de/deadlocker8/budgetmaster/icon.png");
-				new SplashScreenController(Main.primaryStage, icon, false);			
+				new SplashScreenController(Main.primaryStage, icon, false, controller.getShutdownHandler());			
 			}
 			else
 			{
diff --git a/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/ShutdownHandler.java b/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/ShutdownHandler.java
new file mode 100644
index 000000000..616beec09
--- /dev/null
+++ b/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/ShutdownHandler.java
@@ -0,0 +1,49 @@
+package de.deadlocker8.budgetmasterclient.ui;
+
+import de.deadlocker8.budgetmaster.logic.ServerType;
+import de.deadlocker8.budgetmaster.logic.serverconnection.ServerConnection;
+import de.deadlocker8.budgetmasterclient.ui.controller.Controller;
+import logger.Logger;
+import tools.Worker;
+
+public class ShutdownHandler
+{
+	private Thread shutdownThread;
+	private Controller controller;
+	
+	public ShutdownHandler()
+	{
+		shutdownThread = new Thread(() -> {
+			shutdown();
+		});
+	}
+	
+	public Thread getShutdownThread()
+	{
+		return shutdownThread;
+	}	
+	
+	public void setController(Controller controller)
+	{
+		this.controller = controller;
+	}
+
+	public void shutdown()
+	{
+		if(controller.getSettings().getServerType().equals(ServerType.LOCAL))
+		{
+			Logger.debug("Stopping local BudgetMasterServer...");
+			try
+			{
+				ServerConnection connection = new ServerConnection(controller.getSettings());
+				connection.shutdownServer();
+			}
+			catch(Exception e)
+			{
+				Logger.error(e);
+			}
+		}
+		Worker.shutdown();
+		System.exit(0);
+	}
+}
diff --git a/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/controller/Controller.java b/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/controller/Controller.java
index efa35e912..068b72c5f 100644
--- a/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/controller/Controller.java
+++ b/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/controller/Controller.java
@@ -29,6 +29,7 @@ import de.deadlocker8.budgetmaster.logic.updater.Updater;
 import de.deadlocker8.budgetmaster.logic.updater.VersionInformation;
 import de.deadlocker8.budgetmaster.logic.utils.Colors;
 import de.deadlocker8.budgetmaster.logic.utils.Strings;
+import de.deadlocker8.budgetmasterclient.ui.ShutdownHandler;
 import de.deadlocker8.budgetmasterclient.ui.commandLine.CommandBundle;
 import de.deadlocker8.budgetmasterclient.ui.commandLine.CommandLine;
 import de.deadlocker8.budgetmasterclient.ui.controller.settings.LocalServerSettingsController;
@@ -100,6 +101,7 @@ public class Controller extends BaseController
 
 	private Image icon = new Image("de/deadlocker8/budgetmaster/icon.png");	
 	private Settings settings;
+	private ShutdownHandler shutdownHandler;
 	private DateTime currentDate;
 	private ArrayList<CategoryBudget> categoryBudgets;
 	private PaymentHandler paymentHandler;
@@ -113,9 +115,10 @@ public class Controller extends BaseController
 	private boolean alertIsShowing = false;
 	private static DateTimeFormatter DATE_FORMAT;
 	
-	public Controller(Settings settings)
+	public Controller(Settings settings, ShutdownHandler shutdownHandler)
 	{
 		this.settings = settings;
+		this.shutdownHandler = shutdownHandler;
 		DATE_FORMAT = DateTimeFormat.forPattern("MMMM yyyy").withLocale(this.settings.getLanguage().getLocale());
 		load("/de/deadlocker8/budgetmaster/ui/fxml/GUI.fxml", Localization.getBundle());
 		getStage().show();
@@ -134,38 +137,23 @@ public class Controller extends BaseController
 		stage.getScene().getStylesheets().add("/de/deadlocker8/budgetmaster/ui/style.css");
 	}
 	
-	public void shutdown()
-	{
-		if(settings.getServerType().equals(ServerType.LOCAL))
-		{
-			Logger.debug("Stopping local BudgetMasterServer...");
-			try
-			{
-				ServerConnection connection = new ServerConnection(settings);
-				connection.shutdownServer();
-			}
-			catch(Exception e)
-			{
-				Logger.error(e);
-			}
-		}
-		Worker.shutdown();
-		System.exit(0);
-	}
-	
 	@Override
 	public void init()
-	{		
-		Thread shutdownThread = new Thread(() -> {
-			shutdown();
-		});		
+	{
+		this.shutdownHandler.setController(this);
 		
 		getStage().setOnCloseRequest((event)->{
-			Runtime.getRuntime().removeShutdownHook(shutdownThread);
-			shutdown();
+			Runtime.getRuntime().removeShutdownHook(shutdownHandler.getShutdownThread());
+			shutdownHandler.shutdown();
 		});
 		
-		Runtime.getRuntime().addShutdownHook(shutdownThread);
+		try
+		{
+			Runtime.getRuntime().addShutdownHook(shutdownHandler.getShutdownThread());
+		}
+		catch(IllegalArgumentException e)
+		{
+		}
 		
 		if(settings.getServerType() == null)
 		{
@@ -344,6 +332,11 @@ public class Controller extends BaseController
 	{
 		this.settings = settings;
 	}
+	
+	public ShutdownHandler getShutdownHandler()
+	{
+		return shutdownHandler;
+	}
 
 	public void showNotification(String text)
 	{
diff --git a/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/controller/SplashScreenController.java b/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/controller/SplashScreenController.java
index def12fbc8..2bc64ec98 100644
--- a/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/controller/SplashScreenController.java
+++ b/BudgetMasterClient/src/main/java/de/deadlocker8/budgetmasterclient/ui/controller/SplashScreenController.java
@@ -7,6 +7,7 @@ import de.deadlocker8.budgetmaster.logic.utils.Colors;
 import de.deadlocker8.budgetmaster.logic.utils.FileHelper;
 import de.deadlocker8.budgetmaster.logic.utils.Helpers;
 import de.deadlocker8.budgetmaster.logic.utils.Strings;
+import de.deadlocker8.budgetmasterclient.ui.ShutdownHandler;
 import de.deadlocker8.budgetmasterclient.ui.Styleable;
 import de.deadlocker8.budgetmasterclient.ui.customAlert.CustomAlertController;
 import fontAwesome.FontIcon;
@@ -41,12 +42,14 @@ public class SplashScreenController extends BaseController implements Styleable
 	private Settings settings;
 	private boolean isFirstStart;
 	private boolean isStartingAfterUpdate;
+	private ShutdownHandler shutdownHandler;
 	
-	public SplashScreenController(Stage parentStage, Image icon, boolean isStartingAfterUpdate)
+	public SplashScreenController(Stage parentStage, Image icon, boolean isStartingAfterUpdate, ShutdownHandler shutdownHandler)
 	{
 		this.parentStage = parentStage;
 		this.icon = icon;
 		this.isStartingAfterUpdate = isStartingAfterUpdate;
+		this.shutdownHandler = shutdownHandler;
 		load("/de/deadlocker8/budgetmaster/ui/fxml/SplashScreen.fxml", Localization.getBundle());
 		getStage().show();
 	}
@@ -178,7 +181,7 @@ public class SplashScreenController extends BaseController implements Styleable
 	
 	private void openBudgetMaster()
 	{
-		new Controller(settings);
+		new Controller(settings, shutdownHandler);
 	}
 	
 	public Image getIcon()
diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmasterserver/server/SparkServer.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmasterserver/server/SparkServer.java
index 8f51dc8b6..d1c397ea7 100644
--- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmasterserver/server/SparkServer.java
+++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmasterserver/server/SparkServer.java
@@ -72,6 +72,7 @@ import tools.HashUtils;
 public class SparkServer
 {	
 	private Gson gson;
+	private boolean shutdownInProgress = false;
 	
 	public SparkServer(Settings settings, VersionInformation versionInfo)
 	{
@@ -199,7 +200,7 @@ public class SparkServer
 			get("/info", new InformationGet(gson, versionInfo, settings));
 			get("/version", new VersionGet(gson, versionInfo));
 			delete("/log", new LogDelete());
-			get("/shutdown", new Shutdown());
+			get("/shutdown", new Shutdown(shutdownInProgress));
 		}
 		catch(ClassNotFoundException e)
 		{
diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmasterserver/server/shutdown/Shutdown.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmasterserver/server/shutdown/Shutdown.java
index 95a6653d2..9befe246b 100644
--- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmasterserver/server/shutdown/Shutdown.java
+++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmasterserver/server/shutdown/Shutdown.java
@@ -10,9 +10,11 @@ import spark.Response;
 
 public class Shutdown implements AdvancedRoute
 {	
-	public Shutdown()
+	private boolean shutdownInProgress;
+	
+	public Shutdown(boolean shutdownInProgress)
 	{
-		
+		this.shutdownInProgress = shutdownInProgress;
 	}
 
 	@Override
@@ -24,19 +26,28 @@ public class Shutdown implements AdvancedRoute
 	public Object handleRequest(Request req, Response res)
 	{
 		Logger.info("Shutting down server due to client request");
-		TimerTask task = new TimerTask() 
+		if(!shutdownInProgress)
 		{
-			@Override
-			public void run()
+			shutdownInProgress = true;
+			TimerTask task = new TimerTask() 
 			{
-				Logger.info("Shutdown DONE");
-				System.exit(0);		
-			}
-		};
-		
-		Timer timer = new Timer();
-		timer.schedule(task, 2000);
-		return "";
+				@Override
+				public void run()
+				{
+					Logger.info("Shutdown DONE");
+					System.exit(0);		
+				}
+			};
+			
+			Timer timer = new Timer();
+			timer.schedule(task, 2000);
+			return "";
+		}
+		else
+		{
+			Logger.info("Shutdown is already scheduled");
+			return "";
+		}
 	}
 
 	@Override
-- 
GitLab