-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExercise8.java
More file actions
195 lines (160 loc) · 7.61 KB
/
Copy pathExercise8.java
File metadata and controls
195 lines (160 loc) · 7.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package chapter8;
import java.util.Scanner;
/**
* ============================================================
* EXERCISE 8 — Secure ATM & Payment Gateway Simulation 🏧
* ============================================================
*
* Build an enterprise-grade ATM simulator that uses robust
* Exception Handling to model real-world financial failure states:
*
* Custom Exception Classes:
* 1. `InvalidPinException` -> Wrong PIN entered (after 3 attempts: Account Locked)
* 2. `InsufficientFundsException` -> Requested amount exceeds balance (includes deficit info)
* 3. `AccountFrozenException` -> Transactions attempted on locked/suspended accounts
* 4. `DailyLimitExceededException` -> Exceeding daily withdrawal limit ($1,000)
*
* Features:
* - AutoCloseable `AtmSession` resource for session initialization & secure logout
* - Detailed transaction receipts and graceful recovery loops
* ============================================================
*/
// Custom Checked Exceptions
class InvalidPinException extends Exception {
private int remainingAttempts;
public InvalidPinException(String message, int remainingAttempts) {
super(message);
this.remainingAttempts = remainingAttempts;
}
public int getRemainingAttempts() { return remainingAttempts; }
}
class InsufficientFundsException extends Exception {
private double currentBalance;
private double requestedAmount;
public InsufficientFundsException(double currentBalance, double requestedAmount) {
super(String.format("Deficit of $%.2f. Available: $%.2f | Requested: $%.2f",
(requestedAmount - currentBalance), currentBalance, requestedAmount));
this.currentBalance = currentBalance;
this.requestedAmount = requestedAmount;
}
public double getDeficit() { return requestedAmount - currentBalance; }
}
class AccountFrozenException extends Exception {
public AccountFrozenException(String message) {
super(message);
}
}
class DailyLimitExceededException extends Exception {
private double dailyLimit;
public DailyLimitExceededException(double dailyLimit, double requestedAmount) {
super(String.format("Request $%.2f exceeds daily max limit of $%.2f", requestedAmount, dailyLimit));
this.dailyLimit = dailyLimit;
}
}
// AutoCloseable Session Wrapper
class AtmSession implements AutoCloseable {
private String cardNumber;
private boolean authenticated;
public AtmSession(String cardNumber) {
this.cardNumber = cardNumber;
this.authenticated = false;
System.out.println(" 💳 [ATM Hardware] Card inserted: " + cardNumber);
}
public void setAuthenticated(boolean auth) { this.authenticated = auth; }
public boolean isAuthenticated() { return authenticated; }
@Override
public void close() {
System.out.println(" ⏏️ [ATM Hardware] Ejecting card " + cardNumber + "... Session Terminated securely.");
}
}
// ATM Account Model
class BankCardAccount {
public static final double DAILY_LIMIT = 1000.00;
private String cardNumber;
private String correctPin;
private double balance;
private boolean frozen;
private int failedAttempts;
private double dailyWithdrawn;
public BankCardAccount(String cardNumber, String correctPin, double balance) {
this.cardNumber = cardNumber;
this.correctPin = correctPin;
this.balance = balance;
this.frozen = false;
this.failedAttempts = 0;
this.dailyWithdrawn = 0;
}
public void authenticate(String pin) throws InvalidPinException, AccountFrozenException {
if (frozen) {
throw new AccountFrozenException("Account is LOCKED due to excessive failed attempts or fraud alerts.");
}
if (!this.correctPin.equals(pin)) {
failedAttempts++;
int remaining = 3 - failedAttempts;
if (remaining <= 0) {
this.frozen = true;
throw new AccountFrozenException("3 consecutive failed PIN attempts. Card has been seized and frozen.");
}
throw new InvalidPinException("Incorrect PIN entered!", remaining);
}
failedAttempts = 0; // reset on success
System.out.println(" ✓ PIN verified successfully!");
}
public void withdraw(double amount)
throws InsufficientFundsException, AccountFrozenException, DailyLimitExceededException {
if (frozen) {
throw new AccountFrozenException("Cannot withdraw: Account is currently frozen.");
}
if (amount <= 0) {
throw new IllegalArgumentException("Withdrawal amount must be strictly positive.");
}
if (dailyWithdrawn + amount > DAILY_LIMIT) {
throw new DailyLimitExceededException(DAILY_LIMIT, dailyWithdrawn + amount);
}
if (amount > balance) {
throw new InsufficientFundsException(balance, amount);
}
balance -= amount;
dailyWithdrawn += amount;
System.out.printf(" 💵 Dispensing $%.2f... New Balance: $%.2f (Daily used: $%.2f/%.2f)%n",
amount, balance, dailyWithdrawn, DAILY_LIMIT);
}
public double getBalance() { return balance; }
}
public class Exercise8 {
public static void main(String[] args) {
System.out.println("╔══════════════════════════════════════════════════╗");
System.out.println("║ 🏧 SECURE ATM SIMULATOR ║");
System.out.println("╚══════════════════════════════════════════════════╝");
BankCardAccount account = new BankCardAccount("4111-9988-7766-5544", "4321", 850.00);
// Session 1: Test wrong PIN and Recovery
System.out.println("\n--- SCENARIO 1: WRONG PIN ATTEMPTS ---");
try (AtmSession session = new AtmSession("4111-9988-7766-5544")) {
account.authenticate("1111"); // Invalid
} catch (InvalidPinException e) {
System.out.println(" ❌ Auth Failed: " + e.getMessage());
System.out.println(" Remaining attempts before lock: " + e.getRemainingAttempts());
} catch (AccountFrozenException e) {
System.out.println(" ❌ Security Lock: " + e.getMessage());
}
// Session 2: Test Successful Auth + Overdraw Attempt + Daily Limit
System.out.println("\n--- SCENARIO 2: SUCCESSFUL LOGIN & TRANSACTION TRAPS ---");
try (AtmSession session = new AtmSession("4111-9988-7766-5544")) {
account.authenticate("4321"); // Correct PIN
session.setAuthenticated(true);
System.out.println("\nAttempting $200 withdrawal:");
account.withdraw(200.00); // Valid
System.out.println("\nAttempting $1,500 withdrawal (Exceeds Balance):");
account.withdraw(1500.00); // Will trigger InsufficientFundsException
} catch (InvalidPinException | AccountFrozenException e) {
System.out.println(" ❌ Auth Error: " + e.getMessage());
} catch (InsufficientFundsException e) {
System.out.println(" ❌ Transaction Denied: " + e.getMessage());
System.out.printf(" Shortfall amount: $%.2f%n", e.getDeficit());
} catch (DailyLimitExceededException e) {
System.out.println(" ❌ Limit Error: " + e.getMessage());
} catch (Exception e) {
System.out.println(" ❌ Unexpected System Failure: " + e);
}
}
}