Files
jaxwsdemo/README.md
2025-12-05 11:49:01 +01:00

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

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

Quick Start

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

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

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:

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

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


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: