From 44ddc2b21a3e5d3248868ee67684a7b0db61aae0 Mon Sep 17 00:00:00 2001
From: Martin Goik <goik@hdm-stuttgart.de>
Date: Wed, 29 Oct 2014 18:18:00 +0100
Subject: [PATCH] Current transaction state

---
 Sda2/P/account/Sql/schema.sql                 | 12 +++
 Sda2/P/account/pom.xml                        | 17 ++++
 .../hdm_stuttgart/mi/sda2/account/Conf.java   | 21 +++++
 .../mi/sda2/account/TransferDriver.java       | 75 +++++++++++++----
 .../mi/sda2/account/gui/ExceptionDialog.java  | 64 +++++++++++++++
 .../mi/sda2/account/gui/NumberField.java      |  2 +-
 .../mi/sda2/account/sql/DbHandler.java        | 80 +++++++++++++++++++
 .../mi/sda2/account/jdbc.properties           |  3 +
 8 files changed, 257 insertions(+), 17 deletions(-)
 create mode 100644 Sda2/P/account/Sql/schema.sql
 create mode 100644 Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/Conf.java
 create mode 100644 Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/gui/ExceptionDialog.java
 create mode 100644 Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/sql/DbHandler.java
 create mode 100644 Sda2/P/account/src/main/resources/de/hdm_stuttgart/mi/sda2/account/jdbc.properties

diff --git a/Sda2/P/account/Sql/schema.sql b/Sda2/P/account/Sql/schema.sql
new file mode 100644
index 000000000..e4e9f2a06
--- /dev/null
+++ b/Sda2/P/account/Sql/schema.sql
@@ -0,0 +1,12 @@
+CREATE TABLE Account (
+   number INT NOT NULL PRIMARY KEY
+  ,balance INT NOT NULL
+);
+
+DELETE FROM Account;
+
+INSERT INTO Account VALUES (1, 100);
+INSERT INTO Account VALUES (2, 200);
+INSERT INTO Account VALUES (3, 300);
+
+SELECT * FROM Account;
diff --git a/Sda2/P/account/pom.xml b/Sda2/P/account/pom.xml
index 364aa607f..046962b64 100644
--- a/Sda2/P/account/pom.xml
+++ b/Sda2/P/account/pom.xml
@@ -29,6 +29,23 @@
 			<artifactId>log4j</artifactId>
 			<version>1.2.17</version>
 		</dependency>
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<version>5.1.33</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.controlsfx</groupId>
+			<artifactId>controlsfx</artifactId>
+			<version>8.20.8</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.controlsfx</groupId>
+			<artifactId>openjfx-dialogs</artifactId>
+			<version>1.0.2</version>
+		</dependency>
 
 	</dependencies>
 
diff --git a/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/Conf.java b/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/Conf.java
new file mode 100644
index 000000000..a262c8a97
--- /dev/null
+++ b/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/Conf.java
@@ -0,0 +1,21 @@
+package de.hdm_stuttgart.mi.sda2.account;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Conf {
+	private static final String BUNDLE_NAME = "de.hdm_stuttgart.mi.sda2.account.jdbc";
+
+	private static final ResourceBundle RESOURCE_BUNDLE =
+			ResourceBundle.getBundle(BUNDLE_NAME);
+
+	private Conf() {}
+
+	public static String get(String key) {
+		try {
+			return RESOURCE_BUNDLE.getString(key);
+		} catch (MissingResourceException e) {
+			return '!' + key + '!';
+		}
+	}
+}
diff --git a/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/TransferDriver.java b/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/TransferDriver.java
index 15310f4b3..13a4aab10 100644
--- a/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/TransferDriver.java
+++ b/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/TransferDriver.java
@@ -1,5 +1,7 @@
 package de.hdm_stuttgart.mi.sda2.account;
 
+import java.sql.SQLException;
+
 import javafx.application.Application;
 import javafx.geometry.Insets;
 import javafx.geometry.Pos;
@@ -12,38 +14,64 @@ import javafx.scene.text.FontWeight;
 import javafx.scene.text.Text;
 import javafx.stage.Stage;
 import de.hdm_stuttgart.mi.sda2.account.gui.NumberField;
+import de.hdm_stuttgart.mi.sda2.account.sql.DbHandler;
 
 public class TransferDriver extends Application {
 
+	final DbHandler dbh = new DbHandler();
+	
+    final NumberField
+		 srcAccountNoField = new NumberField()
+		,amountField = new NumberField()
+		,destAccountNoField = new NumberField();
+    
+    final Button
+		commitBtn = new Button("Commit transaction"),
+		abortBtn = new Button("Abort transaction");
+    
     public static void main( String[] args ) {
     	launch(args);
     }
-    public TransferDriver() {
+    public TransferDriver() throws SQLException {
     	
     	initEditor();
-    	srcAccountNoField.textProperty().addListener(event -> amountField.setDisable(false));
     	
     	amountField.textProperty().addListener(event -> {
-    		srcAccountNoField.setDisable(true);
     		destAccountNoField.setDisable(false);
     	});
+    	
     	destAccountNoField.textProperty().addListener(event -> {
-    		amountField.setDisable(true);
-    		commitBtn.setDisable(false);
+    		
+    		if (!amountField.isDisabled()) { // Wee need a state representative
+    			// Start transaction, values can no longer be changed
+        		srcAccountNoField.setDisable(true);
+        		amountField.setDisable(true);
+        		
+        		// Allow abort and commit transaction
+        		abortBtn.setDisable(false);
+        		commitBtn.setDisable(false);
+        		
+        		dbh.changeBy(srcAccountNoField.getValue(), - amountField.getValue());
+    		}
     	});
     	
-    	commitBtn.setOnAction(event-> initEditor());
+    	commitBtn.setOnAction(event-> {
+    		dbh.changeBy(destAccountNoField.getValue(), amountField.getValue());
+    		dbh.commit();
+    		initEditor();
+    		});
+    	abortBtn.setOnAction(event-> {
+    		dbh.rollback();
+    		initEditor();
+    	});
     }
     
-    final NumberField
-		 srcAccountNoField = new NumberField()
-		,amountField = new NumberField()
-		,destAccountNoField = new NumberField();
-    
-    final Button commitBtn = new Button("Commit transaction");
-    
     @Override
-    public void start(final Stage primaryStage) {
+    public void start(final Stage primaryStage) throws SQLException {
+    	
+    	dbh.connect();
+
+
         primaryStage.setTitle("Account transfer!");
         
         final GridPane grid = new GridPane();
@@ -70,17 +98,32 @@ public class TransferDriver extends Application {
         grid.add(destAccountNoField, 1, currentRowIndex);
 
         currentRowIndex++;
+        grid.add(abortBtn, 0, currentRowIndex);
         grid.add(commitBtn, 1, currentRowIndex);
         
         Scene scene = new Scene(grid, 300, 250);
         primaryStage.setScene(scene);
         primaryStage.show();
+        
     }
     
-    private void initEditor() {
+    @Override
+	public void stop() throws Exception {
+		super.stop();
+        dbh.close();
+	}
+	private void initEditor() {
+    	// init field values
+    	srcAccountNoField.setText("");
+    	amountField.setText("");
+    	destAccountNoField.setText("");
+    	
+    	// Set disabled state of fields and buttons
     	srcAccountNoField.setDisable(false);
-    	amountField.setDisable(true);
+    	amountField.setDisable(false);
     	destAccountNoField.setDisable(true);
+    	
+    	abortBtn.setDisable(true);
     	commitBtn.setDisable(true);
     }
 }
diff --git a/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/gui/ExceptionDialog.java b/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/gui/ExceptionDialog.java
new file mode 100644
index 000000000..f211f40da
--- /dev/null
+++ b/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/gui/ExceptionDialog.java
@@ -0,0 +1,64 @@
+package de.hdm_stuttgart.mi.sda2.account.gui;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javafx.scene.control.Alert;
+import javafx.scene.control.Alert.AlertType;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextArea;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Priority;
+
+/**
+ * See http://code.makery.ch/blog/javafx-dialogs-official
+ * for further explanations.
+ *
+ */
+public class ExceptionDialog {
+	
+	/**
+	 * Showing an error box and terminating without any further error processing
+	 * 
+	 * @param msg An informative message
+	 * @param ex The exception to be interpreted by an expert
+	 * @param exitCode The exit code to be used by e.g. the calling process.
+	 * 
+	 */
+	public static void showExceptionAndExit(final String msg, final Exception ex, int exitCode) {
+		
+		Alert alert = new Alert(AlertType.ERROR);
+		alert.setTitle("Unrecoverable error");
+		alert.setHeaderText("Application will be terminated!");
+		alert.setContentText(msg);
+
+
+		// Create expandable Exception.
+		StringWriter sw = new StringWriter();
+		PrintWriter pw = new PrintWriter(sw);
+		ex.printStackTrace(pw);
+		String exceptionText = sw.toString();
+
+		Label label = new Label("You may copy and forward this exception stacktrace to an expert:");
+
+		TextArea textArea = new TextArea(exceptionText);
+		textArea.setEditable(false);
+		textArea.setWrapText(true);
+
+		textArea.setMaxWidth(Double.MAX_VALUE);
+		textArea.setMaxHeight(Double.MAX_VALUE);
+		GridPane.setVgrow(textArea, Priority.ALWAYS);
+		GridPane.setHgrow(textArea, Priority.ALWAYS);
+
+		GridPane expContent = new GridPane();
+		expContent.setMaxWidth(Double.MAX_VALUE);
+		expContent.add(label, 0, 0);
+		expContent.add(textArea, 0, 1);
+
+		// Set expandable Exception into the dialog pane.
+		alert.getDialogPane().setExpandableContent(expContent);
+
+		alert.showAndWait();
+		System.exit(exitCode);
+	}
+}
diff --git a/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/gui/NumberField.java b/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/gui/NumberField.java
index fdbc928b0..fa76c24c6 100644
--- a/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/gui/NumberField.java
+++ b/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/gui/NumberField.java
@@ -31,7 +31,7 @@ public class NumberField extends TextField {
 		});
 	}
 
-	int getValue() {
+	public int getValue() {
 		return value;
 	}
 }
\ No newline at end of file
diff --git a/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/sql/DbHandler.java b/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/sql/DbHandler.java
new file mode 100644
index 000000000..f5db4a974
--- /dev/null
+++ b/Sda2/P/account/src/main/java/de/hdm_stuttgart/mi/sda2/account/sql/DbHandler.java
@@ -0,0 +1,80 @@
+package de.hdm_stuttgart.mi.sda2.account.sql;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import org.apache.log4j.Logger;
+
+import de.hdm_stuttgart.mi.sda2.account.Conf;
+import de.hdm_stuttgart.mi.sda2.account.gui.ExceptionDialog;
+
+public class DbHandler {
+	
+	static private final Logger log = Logger.getLogger(DbHandler.class);
+	
+	Connection conn = null;
+	PreparedStatement updateAccount; 
+
+	private String getConnectionName() {
+		return Conf.get("DbHandler.user") + '@' + Conf.get("DbHandler.jdbcUrl");
+	}
+	
+	public boolean connect() {
+		try {
+			conn = DriverManager.getConnection(
+					Conf.get("DbHandler.jdbcUrl"),
+					Conf.get("DbHandler.user"),
+					Conf.get("DbHandler.password"));
+			conn.setAutoCommit(false);
+			updateAccount = conn.prepareStatement("UPDATE Account SET balance = balance + ? WHERE number = ?");
+			log.info("Connection '" + getConnectionName() + "' established" ); 
+			return true;
+		} catch (SQLException e) {
+			log.info("Connection '" + getConnectionName() + "' failed:" + e.getMessage());
+	        ExceptionDialog.showExceptionAndExit("Connection '" + getConnectionName() + "' failed:", e, 1);
+			return false;
+		}
+	}
+	
+	public void close() throws SQLException {
+		if (null != conn) {
+			conn.close();
+			log.debug("Connection '" + getConnectionName() + "' closed" ); 
+			conn = null;
+		}
+	}
+	
+	public void rollback() {
+		try {
+			conn.rollback();
+			log.info("Rollback successfully executed");
+		} catch (SQLException e) {
+			ExceptionDialog.showExceptionAndExit("Rollback of transaction failed: ", e, 1);
+		}
+	}
+	
+	public void commit() {
+		try {
+			conn.commit();
+			log.info("Changes successfully committed");
+		} catch (SQLException e) {
+			ExceptionDialog.showExceptionAndExit("Committing transaction failed: ", e, 1);
+		}
+	}
+	
+	public void changeBy(int accountNo, int amount) {
+		try {
+			updateAccount.setInt(1, accountNo);
+			updateAccount.setInt(2, amount);
+			updateAccount.executeUpdate();
+			log.info("Change account " + accountNo + " by " + amount);
+		} catch (SQLException e) {
+			ExceptionDialog.showExceptionAndExit("Update of account " + accountNo + " failed:", e, 1);
+		}
+	}
+	
+	
+	
+}
diff --git a/Sda2/P/account/src/main/resources/de/hdm_stuttgart/mi/sda2/account/jdbc.properties b/Sda2/P/account/src/main/resources/de/hdm_stuttgart/mi/sda2/account/jdbc.properties
new file mode 100644
index 000000000..581860332
--- /dev/null
+++ b/Sda2/P/account/src/main/resources/de/hdm_stuttgart/mi/sda2/account/jdbc.properties
@@ -0,0 +1,3 @@
+DbHandler.jdbcUrl=jdbc:mysql://localhost:3306/hdm
+DbHandler.password=XYZ
+DbHandler.user=hdmuser
-- 
GitLab