Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 18 additions & 28 deletions src/Lecture4_interfaces_abstract_classes/BaseTransaction.java
Original file line number Diff line number Diff line change
@@ -1,51 +1,41 @@
package Lecture4_interfaces_abstract_classes;

import org.jetbrains.annotations.NotNull;

import java.util.Calendar;

public abstract class BaseTransaction implements TransactionInterface {
private final int amount;
private final Calendar date;
private final String transactionID;

/**
* Lecture1_adt.TransactionInterface Constructor
* @param amount in an integer
* @param date: Not null, and must be a Calendar object
* @return void
* Instialises the field, attributes of a transaction
* Creates a object of this
*/
public BaseTransaction(int amount, @NotNull Calendar date) {
this.amount = amount;
this.date = (Calendar) date.clone();
int uniq = (int) Math.random()*10000;
transactionID = date.toString()+uniq;
int uniq = (int) (Math.random() * 10000);
transactionID = date.toString() + uniq;
}

/**
* getAmount()
* @return integer
*/
public double getAmount() {
return amount; // Because we are dealing with Value types we need not worry about what we return
return amount;
}

/**
* getDate()
* @return Calendar Object
*/
public Calendar getDate() {
// return date; // Because we are dealing with Reference types we need to judiciously copy what our getters return
return (Calendar) date.clone(); // Defensive copying or Judicious Copying
return (Calendar) date.clone();
}

// Method to get a unique identifier for the transaction
public String getTransactionID(){
return transactionID;
return transactionID;
}

public void printTransactionDetails() {
System.out.println("--- Transaction Details ---");
System.out.println("Transaction ID: " + getTransactionID());
System.out.println("Date: " + getDate().getTime());
System.out.println("Amount: " + getAmount());
}

// Added 'throws InsufficientFundsException' so subclasses can throw it
public void apply(BankAccount ba) throws InsufficientFundsException {
System.out.println("Base transaction of " + getAmount() + " processed on account. No balance changes made.");
}
// Method to print a transaction receipt or details
public abstract void printTransactionDetails();
public abstract void apply(BankAccount ba);
}
}
18 changes: 12 additions & 6 deletions src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
package Lecture4_interfaces_abstract_classes;

import org.jetbrains.annotations.NotNull;

import java.util.Calendar;

public class DepositTrasaction extends BaseTransaction {

public DepositTrasaction(int amount, @NotNull Calendar date){
super(amount, date);
}

private boolean checkDepositAmount(int amt){
if (amt < 0){
return false;
}
else{
return true;
return true;
}
}

// Method to print a transaction receipt or details
@Override
public void printTransactionDetails(){
System.out.println("Deposit Trasaction: "+this.toString());
System.out.println("--- Deposit Transaction ---");
System.out.println("Transaction ID: " + getTransactionID());
System.out.println("Date: " + getDate().getTime());
System.out.println("Amount Deposited: " + getAmount());
}

public void apply(BankAccount ba){
// Added 'throws InsufficientFundsException' to maintain signature compatibility
@Override
public void apply(BankAccount ba) throws InsufficientFundsException {
double curr_balance = ba.getBalance();
double new_balance = curr_balance + getAmount();
ba.setBalance(new_balance);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package Lecture4_interfaces_abstract_classes;

public class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}
77 changes: 62 additions & 15 deletions src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package Lecture4_interfaces_abstract_classes;

import org.jetbrains.annotations.NotNull;

import java.util.Calendar;

public class WithdrawalTransaction extends BaseTransaction {
private BankAccount appliedAccount = null;
private boolean isApplied = false;
private double shortfallRecord = 0.0;

public WithdrawalTransaction(int amount, @NotNull Calendar date) {
super(amount, date);
}
Expand All @@ -17,29 +20,73 @@ private boolean checkDepositAmount(int amt) {
}
}

// Method to reverse the transaction
// Question 2: Reversal logic restores the account balance to its original amount
public boolean reverse() {
return true;
} // return true if reversal was successful
if (isApplied && appliedAccount != null) {
double currentBalance = appliedAccount.getBalance();
// Restore original amount (current balance + what was successfully withdrawn)
double restoredBalance = currentBalance + (getAmount() - shortfallRecord);
appliedAccount.setBalance(restoredBalance);
isApplied = false; // Reset state
System.out.println("Withdrawal transaction reversed successfully.");
return true;
}
System.out.println("Reversal failed: Transaction has not been applied yet.");
return false;
}

// Method to print a transaction receipt or details
@Override
public void printTransactionDetails() {
System.out.println("Deposit Trasaction: " + this.toString());
System.out.println("--- Withdrawal Transaction ---");
System.out.println("Transaction ID: " + getTransactionID());
System.out.println("Date: " + getDate().getTime());
System.out.println("Amount Requested: " + getAmount());
if (shortfallRecord > 0) {
System.out.println("Shortfall (Not Withdrawn): " + shortfallRecord);
}
}

/*
Oportunity for assignment: implementing different form of withdrawal
*/
public void apply(BankAccount ba) {
// Question 3: Standard apply using the throws keyword
@Override
public void apply(BankAccount ba) throws InsufficientFundsException {
double curr_balance = ba.getBalance();
if (curr_balance > getAmount()) {
if (curr_balance >= getAmount()) {
double new_balance = curr_balance - getAmount();
ba.setBalance(new_balance);
this.appliedAccount = ba;
this.isApplied = true;
this.shortfallRecord = 0.0;
} else {
throw new InsufficientFundsException("Insufficient funds to complete the withdrawal of " + getAmount());
}
}

/*
Assignment 1 Q3: Write the Reverse method - a method unique to the WithdrawalTransaction Class
*/
}

// Question 3: Overloaded apply handling 0 < balance < withdrawal amount using try...catch...finally
public void apply(BankAccount ba, boolean partialWithdrawalAllowed) {
try {
double curr_balance = ba.getBalance();
if (curr_balance < getAmount()) {
// Check if balance is greater than 0 for partial withdrawal
if (curr_balance > 0) {
shortfallRecord = getAmount() - curr_balance;
ba.setBalance(0.0); // Withdraw all available balance
this.appliedAccount = ba;
this.isApplied = true;
System.out.println("Partial withdrawal executed. Balance set to 0. Shortfall: " + shortfallRecord);
} else {
// Trigger exception block manually if balance is 0 or less
throw new InsufficientFundsException("Account balance is zero or negative. Cannot withdraw.");
}
} else {
// If funds are completely sufficient, proceed normally via standard apply
apply(ba);
}
} catch (InsufficientFundsException e) {
System.out.println("Caught Exception inside overloaded apply: " + e.getMessage());
this.isApplied = false;
} finally {
System.out.println("Transaction processing attempt finished for Transaction ID: " + getTransactionID());
}
}
}
82 changes: 72 additions & 10 deletions src/Main.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Lecture1_adt.*; // Import all classes from Lecture1_adt package to be used in this client code
import Lecture4_interfaces_abstract_classes.*; // Import Lecture 4 assignment files

import java.util.Calendar;
import java.util.GregorianCalendar;
Expand Down Expand Up @@ -56,9 +57,9 @@ public static void testTransaction2() {
System.out.println("Lecture1_adt.TransactionInterface Date: \t "+modified_t.getDate().getTime());

/* Please note that Although we have solved the problem of Transaction1
* And client code can no longer use the dot (.) operator to directly access the data
* There is still some exposure especially if we pass an object of a previous Transaction2 to create a new Transaction2 object
*/
* And client code can no longer use the dot (.) operator to directly access the data
* There is still some exposure especially if we pass an object of a previous Transaction2 to create a new Transaction2 object
*/

}

Expand Down Expand Up @@ -143,14 +144,75 @@ public static void testTransaction4() {
// Please Take a look at all the 12 transaction now and compare with the outputs of the Transaction3 class
}

/**
* Question 4: Client Code to test Assignment 1 functionality
*/
public static void testAssignmentOne() {
System.out.println("========== RUNNING ASSIGNMENT 1 TEST CODE ==========");

// 1. Setup account and common date object
BankAccount account = new BankAccount(5000.0);
Calendar now = new GregorianCalendar();

System.out.println("Initial Bank Account Balance: " + account.getBalance());

// 2. Instantiate Subclass Objects
DepositTrasaction deposit = new DepositTrasaction(2000, now);
WithdrawalTransaction withdrawal1 = new WithdrawalTransaction(3000, now);
WithdrawalTransaction withdrawal2 = new WithdrawalTransaction(6000, now); // Will cause exception
WithdrawalTransaction partialWithdrawal = new WithdrawalTransaction(8000, now); // For overloaded test

// 3. Type casting / Mapping subtype objects to the base type object (Upcasting)
BaseTransaction baseDeposit = (BaseTransaction) deposit;
BaseTransaction baseWithdrawal1 = (BaseTransaction) withdrawal1;
BaseTransaction baseWithdrawal2 = (BaseTransaction) withdrawal2;

try {
// 4. Apply Deposit via Base type mapping
System.out.println("\n--- Executing Deposit ---");
baseDeposit.apply(account);
baseDeposit.printTransactionDetails();
System.out.println("Balance after Deposit: " + account.getBalance());

// 5. Apply valid Withdrawal via Base type mapping
System.out.println("\n--- Executing Valid Withdrawal ---");
baseWithdrawal1.apply(account);
baseWithdrawal1.printTransactionDetails();
System.out.println("Balance after Withdrawal 1: " + account.getBalance());

// 6. Test Reversal on the successful withdrawal
System.out.println("\n--- Testing Reversal on Withdrawal 1 ---");
withdrawal1.reverse();
System.out.println("Balance after Reversal: " + account.getBalance());

// 7. Apply invalid Withdrawal (Should throw InsufficientFundsException)
System.out.println("\n--- Executing Invalid Withdrawal (Expect Exception) ---");
baseWithdrawal2.apply(account); // This line will jump to the catch block

} catch (InsufficientFundsException e) {
System.out.println("Successfully caught handled exception: " + e.getMessage());
}

// 8. Test Overloaded apply method (Partial withdrawal scenario)
System.out.println("\n--- Executing Overloaded Apply (Partial Withdrawal Option) ---");
System.out.println("Current Account Balance before partial: " + account.getBalance());

// Attempting to withdraw 8000 when balance is less than that but greater than 0
partialWithdrawal.apply(account, true);
partialWithdrawal.printTransactionDetails();
System.out.println("Final Account Balance after partial withdrawal loop: " + account.getBalance());

System.out.println("====================================================");
}

public static void main(String[] args) {
// This is the client code
// Uncomment the following lines to test the class which you would like to test

// testTransaction1()
// testTransaction2()
// testTransaction3()
// testTransaction4()
// Run assignment test execution
testAssignmentOne();

// Uncomment the following lines to run historical lecture tests if needed
// testTransaction1();
// testTransaction2();
// testTransaction3();
// testTransaction4();
}
}