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

41 KiB

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

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:

# 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:

REM Windows
run-tests.bat
run-coverage.bat
docker-compose up -d
# Linux/Mac
./run-tests.sh
./run-coverage.sh
docker-compose up -d

1. Start the Application

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:

3. View Application Logs

# 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

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

Pattern 1: Start Application Server

File: docker-compose.yml Purpose: Deploy and run the JAX-WS application on Tomcat

# 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:


Pattern 2: Run Unit Tests

File: docker-compose.test.yml Purpose: Execute JUnit tests and export results to ./target

# 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/

# 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.htmlOpen 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:

# 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:

REM Windows
run-tests.bat
run-coverage.bat

REM Then start server
docker-compose up -d
# 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:

# 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:

# 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.

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.

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

# 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:

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

    # 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:

cd scripts
pip install -r requirements.txt

Linux/Mac:

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

Run all tests in one go with the unified test script:

# 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
# 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
# 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:

# 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
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
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
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
  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:

# 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:

# 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:

# 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:

# 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:

# 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

For detailed test script documentation:

  • Script usage and options
  • Python client class examples
  • Advanced testing scenarios

See 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:

run-tests.bat

Linux/Mac:

./run-tests.sh

Docker Compose:

docker-compose -f docker-compose.test.yml up --build
docker-compose -f docker-compose.test.yml down

Generate Code Coverage Reports

Windows:

run-coverage.bat

Linux/Mac:

./run-coverage.sh

Docker Compose:

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:

# 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

- 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

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:

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

# Ensure test files end with Test.java
# Verify directory: src/test/java/
# Check pom.xml includes maven-surefire-plugin

Coverage Reports Not Generated

# 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)

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
Loan Approval 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:

# 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 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

# 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

# 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: