diff --git a/P2PLendingSystem/Borrower.java b/P2PLendingSystem/Borrower.java new file mode 100644 index 00000000..b0e54c97 --- /dev/null +++ b/P2PLendingSystem/Borrower.java @@ -0,0 +1,78 @@ +package dsa_modules; + +public class Borrower { + private int id; + private String name; + private int creditScore; + private int requestedAmount; + private double requestedRate; + public Borrower left, right; + + /** + * Full constructor including all fields. + */ + public Borrower(int id, String name, int creditScore, int requestedAmount, double requestedRate) { + this.id = id; + this.name = name; + this.creditScore = creditScore; + this.requestedAmount = requestedAmount; + this.requestedRate = requestedRate; + this.left = null; + this.right = null; + } + + /** + * Constructor for DAO usage when only id, name, and creditScore are known. + * requestedAmount and requestedRate default to 0. + */ + public Borrower(int id, String name, int creditScore) { + this(id, name, creditScore, 0, 0.0); + } + + /** + * Constructor for in-memory creation before DB assignment of ID. + */ + public Borrower(String name, int creditScore, int requestedAmount, double requestedRate) { + this(0, name, creditScore, requestedAmount, requestedRate); + } + + // ID getter/setter + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } + + // Name getter/setter + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + // Credit score getter/setter + public int getCreditScore() { + return creditScore; + } + public void setCreditScore(int creditScore) { + this.creditScore = creditScore; + } + + // Requested amount getter/setter + public int getRequestedAmount() { + return requestedAmount; + } + public void setRequestedAmount(int requestedAmount) { + this.requestedAmount = requestedAmount; + } + + // Requested rate getter/setter + public double getRequestedRate() { + return requestedRate; + } + public void setRequestedRate(double requestedRate) { + this.requestedRate = requestedRate; + } +} diff --git a/P2PLendingSystem/BorrowerDAO.java b/P2PLendingSystem/BorrowerDAO.java new file mode 100644 index 00000000..acf7632e --- /dev/null +++ b/P2PLendingSystem/BorrowerDAO.java @@ -0,0 +1,188 @@ +package dao; + +import db.DatabaseUtil; +import dsa_modules.Borrower; +import java.util.Map; +import java.util.HashMap; +import java.sql.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class BorrowerDAO { + + private Connection conn; + + // Constructor + public BorrowerDAO(Connection connection) { + this.conn = connection; + try { + conn.setAutoCommit(true); + } catch (SQLException e) { + System.err.println("Failed to set auto-commit: " + e.getMessage()); + } + } + + // Save borrower (default status = 'active') + public void saveBorrower(Borrower b) { + String sql = "INSERT INTO borrowers (name, credit_score, requested_amount, requested_rate, status) VALUES (?, ?, ?, ?, ?)"; + try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { + stmt.setString(1, b.getName()); + stmt.setInt(2, b.getCreditScore()); + stmt.setInt(3, b.getRequestedAmount()); + stmt.setDouble(4, b.getRequestedRate()); + stmt.setString(5, "active"); // default status + + stmt.executeUpdate(); + + try (ResultSet rs = stmt.getGeneratedKeys()) { + if (rs.next()) { + int generatedId = rs.getInt(1); + b.setId(generatedId); + } + } + } catch (SQLException e) { + System.err.println("Error saving borrower: " + e.getMessage()); + } + } + + // Retrieve borrower by ID + public Borrower getBorrowerById(int id) { + String sql = "SELECT * FROM borrowers WHERE borrower_id = ?"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setInt(1, id); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + return new Borrower( + rs.getInt("borrower_id"), + rs.getString("name"), + rs.getInt("credit_score"), + rs.getInt("requested_amount"), + rs.getDouble("requested_rate") + ); + } + } + } catch (SQLException e) { + System.err.println("Error retrieving borrower: " + e.getMessage()); + } + return null; + } + + // ✅ Retrieve borrower by name + public Borrower getBorrowerByName(String name) { + String sql = "SELECT * FROM borrowers WHERE name = ?"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, name); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + return new Borrower( + rs.getInt("borrower_id"), + rs.getString("name"), + rs.getInt("credit_score"), + rs.getInt("requested_amount"), + rs.getDouble("requested_rate") + ); + } + } + } catch (SQLException e) { + System.err.println("Error retrieving borrower by name: " + e.getMessage()); + } + return null; + } + + // Get borrower status by ID + public String getBorrowerStatusById(int borrowerId) { + String sql = "SELECT status FROM borrowers WHERE borrower_id = ?"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setInt(1, borrowerId); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + String status = rs.getString("status"); + return status != null ? status.trim().toLowerCase() : "active"; + } + } + } catch (SQLException e) { + System.err.println("Error getting borrower status: " + e.getMessage()); + } + return "active"; + } + + // Update borrower status + public void updateBorrowerStatus(int borrowerId, String status) { + String sql = "UPDATE borrowers SET status = ? WHERE borrower_id = ?"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, status); + stmt.setInt(2, borrowerId); + stmt.executeUpdate(); + } catch (SQLException e) { + System.err.println("Error updating borrower status: " + e.getMessage()); + } + } + + // Get all active borrowers sorted by credit score (descending) + public List getAllBorrowersSortedByCreditScore() { + List borrowers = new ArrayList<>(); + String sql = "SELECT * FROM borrowers WHERE status = 'active'"; + try (Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql)) { + + while (rs.next()) { + Borrower b = new Borrower( + rs.getInt("borrower_id"), + rs.getString("name"), + rs.getInt("credit_score"), + rs.getInt("requested_amount"), + rs.getDouble("requested_rate") + ); + borrowers.add(b); + } + + } catch (SQLException e) { + System.err.println("Error retrieving borrowers: " + e.getMessage()); + } + + borrowers.sort(Comparator.comparingInt(Borrower::getCreditScore).reversed()); + return borrowers; + } + + // Update requested amount and rate + public void updateRequestedDetails(int borrowerId, int amount, double rate) throws SQLException { + String sql = "UPDATE borrowers SET requested_amount = ?, requested_rate = ? WHERE borrower_id = ?"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setInt(1, amount); + stmt.setDouble(2, rate); + stmt.setInt(3, borrowerId); + stmt.executeUpdate(); + } + } + + // Load all active borrowers into a map (key = borrower name) + public Map loadAllBorrowersIntoMap() { + Map borrowerMap = new HashMap<>(); + String sql = "SELECT * FROM borrowers WHERE status = 'active'"; + try (Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql)) { + + while (rs.next()) { + Borrower b = new Borrower( + rs.getInt("borrower_id"), + rs.getString("name"), + rs.getInt("credit_score"), + rs.getInt("requested_amount"), + rs.getDouble("requested_rate") + ); + borrowerMap.put(b.getName(), b); + } + + } catch (SQLException e) { + System.err.println("Error loading borrowers into map: " + e.getMessage()); + } + + return borrowerMap; + } + +} + + + + diff --git a/P2PLendingSystem/CreditScoreBST.java b/P2PLendingSystem/CreditScoreBST.java new file mode 100644 index 00000000..a77d8419 --- /dev/null +++ b/P2PLendingSystem/CreditScoreBST.java @@ -0,0 +1,90 @@ +package dsa_modules; + +import dao.BorrowerDAO; +import dao.LenderDAO; +import java.util.ArrayList; +import java.util.List; + +public class CreditScoreBST { + public Borrower root; + private BorrowerDAO borrowerDAO; + + // Default constructor (no DB usage) + public CreditScoreBST() { + this.borrowerDAO = null; + } + + // Constructor for DB-enabled version + public CreditScoreBST(BorrowerDAO borrowerDAO) { + this.borrowerDAO = borrowerDAO; + } + + public void insert(Borrower b) { + root = insertRec(root, b); + System.out.println("📌 Inserted Borrower: " + b.getName() + " | Credit Score: " + b.getCreditScore() + + " | Requested Amount: " + b.getRequestedAmount() + " | Requested Rate: " + b.getRequestedRate()); + + if (borrowerDAO != null) { + borrowerDAO.saveBorrower(b); // Save to DB if DAO is provided + } + } + + private Borrower insertRec(Borrower root, Borrower b) { + if (root == null) return b; + if (b.getCreditScore() < root.getCreditScore()) { + root.left = insertRec(root.left, b); + } else { + root.right = insertRec(root.right, b); + } + return root; + } + + // In-order print (optional) + public void inorder(Borrower root) { + if (root != null) { + inorder(root.left); + System.out.println(root.getName() + ": " + root.getCreditScore()); + inorder(root.right); + } + } + + public List getSortedBorrowers() { + List list = new ArrayList<>(); + inorderHelper(root, list); + return list; + } + + private void inorderHelper(Borrower node, List list) { + if (node != null) { + inorderHelper(node.left, list); + list.add(node); + inorderHelper(node.right, list); + } + } + + // 🔄 Matching logic: true if lender can support borrower's request + public static boolean isMatch(Lender lender, Borrower borrower) { + return lender.getMaxAmount() >= borrower.getRequestedAmount() && + borrower.getRequestedRate() >= lender.getPreferredRate(); + } + + // 🔍 Match all borrowers in BST against a list of lenders + public void matchLenders(List lenders) { + List borrowers = getSortedBorrowers(); + + for (Borrower borrower : borrowers) { + boolean foundMatch = false; + for (Lender lender : lenders) { + if (isMatch(lender, borrower)) { + System.out.println("✅ Match Found: Borrower " + borrower.getName() + + " ↔ Lender " + lender.getName()); + foundMatch = true; + break; + } + } + if (!foundMatch) { + System.out.println("❌ No match for Borrower: " + borrower.getName()); + } + } + } +} diff --git a/P2PLendingSystem/FraudDAO.java b/P2PLendingSystem/FraudDAO.java new file mode 100644 index 00000000..dfd095f0 --- /dev/null +++ b/P2PLendingSystem/FraudDAO.java @@ -0,0 +1,58 @@ +package dao; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class FraudDAO { + private Connection connection; + + public FraudDAO(Connection connection) { + this.connection = connection; + } + + // Original method + public void addToFraudList(String borrowerName) throws SQLException { + String query = "INSERT INTO fraud_list (name) VALUES (?)"; + try (PreparedStatement statement = connection.prepareStatement(query)) { + statement.setString(1, borrowerName); + statement.executeUpdate(); + } + } + + // ✅ Wrapper method that you can call from other parts of your code + public void addFraudulentName(String borrowerName) { + try { + addToFraudList(borrowerName); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + // Check if a user is in the fraud list + public boolean isFraud(String borrowerName) throws SQLException { + String query = "SELECT COUNT(*) FROM fraud_list WHERE name = ?"; + PreparedStatement statement = connection.prepareStatement(query); + statement.setString(1, borrowerName); + ResultSet rs = statement.executeQuery(); + if (rs.next()) { + return rs.getInt(1) > 0; + } + return false; + } + + // Optional: Retrieve all fraud names (used in FraudDetector.loadFromDatabase) + public List getAllFraudulentNames() { + List names = new ArrayList<>(); + String query = "SELECT name FROM fraud_list"; + try (PreparedStatement stmt = connection.prepareStatement(query); + ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + names.add(rs.getString("name")); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return names; + } +} diff --git a/P2PLendingSystem/FraudDetector.java b/P2PLendingSystem/FraudDetector.java new file mode 100644 index 00000000..c3eaf14c --- /dev/null +++ b/P2PLendingSystem/FraudDetector.java @@ -0,0 +1,67 @@ +package dsa_modules; + +import dao.FraudDAO; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FraudDetector { + static class TrieNode { + Map children = new HashMap<>(); + boolean isEndOfWord; + } + + private TrieNode root = new TrieNode(); + private FraudDAO fraudDAO; + + // Constructor with DAO + public FraudDetector(FraudDAO fraudDAO) { + this.fraudDAO = fraudDAO; + loadFromDatabase(); // Populate trie with existing fraud names + } + + // Constructor without DAO (for testing / offline) + public FraudDetector() {} + + public void insert(String word) { + TrieNode current = root; + for (char c : word.toCharArray()) { + current = current.children.computeIfAbsent(c, k -> new TrieNode()); + } + current.isEndOfWord = true; + + if (fraudDAO != null) { + fraudDAO.addFraudulentName(word); + } + } + + public boolean search(String word) { + TrieNode current = root; + for (char c : word.toCharArray()) { + current = current.children.get(c); + if (current == null) return false; + } + return current.isEndOfWord; + } + + // Load fraud names from DB into Trie + private void loadFromDatabase() { + if (fraudDAO != null) { + List names = fraudDAO.getAllFraudulentNames(); + for (String name : names) { + insertWithoutSaving(name); // Avoid re-saving to DB + } + } + } + + // Helper to insert into Trie without saving to DB + private void insertWithoutSaving(String word) { + TrieNode current = root; + for (char c : word.toCharArray()) { + current = current.children.computeIfAbsent(c, k -> new TrieNode()); + } + current.isEndOfWord = true; + } +} + diff --git a/P2PLendingSystem/Graph.java b/P2PLendingSystem/Graph.java new file mode 100644 index 00000000..fc1c0ad5 --- /dev/null +++ b/P2PLendingSystem/Graph.java @@ -0,0 +1,62 @@ +package dsa_modules; + +import java.util.*; + +public class Graph { + private Map> adjList = new HashMap<>(); + + // Add a lender-borrower match to the graph + public void addMatch(int lenderId, Match match) { + adjList.putIfAbsent(lenderId, new ArrayList<>()); + adjList.get(lenderId).add(match); + } + + // Add a borrower node (to ensure borrower is known in the system) + public void addBorrower(int borrowerId) { + adjList.putIfAbsent(borrowerId, new ArrayList<>()); + } + + // Add a lender node (to ensure lender is known in the system) + public void addLender(int lenderId) { + adjList.putIfAbsent(lenderId, new ArrayList<>()); + } + + // Get all matches from the entire graph (useful for matching logic) + public List getMatches(int dummy) { + List allMatches = new ArrayList<>(); + for (List matches : adjList.values()) { + allMatches.addAll(matches); + } + return allMatches; + } + + // Remove all matches involving borrowers in the provided list + public void removeBorrowers(List borrowersToRemove) { + Set borrowerIds = new HashSet<>(); + for (Borrower b : borrowersToRemove) { + borrowerIds.add(b.getId()); + } + + for (List matches : adjList.values()) { + matches.removeIf(m -> borrowerIds.contains(m.getBorrowerId())); // Use getter for borrowerId + } + } + + // Remove all matches involving lenders in the provided list + public void removeLenders(List lendersToRemove) { + Set lenderIds = new HashSet<>(); + for (Lender l : lendersToRemove) { + lenderIds.add(l.getId()); + } + + // Remove lender entries entirely + for (Integer id : lenderIds) { + adjList.remove(id); + } + + // Also remove matches referencing these lenders from other entries + for (List matches : adjList.values()) { + matches.removeIf(m -> lenderIds.contains(m.getLenderId())); // Use getter for lenderId + } + } +} diff --git a/P2PLendingSystem/InterestRateManager.java b/P2PLendingSystem/InterestRateManager.java new file mode 100644 index 00000000..717469d0 --- /dev/null +++ b/P2PLendingSystem/InterestRateManager.java @@ -0,0 +1,26 @@ +package dsa_modules; + +import java.util.Collections; +import java.util.PriorityQueue; + +//2. Heap for Interest Rate Adjustment +public class InterestRateManager { +PriorityQueue borrowerHeap = new PriorityQueue<>(Collections.reverseOrder()); // Max-Heap +PriorityQueue lenderHeap = new PriorityQueue<>(); // Min-Heap + +public void addBorrowerRate(double rate) { + borrowerHeap.offer(rate); +} + +void addLenderRate(double rate) { + lenderHeap.offer(rate); +} + +double getMaxBorrowerRate() { + return borrowerHeap.peek(); +} + +double getMinLenderRate() { + return lenderHeap.peek(); +} +} diff --git a/P2PLendingSystem/Lender.java b/P2PLendingSystem/Lender.java new file mode 100644 index 00000000..fbc2c2ef --- /dev/null +++ b/P2PLendingSystem/Lender.java @@ -0,0 +1,50 @@ +package dsa_modules; + +public class Lender { + private int id; + private String name; + private int preferredRate; // Changed from double to int + private int maxAmount; // Changed from double to int + + public Lender(int id, String name, int preferredRate, int maxAmount) { + this.id = id; + this.name = name; + this.preferredRate = preferredRate; + this.maxAmount = maxAmount; + } + + // Getters + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public int getPreferredRate() { + return preferredRate; // Returns int + } + + public int getMaxAmount() { + return maxAmount; // Returns int + } + + // Setters (if needed) + public void setName(String name) { + this.name = name; + } + + public void setPreferredRate(int preferredRate) { + this.preferredRate = preferredRate; // Accepts int + } + + public void setMaxAmount(int maxAmount) { + this.maxAmount = maxAmount; // Accepts int + } + + // Add setId method for auto-generated id from the database + public void setId(int id) { + this.id = id; + } +} diff --git a/P2PLendingSystem/LenderDAO.java b/P2PLendingSystem/LenderDAO.java new file mode 100644 index 00000000..6535972b --- /dev/null +++ b/P2PLendingSystem/LenderDAO.java @@ -0,0 +1,72 @@ +package dao; + +import dsa_modules.Lender; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class LenderDAO { + private Connection conn; + + public LenderDAO(Connection conn) { + this.conn = conn; + } + + // Save a lender to the database + public void saveLender(Lender lender) throws SQLException { + String sql = "INSERT INTO lenders (name, preferred_rate, max_amount) VALUES (?, ?, ?)"; + try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { + stmt.setString(1, lender.getName()); + stmt.setInt(2, lender.getPreferredRate()); + stmt.setInt(3, lender.getMaxAmount()); + + // Execute the insertion + int rowsAffected = stmt.executeUpdate(); + + // If insertion is successful, retrieve the generated ID + if (rowsAffected > 0) { + ResultSet generatedKeys = stmt.getGeneratedKeys(); + if (generatedKeys.next()) { + lender.setId(generatedKeys.getInt(1)); // Set the auto-generated ID + } + } + } + } + + // Get a lender by ID + public Lender getLenderById(int id) throws SQLException { + String sql = "SELECT * FROM lenders WHERE lender_id = ?"; // Changed id to lender_id + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setInt(1, id); + ResultSet rs = stmt.executeQuery(); + if (rs.next()) { + return new Lender( + rs.getInt("lender_id"), // Changed id to lender_id + rs.getString("name"), + rs.getInt("preferred_rate"), + rs.getInt("max_amount") + ); + } + } + return null; + } + + // Get all lenders from the database + public List getAllLenders() throws SQLException { + List lenders = new ArrayList<>(); + String sql = "SELECT * FROM lenders"; + try (Statement stmt = conn.createStatement()) { + ResultSet rs = stmt.executeQuery(sql); + while (rs.next()) { + lenders.add(new Lender( + rs.getInt("lender_id"), // Changed id to lender_id + rs.getString("name"), + rs.getInt("preferred_rate"), + rs.getInt("max_amount") + )); + } + } + return lenders; + } +} + diff --git a/P2PLendingSystem/LoanDAO.java b/P2PLendingSystem/LoanDAO.java new file mode 100644 index 00000000..60efdacd --- /dev/null +++ b/P2PLendingSystem/LoanDAO.java @@ -0,0 +1,71 @@ +package dao; + +import java.sql.*; + +public class LoanDAO { + private Connection connection; + + public LoanDAO(Connection connection) { + this.connection = connection; + } + + // Insert a new loan into the database + public void addLoan(int borrowerId, int amount, int interestRate) throws SQLException { + // Check if the borrower already has a pending loan + String checkQuery = "SELECT COUNT(*) FROM loans WHERE borrower_id = ? AND loan_status = 'pending'"; + try (PreparedStatement checkStmt = connection.prepareStatement(checkQuery)) { + checkStmt.setInt(1, borrowerId); + ResultSet rs = checkStmt.executeQuery(); + if (rs.next() && rs.getInt(1) > 0) { + System.out.println("❌ Borrower already has a pending loan request."); + return; // Loan already exists + } + } + + // Insert the loan into the loans table + String query = "INSERT INTO loans (borrower_id, amount, interest_rate, loan_status) VALUES (?, ?, ?, 'pending')"; + try (PreparedStatement statement = connection.prepareStatement(query)) { + statement.setInt(1, borrowerId); + statement.setInt(2, amount); + statement.setInt(3, interestRate); + statement.executeUpdate(); + } + } + + // Get loan details by borrower ID + public ResultSet getLoanByBorrowerId(int borrowerId) throws SQLException { + String query = "SELECT * FROM loans WHERE borrower_id = ?"; + PreparedStatement statement = connection.prepareStatement(query); + statement.setInt(1, borrowerId); + return statement.executeQuery(); + } + + // Get total loan amount by borrower ID + public int getTotalLoanAmountByBorrowerId(int borrowerId) throws SQLException { + String query = "SELECT SUM(amount) FROM loans WHERE borrower_id = ?"; + try (PreparedStatement statement = connection.prepareStatement(query)) { + statement.setInt(1, borrowerId); + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + return resultSet.getInt(1); // Return the sum of amounts + } + } + } + return 0; // Return 0 if no loans are found + } + + public void updateLoanStatus(int borrowerId, int lenderId, String status) throws SQLException { + String sql = "UPDATE loans SET loan_status = ? WHERE borrower_id = ? AND lender_id = ?"; + try (PreparedStatement stmt = connection.prepareStatement(sql)) { + stmt.setString(1, status); + stmt.setInt(2, borrowerId); + stmt.setInt(3, lenderId); + int rowsUpdated = stmt.executeUpdate(); + if (rowsUpdated > 0) { + System.out.println("✅ Loan status updated for Borrower ID " + borrowerId + " and Lender ID " + lenderId); + } else { + System.out.println("⚠️ No matching loan found for Borrower ID " + borrowerId + " and Lender ID " + lenderId); + } + } + } +} diff --git a/P2PLendingSystem/Match.java b/P2PLendingSystem/Match.java new file mode 100644 index 00000000..79347a16 --- /dev/null +++ b/P2PLendingSystem/Match.java @@ -0,0 +1,47 @@ +package dsa_modules; + +public class Match { + private int borrowerId; + private int lenderId; + private double interestRate; + + // Constructor with parameters + public Match(int borrowerId, int lenderId, double interestRate) { + this.borrowerId = borrowerId; + this.lenderId = lenderId; + this.interestRate = interestRate; + } + + // Getters + public int getBorrowerId() { + return borrowerId; + } + + public int getLenderId() { + return lenderId; + } + + public double getInterestRate() { + return interestRate; + } + + // Setters + public void setBorrowerId(int borrowerId) { + this.borrowerId = borrowerId; + } + + public void setLenderId(int lenderId) { + this.lenderId = lenderId; + } + + public void setInterestRate(double interestRate) { + this.interestRate = interestRate; + } + + // Add toString method for debugging/logging purposes + @Override + public String toString() { + return "Match [borrowerId=" + borrowerId + ", lenderId=" + lenderId + ", interestRate=" + interestRate + "]"; + } +} + diff --git a/P2PLendingSystem/MatchDAO.java b/P2PLendingSystem/MatchDAO.java new file mode 100644 index 00000000..a5ef6e0e --- /dev/null +++ b/P2PLendingSystem/MatchDAO.java @@ -0,0 +1,65 @@ +package dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.ArrayList; + +import dsa_modules.Match; + +public class MatchDAO { + private final Connection conn; + + public MatchDAO(Connection conn) { + this.conn = conn; + } + + // Save a match to the database + public void saveMatch(Match match) throws SQLException { + String sql = "INSERT INTO matches (borrower_id, lender_id, interest_rate) VALUES (?, ?, ?)"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setInt(1, match.getBorrowerId()); + stmt.setInt(2, match.getLenderId()); + stmt.setInt(3, (int)match.getInterestRate()); // interest rate is now an int + + // Log the match being saved + System.out.println("Saving match: Borrower ID = " + match.getBorrowerId() + + ", Lender ID = " + match.getLenderId() + + ", Interest Rate = " + match.getInterestRate()); + + int rowsAffected = stmt.executeUpdate(); + if (rowsAffected > 0) { + System.out.println("Match saved successfully."); + } else { + System.out.println("Failed to save match."); + } + } catch (SQLException e) { + System.err.println("Error saving match: " + e.getMessage()); + e.printStackTrace(); + throw e; + } + } + + // Retrieve all matches from the database + public List getAllMatches() throws SQLException { + List list = new ArrayList<>(); + String sql = "SELECT borrower_id, lender_id, interest_rate FROM matches"; + try (PreparedStatement stmt = conn.prepareStatement(sql); + ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + int borrowerId = rs.getInt("borrower_id"); + int lenderId = rs.getInt("lender_id"); + int rate = rs.getInt("interest_rate"); // interest rate as int + list.add(new Match(borrowerId, lenderId, rate)); // assuming Match constructor uses int now + } + } catch (SQLException e) { + System.err.println("Error retrieving matches: " + e.getMessage()); + e.printStackTrace(); + throw e; + } + return list; + } +} + diff --git a/P2PLendingSystem/README.md b/P2PLendingSystem/README.md new file mode 100644 index 00000000..6d4fc852 --- /dev/null +++ b/P2PLendingSystem/README.md @@ -0,0 +1,23 @@ +A Java-based P2P lending platform that connects borrowers with lenders directly using efficient data structures and intelligent matching algorithms. Designed with modular components and integrated with a MySQL backend. + +Features +1. Borrower & Lender Management Register, login, and manage profiles for borrowers and lenders. +2. Loan Request & Offer Handling Borrowers can request loans; lenders can offer based on preferred rates. +3. Automated Loan Matching Matches borrowers and lenders using optimized criteria like interest rate and amount. +4. Blacklist & Fraud Check Skips blacklisted borrowers during matching. +5. Real-Time Loan Status Updates Updates loan status (pending, matched, completed) in the database. +6. Data Structures + BST: Borrower records + Heap: Lender priority queue (by rate) + Trie: Lender name search + Segment Tree: Credit score range queries + Graph: Relationship mapping for matching logic + +Tech Stack +Language: Java +Database: MySQL +Database Access: JDBC +IDE: Eclipse +GUI (Graphical User Interface) toolkit : Java Swing + +Video link : https://drive.google.com/file/d/1Qq8O79mFQySgL66B407CyxeEGntOZZLo/view?usp=sharing diff --git a/P2PLendingSystem/RepaymentDAO.java b/P2PLendingSystem/RepaymentDAO.java new file mode 100644 index 00000000..1021cb70 --- /dev/null +++ b/P2PLendingSystem/RepaymentDAO.java @@ -0,0 +1,43 @@ +package dao; + +import java.sql.*; + +public class RepaymentDAO { + private Connection connection; + + public RepaymentDAO(Connection connection) { + this.connection = connection; + } + + // Insert repayment data + public void addRepayment(int loanId, double amount) throws SQLException { + String query = "INSERT INTO repayments (loan_id, amount) VALUES (?, ?)"; + try (PreparedStatement statement = connection.prepareStatement(query)) { + statement.setInt(1, loanId); + statement.setDouble(2, amount); + statement.executeUpdate(); + } + } + + // Update repayment data + public void updateRepayment(int loanId, double amount) throws SQLException { + String query = "UPDATE repayments SET amount = ? WHERE loan_id = ?"; + try (PreparedStatement statement = connection.prepareStatement(query)) { + statement.setDouble(1, amount); + statement.setInt(2, loanId); + statement.executeUpdate(); + } + } + + // Get total repayments for a loan + public double getTotalRepayments(int loanId) throws SQLException { + String query = "SELECT SUM(amount) FROM repayments WHERE loan_id = ?"; + PreparedStatement statement = connection.prepareStatement(query); + statement.setInt(1, loanId); + ResultSet rs = statement.executeQuery(); + if (rs.next()) { + return rs.getDouble(1); + } + return 0.0; + } +} diff --git a/P2PLendingSystem/SegmentTree.java b/P2PLendingSystem/SegmentTree.java new file mode 100644 index 00000000..8ab46b6b --- /dev/null +++ b/P2PLendingSystem/SegmentTree.java @@ -0,0 +1,56 @@ +package dsa_modules; + +//5. Segment Tree for Repayment Tracking +public class SegmentTree { +int[] tree; +int[] repayments; +int n; + +public SegmentTree(int[] repayments) { + this.n = repayments.length; + this.repayments = repayments; + this.tree = new int[4 * n]; + build(0, 0, n - 1); +} + +void build(int node, int start, int end) { + if (start == end) tree[node] = repayments[start]; + else { + int mid = (start + end) / 2; + build(2 * node + 1, start, mid); + build(2 * node + 2, mid + 1, end); + tree[node] = tree[2 * node + 1] + tree[2 * node + 2]; + } +} + +int query(int node, int start, int end, int l, int r) { + if (r < start || end < l) return 0; + if (l <= start && end <= r) return tree[node]; + int mid = (start + end) / 2; + int leftSum = query(2 * node + 1, start, mid, l, r); + int rightSum = query(2 * node + 2, mid + 1, end, l, r); + return leftSum + rightSum; +} + +void update(int node, int start, int end, int idx, int val) { + if (start == end) tree[node] = val; + else { + int mid = (start + end) / 2; + if (idx <= mid) update(2 * node + 1, start, mid, idx, val); + else update(2 * node + 2, mid + 1, end, idx, val); + tree[node] = tree[2 * node + 1] + tree[2 * node + 2]; + } +} + +//Wrapper method for easy usage +public void update(int idx, int val) { + update(0, 0, n - 1, idx, val); +} + +//Public wrapper for querying repayment sum +public int query(int l, int r) { + return query(0, 0, n - 1, l, r); +} + +} + diff --git a/P2PLendingSystem/module-info.java b/P2PLendingSystem/module-info.java new file mode 100644 index 00000000..9ef2d507 --- /dev/null +++ b/P2PLendingSystem/module-info.java @@ -0,0 +1,12 @@ +/** + * + */ +/** + * + */ +module P2PLending { + requires java.desktop; + requires java.sql; // Required for JDBC + exports dao; // Export your DAO classes if other modules use them + exports dsa_modules; // Export DSA modules if needed +} \ No newline at end of file diff --git a/P2PLendingSystem/package connector.java b/P2PLendingSystem/package connector.java new file mode 100644 index 00000000..f49ba7c5 --- /dev/null +++ b/P2PLendingSystem/package connector.java @@ -0,0 +1,318 @@ +package connector; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.*; +import java.sql.ResultSet; +import java.sql.Statement; + +import dao.*; +import dsa_modules.*; +import db.DatabaseUtil; + +import javax.swing.JOptionPane; + +public class P2PLendingSystemConnector { + + private final BorrowerDAO borrowerDAO; + private final LenderDAO lenderDAO; + private final LoanDAO loanDAO; + private final RepaymentDAO repaymentDAO; + private final FraudDAO fraudDAO; + private final MatchDAO matchDAO; + + private final CreditScoreBST creditScoreBST = new CreditScoreBST(); + private final InterestRateManager interestHeap = new InterestRateManager(); + private final FraudDetector fraudTrie = new FraudDetector(); + private final SegmentTree repaymentTree; + private final Graph borrowerLenderGraph = new Graph(); + + private final Map borrowerMap = new HashMap<>(); + private final Map lenderMap = new HashMap<>(); + private int borrowerIdCounter = 1; + private int lenderIdCounter = 1; + + private final Connection conn; + + public P2PLendingSystemConnector() { + Connection connectionTemp = null; + try { + connectionTemp = DatabaseUtil.getConnection(); + } catch (SQLException e) { + System.out.println("Database connection error: " + e.getMessage()); + } + this.conn = connectionTemp; + this.borrowerDAO = new BorrowerDAO(conn); + this.lenderDAO = new LenderDAO(conn); + this.loanDAO = new LoanDAO(conn); + this.repaymentDAO = new RepaymentDAO(conn); + this.fraudDAO = new FraudDAO(conn); + this.matchDAO = new MatchDAO(conn); + this.repaymentTree = new SegmentTree(new int[100]); // Placeholder + + Map loadedBorrowers = borrowerDAO.loadAllBorrowersIntoMap(); + borrowerMap.putAll(loadedBorrowers); + loadedBorrowers.values().forEach(creditScoreBST::insert); + } + + public void registerBorrower(String name, int creditScore) { + try { + if (fraudDAO.isFraud(name)) { + System.out.println("User is flagged as fraudulent. Cannot register."); + return; + } + + Borrower borrower = new Borrower(borrowerIdCounter++, name, creditScore); + creditScoreBST.insert(borrower); + borrowerMap.put(name, borrower); + borrowerLenderGraph.addBorrower(borrower.getId()); + borrowerDAO.saveBorrower(borrower); + + System.out.println("Borrower registered: " + name + " (ID: " + borrower.getId() + ")"); + } catch (SQLException e) { + System.out.println("Borrower registration error: " + e.getMessage()); + } + } + + public void registerLender(String name, int preferredRate, int maxAmount) { + try { + if (fraudDAO.isFraud(name)) { + System.out.println("User is flagged as fraudulent. Cannot register."); + return; + } + + Lender lender = new Lender(lenderIdCounter++, name, preferredRate, maxAmount); + lenderMap.put(name, lender); + borrowerLenderGraph.addLender(lender.getId()); + lenderDAO.saveLender(lender); + + System.out.println("Lender registered: " + name + " (ID: " + lender.getId() + ")"); + } catch (SQLException e) { + System.out.println("Lender registration error: " + e.getMessage()); + } + } + + public void blacklistUser(String name) { + String sql = "UPDATE borrowers SET status = 'blacklisted' WHERE name = ?"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, name); + int rowsUpdated = stmt.executeUpdate(); + if (rowsUpdated > 0) { + System.out.println("User " + name + " has been blacklisted."); + } else { + System.out.println("No user found with name " + name); + } + } catch (SQLException e) { + System.out.println("Error blacklisting user: " + e.getMessage()); + } + } + + public boolean requestLoan(String borrowerName, int amount, int interestRate) { + try { + Borrower borrower = borrowerMap.get(borrowerName); + if (borrower == null) { + System.out.println("❌ Borrower not found in map: " + borrowerName); + return false; + } + + if (fraudDAO.isFraud(borrowerName)) { + System.out.println("🚫 Loan request denied. Borrower is flagged as fraudulent."); + return false; + } + + String status = borrowerDAO.getBorrowerStatusById(borrower.getId()); + System.out.println("Borrower status: " + status); + if ("blacklisted".equalsIgnoreCase(status)) { + System.out.println("🚫 Loan request denied. Borrower is blacklisted."); + return false; + } + + loanDAO.addLoan(borrower.getId(), amount, interestRate); + borrowerDAO.updateRequestedDetails(borrower.getId(), amount, interestRate); + borrower.setRequestedAmount(amount); + borrower.setRequestedRate(interestRate); + interestHeap.addBorrowerRate(interestRate); + + int lenderId = findBestLenderForBorrower(interestRate); + if (lenderId != -1) { + borrowerLenderGraph.addMatch(lenderId, new Match(borrower.getId(), lenderId, interestRate)); + } + + System.out.println("✅ Loan request placed: " + borrowerName + " - Rs." + amount + " @ " + interestRate + "%"); + return true; + } catch (SQLException e) { + System.out.println("⚠️ Loan request error: " + e.getMessage()); + return false; + } + } + + private int findBestLenderForBorrower(int borrowerRate) { + for (Lender lender : lenderMap.values()) { + if (lender.getPreferredRate() <= borrowerRate) { + return lender.getId(); + } + } + return -1; + } + + public void makeRepayment(String borrowerName, int amount) { + try { + Borrower borrower = borrowerMap.get(borrowerName); + if (borrower == null) { + System.out.println("Borrower not found."); + return; + } + + int loanId = borrower.getId(); + repaymentDAO.addRepayment(loanId, amount); + repaymentTree.update(loanId, amount); + + System.out.println("Repayment recorded: " + borrowerName + " - Rs." + amount); + } catch (SQLException e) { + System.out.println("Repayment error: " + e.getMessage()); + } + } + + public Borrower getBorrowerById(int borrowerId) { + return borrowerDAO.getBorrowerById(borrowerId); + } + + public Lender getLenderById(int id) { + try { + return lenderDAO.getLenderById(id); + } catch (SQLException e) { + e.printStackTrace(); + return null; + } + } + + + public String matchLenderToBorrower() { + StringBuilder result = new StringBuilder(); + try { + // Step 1: Select all pending loans + String sql = "SELECT * FROM loans WHERE loan_status = 'pending'"; + try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { + + List matchedBorrowers = new ArrayList<>(); + List matchedLenders = new ArrayList<>(); + + while (rs.next()) { + int borrowerId = rs.getInt("borrower_id"); + double interestRate = rs.getDouble("interest_rate"); + + Borrower borrower = getBorrowerById(borrowerId); + if (borrower == null) { + result.append("❌ Borrower ID ").append(borrowerId).append(" not found.\n"); + continue; + } + + String status = borrowerDAO.getBorrowerStatusById(borrower.getId()); + if ("blacklisted".equalsIgnoreCase(status)) { + result.append("❌ Skipped blacklisted borrower: ").append(borrower.getName()).append("\n"); + continue; + } + + // Step 2: Get eligible lenders + List lenders = lenderDAO.getAllLenders(); // You can filter further if needed + boolean isMatched = false; + + for (Lender lender : lenders) { + if (isMatch(lender, borrower)) { + // Step 3: Assign lender to loan + assignLenderToLoan(borrowerId, lender.getId(), interestRate); + + // Step 4: Save match + Match match = new Match(borrowerId, lender.getId(), interestRate); + matchDAO.saveMatch(match); + + // Step 5: Update loan status + updateLoanStatus(borrowerId, lender.getId(), "matched"); + + result.append("✅ Matched: ").append(borrower.getName()) + .append(" with ").append(lender.getName()) + .append(" @ ").append(interestRate).append("%\n"); + + matchedBorrowers.add(borrower); + matchedLenders.add(lender); + isMatched = true; + break; // Stop after first valid match + } + } + + if (!isMatched) { + result.append("❌ No matching lender found for borrower: ").append(borrower.getName()).append("\n"); + } + } + + // Optional: update graph + borrowerLenderGraph.removeBorrowers(matchedBorrowers); + borrowerLenderGraph.removeLenders(matchedLenders); + } + + } catch (SQLException e) { + result.append("Database error: ").append(e.getMessage()); + } catch (Exception e) { + result.append("An error occurred while matching: ").append(e.getMessage()); + } + + return result.toString(); + } + + public void updateLoanStatus(int borrowerId, int lenderId, String status) throws SQLException { + String sql = "UPDATE loans SET loan_status = ? WHERE borrower_id = ? AND lender_id = ?"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, status); + stmt.setInt(2, borrowerId); + stmt.setInt(3, lenderId); + stmt.executeUpdate(); + System.out.println("✅ Loan status updated for Borrower ID " + borrowerId + " and Lender ID " + lenderId); + } + } + + + public void assignLenderToLoan(int borrowerId, int lenderId, double interestRate) throws SQLException { + String sql = "UPDATE loans SET lender_id = ?, interest_rate = ? WHERE borrower_id = ? AND loan_status = 'pending'"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setInt(1, lenderId); + stmt.setDouble(2, interestRate); + stmt.setInt(3, borrowerId); + stmt.executeUpdate(); + System.out.println("✅ Assigned Lender ID " + lenderId + " to Borrower ID " + borrowerId); + } + } + + private boolean isMatch(Lender lender, Borrower borrower) { + System.out.println("Checking match: Lender " + lender.getId() + " and Borrower " + borrower.getId()); + System.out.println("Lender Max: " + lender.getMaxAmount() + ", Rate: " + lender.getPreferredRate()); + System.out.println("Borrower Request: " + borrower.getRequestedAmount() + ", Rate: " + borrower.getRequestedRate()); + + return lender.getMaxAmount() >= borrower.getRequestedAmount() && + lender.getPreferredRate() <= borrower.getRequestedRate(); + } + + + + public void showTopCreditBorrower() { + try { + List topBorrowers = borrowerDAO.getAllBorrowersSortedByCreditScore(); + if (topBorrowers.isEmpty()) { + JOptionPane.showMessageDialog(null, "No borrowers found."); + return; + } + + StringBuilder sb = new StringBuilder("Top Borrowers by Credit Score:\n"); + for (Borrower b : topBorrowers) { + sb.append("Name: ").append(b.getName()) + .append(" | Credit Score: ").append(b.getCreditScore()) + .append(" | Requested Amount: ").append(b.getRequestedAmount()) + .append(" | Requested Rate: ").append(b.getRequestedRate()).append("%\n"); + } + + JOptionPane.showMessageDialog(null, sb.toString()); + } catch (Exception e) { + System.out.println("Unexpected error: " + e.getMessage()); + } + } +} diff --git a/P2PLendingSystem/package db.java b/P2PLendingSystem/package db.java new file mode 100644 index 00000000..a2373266 --- /dev/null +++ b/P2PLendingSystem/package db.java @@ -0,0 +1,13 @@ +package db; + +import java.sql.*; + +public class DatabaseUtil { + private static final String URL = "jdbc:mysql://localhost:3306/p2p_lending"; + private static final String USER = "root"; + private static final String PASSWORD = "Manjiri.27"; + + public static Connection getConnection() throws SQLException { + return DriverManager.getConnection(URL, USER, PASSWORD); + } +} \ No newline at end of file diff --git a/P2PLendingSystem/package ui.java b/P2PLendingSystem/package ui.java new file mode 100644 index 00000000..0095ad9b --- /dev/null +++ b/P2PLendingSystem/package ui.java @@ -0,0 +1,263 @@ +package ui; + +import connector.P2PLendingSystemConnector; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; + +public class MainUI extends JFrame { + + private final P2PLendingSystemConnector connector = new P2PLendingSystemConnector(); + + public MainUI() { + setTitle("Smart P2P Lending System"); + setSize(600, 500); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setLocationRelativeTo(null); + setLayout(new BorderLayout()); + + JTabbedPane tabbedPane = new JTabbedPane(); + + tabbedPane.addTab("Register Borrower", wrapPanel(createRegisterPanel())); + tabbedPane.addTab("Request Loan", wrapPanel(createLoanPanel())); + tabbedPane.addTab("Make Repayment", wrapPanel(createRepaymentPanel())); + tabbedPane.addTab("Top Borrower", wrapPanel(createTopBorrowerPanel())); + tabbedPane.addTab("Blacklist User", wrapPanel(createBlacklistPanel())); + tabbedPane.addTab("Register Lender", wrapPanel(createLenderRegisterPanel())); + tabbedPane.addTab("Match Lender to Borrower", wrapPanel(createMatchLenderPanel())); + + add(tabbedPane, BorderLayout.CENTER); + } + + private JPanel wrapPanel(JPanel inner) { + JPanel wrapper = new JPanel(new BorderLayout()); + wrapper.setBorder(new EmptyBorder(20, 20, 20, 20)); + wrapper.add(inner, BorderLayout.CENTER); + return wrapper; + } + + private void clearFields(JTextField... fields) { + for (JTextField field : fields) { + field.setText(""); + } + } + + private JPanel createRegisterPanel() { + JPanel panel = new JPanel(new GridLayout(4, 2, 10, 10)); + + JTextField nameField = new JTextField(); + JTextField creditField = new JTextField(); + JButton registerButton = new JButton("Register Borrower"); + + registerButton.addActionListener(e -> { + String name = nameField.getText().trim(); + String creditText = creditField.getText().trim(); + + if (name.isEmpty() || creditText.isEmpty()) { + JOptionPane.showMessageDialog(this, "All fields are required."); + return; + } + + try { + int score = Integer.parseInt(creditText); + connector.registerBorrower(name, score); + JOptionPane.showMessageDialog(this, "Borrower Registered Successfully!"); + clearFields(nameField, creditField); + } catch (NumberFormatException ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(this, "Credit score must be a number."); + } + }); + + panel.add(new JLabel("Borrower Name:")); + panel.add(nameField); + panel.add(new JLabel("Credit Score:")); + panel.add(creditField); + panel.add(new JLabel()); + panel.add(registerButton); + + return panel; + } + + private JPanel createLoanPanel() { + JPanel panel = new JPanel(new GridLayout(4, 2, 10, 10)); + + JTextField nameField = new JTextField(); + JTextField amountField = new JTextField(); + JTextField rateField = new JTextField(); + JButton loanButton = new JButton("Request Loan"); + + loanButton.addActionListener(e -> { + String name = nameField.getText().trim(); + String amountText = amountField.getText().trim(); + String rateText = rateField.getText().trim(); + + if (name.isEmpty() || amountText.isEmpty() || rateText.isEmpty()) { + JOptionPane.showMessageDialog(this, "All fields are required."); + return; + } + + try { + int amount = Integer.parseInt(amountText); + int rate = Integer.parseInt(rateText); + + boolean success = connector.requestLoan(name, amount, rate); + + if (success) { + JOptionPane.showMessageDialog(this, "Loan Requested Successfully!"); + clearFields(nameField, amountField, rateField); + } else { + JOptionPane.showMessageDialog(this, "Loan request denied. Borrower may be blacklisted or not registered."); + } + } catch (NumberFormatException ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(this, "Loan amount and interest rate must be numbers."); + } + }); + + panel.add(new JLabel("Borrower Name:")); + panel.add(nameField); + panel.add(new JLabel("Loan Amount:")); + panel.add(amountField); + panel.add(new JLabel("Interest Rate:")); + panel.add(rateField); + panel.add(new JLabel()); + panel.add(loanButton); + + return panel; + } + + private JPanel createRepaymentPanel() { + JPanel panel = new JPanel(new GridLayout(3, 2, 10, 10)); + + JTextField nameField = new JTextField(); + JTextField amountField = new JTextField(); + JButton repayButton = new JButton("Make Repayment"); + + repayButton.addActionListener(e -> { + String name = nameField.getText().trim(); + String amountText = amountField.getText().trim(); + + if (name.isEmpty() || amountText.isEmpty()) { + JOptionPane.showMessageDialog(this, "All fields are required."); + return; + } + + try { + int amount = Integer.parseInt(amountText); + connector.makeRepayment(name, amount); + JOptionPane.showMessageDialog(this, "Repayment Successful!"); + clearFields(nameField, amountField); + } catch (NumberFormatException ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(this, "Amount must be a number."); + } + }); + + panel.add(new JLabel("Borrower Name:")); + panel.add(nameField); + panel.add(new JLabel("Amount:")); + panel.add(amountField); + panel.add(new JLabel()); + panel.add(repayButton); + + return panel; + } + + private JPanel createTopBorrowerPanel() { + JPanel panel = new JPanel(); + JButton topButton = new JButton("Show Top Borrowers"); + + topButton.addActionListener(e -> { + connector.showTopCreditBorrower(); + }); + + panel.add(topButton); + return panel; + } + + private JPanel createBlacklistPanel() { + JPanel panel = new JPanel(new GridLayout(2, 2, 10, 10)); + + JTextField nameField = new JTextField(); + JButton blacklistButton = new JButton("Blacklist User"); + + blacklistButton.addActionListener(e -> { + String name = nameField.getText().trim(); + if (name.isEmpty()) { + JOptionPane.showMessageDialog(this, "Name cannot be empty."); + return; + } + connector.blacklistUser(name); + JOptionPane.showMessageDialog(this, "User '" + name + "' has been blacklisted."); + clearFields(nameField); + }); + + panel.add(new JLabel("Name to Blacklist:")); + panel.add(nameField); + panel.add(new JLabel()); + panel.add(blacklistButton); + + return panel; + } + + private JPanel createLenderRegisterPanel() { + JPanel panel = new JPanel(new GridLayout(4, 2, 10, 10)); + + JTextField nameField = new JTextField(); + JTextField rateField = new JTextField(); + JTextField amountField = new JTextField(); + JButton registerButton = new JButton("Register Lender"); + + registerButton.addActionListener(e -> { + String name = nameField.getText().trim(); + String rateText = rateField.getText().trim(); + String amountText = amountField.getText().trim(); + + if (name.isEmpty() || rateText.isEmpty() || amountText.isEmpty()) { + JOptionPane.showMessageDialog(this, "All fields are required."); + return; + } + + try { + int preferredRate = Integer.parseInt(rateText); + int maxAmount = Integer.parseInt(amountText); + connector.registerLender(name, preferredRate, maxAmount); + JOptionPane.showMessageDialog(this, "Lender Registered Successfully!"); + clearFields(nameField, rateField, amountField); + } catch (NumberFormatException ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(this, "Rate and amount must be numbers."); + } + }); + + panel.add(new JLabel("Lender Name:")); + panel.add(nameField); + panel.add(new JLabel("Preferred Interest Rate:")); + panel.add(rateField); + panel.add(new JLabel("Maximum Loan Amount:")); + panel.add(amountField); + panel.add(new JLabel()); + panel.add(registerButton); + + return panel; + } + + private JPanel createMatchLenderPanel() { + JPanel panel = new JPanel(); + JButton matchButton = new JButton("Match Lender to Borrower"); + + matchButton.addActionListener(e -> { + String result = connector.matchLenderToBorrower(); + JOptionPane.showMessageDialog(this, result, "Matching Result", JOptionPane.INFORMATION_MESSAGE); + }); + + panel.add(matchButton); + return panel; + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> new MainUI().setVisible(true)); + } +}