Building an object-oreinted management application requires a clear separaiton between data persistence, business rules, and user interface logic. This implementation demonstrates a console-based authentication layer integrated with a core CRUD system, emphasizing validasion constraints and state management.
Architectural Components
The solution revolves around four primary entities:
- ApplicationEntrance: Entry point handling session routing and menu dispatch.
- AuthSubsystem: Manages account lifecycle including registration, credential verification, and recovery workflows.
- DataValidator: Enforces strict formatting rules for identifiers, contact information, and credentials.
- CoreModule: Executes the actual student data manipulation once access is granted.
Registration Workflow Constraints
Account creation triggers a multi-stage validation pipeline:
- Alias: Length between 3 and 15 characters. Must contain alphanumeric characters. Pure numeric strings are rejected. Uniqueness is enforced against the existing registry.
- Secret: Requires dual-entry confirmation to prevent typing errors.
- National ID: Exactly 18 digits. Cannot start with zero. Positions 0-16 must be numeric. Position 17 accepts digits or 'X'/'x'.
- Contact Number: Exactly 11 digits. Leading zero is invalid. Strictly numeric.
Authentication & Recovery Mechanics
Access is gated behind a secure checkpoint. After providing credentials, users must solve a generated CAPTCHA (4 random letters + 1 digit, shuffled positions). Failed authentications increment a retry counter, triggering a temporary blockout after three unsuccessful attempts. Password recovery cross-references the registered ID number and mobile number. Successful verification grants permission to overwrite the stored credential.
Implementation Details
The following code consolidates the architecture into a cohesive, executable unit. Structural improvements include isolated validation utilities, centralized input handling, and explicit state transitions.
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
public class ApplicationEntrance {
private static final Scanner INPUT = new Scanner(System.in);
private static final ArrayList<RegisteredUser> ACCOUNTS = new ArrayList<>();
public static void main(String[] args) {
while (true) {
System.out.println("Welcome to the Academic Portal");
System.out.println("Select action: 1. Login | 2. Register | 3. Recover Access");
String selection = INPUT.next().trim();
switch (selection) {
case "1" -> performLogin();
case "2" -> processRegistration();
case "3" -> handleRecovery();
case "4" -> { System.out.println("Session terminated."); System.exit(0); }
default -> System.out.println("Invalid selection.");
}
}
}
private static void processRegistration() {
String alias, secret, nationalId, contactNum;
// Alias validation loop
do {
System.out.print("Enter username: ");
alias = INPUT.next();
} while (!isAliasValid(alias) || isAliasTaken(alias));
System.out.println("Username available!");
// Secret confirmation loop
do {
System.out.print("Create password: ");
secret = INPUT.next();
System.out.print("Confirm password: ");
} while (!INPUT.next().equals(secret));
System.out.println("Credentials matched.");
// Identity validation loop
do {
System.out.print("Enter National ID: ");
nationalId = INPUT.next();
} while (!DataValidator.validateIdentity(nationalId));
System.out.println("ID format verified.");
// Contact validation loop
do {
System.out.print("Enter phone number: ");
contactNum = INPUT.next();
} while (!DataValidator.validatePhone(contactNum));
System.out.println("Phone format verified.");
RegisteredUser newUser = new RegisteredUser(alias, secret, nationalId, contactNum);
ACCOUNTS.add(newUser);
System.out.println("Registration complete.");
printRegistry();
}
private static void performLogin() {
int attempts = 0;
while (attempts < 3) {
System.out.print("Enter username: ");
String submittedUser = INPUT.next();
if (!isAliasTaken(submittedUser)) {
System.out.println("Account not found. Please register first.");
return;
}
System.out.print("Enter password: ");
String submittedPass = INPUT.next();
while (true) {
String captchaCode = generateCaptcha();
System.out.println("CAPTCHA: " + captchaCode);
System.out.print("Input CAPTCHA: ");
String userInputCode = INPUT.next();
if (userInputCode.equalsIgnoreCase(captchaCode)) break;
System.out.println("Incorrect CAPTCHA. Retry.");
}
RegisteredUser target = findAccount(submittedUser);
if (target != null && target.getSecret().equals(submittedPass)) {
System.out.println("Authentication successful. Entering portal...");
CoreModule.startAcademicSession();
return;
}
System.out.println("Invalid credentials. Remaining attempts: " + (2 - attempts));
attempts++;
}
System.out.println("Account locked due to excessive failures. Contact support.");
}
private static void handleRecovery() {
System.out.print("Enter username: ");
String requestedUser = INPUT.next();
RegisteredUser target = findAccount(requestedUser);
if (target == null) {
System.out.println("Account does not exist.");
return;
}
System.out.print("Enter National ID: ");
String providedId = INPUT.next();
System.out.print("Enter Phone Number: ");
String providedPhone = INPUT.next();
if (!providedId.equalsIgnoreCase(target.getId()) || !providedPhone.equals(target.getPhone())) {
System.out.println("Verification failed. Information mismatch.");
return;
}
System.out.print("New password: ");
String newPass = INPUT.next();
System.out.print("Confirm new password: ");
if (INPUT.next().equals(newPass)) {
target.setSecret(newPass);
System.out.println("Password updated successfully.");
} else {
System.out.println("Mismatch detected. Update cancelled.");
}
}
private static String generateCaptcha() {
char[] letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
Random rng = new Random();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 4; i++) {
builder.append(letters[rng.nextInt(letters.length)]);
}
builder.append(rng.nextInt(10));
char[] chars = builder.toString().toCharArray();
int swapIdx = rng.nextInt(chars.length);
char temp = chars[chars.length - 1];
chars[chars.length - 1] = chars[swapIdx];
chars[swapIdx] = temp;
return new String(chars);
}
private static boolean isAliasValid(String alias) {
int len = alias.length();
if (len < 3 || len > 15) return false;
for (char c : alias.toCharArray()) {
if (!Character.isLetterOrDigit(c)) return false;
}
long digitCount = alias.chars().filter(Character::isDigit).count();
return digitCount < alias.length(); // Rejects pure numbers
}
private static boolean isAliasTaken(String alias) {
return findAccount(alias) != null;
}
private static RegisteredUser findAccount(String alias) {
for (RegisteredUser acc : ACCOUNTS) {
if (acc.getAlias().equals(alias)) return acc;
}
return null;
}
private static void printRegistry() {
for (RegisteredUser acc : ACCOUNTS) {
System.out.printf("%s, %s, %s, %s%n", acc.getAlias(), acc.getSecret(), acc.getId(), acc.getPhone());
}
}
}
// ==========================================
// SUPPORTING CLASSES
// ==========================================
class DataValidator {
public static boolean validateIdentity(String id) {
if (id.length() != 18 || id.startsWith("0")) return false;
for (int i = 0; i < 17; i++) {
if (!Character.isDigit(id.charAt(i))) return false;
}
char last = id.charAt(17);
return Character.isDigit(last) || last == 'X' || last == 'x';
}
public static boolean validatePhone(String num) {
if (num.length() != 11 || num.startsWith("0")) return false;
for (char c : num.toCharArray()) {
if (!Character.isDigit(c)) return false;
}
return true;
}
}
class RegisteredUser {
private String alias;
private String secret;
private String id;
private String phone;
public RegisteredUser(String alias, String secret, String id, String phone) {
this.alias = alias;
this.secret = secret;
this.id = id;
this.phone = phone;
}
public String getAlias() { return alias; }
public String getSecret() { return secret; }
public void setSecret(String secret) { this.secret = secret; }
public String getId() { return id; }
public String getPhone() { return phone; }
}
class CoreModule {
private static final ArrayList<EnrolledStudent> STUDENTS = new ArrayList<>();
private static final Scanner SCAN = new Scanner(System.in);
public static void startAcademicSession() {
label: while (true) {
System.out.println("\n--- ACADEMIC DASHBOARD ---");
System.out.println("1. Add | 2. Remove | 3. Update | 4. List | 5. Exit");
String cmd = SCAN.next().trim();
switch (cmd) {
case "1" -> addStudent();
case "2" -> removeStudent();
case "3" -> updateStudent();
case "4" -> listStudents();
case "5" -> break label;
default -> System.out.println("Unknown command.");
}
}
}
private static void addStudent() {
String id;
do {
System.out.print("Enter Student ID: ");
id = SCAN.next();
} while (findStudentIndex(id) != -1);
System.out.print("Name: "); String name = SCAN.next();
System.out.print("Age: "); int age = SCAN.nextInt();
System.out.print("Location: "); String loc = SCAN.next();
STUDENTS.add(new EnrolledStudent(id, name, age, loc));
System.out.println("Added successfully.");
}
private static void removeStudent() {
System.out.print("ID to delete: ");
String id = SCAN.next();
int idx = findStudentIndex(id);
if (idx >= 0) {
STUDENTS.remove(idx);
System.out.println("Removed.");
} else System.out.println("Not found.");
}
private static void updateStudent() {
System.out.print("ID to modify: ");
String id = SCAN.next();
int idx = findStudentIndex(id);
if (idx == -1) { System.out.println("Record missing."); return; }
EnrolledStudent s = STUDENTS.get(idx);
System.out.print("New Name: "); s.setName(SCAN.next());
System.out.print("New Age: "); s.setAge(SCAN.nextInt());
System.out.print("New Location: "); s.setLocation(SCAN.next());
System.out.println("Updated.");
}
private static void listStudents() {
if (STUDENTS.isEmpty()) { System.out.println("No records."); return; }
System.out.printf("%-10s %-15s %-5s %s%n", "ID", "Name", "Age", "Location");
for (EnrolledStudent s : STUDENTS) System.out.printf("%-10s %-15s %-5d %s%n", s.getId(), s.getName(), s.getAge(), s.getLocation());
}
private static int findStudentIndex(String id) {
for (int i = 0; i < STUDENTS.size(); i++) {
if (STUDENTS.get(i).getId().equals(id)) return i;
}
return -1;
}
}
class EnrolledStudent {
private String id;
private String name;
private int age;
private String location;
public EnrolledStudent(String id, String name, int age, String location) {
this.id = id; this.name = name; this.age = age; this.location = location;
}
public String getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getLocation() { return location; }
public void setLocation(String location) { this.location = location; }
}
Expected Execution Flow
Welcome to the Academic Portal
Select action: 1. Login | 2. Register | 3. Recover Access
2
Enter username: zhangsan
Username available!
Enter Create password: zs123456
Confirm password: zs123456
Credentials matched.
Enter National ID: 342423202407150001
ID format verified.
Enter Phone Number: 12345678912
Phone format verified.
Registration complete.
zhangsan, zs123456, 342423202407150001, 12345678912
Welcome to the Academic Portal
Select action: 1. Login | 2. Register | 3. Recover Access
1
Enter username: zhangsan
Enter password: zs123456
CAPTCHA: ct0bS
Input CAPTCHA: ct0bs
Authentication successful. Entering portal...
--- ACADEMIC DASHBOARD ---
1. Add | 2. Remove | 3. Update | 4. List | 5. Exit
5
Welcome to the Academic Portal
Select action: 1. Login | 2. Register | 3. Recover Access
3
Enter username: zhangsan
Enter National ID: 342423202407150001
Enter Phone Number: 12345678912
New password: zs1234567
Confirm new password: zs1234567
Password updated successfully.