diff --git a/src/me/teridax/jcash/Logging.java b/src/me/teridax/jcash/Logging.java new file mode 100644 index 0000000..289c357 --- /dev/null +++ b/src/me/teridax/jcash/Logging.java @@ -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); + } + } +} diff --git a/src/me/teridax/jcash/Main.java b/src/me/teridax/jcash/Main.java index 17282af..d6e3cfc 100644 --- a/src/me/teridax/jcash/Main.java +++ b/src/me/teridax/jcash/Main.java @@ -5,6 +5,13 @@ import me.teridax.jcash.gui.account.AccountController; import me.teridax.jcash.gui.login.LoginController; 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 { @@ -27,6 +34,8 @@ public final class Main { } public static void main(String[] args) { + initializeSystemLogger(Level.FINE); + // create main instance and show the login screen instance(); getInstance().showLoginScreen(); @@ -51,6 +60,8 @@ public final class Main { if (null != instance) throw new IllegalStateException(Main.class.getName() + " is already initialized"); + LOGGER.fine("Creating singleton instance of class " + Main.class.getName()); + Main.instance = new Main(); } @@ -61,6 +72,8 @@ public final class Main { */ public void showLoginScreen() { SwingUtilities.invokeLater(() -> { + LOGGER.finer("showing login screen"); + try { // select db file var path = Loader.load(); @@ -69,6 +82,8 @@ public final class Main { // when we have logged in set the account viewer as window content login.addAccountSelectionListener(account -> { + LOGGER.finer("account selected: " + Objects.toString(account, "null")); + var profileCont = new AccountController(account, login.getData().getBms()); this.window.setContentPane(profileCont.getView()); this.window.revalidate(); @@ -81,7 +96,8 @@ public final class Main { this.window.setVisible(true); } 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); } }); diff --git a/src/me/teridax/jcash/banking/Bank.java b/src/me/teridax/jcash/banking/Bank.java index 6f04466..90953b4 100644 --- a/src/me/teridax/jcash/banking/Bank.java +++ b/src/me/teridax/jcash/banking/Bank.java @@ -1,5 +1,6 @@ package me.teridax.jcash.banking; +import me.teridax.jcash.Logging; import me.teridax.jcash.banking.accounts.Account; import me.teridax.jcash.banking.accounts.Owner; 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(); } } diff --git a/src/me/teridax/jcash/banking/accounts/Account.java b/src/me/teridax/jcash/banking/accounts/Account.java index 82d344b..0949c0e 100644 --- a/src/me/teridax/jcash/banking/accounts/Account.java +++ b/src/me/teridax/jcash/banking/accounts/Account.java @@ -1,5 +1,6 @@ package me.teridax.jcash.banking.accounts; +import me.teridax.jcash.Logging; import me.teridax.jcash.decode.StringDecoder; import java.util.Objects; @@ -40,6 +41,9 @@ public abstract class Account { */ public static Account fromColumns(String[] columns) throws IllegalArgumentException, NullPointerException { Objects.requireNonNull(columns); + Logging.LOGGER.finer("Parsing account from columns"); + + Logging.LOGGER.finer("Decoding account fields"); // deserialize fields var iban = StringDecoder.decodeUniqueIdentificationNumber(columns[0]); @@ -50,15 +54,20 @@ public abstract class Account { // try to detect the specific runtime class to deserialize try { if (type.equals("Sparkonto")) { + Logging.LOGGER.fine("Account detected as Sparkonto"); var interest = StringDecoder.decodePercent(columns[4]); return new SavingsAccount(iban, pin, balance, interest); } else if (type.equals("Girokonto")) { + Logging.LOGGER.fine("Account detected as Girokonto"); var overdraft = StringDecoder.decodeCurrency(columns[5]); 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); + } } catch (IllegalArgumentException | NullPointerException e) { + Logging.LOGGER.severe("Account field could not be decoded: " + e.getMessage()); throw new IllegalArgumentException("Account format: ", e); } } @@ -110,8 +119,10 @@ public abstract class Account { * @throws IllegalArgumentException if amount is negative */ 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"); + } this.balance += amount; } @@ -128,8 +139,10 @@ public abstract class Account { * @throws IllegalArgumentException if amount is greater than the balance present */ 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"); + } this.balance = this.balance - amount; } diff --git a/src/me/teridax/jcash/banking/accounts/CurrentAccount.java b/src/me/teridax/jcash/banking/accounts/CurrentAccount.java index 9289ee7..97ced18 100644 --- a/src/me/teridax/jcash/banking/accounts/CurrentAccount.java +++ b/src/me/teridax/jcash/banking/accounts/CurrentAccount.java @@ -1,5 +1,7 @@ package me.teridax.jcash.banking.accounts; +import me.teridax.jcash.Logging; + /** * Immutable currency account storing only overdraft. * English equivalent to "Girokonto" @@ -30,9 +32,12 @@ public final class CurrentAccount extends Account { */ @Override public void takeoff(double amount) throws IllegalArgumentException { + Logging.LOGGER.fine("taking off money: " + amount + " from account: " + iban); + var overflow = amount - getBalance(); if (overflow > 0) { + Logging.LOGGER.fine("taking off money with overflow: " + overflow); this.overdraft += overflow; this.balance = 0; } diff --git a/src/me/teridax/jcash/banking/accounts/Owner.java b/src/me/teridax/jcash/banking/accounts/Owner.java index 391d8ae..d45bc01 100644 --- a/src/me/teridax/jcash/banking/accounts/Owner.java +++ b/src/me/teridax/jcash/banking/accounts/Owner.java @@ -1,5 +1,6 @@ package me.teridax.jcash.banking.accounts; +import me.teridax.jcash.Logging; import me.teridax.jcash.decode.StringDecoder; import java.util.Objects; @@ -40,10 +41,12 @@ public final class Owner { */ public static Owner fromColumns(String... columns) throws IllegalArgumentException, NullPointerException { Objects.requireNonNull(columns); + Logging.LOGGER.finer("parsing owner from columns"); if (columns.length != 6) throw new IllegalArgumentException("Invalid number of columns: " + columns.length); + Logging.LOGGER.finer("Decoding owner fields"); // decode fields var uid = StringDecoder.decodeUniqueIdentificationNumber(columns[0]); var familyName = StringDecoder.decodeName(columns[1]); diff --git a/src/me/teridax/jcash/banking/management/BankingManagementSystem.java b/src/me/teridax/jcash/banking/management/BankingManagementSystem.java index 57970a3..2fc6536 100644 --- a/src/me/teridax/jcash/banking/management/BankingManagementSystem.java +++ b/src/me/teridax/jcash/banking/management/BankingManagementSystem.java @@ -10,6 +10,8 @@ import java.nio.file.Files; import java.nio.file.Path; 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. * 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 { + /** + * Separator used to separate columns of CSV files + */ + private static final String SEPARATOR = ";"; + /** * A set of banks */ @@ -64,6 +71,7 @@ public final class BankingManagementSystem { * @return a valid BMS */ public static BankingManagementSystem loadFromCsv(Path file) throws IllegalArgumentException { + LOGGER.fine("parsing banking management system from file: " + Objects.toString(file, "null")); try { var bms = new BankingManagementSystem(); var content = Files.readString(file); @@ -71,13 +79,16 @@ public final class BankingManagementSystem { // read line by line // and skip the first line content.lines().skip(1).forEach(line -> { + + LOGGER.finest("splitting lines by separator: " + SEPARATOR); // split the line into columns - var columns = line.split(";"); + var columns = line.split(SEPARATOR); // one line must contain exactly 14 columns if (columns.length != 14) throw new IllegalArgumentException("invalid column count: " + columns.length); + LOGGER.finer("reading members from line: " + line); // read basic fields var owner = Owner.fromColumns(tail(columns, 8)); 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(); if (bankOfSet.isPresent()) { + LOGGER.fine("bank from current line is already present in management system"); bankOfSet.get().addAccount(owner, account); } else { + LOGGER.fine("bank from current line is new for management system"); bankOfLine.addAccount(owner, account); bms.banks.add(bankOfLine); } @@ -100,8 +113,10 @@ public final class BankingManagementSystem { return bms; } catch (IOException e) { + LOGGER.severe("Could not read file: " + file + " due to: " + e.getMessage()); throw new IllegalArgumentException("Could not read file " + file, 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); } } diff --git a/src/me/teridax/jcash/banking/management/Profile.java b/src/me/teridax/jcash/banking/management/Profile.java index ea5245a..ce13520 100644 --- a/src/me/teridax/jcash/banking/management/Profile.java +++ b/src/me/teridax/jcash/banking/management/Profile.java @@ -1,5 +1,6 @@ package me.teridax.jcash.banking.management; +import me.teridax.jcash.Logging; import me.teridax.jcash.banking.Bank; import me.teridax.jcash.banking.accounts.Account; import me.teridax.jcash.banking.accounts.Owner; @@ -32,8 +33,10 @@ public class Profile { private final 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"); + } this.owner = owner; this.bank = bank; @@ -69,5 +72,6 @@ public class Profile { break; } } + Logging.LOGGER.warning("Account " + description + " not found in associated account list"); } } diff --git a/src/me/teridax/jcash/gui/Loader.java b/src/me/teridax/jcash/gui/Loader.java index 19d5946..fe0ec6b 100644 --- a/src/me/teridax/jcash/gui/Loader.java +++ b/src/me/teridax/jcash/gui/Loader.java @@ -1,5 +1,6 @@ package me.teridax.jcash.gui; +import me.teridax.jcash.Logging; import me.teridax.jcash.banking.management.BankingManagementSystem; import javax.swing.*; @@ -42,6 +43,7 @@ public class Loader { } } + Logging.LOGGER.warning("no file selected"); throw new IllegalStateException("No file selected"); } } diff --git a/src/me/teridax/jcash/gui/account/AccountController.java b/src/me/teridax/jcash/gui/account/AccountController.java index 28a0306..7280bb1 100644 --- a/src/me/teridax/jcash/gui/account/AccountController.java +++ b/src/me/teridax/jcash/gui/account/AccountController.java @@ -1,5 +1,6 @@ package me.teridax.jcash.gui.account; +import me.teridax.jcash.Logging; import me.teridax.jcash.Main; import me.teridax.jcash.banking.management.BankingManagementSystem; import me.teridax.jcash.banking.management.Profile; @@ -17,7 +18,10 @@ public class AccountController { */ private final AccountView view; + private final Profile profile; + public AccountController(Profile profile, BankingManagementSystem bms) { + this.profile = profile; this.view = new AccountView(); this.view.setProfile(profile); this.data = new AccountData(bms); @@ -26,16 +30,9 @@ public class AccountController { } private void createListeners(Profile profile) { - this.view.getAccountSelection().addActionListener(e -> { - var description = ((String) this.view.getAccountSelection().getSelectedItem()); - profile.setPrimaryAccount(description); - this.view.setProfile(profile); - }); + this.view.getAccountSelection().addActionListener(e -> changeAccount()); - this.view.getLogout().addActionListener(e -> { - Main.getInstance().logout(); - Main.getInstance().showLoginScreen(); - }); + this.view.getLogout().addActionListener(e -> logout()); 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))); } + 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() { return view; } diff --git a/src/me/teridax/jcash/gui/account/AccountView.java b/src/me/teridax/jcash/gui/account/AccountView.java index 455aa95..2f29caf 100644 --- a/src/me/teridax/jcash/gui/account/AccountView.java +++ b/src/me/teridax/jcash/gui/account/AccountView.java @@ -1,5 +1,6 @@ package me.teridax.jcash.gui.account; +import me.teridax.jcash.Logging; import me.teridax.jcash.banking.accounts.CurrentAccount; import me.teridax.jcash.banking.accounts.SavingsAccount; import me.teridax.jcash.banking.management.Profile; @@ -35,6 +36,7 @@ public class AccountView extends JPanel { } public void setProfile(Profile profile) { + Logging.LOGGER.finer("Changing profile of account view"); var bank = profile.getBank(); var account = profile.getPrimaryAccount(); var owner = profile.getOwner(); @@ -49,12 +51,14 @@ public class AccountView extends JPanel { this.balance.setText(StringDecoder.LOCAL_NUMBER_FORMAT.format(account.getBalance()) + " €"); this.type.setText(account.getClass().getSimpleName()); - if (account instanceof CurrentAccount) { + if (account instanceof CurrentAccount) {; this.typeSpecialLabel.setText("Overdraft"); this.typeSpecialProperty.setText( StringDecoder.LOCAL_NUMBER_FORMAT.format(((CurrentAccount) account).getOverdraft()) + " €"); } else if (account instanceof SavingsAccount) { this.typeSpecialLabel.setText("Interest rate"); this.typeSpecialProperty.setText( ((SavingsAccount) account).getInterest() + " %" ); + } else { + Logging.LOGGER.severe("Type of new primary account cannot be determined: " + account.getClass().getName()); } this.accountSelection.removeAllItems(); diff --git a/src/me/teridax/jcash/gui/deposit/DepositDialog.java b/src/me/teridax/jcash/gui/deposit/DepositDialog.java index dce88a3..352a967 100644 --- a/src/me/teridax/jcash/gui/deposit/DepositDialog.java +++ b/src/me/teridax/jcash/gui/deposit/DepositDialog.java @@ -1,17 +1,37 @@ package me.teridax.jcash.gui.deposit; +import me.teridax.jcash.Logging; import me.teridax.jcash.banking.accounts.Account; public class DepositDialog { + private final DepositView view; + private final Account account; + private final Runnable onDeposit; + public DepositDialog(Account account, Runnable onDeposit) { - var view = new DepositView(); - view.getDeposit().addActionListener(e -> { - account.deposit(view.getAmount()); + this.account = account; + this.onDeposit = onDeposit; + + 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(); + } catch (IllegalArgumentException ex) { + Logging.LOGGER.severe("Cannot deposit money of account: " + account.getIban() + " because: " + ex.getMessage()); + } finally { view.dispose(); - }); - view.getCancel().addActionListener(e -> view.dispose()); - view.showDialog(); + } } } diff --git a/src/me/teridax/jcash/gui/deposit/DepositView.java b/src/me/teridax/jcash/gui/deposit/DepositView.java index afba716..5c24469 100644 --- a/src/me/teridax/jcash/gui/deposit/DepositView.java +++ b/src/me/teridax/jcash/gui/deposit/DepositView.java @@ -1,5 +1,6 @@ package me.teridax.jcash.gui.deposit; +import me.teridax.jcash.Logging; import me.teridax.jcash.decode.StringDecoder; import javax.swing.*; @@ -96,6 +97,7 @@ public class DepositView { try { return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue(); } catch (ParseException e) { + Logging.LOGGER.severe("Amount text field contains invalid value: " + value); throw new RuntimeException(e); } } diff --git a/src/me/teridax/jcash/gui/login/LoginController.java b/src/me/teridax/jcash/gui/login/LoginController.java index 1344adb..3b16452 100644 --- a/src/me/teridax/jcash/gui/login/LoginController.java +++ b/src/me/teridax/jcash/gui/login/LoginController.java @@ -1,5 +1,6 @@ package me.teridax.jcash.gui.login; +import me.teridax.jcash.Logging; import me.teridax.jcash.banking.management.BankingManagementSystem; import java.awt.event.ActionEvent; @@ -31,6 +32,7 @@ public class LoginController { var iban = this.view.getIban().getText(); return Optional.of(Integer.parseUnsignedInt(iban)); } catch (NumberFormatException e) { + Logging.LOGGER.warning("IBAN text field contains invalid value: " + this.view.getIban().getText()); return Optional.empty(); } } @@ -40,6 +42,7 @@ public class LoginController { var iban = this.view.getPin().getPassword(); return Optional.of(Integer.parseUnsignedInt(new String(iban))); } catch (NumberFormatException e) { + Logging.LOGGER.severe("PIN text field contains invalid value: " + String.valueOf(view.getPin().getPassword())); return Optional.empty(); } } @@ -48,12 +51,14 @@ public class LoginController { var blz = this.view.getBlz().getText(); var iban = this.getIban(); if (iban.isEmpty()) { + Logging.LOGGER.severe("IBAN is invalid: " + iban); showMessageDialog(null, "invalid IBAN", "Faulty login attempt", ERROR_MESSAGE); return; } var pin = this.getPin(); if (pin.isEmpty()) { + Logging.LOGGER.severe("PIN is invalid: " + pin); showMessageDialog(null, "invalid pin", "Faulty login attempt", ERROR_MESSAGE); return; } @@ -62,6 +67,7 @@ public class LoginController { if (account.isPresent()) { this.listener.onAccountSelected(account.get()); } else { + Logging.LOGGER.severe("invalid login credentials: " + iban + " / " + pin); showMessageDialog(null, "invalid login credentials", "Faulty login attempt", ERROR_MESSAGE); } } diff --git a/src/me/teridax/jcash/gui/login/LoginData.java b/src/me/teridax/jcash/gui/login/LoginData.java index 04ae706..b3a48c2 100644 --- a/src/me/teridax/jcash/gui/login/LoginData.java +++ b/src/me/teridax/jcash/gui/login/LoginData.java @@ -1,5 +1,6 @@ package me.teridax.jcash.gui.login; +import me.teridax.jcash.Logging; import me.teridax.jcash.banking.management.BankingManagementSystem; 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 */ public Optional authenticateAccount(String blz, int iban, int pin) { + Logging.LOGGER.info("Authenticating account " + iban); var optionalBank = bms.getBank(blz); if (optionalBank.isEmpty()) return Optional.empty(); diff --git a/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java b/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java index 1425761..547710e 100644 --- a/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java +++ b/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java @@ -1,5 +1,6 @@ package me.teridax.jcash.gui.takeoff; +import me.teridax.jcash.Logging; import me.teridax.jcash.banking.accounts.Account; import static javax.swing.JOptionPane.ERROR_MESSAGE; @@ -7,18 +8,29 @@ import static javax.swing.JOptionPane.showMessageDialog; public class TakeoffDialog { + private final Account account; + private final Runnable onTakeoff; + private final TakeoffView view; + public TakeoffDialog(Account account, Runnable onTakeoff) { - var view = new TakeoffView(); - view.getTakeoff().addActionListener(e -> { - try { - account.takeoff(view.getAmount()); - onTakeoff.run(); - view.dispose(); - } catch (IllegalArgumentException ex) { - showMessageDialog(null, "Reason: " + ex.getMessage(), "Could not take off money", ERROR_MESSAGE); - } - }); - view.getCancel().addActionListener(e -> view.dispose()); - view.showDialog(); + this.account = account; + this.onTakeoff = onTakeoff; + + this.view = new TakeoffView(); + + this.view.getTakeoff().addActionListener(e -> takeOff()); + this.view.getCancel().addActionListener(e -> view.dispose()); + this.view.showDialog(); + } + + private void takeOff() { + 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); + } } } diff --git a/src/me/teridax/jcash/gui/transfer/TransferData.java b/src/me/teridax/jcash/gui/transfer/TransferData.java index 8ddb3e4..6680683 100644 --- a/src/me/teridax/jcash/gui/transfer/TransferData.java +++ b/src/me/teridax/jcash/gui/transfer/TransferData.java @@ -1,5 +1,6 @@ package me.teridax.jcash.gui.transfer; +import me.teridax.jcash.Logging; import me.teridax.jcash.banking.management.BankingManagementSystem; import me.teridax.jcash.decode.StringDecoder; @@ -20,19 +21,24 @@ public class TransferData { */ public void transferValue(double amount, String blz, String ibanString) throws IllegalArgumentException { 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); + } var iban = 0; try { iban = StringDecoder.decodeUniqueIdentificationNumber(ibanString); } catch (Exception ex) { + Logging.LOGGER.warning("IBAN has invalid format: " + ibanString + " because: " + ex.getMessage()); throw new IllegalArgumentException("IBAN has invalid format: " + ibanString); } 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); + } account.get().getPrimaryAccount().deposit(amount); } diff --git a/src/me/teridax/jcash/gui/transfer/TransferDialog.java b/src/me/teridax/jcash/gui/transfer/TransferDialog.java index 658981f..b774d4e 100644 --- a/src/me/teridax/jcash/gui/transfer/TransferDialog.java +++ b/src/me/teridax/jcash/gui/transfer/TransferDialog.java @@ -1,5 +1,6 @@ package me.teridax.jcash.gui.transfer; +import me.teridax.jcash.Logging; import me.teridax.jcash.banking.accounts.Account; import me.teridax.jcash.banking.management.BankingManagementSystem; @@ -8,22 +9,33 @@ import static javax.swing.JOptionPane.showMessageDialog; public class TransferDialog { - public TransferDialog(Account account, BankingManagementSystem bms, Runnable onDeposit) { - var view = new TransferView(); - var data = new TransferData(bms); - view.getTransfer().addActionListener(e -> { - try { - var amount = view.getAmount(); + private final Account account; + private final Runnable onDeposit; + private final TransferData transferData; + private final TransferView transferView; - account.takeoff(amount); - data.transferValue(amount, view.getBlz(), view.getIban()); - onDeposit.run(); - view.dispose(); - } catch (IllegalArgumentException ex) { - showMessageDialog(null, "invalid account", "Could not transfer", ERROR_MESSAGE); - } - }); - view.getCancel().addActionListener(e -> view.dispose()); - view.showDialog(); + public TransferDialog(Account account, BankingManagementSystem bms, Runnable onDeposit) { + this.account = account; + this.onDeposit = onDeposit; + + transferView = new TransferView(); + transferData = new TransferData(bms); + transferView.getTransfer().addActionListener(e -> transfer()); + transferView.getCancel().addActionListener(e -> transferView.dispose()); + transferView.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); + } } } diff --git a/src/me/teridax/jcash/gui/transfer/TransferView.java b/src/me/teridax/jcash/gui/transfer/TransferView.java index 1a17bb9..484cf1c 100644 --- a/src/me/teridax/jcash/gui/transfer/TransferView.java +++ b/src/me/teridax/jcash/gui/transfer/TransferView.java @@ -1,11 +1,10 @@ package me.teridax.jcash.gui.transfer; +import me.teridax.jcash.Logging; import me.teridax.jcash.decode.StringDecoder; import javax.swing.*; import java.awt.*; -import java.text.NumberFormat; -import java.text.ParseException; import static javax.swing.JOptionPane.ERROR_MESSAGE; import static javax.swing.JOptionPane.showMessageDialog; @@ -118,13 +117,15 @@ public class TransferView { public double getAmount() { if (value.getText().isBlank()) { + Logging.LOGGER.severe("Amount is empty"); showMessageDialog(null, "invalid amount", "currency must not be blank", ERROR_MESSAGE); return 0; } try { - return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue(); - } catch (ParseException e) { + return StringDecoder.decodeCurrency(value.getText()); + } catch (IllegalArgumentException e) { + Logging.LOGGER.severe("Invalid amount: " + value.getText()); throw new RuntimeException(e); } }