parent
0840db44c2
commit
2a0d97c834
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
this.view = new TakeoffView();
|
||||||
|
|
||||||
|
this.view.getTakeoff().addActionListener(e -> takeOff());
|
||||||
|
this.view.getCancel().addActionListener(e -> view.dispose());
|
||||||
|
this.view.showDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void takeOff() {
|
||||||
try {
|
try {
|
||||||
account.takeoff(view.getAmount());
|
account.takeoff(view.getAmount());
|
||||||
onTakeoff.run();
|
onTakeoff.run();
|
||||||
view.dispose();
|
view.dispose();
|
||||||
} catch (IllegalArgumentException ex) {
|
} 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);
|
showMessageDialog(null, "Reason: " + ex.getMessage(), "Could not take off money", ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
view.getCancel().addActionListener(e -> view.dispose());
|
|
||||||
view.showDialog();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
private final Account account;
|
||||||
|
private final Runnable onDeposit;
|
||||||
|
private final TransferData transferData;
|
||||||
|
private final TransferView transferView;
|
||||||
|
|
||||||
public TransferDialog(Account account, BankingManagementSystem bms, Runnable onDeposit) {
|
public TransferDialog(Account account, BankingManagementSystem bms, Runnable onDeposit) {
|
||||||
var view = new TransferView();
|
this.account = account;
|
||||||
var data = new TransferData(bms);
|
this.onDeposit = onDeposit;
|
||||||
view.getTransfer().addActionListener(e -> {
|
|
||||||
|
transferView = new TransferView();
|
||||||
|
transferData = new TransferData(bms);
|
||||||
|
transferView.getTransfer().addActionListener(e -> transfer());
|
||||||
|
transferView.getCancel().addActionListener(e -> transferView.dispose());
|
||||||
|
transferView.showDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transfer() {
|
||||||
try {
|
try {
|
||||||
var amount = view.getAmount();
|
var amount = transferView.getAmount();
|
||||||
|
|
||||||
account.takeoff(amount);
|
account.takeoff(amount);
|
||||||
data.transferValue(amount, view.getBlz(), view.getIban());
|
transferData.transferValue(amount, transferView.getBlz(), transferView.getIban());
|
||||||
onDeposit.run();
|
onDeposit.run();
|
||||||
view.dispose();
|
transferView.dispose();
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
|
Logging.LOGGER.severe("Could not transfer: " + ex.getMessage());
|
||||||
showMessageDialog(null, "invalid account", "Could not transfer", ERROR_MESSAGE);
|
showMessageDialog(null, "invalid account", "Could not transfer", ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
view.getCancel().addActionListener(e -> view.dispose());
|
|
||||||
view.showDialog();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue