# JAX-WS Loan Approval System A complete JAX-WS SOAP web services application for loan processing, featuring customer registration, credit score evaluation, and loan approval workflows with SQLite database persistence. ## Project Details ### Overview This project demonstrates a production-ready JAX-WS web service implementation using Java 8, Maven, and Apache Tomcat. The system provides three main SOAP services: 1. **Hello World Service** - A simple demonstration service for testing SOAP connectivity 2. **Loan Approval Service** - Complete loan processing system with: - Customer registration with blacklist management - Automated credit score evaluation - Risk-based interest rate calculation - Loan application processing and approval workflows ### Technology Stack - **Java**: 1.8 (JDK 8) - **Web Services**: JAX-WS 2.3.1 (SOAP) - **Build Tool**: Apache Maven 3.x - **Application Server**: Apache Tomcat 9+ - **Database**: SQLite 3.43.0 - **Containerization**: Docker & Docker Compose - **Testing**: Python 3 with zeep library ### Key Features - **RESTful SOAP Services**: Industry-standard JAX-WS implementation - **Database Persistence**: SQLite database with automatic schema initialization - **Credit Risk Assessment**: Tiered approval logic based on credit scores - **Blacklist Management**: Customer screening and rejection system - **Docker Support**: Fully containerized with one-command deployment - **Comprehensive Testing**: Python test clients for all services - **Production-Ready**: Singleton patterns, prepared statements, error handling --- ## How to Run and Rebuild Using Docker Compose ### Prerequisites - [Docker Desktop](https://www.docker.com/products/docker-desktop/) (Windows/Mac) or [Docker Engine](https://docs.docker.com/engine/install/) (Linux) - Docker Compose (included with Docker Desktop) ### Quick Start #### 1. Start the Application ```bash docker-compose up -d ``` This command will: - Build the Docker image with Maven multi-stage build - Compile the Java application - Package it as a WAR file - Deploy to Tomcat - Start the container in detached mode **Wait 30-40 seconds for Tomcat to fully start** #### 2. Verify the Deployment Access the following URLs in your browser: - **Hello World WSDL**: http://localhost:8080/jaxws-hello-world/hello?wsdl - **Loan Service WSDL**: http://localhost:8080/jaxws-hello-world/loan?wsdl - **Tomcat Manager**: http://localhost:8080/manager (username: `admin`, password: `admin123`) #### 3. View Application Logs ```bash # Follow logs in real-time docker-compose logs -f # View recent logs docker-compose logs --tail=100 # View logs for specific service docker-compose logs jaxws-service ``` #### 4. Stop the Application ```bash docker-compose down ``` ### Rebuild After Code Changes When you modify the source code, rebuild and restart: ```bash # Rebuild and restart docker-compose up -d --build # Or rebuild without cache (clean build) docker-compose build --no-cache docker-compose up -d ``` ### Docker Commands Reference | Command | Description | |---------|-------------| | `docker-compose up -d` | Start services in detached mode | | `docker-compose up -d --build` | Rebuild and start services | | `docker-compose down` | Stop and remove containers | | `docker-compose logs -f` | Follow logs output | | `docker-compose ps` | List running containers | | `docker-compose restart` | Restart services | | `docker-compose exec jaxws-service bash` | Access container shell | ### Accessing the Database The SQLite database is mounted to the host machine and persists between container restarts: ```bash # Access database from host sqlite3 loan_app.db "SELECT * FROM customers;" # Or access from within container docker-compose exec jaxws-service sqlite3 /usr/local/tomcat/loan_app.db ``` ### Environment Configuration The `docker-compose.yml` includes these configurations: - **Port Mapping**: `8080:8080` (host:container) - **Memory Settings**: Xms256m, Xmx512m - **Health Check**: Automatic WSDL availability check every 30s - **Auto Restart**: Container restarts unless manually stopped - **Volume Mounts**: - `./logs:/usr/local/tomcat/logs` - Log persistence - `./loan_app.db:/usr/local/tomcat/loan_app.db` - Database persistence --- ## File Structure ``` jaxws-hello-world/ │ ├── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ ├── listener/ │ │ │ └── DatabaseInitializationListener.java # Application startup initialization │ │ │ │ │ ├── model/ # Data models (POJOs) │ │ │ ├── CustomerRegistrationRequest.java # Customer registration request │ │ │ ├── LoanRequest.java # Loan application request │ │ │ └── LoanResponse.java # Loan application response │ │ │ │ │ ├── repository/ # Data access layer │ │ │ ├── CustomerRepository.java # Customer DAO interface │ │ │ ├── LoanHistoryRepository.java # Loan history DAO interface │ │ │ └── impl/ │ │ │ ├── CustomerRepositoryImpl.java # Customer DAO implementation │ │ │ └── LoanHistoryRepositoryImpl.java # Loan history DAO implementation │ │ │ │ │ ├── service/ # Web service layer │ │ │ ├── HelloWorldService.java # Hello World interface │ │ │ ├── HelloWorldServiceImpl.java # Hello World implementation │ │ │ ├── LoanApprovalService.java # Loan service (interface + impl) │ │ │ └── CreditScoreService.java # Credit score evaluation │ │ │ │ │ └── util/ │ │ └── DatabaseManager.java # Singleton DB connection manager │ │ │ └── webapp/ │ └── WEB-INF/ │ ├── web.xml # Web application descriptor │ └── sun-jaxws.xml # JAX-WS endpoint configuration │ ├── scripts/ # Python test clients │ ├── test_all_services.py # Comprehensive test suite │ ├── test_hello_world.py # Hello World service tests │ ├── test_register_customer.py # Customer registration tests │ ├── simple_test.py # Quick smoke test │ └── README.md # Test scripts documentation │ ├── logs/ # Tomcat logs (Docker volume) │ ├── pom.xml # Maven project configuration ├── docker-compose.yml # Docker Compose orchestration ├── Dockerfile # Multi-stage Docker build ├── tomcat-users.xml # Tomcat manager users ├── loan_app.db # SQLite database (created on first run) ├── README.md # This file ├── apidoc.md # Complete API documentation ├── requirements.md # Project requirements specification ├── .dockerignore # Docker build exclusions └── .gitignore # Git exclusions ``` ### Architecture Layers #### 1. **Listener Layer** (`listener/`) - Application lifecycle management - Database schema initialization on startup - Connection validation #### 2. **Model Layer** (`model/`) - Plain Old Java Objects (POJOs) - Request/Response DTOs for web services - JAX-WS annotated data structures #### 3. **Repository Layer** (`repository/`) - Data access objects (DAO pattern) - Database CRUD operations - SQL query execution with prepared statements #### 4. **Service Layer** (`service/`) - JAX-WS web service endpoints - Business logic implementation - Credit score evaluation - Loan approval decision engine #### 5. **Utility Layer** (`util/`) - Singleton database connection manager - Reusable helper classes - Schema initialization and reset utilities --- ## Database Structure The application uses SQLite with the following schema: ### Database File - **Location**: `loan_app.db` (project root) - **Type**: SQLite 3 - **JDBC URL**: `jdbc:sqlite:loan_app.db` - **Initialization**: Automatic on application startup via `DatabaseInitializationListener` ### Schema #### Table: `customers` Stores registered customer information with blacklist status. ```sql CREATE TABLE customers ( customer_name TEXT PRIMARY KEY, is_blacklisted INTEGER DEFAULT 0, registered_at TEXT ); ``` **Column Details:** | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | `customer_name` | TEXT | PRIMARY KEY | Customer's unique name identifier | | `is_blacklisted` | INTEGER | DEFAULT 0 | Blacklist flag (0 = not blacklisted, 1 = blacklisted) | | `registered_at` | TEXT | NOT NULL | Registration timestamp (ISO 8601 format) | **Indexes:** - Primary key index on `customer_name` (automatic) **Business Rules:** - Customer names must be unique - Blacklisted customers cannot get loan approvals - Registration timestamp is automatically set during registration #### Table: `loan_history` Stores all loan application records for audit and reporting. ```sql CREATE TABLE loan_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, applicant_name TEXT, requested_amount INTEGER, approved INTEGER, approved_rate REAL, rejection_reason TEXT, processed_at TEXT ); ``` **Column Details:** | Column | Type | Constraints | Description | |--------|------|-------------|-------------| | `id` | INTEGER | PRIMARY KEY AUTOINCREMENT | Unique record identifier | | `applicant_name` | TEXT | | Applicant's name (may not be registered customer) | | `requested_amount` | INTEGER | | Loan amount requested in currency units | | `approved` | INTEGER | | Approval status (0 = rejected, 1 = approved) | | `approved_rate` | REAL | | Interest rate if approved (0.0 if rejected) | | `rejection_reason` | TEXT | NULL | Reason for rejection (NULL if approved) | | `processed_at` | TEXT | NOT NULL | Processing timestamp (ISO 8601 format) | **Indexes:** - Primary key index on `id` (automatic) **Business Rules:** - Every loan application is logged regardless of approval status - Approved loans have `approved=1` and `rejection_reason=NULL` - Rejected loans have `approved=0` and populated `rejection_reason` - Timestamp is automatically set during processing ### Credit Score Tiers & Interest Rates The loan approval logic uses the following credit score tiers: | Credit Score Range | Approval Status | Interest Rate | Rejection Reason | |-------------------|-----------------|---------------|------------------| | **>= 700** | ✅ Approved | 3.5% | - | | **600 - 699** | ✅ Approved | 5.5% | - | | **500 - 599** | ✅ Approved | 8.5% | - | | **< 500** | ❌ Rejected | - | "Credit score too low" | | **Blacklisted** | ❌ Rejected | - | "Applicant is blacklisted" | ### Database Operations #### Manual Database Access ```bash # View all customers sqlite3 loan_app.db "SELECT * FROM customers;" # View all loan applications sqlite3 loan_app.db "SELECT * FROM loan_history;" # View approved loans only sqlite3 loan_app.db "SELECT * FROM loan_history WHERE approved = 1;" # View rejected loans with reasons sqlite3 loan_app.db "SELECT applicant_name, rejection_reason FROM loan_history WHERE approved = 0;" # Count customers by blacklist status sqlite3 loan_app.db "SELECT is_blacklisted, COUNT(*) FROM customers GROUP BY is_blacklisted;" # View loan approval rate sqlite3 loan_app.db "SELECT COUNT(*) as total, SUM(approved) as approved, ROUND(CAST(SUM(approved) AS FLOAT) / COUNT(*) * 100, 2) as approval_rate FROM loan_history;" ``` #### Database Reset (Testing) The `DatabaseManager` class provides a reset method for testing: ```java DatabaseManager.getInstance().resetDatabase(); ``` This will: 1. Drop all tables 2. Recreate the schema 3. Clear all data --- ## How to Run Tests ### Prerequisites Before running tests, ensure: 1. **Service is Running** ```bash # Start the service docker-compose up -d # Wait 30-40 seconds, then verify curl http://localhost:8080/jaxws-hello-world/hello?wsdl ``` 2. **Python Environment** - Python 3.6 or higher - pip (Python package installer) ### Step 1: Install Test Dependencies Navigate to the scripts directory and install dependencies: **Windows:** ```cmd cd scripts pip install -r requirements.txt ``` **Linux/Mac:** ```bash cd scripts pip3 install -r requirements.txt ``` **Required Python Package:** - `requests>=2.31.0` - HTTP library for SOAP requests ### Step 2: Choose Your Test Approach #### Option 1: Comprehensive Test Suite (Recommended) Run all tests in one go with the unified test script: ```bash # Windows python test_all_services.py # Linux/Mac python3 test_all_services.py ``` **What it tests:** - ✅ Hello World Service (2 test cases) - ✅ Customer Registration (4 test cases with validation) - ✅ Loan Application Processing (14 test cases covering all scenarios) - ✅ WSDL availability checks - ✅ Error handling and edge cases **Expected Output:** ``` ================================================================================ JAX-WS UNIFIED TEST CLIENT ================================================================================ Testing all services and operations Checking services availability... Hello World Service: Service is accessible Loan Approval Service: Service is accessible ================================================================================ AUTOMATED TEST SUITE ================================================================================ -------------------------------------------------------------------------------- 1. Testing Hello World Service -------------------------------------------------------------------------------- ✓ PASS | getHelloWorld('John') - Should return greeting Hello World, John! ✓ PASS | getHelloWorld('Alice') - Should return greeting Hello World, Alice! -------------------------------------------------------------------------------- 2. Testing Customer Registration Service -------------------------------------------------------------------------------- ✓ PASS | registerNewCustomer('Alice Johnson', blacklisted=False) Registration Successful ✓ PASS | registerNewCustomer('Bob Smith', blacklisted=False) Registration Successful ✓ PASS | registerNewCustomer('Charlie Brown', blacklisted=True) Registration Successful ✓ PASS | registerNewCustomer('Alice Johnson', blacklisted=False) - Duplicate Error: Customer already exists -------------------------------------------------------------------------------- 3. Testing Loan Application Processing Service -------------------------------------------------------------------------------- ✓ PASS | processLoanApplication('Alice Johnson', $50000, score=750) approved: True | rate: 3.5% | Loan approved with excellent rate ✓ PASS | processLoanApplication('Bob Smith', $30000, score=650) approved: True | rate: 5.5% | Loan approved with standard rate ✓ PASS | processLoanApplication('New Customer', $25000, score=550) approved: True | rate: 8.5% | Loan approved with high risk rate ✓ PASS | processLoanApplication('Poor Credit', $20000, score=450) approved: False | Credit score too low ✓ PASS | processLoanApplication('Charlie Brown', $40000, score=700) approved: False | Applicant is blacklisted ================================================================================ TEST SUMMARY ================================================================================ Total Tests: 20 Passed: 20 Failed: 0 Success Rate: 100.0% Would you like to enter interactive mode? (y/n): ``` **Interactive Mode:** After automated tests, you can enter interactive mode for manual testing: ``` Available commands: hello - Test Hello World service register - Register regular customer blacklist - Register blacklisted customer loan - Process loan application quit - Exit > hello TestUser Response: Hello World, TestUser! > register John Doe Result: Registration Successful > loan John Doe 50000 720 Result: approved: True approvedRate: 3.5 message: Loan approved with excellent rate > quit ``` #### Option 2: Individual Test Scripts Test specific services individually: ##### A. Hello World Service Test ```bash # Windows python test_hello_world.py # Linux/Mac python3 test_hello_world.py ``` Tests the basic Hello World SOAP service with predefined test cases and interactive mode. ##### B. Customer Registration Test ```bash # Windows python test_register_customer.py # Linux/Mac python3 test_register_customer.py ``` Tests customer registration including: - Regular customer registration - Blacklisted customer registration - Duplicate registration handling - Interactive registration mode ##### C. Simple Smoke Test Quick test for CI/CD pipelines: ```bash # Windows python simple_test.py "Test Name" # Linux/Mac python3 simple_test.py "Test Name" ``` Returns exit code 0 on success, 1 on failure. #### Option 3: Manual Testing with cURL Test services directly using cURL commands: ##### Test Hello World Service ```bash curl -X POST http://localhost:8080/jaxws-hello-world/hello \ -H "Content-Type: text/xml; charset=utf-8" \ -H "SOAPAction: " \ -d ' TestUser ' ``` ##### Test Customer Registration ```bash curl -X POST http://localhost:8080/jaxws-hello-world/loan \ -H "Content-Type: text/xml; charset=utf-8" \ -H "SOAPAction: " \ -d ' John Doe false ' ``` ##### Test Loan Application ```bash curl -X POST http://localhost:8080/jaxws-hello-world/loan \ -H "Content-Type: text/xml; charset=utf-8" \ -H "SOAPAction: " \ -d ' John Doe 50000 720 ' ``` #### Option 4: Testing with SoapUI 1. Download and install [SoapUI](https://www.soapui.org/downloads/soapui/) 2. Create a new SOAP project 3. Import WSDL URLs: - **Hello World**: `http://localhost:8080/jaxws-hello-world/hello?wsdl` - **Loan Approval**: `http://localhost:8080/jaxws-hello-world/loan?wsdl` 4. SoapUI automatically generates request templates 5. Fill in parameters and execute requests ### Step 3: Verify Database Records After running tests, verify data was persisted: ```bash # View registered customers sqlite3 loan_app.db "SELECT * FROM customers;" # View loan application history sqlite3 loan_app.db "SELECT * FROM loan_history;" # View approved loans with rates sqlite3 loan_app.db " SELECT applicant_name, requested_amount, approved_rate FROM loan_history WHERE approved = 1;" # View rejection reasons sqlite3 loan_app.db " SELECT applicant_name, rejection_reason FROM loan_history WHERE approved = 0;" ``` ### Troubleshooting Tests #### Service Not Available **Error:** `Connection refused` or `Failed to establish connection` **Solutions:** ```bash # Check if container is running docker-compose ps # Check container logs docker-compose logs -f # Restart the service docker-compose restart # Verify WSDL is accessible curl http://localhost:8080/jaxws-hello-world/hello?wsdl ``` #### Python Command Not Found **Error:** `python: command not found` **Solutions:** - **Windows**: Try `py` or `python3` - **Linux/Mac**: Use `python3` instead of `python` - **Check installation**: `python --version` or `python3 --version` #### Dependencies Installation Failed **Error:** `Could not install packages` **Solutions:** ```bash # Upgrade pip python -m pip install --upgrade pip # Use virtual environment (recommended) python -m venv venv # Windows venv\Scripts\activate # Linux/Mac source venv/bin/activate # Install dependencies in venv pip install -r requirements.txt ``` #### Port Already in Use **Error:** `Port 8080 already in use` **Solutions:** ```bash # Windows - Find process using port netstat -ano | findstr :8080 # Linux/Mac - Find process using port lsof -i :8080 # Kill the process or change docker-compose port mapping ``` #### Database Locked **Error:** `database is locked` **Solutions:** ```bash # Stop all running tests # Restart the service docker-compose restart # If persists, reset database rm loan_app.db docker-compose restart ``` ### Test Coverage The comprehensive test suite covers: | Category | Test Cases | Coverage | |----------|-----------|----------| | Hello World Service | 2 | Basic functionality, edge cases | | Customer Registration | 4 | Regular, blacklisted, duplicates, validation | | Loan Processing - Approvals | 7 | All credit score tiers (3.5%, 5.5%, 8.5%) | | Loan Processing - Rejections | 5 | Low credit, blacklisted, validation errors | | WSDL Availability | 2 | Both service endpoints | | **Total** | **20** | **Full workflow coverage** | ### API Documentation For detailed API documentation including: - Complete SOAP request/response examples - All service operations and parameters - Error handling and SOAP faults - Business logic and validation rules - Production testing considerations See [apidoc.md](apidoc.md) For detailed test script documentation: - Script usage and options - Python client class examples - Advanced testing scenarios See [scripts/README.md](scripts/README.md) --- ## Service Endpoints Once running, the following endpoints are available: | Service | Endpoint | WSDL | |---------|----------|------| | Hello World | http://localhost:8080/jaxws-hello-world/hello | [WSDL](http://localhost:8080/jaxws-hello-world/hello?wsdl) | | Loan Approval | http://localhost:8080/jaxws-hello-world/loan | [WSDL](http://localhost:8080/jaxws-hello-world/loan?wsdl) | | Tomcat Manager | http://localhost:8080/manager | admin/admin123 | --- ## Development ### Building Locally (without Docker) **Prerequisites:** - Java JDK 8+ - Apache Maven 3.6+ - Apache Tomcat 9+ **Build Commands:** ```bash # Clean and build mvn clean package # The WAR file will be created at: # target/jaxws-hello-world.war # Deploy to Tomcat webapps directory cp target/jaxws-hello-world.war $CATALINA_HOME/webapps/ ``` ### Project Dependencies See [pom.xml](pom.xml) for complete dependency list: - `javax.xml.ws:jaxws-api:2.3.1` - JAX-WS API - `com.sun.xml.ws:jaxws-rt:2.3.3` - JAX-WS Runtime - `javax.servlet:javax.servlet-api:4.0.1` - Servlet API - `org.xerial:sqlite-jdbc:3.43.0.0` - SQLite JDBC Driver --- ## Production Considerations ### Security ⚠️ **This is a demonstration project. For production use:** - Implement WS-Security for authentication - Use HTTPS/TLS for all communications - Add input sanitization beyond current validation - Implement rate limiting - Add audit logging for sensitive operations - Store credentials in secure vault (not in `tomcat-users.xml`) ### Database - Consider PostgreSQL or MySQL for production workloads - Implement connection pooling (HikariCP, c3p0) - Add database backup strategy - Implement database migration tool (Flyway, Liquibase) ### Performance - The current `CreditScoreService` returns a fixed value (700) - Integrate with real credit bureau APIs for production - Add caching layer for credit scores - Implement request/response logging - Add monitoring and metrics (Prometheus, Grafana) --- ## Troubleshooting ### Container won't start ```bash # Check container logs docker-compose logs # Check if port 8080 is already in use netstat -ano | findstr :8080 # Windows lsof -i :8080 # Linux/Mac # Remove and rebuild docker-compose down docker-compose up -d --build ``` ### Database errors ```bash # Check database file permissions ls -la loan_app.db # Reset database (will delete all data) rm loan_app.db docker-compose restart ``` ### WSDL not accessible - Wait 30-40 seconds for Tomcat to fully start - Check logs: `docker-compose logs -f` - Verify container is running: `docker-compose ps` --- ## License This is a demonstration project for educational purposes. --- ## Support For issues, questions, or contributions: - Review the [API Documentation](apidoc.md) - Check the [Requirements Specification](requirements.md) - Review test scripts in [scripts/README.md](scripts/README.md)