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
69 changes: 48 additions & 21 deletions src/Lecture4_interfaces_abstract_classes/BaseTransaction.java
Original file line number Diff line number Diff line change
@@ -1,51 +1,78 @@
package Lecture4_interfaces_abstract_classes;

import org.jetbrains.annotations.NotNull;

import java.util.Calendar;

public abstract class BaseTransaction implements TransactionInterface {
/**
* Concrete class BaseTransaction representing a general financial transaction.
* Implements the TransactionInterface.
*/
public 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
* BaseTransaction Constructor.
* @param amount the transaction amount as an integer.
* @param date: Not null, and must be a Calendar object.
* Initializes the fields of a transaction and generates a unique ID.
*/
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;
// Correcting the precedence issue: (int) Math.random() is always 0.
// We cast to int after multiplying by 10000.
int uniq = (int) (Math.random() * 10000);
this.transactionID = date.toString() + uniq;
}

/**
* getAmount()
* @return integer
* @return the transaction amount as a double.
*/
@Override
public double getAmount() {
return amount; // Because we are dealing with Value types we need not worry about what we return
return amount; // Value type, safe to return directly
}

/**
* getDate()
* @return Calendar Object
* @return a defensive clone of the transaction date Calendar object.
*/
@Override
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(); // Defensive copying
}

/**
* getTransactionID()
* @return the unique transaction identifier.
*/
@Override
public String getTransactionID() {
return transactionID;
}

// Method to get a unique identifier for the transaction
public String getTransactionID(){
return transactionID;
/**
* Prints the details of the transaction.
*/
public void printTransactionDetails() {
System.out.println("--- Generic Transaction Details ---");
System.out.println("Transaction ID: " + getTransactionID());
System.out.println("Date: " + getDate().getTime());
System.out.println("Amount: $" + getAmount());
System.out.println("------------------------------------");
}

/**
* Applies the transaction on the BankAccount object.
* Declares that it can throw InsufficientFundsException.
* This generic implementation differs substantially from Deposit/Withdrawal subclasses.
* @param ba the BankAccount to apply the transaction to.
* @throws InsufficientFundsException if balance is insufficient (not thrown by this base class).
*/
public void apply(BankAccount ba) throws InsufficientFundsException {
System.out.println("Applying BaseTransaction: Generic transaction applied. No balance changes made.");
}
// Method to print a transaction receipt or details
public abstract void printTransactionDetails();
public abstract void apply(BankAccount ba);
}
58 changes: 58 additions & 0 deletions src/Lecture4_interfaces_abstract_classes/DepositTransaction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package Lecture4_interfaces_abstract_classes;

import org.jetbrains.annotations.NotNull;
import java.util.Calendar;

/**
* Concrete class DepositTransaction representing a deposit transaction.
* Inherits from BaseTransaction.
*/
public class DepositTransaction extends BaseTransaction {

/**
* DepositTransaction Constructor.
* @param amount the deposit amount.
* @param date the transaction date.
*/
public DepositTransaction(int amount, @NotNull Calendar date) {
super(amount, date);
}

/**
* Helper method to validate deposit amount.
* @param amt the amount to check.
* @return true if amount is positive, false otherwise.
*/
private boolean checkDepositAmount(int amt) {
return amt >= 0;
}

/**
* Prints the details of the deposit transaction.
*/
@Override
public void printTransactionDetails() {
System.out.println("--- Deposit Transaction Details ---");
System.out.println("Transaction ID: " + getTransactionID());
System.out.println("Date: " + getDate().getTime());
System.out.println("Amount: $" + getAmount());
System.out.println("------------------------------------");
}

/**
* Applies the deposit transaction by adding the amount to the bank account's balance.
* Overrides the apply method inherited from BaseTransaction.
* @param ba the BankAccount to deposit to.
*/
@Override
public void apply(BankAccount ba) {
if (!checkDepositAmount((int) getAmount())) {
System.out.println("Deposit failed: Invalid amount.");
return;
}
double curr_balance = ba.getBalance();
double new_balance = curr_balance + getAmount();
ba.setBalance(new_balance);
System.out.println("Deposited $" + getAmount() + " successfully. New balance: $" + new_balance);
}
}
30 changes: 0 additions & 30 deletions src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package Lecture4_interfaces_abstract_classes;

/**
* Custom Exception class representing insufficient funds for withdrawal transactions.
* Inherits from the standard Java Exception class.
*/
public class InsufficientFundsException extends Exception {

/**
* Constructor for InsufficientFundsException.
* @param message The detailed error message.
*/
public InsufficientFundsException(String message) {
super(message);
}
}
168 changes: 146 additions & 22 deletions src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java
Original file line number Diff line number Diff line change
@@ -1,45 +1,169 @@
package Lecture4_interfaces_abstract_classes;

import org.jetbrains.annotations.NotNull;

import java.util.Calendar;

/**
* Concrete class WithdrawalTransaction representing a withdrawal transaction.
* Inherits from BaseTransaction.
*/
public class WithdrawalTransaction extends BaseTransaction {
// State-tracking fields for reversal and partial withdrawals
private BankAccount appliedAccount = null;
private double withdrawnAmount = 0.0;
private boolean isApplied = false;
private boolean isReversed = false;
private double amountNotWithdrawn = 0.0;

/**
* WithdrawalTransaction Constructor.
* @param amount the withdrawal amount.
* @param date the transaction date.
*/
public WithdrawalTransaction(int amount, @NotNull Calendar date) {
super(amount, date);
}

/**
* Helper method to validate deposit/withdrawal amount check.
* @param amt the amount to check.
* @return true if amount is positive, false otherwise.
*/
private boolean checkDepositAmount(int amt) {
if (amt < 0) {
return false;
} else {
return true;
}
return amt >= 0;
}

// Method to reverse the transaction
public boolean reverse() {
return true;
} // return true if reversal was successful

// Method to print a transaction receipt or details
/**
* Prints the details of the withdrawal transaction.
*/
@Override
public void printTransactionDetails() {
System.out.println("Deposit Trasaction: " + this.toString());
System.out.println("--- Withdrawal Transaction Details ---");
System.out.println("Transaction ID: " + getTransactionID());
System.out.println("Date: " + getDate().getTime());
System.out.println("Amount: $" + getAmount());
System.out.println("Status: " + (isApplied ? (isReversed ? "Reversed" : "Applied") : "Not Applied"));
if (isApplied) {
System.out.println(" Actually Withdrawn: $" + withdrawnAmount);
}
if (amountNotWithdrawn > 0) {
System.out.println(" Amount Not Withdrawn (Unpaid): $" + amountNotWithdrawn);
}
System.out.println("---------------------------------------");
}

/*
Oportunity for assignment: implementing different form of withdrawal
/**
* Applies the withdrawal transaction on a BankAccount.
* Overrides the BaseTransaction apply method.
* @param ba the BankAccount to withdraw from.
* @throws InsufficientFundsException if the account balance is less than the withdrawal amount.
*/
public void apply(BankAccount ba) {
@Override
public void apply(BankAccount ba) throws InsufficientFundsException {
double curr_balance = ba.getBalance();
if (curr_balance > getAmount()) {
double new_balance = curr_balance - getAmount();
ba.setBalance(new_balance);
if (curr_balance < getAmount()) {
throw new InsufficientFundsException("Insufficient funds: Account balance is $" + curr_balance + ", but tried to withdraw $" + getAmount());
}
double new_balance = curr_balance - getAmount();
ba.setBalance(new_balance);

this.appliedAccount = ba;
this.withdrawnAmount = getAmount();
this.isApplied = true;
this.isReversed = false;
this.amountNotWithdrawn = 0.0;
System.out.println("Withdrew $" + getAmount() + " successfully. New balance: $" + new_balance);
}

/*
Assignment 1 Q3: Write the Reverse method - a method unique to the WithdrawalTransaction Class
/**
* Overloaded apply method that handles partial withdrawal.
* If partial is true, and the balance is insufficient but > 0, it withdraws all remaining balance.
* Uses try-catch-finally block to handle InsufficientFundsException.
* @param ba the BankAccount to withdraw from.
* @param partial true to allow partial withdrawal of remaining balance.
*/
}
public void apply(BankAccount ba, boolean partial) {
if (partial) {
try {
// Attempt standard withdrawal
apply(ba);
} catch (InsufficientFundsException e) {
System.out.println("Standard withdrawal failed during partial attempt: " + e.getMessage());
double currentBalance = ba.getBalance();
// Check if 0 < balance < withdrawal amount
if (currentBalance > 0 && currentBalance < getAmount()) {
double originalBalance = currentBalance;
ba.setBalance(0.0);

this.appliedAccount = ba;
this.withdrawnAmount = originalBalance;
this.isApplied = true;
this.isReversed = false;
this.amountNotWithdrawn = getAmount() - originalBalance;

System.out.println("Partial withdrawal applied. Withdrew remaining balance of $" + originalBalance +
". Amount not withdrawn: $" + amountNotWithdrawn);
} else {
System.out.println("Partial withdrawal failed: Account balance is $" + currentBalance +
". Cannot perform withdrawal of $" + getAmount());
}
} finally {
System.out.println("Finished partial withdrawal execution. Current account balance: $" + ba.getBalance());
}
} else {
try {
apply(ba);
} catch (InsufficientFundsException e) {
System.out.println("Standard withdrawal failed: " + e.getMessage());
} finally {
System.out.println("Finished standard withdrawal execution. Current account balance: $" + ba.getBalance());
}
}
}

/**
* Reverses the withdrawal transaction.
* Restores the balance of the BankAccount it was applied to to its original amount.
* @return true if reversal was successful, false otherwise.
*/
public boolean reverse() {
if (!isApplied) {
System.out.println("Reversal failed: Transaction was not successfully applied.");
return false;
}
if (isReversed) {
System.out.println("Reversal failed: Transaction has already been reversed.");
return false;
}
if (appliedAccount == null) {
System.out.println("Reversal failed: No associated bank account found.");
return false;
}
double currentBalance = appliedAccount.getBalance();
appliedAccount.setBalance(currentBalance + withdrawnAmount);
isReversed = true;
System.out.println("Withdrawal transaction reversed successfully. Restored $" + withdrawnAmount + " to the account.");
return true;
}

// Getters for status monitoring
public BankAccount getAppliedAccount() {
return appliedAccount;
}

public double getWithdrawnAmount() {
return withdrawnAmount;
}

public boolean isApplied() {
return isApplied;
}

public boolean isReversed() {
return isReversed;
}

public double getAmountNotWithdrawn() {
return amountNotWithdrawn;
}
}
Loading