Files
jaxwsdemo/README.md
2025-12-05 18:51:13 +01:00

1406 lines
41 KiB
Markdown

# 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.
## Quick Reference Card
### 🚀 Three Ways to Use This Project
| Task | Command | Result |
|------|---------|--------|
| **Run Tests** | `docker-compose -f docker-compose.test.yml up --build` | Tests run, results in `./target/surefire-reports/` |
| **Generate Coverage** | `docker-compose -f docker-compose.coverage.yml up --build` | Coverage report in `./target/site/jacoco/index.html` |
| **Start Server** | `docker-compose up -d` | Server running at http://localhost:8080 |
### 📝 Convenience Scripts
| Platform | Run Tests | Generate Coverage |
|----------|-----------|-------------------|
| **Windows** | `run-tests.bat` | `run-coverage.bat` |
| **Linux/Mac** | `./run-tests.sh` | `./run-coverage.sh` |
---
## 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
- **Unit Testing**: JUnit 5 (Jupiter), Mockito, JaCoCo
- **Integration Testing**: Python 3 with requests 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
- **Unit Testing**: JUnit 5 tests with JaCoCo code coverage
- **Integration 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
#### Three Docker Compose Configurations
This project provides three Docker Compose files for different purposes:
| Purpose | File | Command | Output Location |
|---------|------|---------|----------------|
| **🚀 Start Server** | `docker-compose.yml` | `docker-compose up -d` | http://localhost:8080 |
| **✅ Run Tests** | `docker-compose.test.yml` | `docker-compose -f docker-compose.test.yml up --build` | `./target/surefire-reports/` |
| **📊 Coverage Report** | `docker-compose.coverage.yml` | `docker-compose -f docker-compose.coverage.yml up --build` | `./target/site/jacoco/index.html` |
**Visual Workflow:**
```
┌─────────────────────────────────────────────────────────────────┐
│ Development Workflow │
└─────────────────────────────────────────────────────────────────┘
1. Write Code
┌─────────────────────────┐
│ Run Unit Tests │ ──► docker-compose -f docker-compose.test.yml up --build
│ (docker-compose.test) │
└──────────┬──────────────┘
│ Tests Pass ✓
┌─────────────────────────┐
│ Generate Coverage │ ──► docker-compose -f docker-compose.coverage.yml up --build
│ (docker-compose.coverage│
└──────────┬──────────────┘ Open: ./target/site/jacoco/index.html
│ Coverage OK ✓
┌─────────────────────────┐
│ Deploy Application │ ──► docker-compose up -d
│ (docker-compose.yml) │
└──────────┬──────────────┘ Access: http://localhost:8080
Production Ready!
```
**Quick Commands:**
```bash
# Run all tests
docker-compose -f docker-compose.test.yml up --build && docker-compose -f docker-compose.test.yml down
# Generate coverage report
docker-compose -f docker-compose.coverage.yml up --build && docker-compose -f docker-compose.coverage.yml down
# Start application server
docker-compose up -d
```
**Or use convenience scripts:**
```cmd
REM Windows
run-tests.bat
run-coverage.bat
docker-compose up -d
```
```bash
# Linux/Mac
./run-tests.sh
./run-coverage.sh
docker-compose up -d
```
---
#### 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
```
---
### Docker Compose Patterns
This project includes three Docker Compose configurations for different purposes.
> **📖 For detailed patterns, workflows, and troubleshooting, see [DOCKER_COMPOSE_GUIDE.md](DOCKER_COMPOSE_GUIDE.md)**
#### Pattern 1: Start Application Server
**File**: `docker-compose.yml`
**Purpose**: Deploy and run the JAX-WS application on Tomcat
```bash
# Start the server in detached mode
docker-compose up -d
# Start with build (after code changes)
docker-compose up -d --build
# View logs in real-time
docker-compose logs -f
# Stop the server
docker-compose down
```
**What happens:**
1. Runs unit tests (Stage 1: tester)
2. Builds WAR file (Stage 2: builder)
3. Deploys to Tomcat (Stage 3)
4. Exposes port 8080
5. Creates/persists SQLite database
**Access points:**
- Hello World Service: http://localhost:8080/jaxws-hello-world/hello?wsdl
- Loan Service: http://localhost:8080/jaxws-hello-world/loan?wsdl
- Tomcat Manager: http://localhost:8080/manager (admin/admin123)
---
#### Pattern 2: Run Unit Tests
**File**: `docker-compose.test.yml`
**Purpose**: Execute JUnit tests and export results to `./target`
```bash
# Run tests
docker-compose -f docker-compose.test.yml up --build
# Run tests in background
docker-compose -f docker-compose.test.yml up -d
# View test output
docker-compose -f docker-compose.test.yml logs
# Clean up
docker-compose -f docker-compose.test.yml down
```
**What happens:**
1. Builds test environment (tester stage)
2. Runs `mvn test`
3. Executes all *Test.java files
4. Exports test reports to `./target/surefire-reports/`
5. Exports coverage data to `./target/jacoco.exec`
**Test results location:**
- Console output: Test summary with pass/fail counts
- Reports: `./target/surefire-reports/` (text and XML)
**Example output:**
```
Tests run: 10, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
```
---
#### Pattern 3: Generate Code Coverage Report
**File**: `docker-compose.coverage.yml`
**Purpose**: Run tests and generate JaCoCo coverage reports in `./target/site/jacoco/`
```bash
# Generate coverage reports
docker-compose -f docker-compose.coverage.yml up --build
# Generate coverage in background
docker-compose -f docker-compose.coverage.yml up -d
# View coverage generation logs
docker-compose -f docker-compose.coverage.yml logs
# Clean up
docker-compose -f docker-compose.coverage.yml down
```
**What happens:**
1. Builds test environment
2. Runs `mvn test` with JaCoCo agent
3. Generates coverage reports in multiple formats
4. Exports to `./target/site/jacoco/`
**Coverage reports location:**
- **HTML Report**: `./target/site/jacoco/index.html`**Open this in browser**
- **XML Report**: `./target/site/jacoco/jacoco.xml` (for CI/CD)
- **CSV Report**: `./target/site/jacoco/jacoco.csv` (for spreadsheets)
**Example output:**
```
=================================================================================
Coverage report generated successfully!
=================================================================================
HTML Report: ./target/site/jacoco/index.html
XML Report: ./target/site/jacoco/jacoco.xml
CSV Report: ./target/site/jacoco/jacoco.csv
=================================================================================
```
---
### Complete Workflow Example
Here's a typical development workflow using all three patterns:
```bash
# 1. Run tests to ensure code works
docker-compose -f docker-compose.test.yml up --build
docker-compose -f docker-compose.test.yml down
# 2. Generate coverage report to check test quality
docker-compose -f docker-compose.coverage.yml up --build
docker-compose -f docker-compose.coverage.yml down
# 3. View coverage report
# Open target/site/jacoco/index.html in browser
# 4. Deploy application if tests pass
docker-compose up -d --build
# 5. Verify deployment
curl http://localhost:8080/jaxws-hello-world/hello?wsdl
# 6. View application logs
docker-compose logs -f
# 7. Stop when done
docker-compose down
```
---
### Quick Reference Scripts
For convenience, use the provided scripts instead of typing full commands:
| Task | Windows | Linux/Mac | Docker Compose Equivalent |
|------|---------|-----------|--------------------------|
| Run Tests | `run-tests.bat` | `./run-tests.sh` | `docker-compose -f docker-compose.test.yml up --build` |
| Generate Coverage | `run-coverage.bat` | `./run-coverage.sh` | `docker-compose -f docker-compose.coverage.yml up --build` |
| Start Server | N/A | N/A | `docker-compose up -d` |
**Example:**
```cmd
REM Windows
run-tests.bat
run-coverage.bat
REM Then start server
docker-compose up -d
```
```bash
# Linux/Mac
./run-tests.sh
./run-coverage.sh
# Then start server
docker-compose up -d
```
---
### 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
#### Application Server Commands
| Command | Description |
|---------|-------------|
| `docker-compose up -d` | Start application server in detached mode |
| `docker-compose up -d --build` | Rebuild and start application server |
| `docker-compose down` | Stop and remove application containers |
| `docker-compose logs -f` | Follow application logs in real-time |
| `docker-compose ps` | List running containers |
| `docker-compose restart` | Restart application services |
| `docker-compose exec jaxws-service bash` | Access application container shell |
#### Test Commands
| Command | Description |
|---------|-------------|
| `docker-compose -f docker-compose.test.yml up --build` | Run unit tests |
| `docker-compose -f docker-compose.test.yml logs` | View test output |
| `docker-compose -f docker-compose.test.yml down` | Clean up test containers |
#### Coverage Commands
| Command | Description |
|---------|-------------|
| `docker-compose -f docker-compose.coverage.yml up --build` | Generate coverage reports |
| `docker-compose -f docker-compose.coverage.yml logs` | View coverage generation logs |
| `docker-compose -f docker-compose.coverage.yml down` | Clean up coverage containers |
### 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
│ │
│ └── test/
│ └── java/
│ └── com/
│ └── example/
│ └── service/
│ └── HelloWorldServiceImplTest.java # Unit tests for Hello World service
├── 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)
├── target/ # Build output (generated)
│ ├── site/jacoco/ # Code coverage reports
│ │ ├── index.html # HTML coverage report
│ │ ├── jacoco.xml # XML coverage report
│ │ └── jacoco.csv # CSV coverage report
│ └── surefire-reports/ # Test execution reports
├── pom.xml # Maven project configuration
├── docker-compose.yml # Docker Compose orchestration
├── docker-compose.test.yml # Docker Compose for unit tests
├── docker-compose.coverage.yml # Docker Compose for coverage
├── Dockerfile # Multi-stage Docker build
├── Dockerfile.coverage.simple # Dockerfile for coverage
├── tomcat-users.xml # Tomcat manager users
├── loan_app.db # SQLite database (created on first run)
├── run-tests.bat # Windows test runner script
├── run-tests.sh # Linux/Mac test runner script
├── run-coverage.bat # Windows coverage script
├── run-coverage.sh # Linux/Mac coverage script
├── README.md # This file
├── DOCKER_COMPOSE_GUIDE.md # Docker Compose patterns reference
├── 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 <name> - Test Hello World service
register <name> - Register regular customer
blacklist <name> - Register blacklisted customer
loan <name> <amount> <credit_score> - 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 '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:getHelloWorld>
<arg0>TestUser</arg0>
</ser:getHelloWorld>
</soapenv:Body>
</soapenv:Envelope>'
```
##### 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 '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:registerNewCustomer>
<arg0>
<customerName>John Doe</customerName>
<blacklisted>false</blacklisted>
</arg0>
</ser:registerNewCustomer>
</soapenv:Body>
</soapenv:Envelope>'
```
##### 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 '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:processLoanApplication>
<arg0>
<applicantName>John Doe</applicantName>
<requestedAmount>50000</requestedAmount>
<creditScore>720</creditScore>
</arg0>
</ser:processLoanApplication>
</soapenv:Body>
</soapenv:Envelope>'
```
#### 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)
---
## Unit Tests and Code Coverage
### Overview
This project includes comprehensive unit testing with JUnit 5 and code coverage analysis with JaCoCo. All test results and coverage reports are automatically exported to the `./target` directory for easy access.
### Quick Start
#### Run Unit Tests
**Windows:**
```cmd
run-tests.bat
```
**Linux/Mac:**
```bash
./run-tests.sh
```
**Docker Compose:**
```bash
docker-compose -f docker-compose.test.yml up --build
docker-compose -f docker-compose.test.yml down
```
#### Generate Code Coverage Reports
**Windows:**
```cmd
run-coverage.bat
```
**Linux/Mac:**
```bash
./run-coverage.sh
```
**Docker Compose:**
```bash
docker-compose -f docker-compose.coverage.yml up --build
docker-compose -f docker-compose.coverage.yml down
```
### Coverage Reports
All coverage reports are generated in `./target/site/jacoco/`:
- **HTML Report**: `target/site/jacoco/index.html` (open in browser)
- **XML Report**: `target/site/jacoco/jacoco.xml` (for CI/CD tools)
- **CSV Report**: `target/site/jacoco/jacoco.csv` (for spreadsheets)
### Test Framework
The project uses:
- **JUnit 5 (Jupiter)** - Modern testing framework with annotations
- **Mockito** - Mocking framework for complex test scenarios
- **JaCoCo** - Code coverage analysis and reporting
- **Maven Surefire** - Test execution plugin
### Current Test Coverage
| Service | Test Class | Test Cases | Status |
|---------|-----------|------------|--------|
| Hello World Service | HelloWorldServiceImplTest | 10 | ✅ Passing |
### Understanding Coverage Reports
**Coverage Metrics:**
- **Line Coverage**: Percentage of executable lines tested
- **Branch Coverage**: Percentage of decision points (if/else) tested
- **Method Coverage**: Percentage of methods invoked during tests
- **Class Coverage**: Percentage of classes with at least one test
**Coverage Goals:**
- Line Coverage: > 80%
- Branch Coverage: > 70%
- Method Coverage: > 85%
### Running Tests with Maven (Local)
If you have Maven installed locally:
```bash
# Run tests only
mvn test
# Run tests with coverage
mvn clean test
# View coverage report
# Open target/site/jacoco/index.html in your browser
```
### CI/CD Integration
#### GitHub Actions Example
```yaml
- name: Run tests with coverage
run: mvn clean test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: ./target/site/jacoco/jacoco.xml
```
#### Jenkins Example
```groovy
stage('Test') {
steps {
sh 'mvn clean test'
jacoco(
execPattern: 'target/jacoco.exec',
classPattern: 'target/classes',
sourcePattern: 'src/main/java'
)
}
}
```
### Writing New Tests
Create test classes in `src/test/java/` following this pattern:
```java
package com.example.service;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import static org.junit.jupiter.api.Assertions.*;
@DisplayName("Your Service Tests")
class YourServiceTest {
private YourService service;
@BeforeEach
void setUp() {
service = new YourServiceImpl();
}
@Test
@DisplayName("Should do something")
void testSomething() {
// Arrange
String input = "test";
String expected = "result";
// Act
String result = service.doSomething(input);
// Assert
assertEquals(expected, result);
}
}
```
### Troubleshooting
#### Tests Not Running
```bash
# Ensure test files end with Test.java
# Verify directory: src/test/java/
# Check pom.xml includes maven-surefire-plugin
```
#### Coverage Reports Not Generated
```bash
# Ensure JaCoCo plugin is in pom.xml
mvn clean test
# Or use Docker
docker-compose -f docker-compose.coverage.yml up --build
```
#### Permission Issues (Linux/Mac)
```bash
chmod +x run-tests.sh
chmod +x run-coverage.sh
```
---
## 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)