- added logger
- restructured internal dialogs
This commit is contained in:
Sven Vogel 2023-07-11 20:43:40 +02:00
parent 0840db44c2
commit 2a0d97c834
19 changed files with 254 additions and 56 deletions

View File

@ -0,0 +1,63 @@
package me.teridax.jcash;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.logging.*;
public final class Logging {
public static final Logger LOGGER = Logger.getLogger(Logging.class.getName());
private static final String LOG_FOLDER_NAME = "logs/";
/**
* Initialize the global system logger.
* Adds a file logging handler
*/
static void initializeSystemLogger(Level level) {
LogManager.getLogManager().reset();
createConsoleLogger(level);
createFileLogger(level);
LOGGER.setLevel(level);
}
private static void createConsoleLogger(Level level) {
var ch = new ConsoleHandler();
ch.setLevel(level);
LOGGER.addHandler(ch);
}
private static void createFileLogger(Level level) {
var now = LocalDateTime.now();
var dateTime = DateTimeFormatter.ISO_DATE_TIME.format(now);
var logFileName = LOG_FOLDER_NAME + dateTime + ".log";
initializeLogFolder();
try {
var fh = new FileHandler(logFileName);
fh.setLevel(level);
LOGGER.addHandler(fh);
} catch (IOException e) {
LOGGER.warning("Unable to initialize logging for file: " + logFileName);
}
}
private static void initializeLogFolder() {
var folderPath = Path.of(LOG_FOLDER_NAME);
if (Files.isDirectory(folderPath))
return;
try {
Files.createDirectory(folderPath);
} catch (IOException e) {
LOGGER.warning("Unable to create directory: " + folderPath);
}
}
}

View File

@ -5,6 +5,13 @@ import me.teridax.jcash.gui.account.AccountController;
import me.teridax.jcash.gui.login.LoginController; import me.teridax.jcash.gui.login.LoginController;
import javax.swing.*; import javax.swing.*;
import java.util.Objects;
import java.util.logging.*;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.showMessageDialog;
import static me.teridax.jcash.Logging.LOGGER;
import static me.teridax.jcash.Logging.initializeSystemLogger;
public final class Main { public final class Main {
@ -27,6 +34,8 @@ public final class Main {
} }
public static void main(String[] args) { public static void main(String[] args) {
initializeSystemLogger(Level.FINE);
// create main instance and show the login screen // create main instance and show the login screen
instance(); instance();
getInstance().showLoginScreen(); getInstance().showLoginScreen();
@ -51,6 +60,8 @@ public final class Main {
if (null != instance) if (null != instance)
throw new IllegalStateException(Main.class.getName() + " is already initialized"); throw new IllegalStateException(Main.class.getName() + " is already initialized");
LOGGER.fine("Creating singleton instance of class " + Main.class.getName());
Main.instance = new Main(); Main.instance = new Main();
} }
@ -61,6 +72,8 @@ public final class Main {
*/ */
public void showLoginScreen() { public void showLoginScreen() {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
LOGGER.finer("showing login screen");
try { try {
// select db file // select db file
var path = Loader.load(); var path = Loader.load();
@ -69,6 +82,8 @@ public final class Main {
// when we have logged in set the account viewer as window content // when we have logged in set the account viewer as window content
login.addAccountSelectionListener(account -> { login.addAccountSelectionListener(account -> {
LOGGER.finer("account selected: " + Objects.toString(account, "null"));
var profileCont = new AccountController(account, login.getData().getBms()); var profileCont = new AccountController(account, login.getData().getBms());
this.window.setContentPane(profileCont.getView()); this.window.setContentPane(profileCont.getView());
this.window.revalidate(); this.window.revalidate();
@ -81,7 +96,8 @@ public final class Main {
this.window.setVisible(true); this.window.setVisible(true);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
System.out.println("no file selected. goodbye"); LOGGER.fine("Unable to show login mask: " + e.getMessage());
showMessageDialog(null, e.getMessage(), "Closing JCash", ERROR_MESSAGE);
System.exit(0); System.exit(0);
} }
}); });

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.banking; package me.teridax.jcash.banking;
import me.teridax.jcash.Logging;
import me.teridax.jcash.banking.accounts.Account; import me.teridax.jcash.banking.accounts.Account;
import me.teridax.jcash.banking.accounts.Owner; import me.teridax.jcash.banking.accounts.Owner;
import me.teridax.jcash.banking.management.Profile; import me.teridax.jcash.banking.management.Profile;
@ -107,6 +108,7 @@ public final class Bank {
} }
} }
} }
Logging.LOGGER.finer("Account not found: " + iban);
return Optional.empty(); return Optional.empty();
} }
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.banking.accounts; package me.teridax.jcash.banking.accounts;
import me.teridax.jcash.Logging;
import me.teridax.jcash.decode.StringDecoder; import me.teridax.jcash.decode.StringDecoder;
import java.util.Objects; import java.util.Objects;
@ -40,6 +41,9 @@ public abstract class Account {
*/ */
public static Account fromColumns(String[] columns) throws IllegalArgumentException, NullPointerException { public static Account fromColumns(String[] columns) throws IllegalArgumentException, NullPointerException {
Objects.requireNonNull(columns); Objects.requireNonNull(columns);
Logging.LOGGER.finer("Parsing account from columns");
Logging.LOGGER.finer("Decoding account fields");
// deserialize fields // deserialize fields
var iban = StringDecoder.decodeUniqueIdentificationNumber(columns[0]); var iban = StringDecoder.decodeUniqueIdentificationNumber(columns[0]);
@ -50,15 +54,20 @@ public abstract class Account {
// try to detect the specific runtime class to deserialize // try to detect the specific runtime class to deserialize
try { try {
if (type.equals("Sparkonto")) { if (type.equals("Sparkonto")) {
Logging.LOGGER.fine("Account detected as Sparkonto");
var interest = StringDecoder.decodePercent(columns[4]); var interest = StringDecoder.decodePercent(columns[4]);
return new SavingsAccount(iban, pin, balance, interest); return new SavingsAccount(iban, pin, balance, interest);
} else if (type.equals("Girokonto")) { } else if (type.equals("Girokonto")) {
Logging.LOGGER.fine("Account detected as Girokonto");
var overdraft = StringDecoder.decodeCurrency(columns[5]); var overdraft = StringDecoder.decodeCurrency(columns[5]);
return new CurrentAccount(iban, pin, balance, overdraft); return new CurrentAccount(iban, pin, balance, overdraft);
} else } else {
Logging.LOGGER.severe("Account type could not be detected");
throw new IllegalArgumentException("Invalid account type: " + type); throw new IllegalArgumentException("Invalid account type: " + type);
}
} catch (IllegalArgumentException | NullPointerException e) { } catch (IllegalArgumentException | NullPointerException e) {
Logging.LOGGER.severe("Account field could not be decoded: " + e.getMessage());
throw new IllegalArgumentException("Account format: ", e); throw new IllegalArgumentException("Account format: ", e);
} }
} }
@ -110,8 +119,10 @@ public abstract class Account {
* @throws IllegalArgumentException if amount is negative * @throws IllegalArgumentException if amount is negative
*/ */
public void deposit(double amount) throws IllegalArgumentException { public void deposit(double amount) throws IllegalArgumentException {
if (amount < 0) if (amount < 0) {
Logging.LOGGER.severe("Cannot deposit negative amount of money: " + amount);
throw new IllegalArgumentException("amount must be positive"); throw new IllegalArgumentException("amount must be positive");
}
this.balance += amount; this.balance += amount;
} }
@ -128,8 +139,10 @@ public abstract class Account {
* @throws IllegalArgumentException if amount is greater than the balance present * @throws IllegalArgumentException if amount is greater than the balance present
*/ */
public void takeoff(double amount) throws IllegalArgumentException { public void takeoff(double amount) throws IllegalArgumentException {
if (amount > this.balance) if (amount > this.balance) {
Logging.LOGGER.severe("Cannot take off more money than present in balance: " + amount);
throw new IllegalArgumentException("amount must be smaller or equals the accounts balance"); throw new IllegalArgumentException("amount must be smaller or equals the accounts balance");
}
this.balance = this.balance - amount; this.balance = this.balance - amount;
} }

View File

@ -1,5 +1,7 @@
package me.teridax.jcash.banking.accounts; package me.teridax.jcash.banking.accounts;
import me.teridax.jcash.Logging;
/** /**
* Immutable currency account storing only overdraft. * Immutable currency account storing only overdraft.
* English equivalent to "Girokonto" * English equivalent to "Girokonto"
@ -30,9 +32,12 @@ public final class CurrentAccount extends Account {
*/ */
@Override @Override
public void takeoff(double amount) throws IllegalArgumentException { public void takeoff(double amount) throws IllegalArgumentException {
Logging.LOGGER.fine("taking off money: " + amount + " from account: " + iban);
var overflow = amount - getBalance(); var overflow = amount - getBalance();
if (overflow > 0) { if (overflow > 0) {
Logging.LOGGER.fine("taking off money with overflow: " + overflow);
this.overdraft += overflow; this.overdraft += overflow;
this.balance = 0; this.balance = 0;
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.banking.accounts; package me.teridax.jcash.banking.accounts;
import me.teridax.jcash.Logging;
import me.teridax.jcash.decode.StringDecoder; import me.teridax.jcash.decode.StringDecoder;
import java.util.Objects; import java.util.Objects;
@ -40,10 +41,12 @@ public final class Owner {
*/ */
public static Owner fromColumns(String... columns) throws IllegalArgumentException, NullPointerException { public static Owner fromColumns(String... columns) throws IllegalArgumentException, NullPointerException {
Objects.requireNonNull(columns); Objects.requireNonNull(columns);
Logging.LOGGER.finer("parsing owner from columns");
if (columns.length != 6) if (columns.length != 6)
throw new IllegalArgumentException("Invalid number of columns: " + columns.length); throw new IllegalArgumentException("Invalid number of columns: " + columns.length);
Logging.LOGGER.finer("Decoding owner fields");
// decode fields // decode fields
var uid = StringDecoder.decodeUniqueIdentificationNumber(columns[0]); var uid = StringDecoder.decodeUniqueIdentificationNumber(columns[0]);
var familyName = StringDecoder.decodeName(columns[1]); var familyName = StringDecoder.decodeName(columns[1]);

View File

@ -10,6 +10,8 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
import static me.teridax.jcash.Logging.LOGGER;
/** /**
* Management system for banks and all accounts provided by these banks and their respective account owners. * Management system for banks and all accounts provided by these banks and their respective account owners.
* This class serves a read only database which can only modify runtime data without any respect to CRUD or the ACID * This class serves a read only database which can only modify runtime data without any respect to CRUD or the ACID
@ -17,6 +19,11 @@ import java.util.*;
*/ */
public final class BankingManagementSystem { public final class BankingManagementSystem {
/**
* Separator used to separate columns of CSV files
*/
private static final String SEPARATOR = ";";
/** /**
* A set of banks * A set of banks
*/ */
@ -64,6 +71,7 @@ public final class BankingManagementSystem {
* @return a valid BMS * @return a valid BMS
*/ */
public static BankingManagementSystem loadFromCsv(Path file) throws IllegalArgumentException { public static BankingManagementSystem loadFromCsv(Path file) throws IllegalArgumentException {
LOGGER.fine("parsing banking management system from file: " + Objects.toString(file, "null"));
try { try {
var bms = new BankingManagementSystem(); var bms = new BankingManagementSystem();
var content = Files.readString(file); var content = Files.readString(file);
@ -71,13 +79,16 @@ public final class BankingManagementSystem {
// read line by line // read line by line
// and skip the first line // and skip the first line
content.lines().skip(1).forEach(line -> { content.lines().skip(1).forEach(line -> {
LOGGER.finest("splitting lines by separator: " + SEPARATOR);
// split the line into columns // split the line into columns
var columns = line.split(";"); var columns = line.split(SEPARATOR);
// one line must contain exactly 14 columns // one line must contain exactly 14 columns
if (columns.length != 14) if (columns.length != 14)
throw new IllegalArgumentException("invalid column count: " + columns.length); throw new IllegalArgumentException("invalid column count: " + columns.length);
LOGGER.finer("reading members from line: " + line);
// read basic fields // read basic fields
var owner = Owner.fromColumns(tail(columns, 8)); var owner = Owner.fromColumns(tail(columns, 8));
var account = Account.fromColumns(tail(columns, 2)); var account = Account.fromColumns(tail(columns, 2));
@ -90,8 +101,10 @@ public final class BankingManagementSystem {
var bankOfSet = bms.banks.stream().filter(b -> b.equals(bankOfLine)).findFirst(); var bankOfSet = bms.banks.stream().filter(b -> b.equals(bankOfLine)).findFirst();
if (bankOfSet.isPresent()) { if (bankOfSet.isPresent()) {
LOGGER.fine("bank from current line is already present in management system");
bankOfSet.get().addAccount(owner, account); bankOfSet.get().addAccount(owner, account);
} else { } else {
LOGGER.fine("bank from current line is new for management system");
bankOfLine.addAccount(owner, account); bankOfLine.addAccount(owner, account);
bms.banks.add(bankOfLine); bms.banks.add(bankOfLine);
} }
@ -100,8 +113,10 @@ public final class BankingManagementSystem {
return bms; return bms;
} catch (IOException e) { } catch (IOException e) {
LOGGER.severe("Could not read file: " + file + " due to: " + e.getMessage());
throw new IllegalArgumentException("Could not read file " + file, e); throw new IllegalArgumentException("Could not read file " + file, e);
} catch (IllegalArgumentException | NullPointerException e) { } catch (IllegalArgumentException | NullPointerException e) {
LOGGER.severe("Could not parse file: " + file + " due to: " + e.getMessage());
throw new IllegalArgumentException("Could not parse file " + file, e); throw new IllegalArgumentException("Could not parse file " + file, e);
} }
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.banking.management; package me.teridax.jcash.banking.management;
import me.teridax.jcash.Logging;
import me.teridax.jcash.banking.Bank; import me.teridax.jcash.banking.Bank;
import me.teridax.jcash.banking.accounts.Account; import me.teridax.jcash.banking.accounts.Account;
import me.teridax.jcash.banking.accounts.Owner; import me.teridax.jcash.banking.accounts.Owner;
@ -32,8 +33,10 @@ public class Profile {
private final Account[] accounts; private final Account[] accounts;
public Profile(Owner owner, Bank bank, Account account, Account[] accounts) { public Profile(Owner owner, Bank bank, Account account, Account[] accounts) {
if (!Arrays.asList(accounts).contains(account)) if (!Arrays.asList(accounts).contains(account)) {
Logging.LOGGER.severe("Account not found:" + account.getDescription());
throw new IllegalArgumentException("Primary account is not registered at the bank"); throw new IllegalArgumentException("Primary account is not registered at the bank");
}
this.owner = owner; this.owner = owner;
this.bank = bank; this.bank = bank;
@ -69,5 +72,6 @@ public class Profile {
break; break;
} }
} }
Logging.LOGGER.warning("Account " + description + " not found in associated account list");
} }
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.gui; package me.teridax.jcash.gui;
import me.teridax.jcash.Logging;
import me.teridax.jcash.banking.management.BankingManagementSystem; import me.teridax.jcash.banking.management.BankingManagementSystem;
import javax.swing.*; import javax.swing.*;
@ -42,6 +43,7 @@ public class Loader {
} }
} }
Logging.LOGGER.warning("no file selected");
throw new IllegalStateException("No file selected"); throw new IllegalStateException("No file selected");
} }
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.gui.account; package me.teridax.jcash.gui.account;
import me.teridax.jcash.Logging;
import me.teridax.jcash.Main; import me.teridax.jcash.Main;
import me.teridax.jcash.banking.management.BankingManagementSystem; import me.teridax.jcash.banking.management.BankingManagementSystem;
import me.teridax.jcash.banking.management.Profile; import me.teridax.jcash.banking.management.Profile;
@ -17,7 +18,10 @@ public class AccountController {
*/ */
private final AccountView view; private final AccountView view;
private final Profile profile;
public AccountController(Profile profile, BankingManagementSystem bms) { public AccountController(Profile profile, BankingManagementSystem bms) {
this.profile = profile;
this.view = new AccountView(); this.view = new AccountView();
this.view.setProfile(profile); this.view.setProfile(profile);
this.data = new AccountData(bms); this.data = new AccountData(bms);
@ -26,16 +30,9 @@ public class AccountController {
} }
private void createListeners(Profile profile) { private void createListeners(Profile profile) {
this.view.getAccountSelection().addActionListener(e -> { this.view.getAccountSelection().addActionListener(e -> changeAccount());
var description = ((String) this.view.getAccountSelection().getSelectedItem());
profile.setPrimaryAccount(description);
this.view.setProfile(profile);
});
this.view.getLogout().addActionListener(e -> { this.view.getLogout().addActionListener(e -> logout());
Main.getInstance().logout();
Main.getInstance().showLoginScreen();
});
this.view.getDeposit().addActionListener(e -> new DepositDialog(profile.getPrimaryAccount(), () -> this.view.setProfile(profile))); this.view.getDeposit().addActionListener(e -> new DepositDialog(profile.getPrimaryAccount(), () -> this.view.setProfile(profile)));
@ -44,6 +41,19 @@ public class AccountController {
this.view.getTransfer().addActionListener(e -> new TransferDialog(profile.getPrimaryAccount(), data.getBms(), () -> this.view.setProfile(profile))); this.view.getTransfer().addActionListener(e -> new TransferDialog(profile.getPrimaryAccount(), data.getBms(), () -> this.view.setProfile(profile)));
} }
private void logout() {
Logging.LOGGER.fine("Logging out of account");
Main.getInstance().logout();
Main.getInstance().showLoginScreen();
}
private void changeAccount() {
var description = ((String) this.view.getAccountSelection().getSelectedItem());
Logging.LOGGER.fine("Changing primary account selected: " + description);
this.profile.setPrimaryAccount(description);
this.view.setProfile(profile);
}
public AccountView getView() { public AccountView getView() {
return view; return view;
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.gui.account; package me.teridax.jcash.gui.account;
import me.teridax.jcash.Logging;
import me.teridax.jcash.banking.accounts.CurrentAccount; import me.teridax.jcash.banking.accounts.CurrentAccount;
import me.teridax.jcash.banking.accounts.SavingsAccount; import me.teridax.jcash.banking.accounts.SavingsAccount;
import me.teridax.jcash.banking.management.Profile; import me.teridax.jcash.banking.management.Profile;
@ -35,6 +36,7 @@ public class AccountView extends JPanel {
} }
public void setProfile(Profile profile) { public void setProfile(Profile profile) {
Logging.LOGGER.finer("Changing profile of account view");
var bank = profile.getBank(); var bank = profile.getBank();
var account = profile.getPrimaryAccount(); var account = profile.getPrimaryAccount();
var owner = profile.getOwner(); var owner = profile.getOwner();
@ -49,12 +51,14 @@ public class AccountView extends JPanel {
this.balance.setText(StringDecoder.LOCAL_NUMBER_FORMAT.format(account.getBalance()) + ""); this.balance.setText(StringDecoder.LOCAL_NUMBER_FORMAT.format(account.getBalance()) + "");
this.type.setText(account.getClass().getSimpleName()); this.type.setText(account.getClass().getSimpleName());
if (account instanceof CurrentAccount) { if (account instanceof CurrentAccount) {;
this.typeSpecialLabel.setText("Overdraft"); this.typeSpecialLabel.setText("Overdraft");
this.typeSpecialProperty.setText( StringDecoder.LOCAL_NUMBER_FORMAT.format(((CurrentAccount) account).getOverdraft()) + ""); this.typeSpecialProperty.setText( StringDecoder.LOCAL_NUMBER_FORMAT.format(((CurrentAccount) account).getOverdraft()) + "");
} else if (account instanceof SavingsAccount) { } else if (account instanceof SavingsAccount) {
this.typeSpecialLabel.setText("Interest rate"); this.typeSpecialLabel.setText("Interest rate");
this.typeSpecialProperty.setText( ((SavingsAccount) account).getInterest() + " %" ); this.typeSpecialProperty.setText( ((SavingsAccount) account).getInterest() + " %" );
} else {
Logging.LOGGER.severe("Type of new primary account cannot be determined: " + account.getClass().getName());
} }
this.accountSelection.removeAllItems(); this.accountSelection.removeAllItems();

View File

@ -1,17 +1,37 @@
package me.teridax.jcash.gui.deposit; package me.teridax.jcash.gui.deposit;
import me.teridax.jcash.Logging;
import me.teridax.jcash.banking.accounts.Account; import me.teridax.jcash.banking.accounts.Account;
public class DepositDialog { public class DepositDialog {
private final DepositView view;
private final Account account;
private final Runnable onDeposit;
public DepositDialog(Account account, Runnable onDeposit) { public DepositDialog(Account account, Runnable onDeposit) {
var view = new DepositView(); this.account = account;
view.getDeposit().addActionListener(e -> { this.onDeposit = onDeposit;
account.deposit(view.getAmount());
this.view = new DepositView();
this.view.getDeposit().addActionListener(e -> depositMoney());
this.view.getCancel().addActionListener(e -> view.dispose());
this.view.showDialog();
}
private void depositMoney() {
var amount = view.getAmount();
Logging.LOGGER.fine("Depositing money of account: " + account.getIban() + " amount: " + amount);
try {
account.deposit(amount);
onDeposit.run(); onDeposit.run();
} catch (IllegalArgumentException ex) {
Logging.LOGGER.severe("Cannot deposit money of account: " + account.getIban() + " because: " + ex.getMessage());
} finally {
view.dispose(); view.dispose();
}); }
view.getCancel().addActionListener(e -> view.dispose());
view.showDialog();
} }
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.gui.deposit; package me.teridax.jcash.gui.deposit;
import me.teridax.jcash.Logging;
import me.teridax.jcash.decode.StringDecoder; import me.teridax.jcash.decode.StringDecoder;
import javax.swing.*; import javax.swing.*;
@ -96,6 +97,7 @@ public class DepositView {
try { try {
return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue(); return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue();
} catch (ParseException e) { } catch (ParseException e) {
Logging.LOGGER.severe("Amount text field contains invalid value: " + value);
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.gui.login; package me.teridax.jcash.gui.login;
import me.teridax.jcash.Logging;
import me.teridax.jcash.banking.management.BankingManagementSystem; import me.teridax.jcash.banking.management.BankingManagementSystem;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
@ -31,6 +32,7 @@ public class LoginController {
var iban = this.view.getIban().getText(); var iban = this.view.getIban().getText();
return Optional.of(Integer.parseUnsignedInt(iban)); return Optional.of(Integer.parseUnsignedInt(iban));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Logging.LOGGER.warning("IBAN text field contains invalid value: " + this.view.getIban().getText());
return Optional.empty(); return Optional.empty();
} }
} }
@ -40,6 +42,7 @@ public class LoginController {
var iban = this.view.getPin().getPassword(); var iban = this.view.getPin().getPassword();
return Optional.of(Integer.parseUnsignedInt(new String(iban))); return Optional.of(Integer.parseUnsignedInt(new String(iban)));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Logging.LOGGER.severe("PIN text field contains invalid value: " + String.valueOf(view.getPin().getPassword()));
return Optional.empty(); return Optional.empty();
} }
} }
@ -48,12 +51,14 @@ public class LoginController {
var blz = this.view.getBlz().getText(); var blz = this.view.getBlz().getText();
var iban = this.getIban(); var iban = this.getIban();
if (iban.isEmpty()) { if (iban.isEmpty()) {
Logging.LOGGER.severe("IBAN is invalid: " + iban);
showMessageDialog(null, "invalid IBAN", "Faulty login attempt", ERROR_MESSAGE); showMessageDialog(null, "invalid IBAN", "Faulty login attempt", ERROR_MESSAGE);
return; return;
} }
var pin = this.getPin(); var pin = this.getPin();
if (pin.isEmpty()) { if (pin.isEmpty()) {
Logging.LOGGER.severe("PIN is invalid: " + pin);
showMessageDialog(null, "invalid pin", "Faulty login attempt", ERROR_MESSAGE); showMessageDialog(null, "invalid pin", "Faulty login attempt", ERROR_MESSAGE);
return; return;
} }
@ -62,6 +67,7 @@ public class LoginController {
if (account.isPresent()) { if (account.isPresent()) {
this.listener.onAccountSelected(account.get()); this.listener.onAccountSelected(account.get());
} else { } else {
Logging.LOGGER.severe("invalid login credentials: " + iban + " / " + pin);
showMessageDialog(null, "invalid login credentials", "Faulty login attempt", ERROR_MESSAGE); showMessageDialog(null, "invalid login credentials", "Faulty login attempt", ERROR_MESSAGE);
} }
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.gui.login; package me.teridax.jcash.gui.login;
import me.teridax.jcash.Logging;
import me.teridax.jcash.banking.management.BankingManagementSystem; import me.teridax.jcash.banking.management.BankingManagementSystem;
import me.teridax.jcash.banking.management.Profile; import me.teridax.jcash.banking.management.Profile;
@ -24,6 +25,7 @@ public class LoginData {
* @return an optional wrapping the specified account if authentication was successful * @return an optional wrapping the specified account if authentication was successful
*/ */
public Optional<Profile> authenticateAccount(String blz, int iban, int pin) { public Optional<Profile> authenticateAccount(String blz, int iban, int pin) {
Logging.LOGGER.info("Authenticating account " + iban);
var optionalBank = bms.getBank(blz); var optionalBank = bms.getBank(blz);
if (optionalBank.isEmpty()) if (optionalBank.isEmpty())
return Optional.empty(); return Optional.empty();

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.gui.takeoff; package me.teridax.jcash.gui.takeoff;
import me.teridax.jcash.Logging;
import me.teridax.jcash.banking.accounts.Account; import me.teridax.jcash.banking.accounts.Account;
import static javax.swing.JOptionPane.ERROR_MESSAGE; import static javax.swing.JOptionPane.ERROR_MESSAGE;
@ -7,18 +8,29 @@ import static javax.swing.JOptionPane.showMessageDialog;
public class TakeoffDialog { public class TakeoffDialog {
private final Account account;
private final Runnable onTakeoff;
private final TakeoffView view;
public TakeoffDialog(Account account, Runnable onTakeoff) { public TakeoffDialog(Account account, Runnable onTakeoff) {
var view = new TakeoffView(); this.account = account;
view.getTakeoff().addActionListener(e -> { this.onTakeoff = onTakeoff;
try {
account.takeoff(view.getAmount()); this.view = new TakeoffView();
onTakeoff.run();
view.dispose(); this.view.getTakeoff().addActionListener(e -> takeOff());
} catch (IllegalArgumentException ex) { this.view.getCancel().addActionListener(e -> view.dispose());
showMessageDialog(null, "Reason: " + ex.getMessage(), "Could not take off money", ERROR_MESSAGE); this.view.showDialog();
} }
});
view.getCancel().addActionListener(e -> view.dispose()); private void takeOff() {
view.showDialog(); try {
account.takeoff(view.getAmount());
onTakeoff.run();
view.dispose();
} catch (IllegalArgumentException ex) {
Logging.LOGGER.severe("Could not take off money: " + ex.getMessage());
showMessageDialog(null, "Reason: " + ex.getMessage(), "Could not take off money", ERROR_MESSAGE);
}
} }
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.gui.transfer; package me.teridax.jcash.gui.transfer;
import me.teridax.jcash.Logging;
import me.teridax.jcash.banking.management.BankingManagementSystem; import me.teridax.jcash.banking.management.BankingManagementSystem;
import me.teridax.jcash.decode.StringDecoder; import me.teridax.jcash.decode.StringDecoder;
@ -20,19 +21,24 @@ public class TransferData {
*/ */
public void transferValue(double amount, String blz, String ibanString) throws IllegalArgumentException { public void transferValue(double amount, String blz, String ibanString) throws IllegalArgumentException {
var bank = bms.getBank(blz); var bank = bms.getBank(blz);
if (bank.isEmpty()) if (bank.isEmpty()) {
Logging.LOGGER.warning("Bank not found: " + blz);
throw new IllegalArgumentException("Bank not found: " + blz); throw new IllegalArgumentException("Bank not found: " + blz);
}
var iban = 0; var iban = 0;
try { try {
iban = StringDecoder.decodeUniqueIdentificationNumber(ibanString); iban = StringDecoder.decodeUniqueIdentificationNumber(ibanString);
} catch (Exception ex) { } catch (Exception ex) {
Logging.LOGGER.warning("IBAN has invalid format: " + ibanString + " because: " + ex.getMessage());
throw new IllegalArgumentException("IBAN has invalid format: " + ibanString); throw new IllegalArgumentException("IBAN has invalid format: " + ibanString);
} }
var account = bank.get().getAccount(iban); var account = bank.get().getAccount(iban);
if (account.isEmpty()) if (account.isEmpty()) {
Logging.LOGGER.warning("Account not found: " + iban);
throw new IllegalArgumentException("Account not found: " + iban); throw new IllegalArgumentException("Account not found: " + iban);
}
account.get().getPrimaryAccount().deposit(amount); account.get().getPrimaryAccount().deposit(amount);
} }

View File

@ -1,5 +1,6 @@
package me.teridax.jcash.gui.transfer; package me.teridax.jcash.gui.transfer;
import me.teridax.jcash.Logging;
import me.teridax.jcash.banking.accounts.Account; import me.teridax.jcash.banking.accounts.Account;
import me.teridax.jcash.banking.management.BankingManagementSystem; import me.teridax.jcash.banking.management.BankingManagementSystem;
@ -8,22 +9,33 @@ import static javax.swing.JOptionPane.showMessageDialog;
public class TransferDialog { public class TransferDialog {
public TransferDialog(Account account, BankingManagementSystem bms, Runnable onDeposit) { private final Account account;
var view = new TransferView(); private final Runnable onDeposit;
var data = new TransferData(bms); private final TransferData transferData;
view.getTransfer().addActionListener(e -> { private final TransferView transferView;
try {
var amount = view.getAmount();
account.takeoff(amount); public TransferDialog(Account account, BankingManagementSystem bms, Runnable onDeposit) {
data.transferValue(amount, view.getBlz(), view.getIban()); this.account = account;
onDeposit.run(); this.onDeposit = onDeposit;
view.dispose();
} catch (IllegalArgumentException ex) { transferView = new TransferView();
showMessageDialog(null, "invalid account", "Could not transfer", ERROR_MESSAGE); transferData = new TransferData(bms);
} transferView.getTransfer().addActionListener(e -> transfer());
}); transferView.getCancel().addActionListener(e -> transferView.dispose());
view.getCancel().addActionListener(e -> view.dispose()); transferView.showDialog();
view.showDialog(); }
private void transfer() {
try {
var amount = transferView.getAmount();
account.takeoff(amount);
transferData.transferValue(amount, transferView.getBlz(), transferView.getIban());
onDeposit.run();
transferView.dispose();
} catch (IllegalArgumentException ex) {
Logging.LOGGER.severe("Could not transfer: " + ex.getMessage());
showMessageDialog(null, "invalid account", "Could not transfer", ERROR_MESSAGE);
}
} }
} }

View File

@ -1,11 +1,10 @@
package me.teridax.jcash.gui.transfer; package me.teridax.jcash.gui.transfer;
import me.teridax.jcash.Logging;
import me.teridax.jcash.decode.StringDecoder; import me.teridax.jcash.decode.StringDecoder;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.text.NumberFormat;
import java.text.ParseException;
import static javax.swing.JOptionPane.ERROR_MESSAGE; import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.showMessageDialog; import static javax.swing.JOptionPane.showMessageDialog;
@ -118,13 +117,15 @@ public class TransferView {
public double getAmount() { public double getAmount() {
if (value.getText().isBlank()) { if (value.getText().isBlank()) {
Logging.LOGGER.severe("Amount is empty");
showMessageDialog(null, "invalid amount", "currency must not be blank", ERROR_MESSAGE); showMessageDialog(null, "invalid amount", "currency must not be blank", ERROR_MESSAGE);
return 0; return 0;
} }
try { try {
return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue(); return StringDecoder.decodeCurrency(value.getText());
} catch (ParseException e) { } catch (IllegalArgumentException e) {
Logging.LOGGER.severe("Invalid amount: " + value.getText());
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }