initial implementation of loan approval service
This commit is contained in:
@ -12,7 +12,12 @@
|
|||||||
"Bash(pip install:*)",
|
"Bash(pip install:*)",
|
||||||
"Bash(python:*)",
|
"Bash(python:*)",
|
||||||
"Bash(git init:*)",
|
"Bash(git init:*)",
|
||||||
"Bash(git add:*)"
|
"Bash(git add:*)",
|
||||||
|
"Bash(git commit -m \"$(cat <<''EOF''\nInitial commit: JAX-WS Hello World Service\n\n- Complete JAX-WS Hello World implementation\n- Docker and Docker Compose support for easy deployment\n- Python test scripts for service validation\n- Comprehensive README with setup instructions for Windows and Linux\n- Maven configuration with JAX-WS dependencies\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nEOF\n)\")",
|
||||||
|
"Bash(git remote add:*)",
|
||||||
|
"Bash(git push:*)",
|
||||||
|
"Bash(git commit:*)",
|
||||||
|
"Bash(docker-compose ps:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|||||||
@ -63,6 +63,11 @@ The easiest way to test this application is using Docker. No need to install Jav
|
|||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**1. Start the application ( when you changed code ):**
|
||||||
|
```bash
|
||||||
|
docker-compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
**2. Wait for the application to start (about 30-40 seconds), then access:**
|
**2. Wait for the application to start (about 30-40 seconds), then access:**
|
||||||
- **WSDL**: http://localhost:8080/jaxws-hello-world/hello?wsdl
|
- **WSDL**: http://localhost:8080/jaxws-hello-world/hello?wsdl
|
||||||
- **Tomcat Manager**: http://localhost:8080/manager (username: `admin`, password: `admin123`)
|
- **Tomcat Manager**: http://localhost:8080/manager (username: `admin`, password: `admin123`)
|
||||||
|
|||||||
7
pom.xml
7
pom.xml
@ -41,6 +41,13 @@
|
|||||||
<version>4.0.1</version>
|
<version>4.0.1</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SQLite JDBC Driver -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xerial</groupId>
|
||||||
|
<artifactId>sqlite-jdbc</artifactId>
|
||||||
|
<version>3.43.0.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.example.listener;
|
||||||
|
|
||||||
|
import com.example.util.DatabaseManager;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContextEvent;
|
||||||
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DatabaseInitializationListener - Initializes database schema when application starts
|
||||||
|
*/
|
||||||
|
public class DatabaseInitializationListener implements ServletContextListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextInitialized(ServletContextEvent sce) {
|
||||||
|
System.out.println("===========================================");
|
||||||
|
System.out.println("Starting Database Initialization...");
|
||||||
|
System.out.println("===========================================");
|
||||||
|
|
||||||
|
try {
|
||||||
|
DatabaseManager dbManager = DatabaseManager.getInstance();
|
||||||
|
|
||||||
|
// Test connection
|
||||||
|
if (dbManager.testConnection()) {
|
||||||
|
System.out.println("Database connection test: PASSED");
|
||||||
|
} else {
|
||||||
|
System.err.println("Database connection test: FAILED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize schema (create tables if they don't exist)
|
||||||
|
dbManager.initializeSchema();
|
||||||
|
|
||||||
|
System.out.println("Database initialization completed successfully");
|
||||||
|
System.out.println("===========================================");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("FATAL: Database initialization failed!");
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Failed to initialize database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextDestroyed(ServletContextEvent sce) {
|
||||||
|
System.out.println("Application shutdown - Database cleanup completed");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package com.example.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomerRegistrationRequest - Input model for customer registration
|
||||||
|
*/
|
||||||
|
public class CustomerRegistrationRequest {
|
||||||
|
|
||||||
|
private String customerName;
|
||||||
|
private boolean blacklisted;
|
||||||
|
|
||||||
|
public CustomerRegistrationRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomerRegistrationRequest(String customerName, boolean blacklisted) {
|
||||||
|
this.customerName = customerName;
|
||||||
|
this.blacklisted = blacklisted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomerName() {
|
||||||
|
return customerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerName(String customerName) {
|
||||||
|
this.customerName = customerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBlacklisted() {
|
||||||
|
return blacklisted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlacklisted(boolean blacklisted) {
|
||||||
|
this.blacklisted = blacklisted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CustomerRegistrationRequest{" +
|
||||||
|
"customerName='" + customerName + '\'' +
|
||||||
|
", blacklisted=" + blacklisted +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/main/java/com/example/model/LoanRequest.java
Normal file
53
src/main/java/com/example/model/LoanRequest.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package com.example.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LoanRequest - Input model for loan application processing
|
||||||
|
*/
|
||||||
|
public class LoanRequest {
|
||||||
|
|
||||||
|
private String applicantName;
|
||||||
|
private int requestedAmount;
|
||||||
|
private int creditScore;
|
||||||
|
|
||||||
|
public LoanRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanRequest(String applicantName, int requestedAmount, int creditScore) {
|
||||||
|
this.applicantName = applicantName;
|
||||||
|
this.requestedAmount = requestedAmount;
|
||||||
|
this.creditScore = creditScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApplicantName() {
|
||||||
|
return applicantName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApplicantName(String applicantName) {
|
||||||
|
this.applicantName = applicantName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRequestedAmount() {
|
||||||
|
return requestedAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestedAmount(int requestedAmount) {
|
||||||
|
this.requestedAmount = requestedAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCreditScore() {
|
||||||
|
return creditScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreditScore(int creditScore) {
|
||||||
|
this.creditScore = creditScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "LoanRequest{" +
|
||||||
|
"applicantName='" + applicantName + '\'' +
|
||||||
|
", requestedAmount=" + requestedAmount +
|
||||||
|
", creditScore=" + creditScore +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/main/java/com/example/model/LoanResponse.java
Normal file
64
src/main/java/com/example/model/LoanResponse.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package com.example.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LoanResponse - Output model for loan application result
|
||||||
|
*/
|
||||||
|
public class LoanResponse {
|
||||||
|
|
||||||
|
private boolean approved;
|
||||||
|
private double approvedRate;
|
||||||
|
private String rejectionReason;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public LoanResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanResponse(boolean approved, double approvedRate, String rejectionReason, String message) {
|
||||||
|
this.approved = approved;
|
||||||
|
this.approvedRate = approvedRate;
|
||||||
|
this.rejectionReason = rejectionReason;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isApproved() {
|
||||||
|
return approved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApproved(boolean approved) {
|
||||||
|
this.approved = approved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getApprovedRate() {
|
||||||
|
return approvedRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovedRate(double approvedRate) {
|
||||||
|
this.approvedRate = approvedRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRejectionReason() {
|
||||||
|
return rejectionReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRejectionReason(String rejectionReason) {
|
||||||
|
this.rejectionReason = rejectionReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "LoanResponse{" +
|
||||||
|
"approved=" + approved +
|
||||||
|
", approvedRate=" + approvedRate +
|
||||||
|
", rejectionReason='" + rejectionReason + '\'' +
|
||||||
|
", message='" + message + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/main/java/com/example/repository/CustomerRepository.java
Normal file
22
src/main/java/com/example/repository/CustomerRepository.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package com.example.repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomerRepository - Interface for customer data access
|
||||||
|
*/
|
||||||
|
public interface CustomerRepository {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the customer is on the blacklist
|
||||||
|
* @param name Customer name
|
||||||
|
* @return true if blacklisted, false otherwise
|
||||||
|
*/
|
||||||
|
boolean isBlacklisted(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a new customer into the database
|
||||||
|
* @param name Customer name
|
||||||
|
* @param isBlacklisted Blacklist status
|
||||||
|
* @return true if registered successfully, false if customer already exists
|
||||||
|
*/
|
||||||
|
boolean registerCustomer(String name, boolean isBlacklisted);
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package com.example.repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LoanHistoryRepository - Interface for loan history data access
|
||||||
|
*/
|
||||||
|
public interface LoanHistoryRepository {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves loan application history to the database
|
||||||
|
* @param applicantName Name of the applicant
|
||||||
|
* @param requestedAmount Requested loan amount
|
||||||
|
* @param approved Whether the loan was approved
|
||||||
|
* @param approvedRate Interest rate if approved
|
||||||
|
* @param rejectionReason Reason for rejection if declined
|
||||||
|
*/
|
||||||
|
void saveHistory(String applicantName, int requestedAmount, boolean approved,
|
||||||
|
double approvedRate, String rejectionReason);
|
||||||
|
}
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
package com.example.repository.impl;
|
||||||
|
|
||||||
|
import com.example.repository.CustomerRepository;
|
||||||
|
import com.example.util.DatabaseManager;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomerRepositoryImpl - SQLite implementation of CustomerRepository
|
||||||
|
*/
|
||||||
|
public class CustomerRepositoryImpl implements CustomerRepository {
|
||||||
|
|
||||||
|
private final DatabaseManager dbManager;
|
||||||
|
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
public CustomerRepositoryImpl() {
|
||||||
|
this.dbManager = DatabaseManager.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBlacklisted(String name) {
|
||||||
|
String query = "SELECT is_blacklisted FROM customers WHERE customer_name = ?";
|
||||||
|
|
||||||
|
try (Connection conn = dbManager.getConnection();
|
||||||
|
PreparedStatement pstmt = conn.prepareStatement(query)) {
|
||||||
|
|
||||||
|
pstmt.setString(1, name);
|
||||||
|
|
||||||
|
try (ResultSet rs = pstmt.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
int blacklisted = rs.getInt("is_blacklisted");
|
||||||
|
return blacklisted == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Customer not found, not blacklisted by default
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException("Error checking blacklist status for: " + name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean registerCustomer(String name, boolean isBlacklisted) {
|
||||||
|
if (name == null || name.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Customer name cannot be null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if customer already exists
|
||||||
|
if (customerExists(name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String insert = "INSERT INTO customers (customer_name, is_blacklisted, registered_at) VALUES (?, ?, ?)";
|
||||||
|
|
||||||
|
try (Connection conn = dbManager.getConnection();
|
||||||
|
PreparedStatement pstmt = conn.prepareStatement(insert)) {
|
||||||
|
|
||||||
|
pstmt.setString(1, name);
|
||||||
|
pstmt.setInt(2, isBlacklisted ? 1 : 0);
|
||||||
|
pstmt.setString(3, LocalDateTime.now().format(DATE_FORMATTER));
|
||||||
|
|
||||||
|
int rowsAffected = pstmt.executeUpdate();
|
||||||
|
return rowsAffected > 0;
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException("Error registering customer: " + name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to check if customer already exists
|
||||||
|
* @param name Customer name
|
||||||
|
* @return true if exists, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean customerExists(String name) {
|
||||||
|
String query = "SELECT COUNT(*) as count FROM customers WHERE customer_name = ?";
|
||||||
|
|
||||||
|
try (Connection conn = dbManager.getConnection();
|
||||||
|
PreparedStatement pstmt = conn.prepareStatement(query)) {
|
||||||
|
|
||||||
|
pstmt.setString(1, name);
|
||||||
|
|
||||||
|
try (ResultSet rs = pstmt.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
return rs.getInt("count") > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException("Error checking customer existence: " + name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package com.example.repository.impl;
|
||||||
|
|
||||||
|
import com.example.repository.LoanHistoryRepository;
|
||||||
|
import com.example.util.DatabaseManager;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LoanHistoryRepositoryImpl - SQLite implementation of LoanHistoryRepository
|
||||||
|
*/
|
||||||
|
public class LoanHistoryRepositoryImpl implements LoanHistoryRepository {
|
||||||
|
|
||||||
|
private final DatabaseManager dbManager;
|
||||||
|
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
public LoanHistoryRepositoryImpl() {
|
||||||
|
this.dbManager = DatabaseManager.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveHistory(String applicantName, int requestedAmount, boolean approved,
|
||||||
|
double approvedRate, String rejectionReason) {
|
||||||
|
|
||||||
|
String insert = "INSERT INTO loan_history " +
|
||||||
|
"(applicant_name, requested_amount, approved, approved_rate, rejection_reason, processed_at) " +
|
||||||
|
"VALUES (?, ?, ?, ?, ?, ?)";
|
||||||
|
|
||||||
|
try (Connection conn = dbManager.getConnection();
|
||||||
|
PreparedStatement pstmt = conn.prepareStatement(insert)) {
|
||||||
|
|
||||||
|
pstmt.setString(1, applicantName);
|
||||||
|
pstmt.setInt(2, requestedAmount);
|
||||||
|
pstmt.setInt(3, approved ? 1 : 0);
|
||||||
|
pstmt.setDouble(4, approvedRate);
|
||||||
|
pstmt.setString(5, rejectionReason);
|
||||||
|
pstmt.setString(6, LocalDateTime.now().format(DATE_FORMATTER));
|
||||||
|
|
||||||
|
pstmt.executeUpdate();
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException("Error saving loan history for: " + applicantName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/main/java/com/example/service/CreditScoreService.java
Normal file
15
src/main/java/com/example/service/CreditScoreService.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package com.example.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CreditScoreService - Interface for external credit score checking
|
||||||
|
* This interface is designed to be mocked in unit tests
|
||||||
|
*/
|
||||||
|
public interface CreditScoreService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get credit score for an applicant
|
||||||
|
* @param applicantName Name of the applicant
|
||||||
|
* @return Credit score (0-850)
|
||||||
|
*/
|
||||||
|
int getCreditScore(String applicantName);
|
||||||
|
}
|
||||||
193
src/main/java/com/example/service/LoanApprovalService.java
Normal file
193
src/main/java/com/example/service/LoanApprovalService.java
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
package com.example.service;
|
||||||
|
|
||||||
|
import com.example.model.CustomerRegistrationRequest;
|
||||||
|
import com.example.model.LoanRequest;
|
||||||
|
import com.example.model.LoanResponse;
|
||||||
|
import com.example.repository.CustomerRepository;
|
||||||
|
import com.example.repository.LoanHistoryRepository;
|
||||||
|
import com.example.repository.impl.CustomerRepositoryImpl;
|
||||||
|
import com.example.repository.impl.LoanHistoryRepositoryImpl;
|
||||||
|
|
||||||
|
import javax.jws.WebMethod;
|
||||||
|
import javax.jws.WebService;
|
||||||
|
import javax.xml.ws.soap.SOAPFaultException;
|
||||||
|
import javax.xml.soap.SOAPFactory;
|
||||||
|
import javax.xml.soap.SOAPFault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LoanApprovalService - Main JAX-WS service for loan processing and customer management
|
||||||
|
*/
|
||||||
|
@WebService(
|
||||||
|
serviceName = "LoanApprovalService",
|
||||||
|
portName = "LoanApprovalPort"
|
||||||
|
)
|
||||||
|
public class LoanApprovalService {
|
||||||
|
|
||||||
|
private CustomerRepository customerRepository;
|
||||||
|
private LoanHistoryRepository loanHistoryRepository;
|
||||||
|
private CreditScoreService creditScoreService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor - initializes with real implementations
|
||||||
|
*/
|
||||||
|
public LoanApprovalService() {
|
||||||
|
this.customerRepository = new CustomerRepositoryImpl();
|
||||||
|
this.loanHistoryRepository = new LoanHistoryRepositoryImpl();
|
||||||
|
// Default credit score service (can be overridden for testing)
|
||||||
|
this.creditScoreService = new CreditScoreService() {
|
||||||
|
@Override
|
||||||
|
public int getCreditScore(String applicantName) {
|
||||||
|
// Simple mock implementation - returns a fixed score
|
||||||
|
// In production, this would call an external API
|
||||||
|
return 700;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter for CustomerRepository (for dependency injection in tests)
|
||||||
|
*/
|
||||||
|
@WebMethod(exclude = true)
|
||||||
|
public void setCustomerRepository(CustomerRepository customerRepository) {
|
||||||
|
this.customerRepository = customerRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter for LoanHistoryRepository (for dependency injection in tests)
|
||||||
|
*/
|
||||||
|
@WebMethod(exclude = true)
|
||||||
|
public void setLoanHistoryRepository(LoanHistoryRepository loanHistoryRepository) {
|
||||||
|
this.loanHistoryRepository = loanHistoryRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter for CreditScoreService (for dependency injection in tests)
|
||||||
|
*/
|
||||||
|
@WebMethod(exclude = true)
|
||||||
|
public void setCreditScoreService(CreditScoreService creditScoreService) {
|
||||||
|
this.creditScoreService = creditScoreService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new customer
|
||||||
|
* @param request Customer registration request
|
||||||
|
* @return Success or error message
|
||||||
|
*/
|
||||||
|
@WebMethod
|
||||||
|
public String registerNewCustomer(CustomerRegistrationRequest request) {
|
||||||
|
// Input validation
|
||||||
|
if (request == null || request.getCustomerName() == null ||
|
||||||
|
request.getCustomerName().trim().isEmpty()) {
|
||||||
|
throw createSOAPFault("Customer name cannot be null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register customer
|
||||||
|
boolean registered = customerRepository.registerCustomer(
|
||||||
|
request.getCustomerName(),
|
||||||
|
request.isBlacklisted()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (registered) {
|
||||||
|
return "Registration Successful";
|
||||||
|
} else {
|
||||||
|
return "Error: Customer already exists";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process loan application
|
||||||
|
* @param request Loan application request
|
||||||
|
* @return Loan decision response
|
||||||
|
*/
|
||||||
|
@WebMethod
|
||||||
|
public LoanResponse processLoanApplication(LoanRequest request) {
|
||||||
|
// Input validation
|
||||||
|
if (request == null || request.getApplicantName() == null ||
|
||||||
|
request.getApplicantName().trim().isEmpty()) {
|
||||||
|
throw createSOAPFault("Applicant name cannot be null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getRequestedAmount() <= 0) {
|
||||||
|
throw createSOAPFault("Requested amount must be greater than 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check blacklist
|
||||||
|
if (customerRepository.isBlacklisted(request.getApplicantName())) {
|
||||||
|
LoanResponse response = new LoanResponse(
|
||||||
|
false,
|
||||||
|
0.0,
|
||||||
|
"Applicant is blacklisted",
|
||||||
|
"Loan application rejected"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Save history
|
||||||
|
loanHistoryRepository.saveHistory(
|
||||||
|
request.getApplicantName(),
|
||||||
|
request.getRequestedAmount(),
|
||||||
|
false,
|
||||||
|
0.0,
|
||||||
|
"Applicant is blacklisted"
|
||||||
|
);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get credit score
|
||||||
|
int creditScore = creditScoreService.getCreditScore(request.getApplicantName());
|
||||||
|
|
||||||
|
// Loan approval logic
|
||||||
|
boolean approved;
|
||||||
|
double approvedRate;
|
||||||
|
String rejectionReason = null;
|
||||||
|
String message;
|
||||||
|
|
||||||
|
if (creditScore >= 700) {
|
||||||
|
// Good credit - approved with low rate
|
||||||
|
approved = true;
|
||||||
|
approvedRate = 3.5;
|
||||||
|
message = "Loan approved with excellent rate";
|
||||||
|
} else if (creditScore >= 600) {
|
||||||
|
// Fair credit - approved with standard rate
|
||||||
|
approved = true;
|
||||||
|
approvedRate = 5.5;
|
||||||
|
message = "Loan approved with standard rate";
|
||||||
|
} else if (creditScore >= 500) {
|
||||||
|
// Poor credit - approved with high rate
|
||||||
|
approved = true;
|
||||||
|
approvedRate = 8.5;
|
||||||
|
message = "Loan approved with high risk rate";
|
||||||
|
} else {
|
||||||
|
// Very poor credit - rejected
|
||||||
|
approved = false;
|
||||||
|
approvedRate = 0.0;
|
||||||
|
rejectionReason = "Credit score too low";
|
||||||
|
message = "Loan application rejected";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save history
|
||||||
|
loanHistoryRepository.saveHistory(
|
||||||
|
request.getApplicantName(),
|
||||||
|
request.getRequestedAmount(),
|
||||||
|
approved,
|
||||||
|
approvedRate,
|
||||||
|
rejectionReason
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create response
|
||||||
|
return new LoanResponse(approved, approvedRate, rejectionReason, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to create SOAP fault
|
||||||
|
*/
|
||||||
|
private SOAPFaultException createSOAPFault(String message) {
|
||||||
|
try {
|
||||||
|
SOAPFactory soapFactory = SOAPFactory.newInstance();
|
||||||
|
SOAPFault soapFault = soapFactory.createFault();
|
||||||
|
soapFault.setFaultString(message);
|
||||||
|
return new SOAPFaultException(soapFault);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Error creating SOAP fault", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
137
src/main/java/com/example/util/DatabaseManager.java
Normal file
137
src/main/java/com/example/util/DatabaseManager.java
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package com.example.util;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DatabaseManager - Utility class for managing SQLite database connections and schema initialization.
|
||||||
|
* This class provides methods to:
|
||||||
|
* - Get database connections
|
||||||
|
* - Initialize database schema (create tables)
|
||||||
|
* - Reset database (drop and recreate tables)
|
||||||
|
*/
|
||||||
|
public class DatabaseManager {
|
||||||
|
|
||||||
|
private static final String DB_URL = "jdbc:sqlite:loan_app.db";
|
||||||
|
private static DatabaseManager instance;
|
||||||
|
|
||||||
|
// Private constructor for singleton pattern
|
||||||
|
private DatabaseManager() {
|
||||||
|
try {
|
||||||
|
// Load SQLite JDBC driver
|
||||||
|
Class.forName("org.sqlite.JDBC");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new RuntimeException("Failed to load SQLite JDBC driver", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get singleton instance of DatabaseManager
|
||||||
|
* @return DatabaseManager instance
|
||||||
|
*/
|
||||||
|
public static synchronized DatabaseManager getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new DatabaseManager();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a new database connection
|
||||||
|
* @return Connection object
|
||||||
|
* @throws SQLException if connection fails
|
||||||
|
*/
|
||||||
|
public Connection getConnection() throws SQLException {
|
||||||
|
return DriverManager.getConnection(DB_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize database schema - create tables if they don't exist
|
||||||
|
*/
|
||||||
|
public void initializeSchema() {
|
||||||
|
String createCustomersTable =
|
||||||
|
"CREATE TABLE IF NOT EXISTS customers (" +
|
||||||
|
" customer_name TEXT PRIMARY KEY," +
|
||||||
|
" is_blacklisted INTEGER DEFAULT 0," +
|
||||||
|
" registered_at TEXT" +
|
||||||
|
")";
|
||||||
|
|
||||||
|
String createLoanHistoryTable =
|
||||||
|
"CREATE TABLE IF NOT EXISTS loan_history (" +
|
||||||
|
" id INTEGER PRIMARY KEY AUTOINCREMENT," +
|
||||||
|
" applicant_name TEXT," +
|
||||||
|
" requested_amount INTEGER," +
|
||||||
|
" approved INTEGER," +
|
||||||
|
" approved_rate REAL," +
|
||||||
|
" rejection_reason TEXT," +
|
||||||
|
" processed_at TEXT" +
|
||||||
|
")";
|
||||||
|
|
||||||
|
try (Connection conn = getConnection();
|
||||||
|
Statement stmt = conn.createStatement()) {
|
||||||
|
|
||||||
|
// Create tables
|
||||||
|
stmt.execute(createCustomersTable);
|
||||||
|
stmt.execute(createLoanHistoryTable);
|
||||||
|
|
||||||
|
System.out.println("Database schema initialized successfully");
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException("Failed to initialize database schema", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset database - drop all tables and recreate them
|
||||||
|
* Useful for testing scenarios
|
||||||
|
*/
|
||||||
|
public void resetDatabase() {
|
||||||
|
String dropCustomers = "DROP TABLE IF EXISTS customers";
|
||||||
|
String dropLoanHistory = "DROP TABLE IF EXISTS loan_history";
|
||||||
|
|
||||||
|
try (Connection conn = getConnection();
|
||||||
|
Statement stmt = conn.createStatement()) {
|
||||||
|
|
||||||
|
// Drop tables
|
||||||
|
stmt.execute(dropCustomers);
|
||||||
|
stmt.execute(dropLoanHistory);
|
||||||
|
|
||||||
|
System.out.println("Database tables dropped");
|
||||||
|
|
||||||
|
// Recreate tables
|
||||||
|
initializeSchema();
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException("Failed to reset database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test database connection
|
||||||
|
* @return true if connection is successful
|
||||||
|
*/
|
||||||
|
public boolean testConnection() {
|
||||||
|
try (Connection conn = getConnection()) {
|
||||||
|
return conn != null && !conn.isClosed();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
System.err.println("Database connection test failed: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close connection safely
|
||||||
|
* @param conn Connection to close
|
||||||
|
*/
|
||||||
|
public static void closeConnection(Connection conn) {
|
||||||
|
if (conn != null) {
|
||||||
|
try {
|
||||||
|
conn.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
System.err.println("Error closing connection: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,4 +6,9 @@
|
|||||||
implementation="com.example.service.HelloWorldServiceImpl"
|
implementation="com.example.service.HelloWorldServiceImpl"
|
||||||
url-pattern="/hello"/>
|
url-pattern="/hello"/>
|
||||||
|
|
||||||
|
<endpoint
|
||||||
|
name="LoanApprovalService"
|
||||||
|
implementation="com.example.service.LoanApprovalService"
|
||||||
|
url-pattern="/loan"/>
|
||||||
|
|
||||||
</endpoints>
|
</endpoints>
|
||||||
|
|||||||
@ -5,12 +5,19 @@
|
|||||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
||||||
version="4.0">
|
version="4.0">
|
||||||
|
|
||||||
<display-name>JAX-WS Hello World Service</display-name>
|
<display-name>JAX-WS Loan Approval Service</display-name>
|
||||||
|
|
||||||
|
<!-- Database Initialization Listener -->
|
||||||
|
<listener>
|
||||||
|
<listener-class>com.example.listener.DatabaseInitializationListener</listener-class>
|
||||||
|
</listener>
|
||||||
|
|
||||||
|
<!-- JAX-WS Context Listener -->
|
||||||
<listener>
|
<listener>
|
||||||
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
|
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
|
||||||
</listener>
|
</listener>
|
||||||
|
|
||||||
|
<!-- Hello World Service Servlet -->
|
||||||
<servlet>
|
<servlet>
|
||||||
<servlet-name>HelloWorldService</servlet-name>
|
<servlet-name>HelloWorldService</servlet-name>
|
||||||
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
|
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
|
||||||
@ -22,4 +29,16 @@
|
|||||||
<url-pattern>/hello</url-pattern>
|
<url-pattern>/hello</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<!-- Loan Approval Service Servlet -->
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>LoanApprovalService</servlet-name>
|
||||||
|
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
|
||||||
|
<load-on-startup>2</load-on-startup>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>LoanApprovalService</servlet-name>
|
||||||
|
<url-pattern>/loan</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
</web-app>
|
</web-app>
|
||||||
|
|||||||
Reference in New Issue
Block a user