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