-
Notifications
You must be signed in to change notification settings - Fork 24
feat: implement bank account system with audit logging to BankATM #526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b0ac1a4
0e88098
c2e71de
a76da9d
1f7dae4
36f06a1
c36cc92
4d25713
387c5e1
b9c341d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package com.codedifferently.lesson17.bank; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import org.apache.logging.log4j.LogManager; | ||
import org.apache.logging.log4j.Logger; | ||
|
||
/** | ||
* The {@code AuditLog} class is responsible for logging important events in the banking system. It | ||
* uses the Log4j logging framework to log messages at different levels. | ||
*/ | ||
public class AuditLog { | ||
|
||
private static final Logger logger = LogManager.getLogger(AuditLog.class.getName()); | ||
private final List<String> logEntries = new ArrayList<>(); | ||
|
||
/** | ||
* Logs a message at the INFO level and adds it to the internal list of log entries. | ||
* | ||
* @param message | ||
*/ | ||
public void log(String message) { | ||
logger.info(message); | ||
logEntries.add(message); | ||
} | ||
|
||
/** | ||
* Logs an error message at the ERROR level and adds it to the internal list of log entries. | ||
* | ||
* @param message | ||
*/ | ||
public void logError(String message) { | ||
logger.error(message); | ||
logEntries.add(message); | ||
} | ||
|
||
/** | ||
* Returns the list of log entries. | ||
* | ||
* @return A list of log entries | ||
*/ | ||
public List<String> getLogEntries() { | ||
return logEntries; | ||
} | ||
|
||
public void clear() { | ||
logEntries.clear(); | ||
logger.debug("Audit log cleared"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ public class BankAtm { | |
|
||
private final Map<UUID, Customer> customerById = new HashMap<>(); | ||
private final Map<String, CheckingAccount> accountByNumber = new HashMap<>(); | ||
private final AuditLog auditLog = new AuditLog(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Violates the D in SOLID, no? |
||
|
||
/** | ||
* Adds a checking account to the bank. | ||
|
@@ -25,6 +26,7 @@ public void addAccount(CheckingAccount account) { | |
owner -> { | ||
customerById.put(owner.getId(), owner); | ||
}); | ||
auditLog.log("Added account " + account.getAccountNumber() + " to the bank"); | ||
} | ||
|
||
/** | ||
|
@@ -34,6 +36,7 @@ public void addAccount(CheckingAccount account) { | |
* @return The unique set of accounts owned by the customer. | ||
*/ | ||
public Set<CheckingAccount> findAccountsByCustomerId(UUID customerId) { | ||
auditLog.log("Finding accounts for customer " + customerId); | ||
return customerById.containsKey(customerId) | ||
? customerById.get(customerId).getAccounts() | ||
: Set.of(); | ||
|
@@ -48,6 +51,7 @@ public Set<CheckingAccount> findAccountsByCustomerId(UUID customerId) { | |
public void depositFunds(String accountNumber, double amount) { | ||
CheckingAccount account = getAccountOrThrow(accountNumber); | ||
account.deposit(amount); | ||
auditLog.log("Deposited " + amount + " into account " + accountNumber); | ||
} | ||
|
||
/** | ||
|
@@ -58,7 +62,9 @@ public void depositFunds(String accountNumber, double amount) { | |
*/ | ||
public void depositFunds(String accountNumber, Check check) { | ||
CheckingAccount account = getAccountOrThrow(accountNumber); | ||
|
||
check.depositFunds(account); | ||
auditLog.log("Deposited check into account " + accountNumber); | ||
} | ||
|
||
/** | ||
|
@@ -67,9 +73,11 @@ public void depositFunds(String accountNumber, Check check) { | |
* @param accountNumber | ||
* @param amount | ||
*/ | ||
public void withdrawFunds(String accountNumber, double amount) { | ||
public void withdrawFunds(String accountNumber, double amount, Check check) { | ||
CheckingAccount account = getAccountOrThrow(accountNumber); | ||
account.withdraw(amount); | ||
|
||
auditLog.log("Withdrew " + amount + " from account " + accountNumber); | ||
} | ||
|
||
/** | ||
|
@@ -83,6 +91,7 @@ private CheckingAccount getAccountOrThrow(String accountNumber) { | |
if (account == null || account.isClosed()) { | ||
throw new AccountNotFoundException("Account not found"); | ||
} | ||
auditLog.log("Retrieved account " + accountNumber); | ||
return account; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,9 +68,11 @@ public void withdraw(double amount) throws InsufficientFundsException { | |
if (isClosed()) { | ||
throw new IllegalStateException("Cannot withdraw from a closed account"); | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? |
||
if (amount <= 0) { | ||
throw new IllegalStateException("Withdrawal amount must be positive"); | ||
} | ||
|
||
if (balance < amount) { | ||
throw new InsufficientFundsException("Account does not have enough funds for withdrawal"); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package com.codedifferently.lesson17.bank; | ||
|
||
import com.codedifferently.lesson17.bank.exceptions.InsufficientFundsException; | ||
import java.util.Set; | ||
|
||
/** | ||
* The {@code SavingsAccount} class represents a savings account in a banking system. It extends the | ||
* {@code CheckingAccount} class and provides additional functionality specific to savings accounts. | ||
*/ | ||
public class SavingsAccount extends CheckingAccount { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A savings accounts is not a checking account. |
||
|
||
/** | ||
* Constructs a new SavingsAccount with the specified account number, owners, and balance. | ||
* | ||
* @param accountNumber | ||
* @param owners | ||
* @param balance | ||
*/ | ||
public SavingsAccount(String accountNumber, Set<Customer> owners, double balance) { | ||
super(accountNumber, owners, balance); | ||
} | ||
|
||
/** | ||
* Gets the HashCode of the account number. | ||
* | ||
* @return The hash code of the account number. | ||
*/ | ||
@Override | ||
public int hashCode() { | ||
return getAccountNumber().hashCode(); | ||
} | ||
|
||
/** | ||
* Checks if this SavingsAccount is equal to another object. | ||
* | ||
* @param obj The object to compare with. | ||
* @return true if the objects are equal, false otherwise. | ||
*/ | ||
@Override | ||
public boolean equals(Object obj) { | ||
if (obj instanceof SavingsAccount other) { | ||
return getAccountNumber().equals(other.getAccountNumber()) | ||
&& getOwners().equals(other.getOwners()) | ||
&& getBalance() == other.getBalance() | ||
&& isClosed() == other.isClosed(); | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* Will throw and exception if the user attempt to make a withdrawl while under the instance of | ||
* SavingsAccount. | ||
* | ||
* <p>And the makes a second withdrawl that will check if there is a check and throw an error if | ||
* one comes in. | ||
* | ||
* @param amount The amount to deposit. | ||
*/ | ||
@Override | ||
public void withdraw(double amount) throws InsufficientFundsException { | ||
throw new IllegalStateException("you cannot write a check from the savings account"); | ||
} | ||
|
||
public void withdraw(double amount, Check check) { | ||
if (check != null) { | ||
throw new IllegalStateException("Cannot withdraw from a savings account using a check"); | ||
} | ||
withdraw(amount); // Call the original withdraw method | ||
} | ||
|
||
/** | ||
* Returns a string representation of the SavingsAccount. | ||
* | ||
* @return A string representation of the SavingsAccount. | ||
*/ | ||
@Override | ||
public String toString() { | ||
return "SavingsAccount" | ||
+ "accountNumber='" | ||
+ getAccountNumber() | ||
+ '\'' | ||
+ ", owners=" | ||
+ getOwners() | ||
+ ", balance=" | ||
+ getBalance() | ||
+ ", isActive=" | ||
+ isClosed() | ||
+ '}'; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.codedifferently.lesson17.bank; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
public class AuditLogTest { | ||
@Test | ||
public void testLog() { | ||
AuditLog auditLog = new AuditLog(); | ||
|
||
String message = "Test log message"; | ||
auditLog.log(message); | ||
} | ||
|
||
@Test | ||
public void testGetLogEntries() { | ||
AuditLog auditLog = new AuditLog(); | ||
|
||
String message1 = "Test log message 1"; | ||
String message2 = "Test log message 2"; | ||
auditLog.log(message1); | ||
auditLog.log(message2); | ||
|
||
assert auditLog.getLogEntries().size() == 2; | ||
assert auditLog.getLogEntries().get(0).equals(message1); | ||
assert auditLog.getLogEntries().get(1).equals(message2); | ||
} | ||
|
||
@Test | ||
public void testClear() { | ||
AuditLog auditLog = new AuditLog(); | ||
|
||
String message = "Test log message"; | ||
auditLog.log(message); | ||
auditLog.clear(); | ||
|
||
assert auditLog.getLogEntries().isEmpty(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.codedifferently.lesson17.bank; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
||
import java.util.HashSet; | ||
import java.util.UUID; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
public class SavingsAccountTest { | ||
|
||
private SavingsAccount classUnderTest; | ||
private HashSet<Customer> owners; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
owners = new HashSet<>(); | ||
owners.add(new Customer(UUID.randomUUID(), "John Doe")); | ||
owners.add(new Customer(UUID.randomUUID(), "Jane Smith")); | ||
classUnderTest = new SavingsAccount("123456789", owners, 100.0); | ||
} | ||
|
||
@Test | ||
void testHashCode() { | ||
int expected = classUnderTest.getAccountNumber().hashCode(); | ||
int actual = classUnderTest.hashCode(); | ||
assertEquals(expected, actual); | ||
} | ||
|
||
@Test | ||
void testEquals() { | ||
SavingsAccount other = new SavingsAccount("123456789", owners, 100.0); | ||
boolean expected = true; | ||
boolean actual = classUnderTest.equals(other); | ||
assertEquals(expected, actual); | ||
} | ||
|
||
@Test | ||
void testCheckWithdrawl() { | ||
Check check = new Check("123456789", 1000.0, classUnderTest); | ||
|
||
IllegalStateException exception = | ||
assertThrows( | ||
IllegalStateException.class, | ||
() -> { | ||
classUnderTest.withdraw(1000, check); | ||
}); | ||
|
||
assertEquals("Cannot withdraw from a savings account using a check", exception.getMessage()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a bad implementation, good work. You might be interested in a library called
Log4j
that could be useful to you as well, but this is good enough for your homework.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored AuditLog class to Implement Log4j logic instead of custom implementation.