๐ŸŽฏ What You'll Learn

  • How Dione's modular monolith actually works
  • Real vs. intended architecture patterns
  • Data flow through the system layers
  • External system integration reality
  • Why certain architectural decisions were made

The Real Architecture

โš ๏ธ Reality Check

This is NOT a microservices architecture. It's a modular monolith with SOAP-based web services. Understanding this is crucial to being productive.

High-Level Architecture Diagram

Actual System Architecture
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   Customer      โ”‚    โ”‚   Admin         โ”‚    โ”‚   Etailer       โ”‚
โ”‚   Portal        โ”‚    โ”‚   Portal        โ”‚    โ”‚   Portal        โ”‚
โ”‚   (JSP/jQuery)  โ”‚    โ”‚   (JSP/jQuery)  โ”‚    โ”‚   (JSP/jQuery)  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚                       โ”‚                       โ”‚
         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ”‚
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚        SOAP Web Services             โ”‚
              โ”‚    (Apache CXF + Spring)            โ”‚
              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ”‚
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚     Business Logic Layer            โ”‚
              โ”‚   (Handlers + Processors)           โ”‚
              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ”‚
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚    Data Transformation              โ”‚
              โ”‚      (Transformers)                 โ”‚
              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ”‚
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚      Data Access Layer              โ”‚
              โ”‚    (JPA/Hibernate + DAOs)           โ”‚
              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ”‚
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚   SQL Server    โ”‚   Infinispan    โ”‚   External      โ”‚
    โ”‚   Database      โ”‚   Cache         โ”‚   Systems       โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Key Architectural Principles

๐Ÿ—๏ธ

Modular Monolith

Single deployment with clear module boundaries. Not microservices, but well-organized code.

๐Ÿข

Multi-Tenant

Single codebase serves multiple organizations with data isolation by Organization ID.

๐Ÿงผ

SOAP-First

All APIs are SOAP-based using Apache CXF. No REST endpoints exist.

๐Ÿ”„

Layered Architecture

Clear separation: Web โ†’ Services โ†’ Handlers โ†’ Transformers โ†’ DAOs โ†’ Database

Module Structure Reality

Development/Codebase/
Dione/Development/Codebase/
โ”œโ”€โ”€ pom.xml                    # Parent POM (Maven 3.6+)
โ”œโ”€โ”€ ngop.properties           # Main configuration (the heart of everything)
โ”œโ”€โ”€ services/                 # Business logic modules
โ”‚   โ”œโ”€โ”€ business/            # Core business services  
โ”‚   โ””โ”€โ”€ dioneservices/       # Service orchestration
โ”œโ”€โ”€ customer_portal/         # Customer-facing web app
โ”œโ”€โ”€ schema/                  # Database scripts
โ””โ”€โ”€ source_mapper/          # Data mapping utilities

Module Responsibilities

Services/Business Module

This is where the real work happens:

  • Web Services: SOAP endpoints for all functionality
  • Business Logic: Handlers containing business rules
  • Data Access: JPA entities and DAO implementations
  • External Integration: Touchpoints to external systems
services/business/WebContent/WEB-INF/service-definition-beans.xml
<!-- Authentication & Session Management -->
<jaxws:endpoint id="auth" 
    implementor="com.currenciesdirect.gtg.ngop.business.services.auth.AuthServiceIMPL"
    address="/authServices" />

<!-- Customer Management -->
<jaxws:endpoint id="customer"
    implementor="com.currenciesdirect.gtg.ngop.business.services.customer.CustomerManagementIMPL"
    address="/customerServices" />

<!-- Payment Processing -->
<jaxws:endpoint id="payment"
    implementor="com.currenciesdirect.gtg.ngop.business.services.pfx.payment.PaymentManagementIMPL"
    address="/paymentServices" />

Customer Portal Module

Traditional web application with:

  • JSP Pages: Server-side rendered views
  • Spring MVC Controllers: Web request handlers
  • Service Invokers: SOAP client wrappers
  • jQuery Frontend: Client-side interactions

๐Ÿ’ก Why This Architecture?

This architecture was chosen because:

  • Financial Compliance: Easier to audit monolithic systems
  • Transaction Consistency: ACID properties across operations
  • Team Size: Small team could manage everything
  • Technology Maturity: SOAP was the enterprise standard

Data Flow Pattern

Every request follows this exact pattern. Understanding this is key to debugging issues:

Complete Request Flow
// 1. Web Controller (CustomerPortal)
@Controller
public class LoginController {
    @RequestMapping("/login.htm")
    public ModelAndView login(HttpServletRequest request) {
        // Controller logic
        return serviceInvoker.callLoginService(request);
    }
}

// 2. Service Invoker (SOAP Call)
LoginControllerService.loginCustomer()
    โ†“
// 3. Business Service (SOAP Implementation)  
AuthServiceIMPL.login()
    โ†“
// 4. Business Handler
LoginAndProfileHandlerImpl.createNGOPSession()
    โ†“
// 5. Data Access
NGOPCusDaoImpl.getCustomerByEmail()
    โ†“
// 6. Database Query (JPA)
entityManager.createQuery(SqlServerQueries.LOOKUP_CUSTOMER_BY_EMAIL)

Layer Responsibilities

Layer Purpose Technologies Location
Web Controllers HTTP request handling Spring MVC customer_portal/
Service Invokers SOAP client wrappers Apache CXF customer_portal/
Web Services SOAP endpoints JAX-WS + CXF services/business/
Business Handlers Business logic Spring Beans services/business/
Transformers Data conversion Custom mappers services/business/
DAOs Data access JPA/Hibernate services/business/

Real Data Flow Example

Customer Login Flow
// 1. User submits login form
POST /CustomerPortal/login.htm
{
    email: "user@example.com",
    password: "password123",
    orgCode: "CD"
}

// 2. LoginController processes request
@RequestMapping("/login.htm")
public ModelAndView login(HttpServletRequest request) {
    AuthRequest authRequest = buildAuthRequest(request);
    AuthResponse response = loginControllerService.loginCustomer(authRequest);
    return new ModelAndView("dashboard", "user", response.getUser());
}

// 3. Service Invoker calls SOAP service
public AuthResponse loginCustomer(AuthRequest request) {
    WSAuth authService = getAuthService();
    Holder<ResponseStatusHeader> statusHeader = new Holder<>();
    return authService.login(statusHeader, request, "en", "WEB");
}

// 4. AuthServiceIMPL processes login
@WebService
public class AuthServiceIMPL implements WSAuth {
    public AuthResponse login(Holder<ResponseStatusHeader> responseStatusHeader,
                             AuthRequest authRequest, String locale, String source) {
        
        // Business logic delegation
        PojoMap sessionData = loginAndProfileHandlerRef.createNGOPSession(
            responseStatusHeader, authRequest, locale, source);
        
        // Build response
        AuthResponse response = new AuthResponse();
        response.setSessionID(sessionData.getString("sessionID"));
        response.setCustomerID(sessionData.getInteger("customerID"));
        return response;
    }
}

// 5. Handler implements business logic
public PojoMap createNGOPSession(Holder<ResponseStatusHeader> responseStatusHeader,
                                AuthRequest authRequest, String locale, String source) {
    
    // Get customer from database
    Customer customer = nGOPCusDaoRef.getCustomerByEmail(
        authRequest.getEmail(), getOrganizationId(authRequest.getOrgCode()));
    
    // Verify password
    if (!verifyPassword(customer, authRequest.getPassword())) {
        throw new NGOPBaseException("Invalid credentials");
    }
    
    // Create session
    String sessionId = SessionManager.createSessionId();
    PojoMap sessionData = SessionManager.createSessionData(customer, authRequest.getOrgCode());
    
    // Store in cache
    cacheDataConsumer.put(sessionId, sessionData, SESSION_TIMEOUT);
    
    return sessionData;
}

External System Integration

Dione integrates with numerous external systems. Understanding these integrations is crucial for debugging:

Core External Systems

ngop.properties - External Integrations
# Salesforce CRM
ngop.sf.connectionurl=https://test.salesforce.com/services/Soap/c/38.0

# Pricing Engine  
pe.serivce.host=172.31.4.4
pe.serivce.url.template=http://%s:%s/PricingEngine/%s?WSDL

# Communication Hub
commhub.service.url=http://sitcommhub.currenciesdirect.com/commhub/

# Titan Payment System
titan.service.url=http://172.31.2.129:8080/titan-wrapper/services/

# Rate Alert Service
ratealert.service.rest.url=https://sitpe.currenciesdirect.com/RateAlert/rest/

Integration Architecture Pattern

All external calls go through "Touchpoint" classes that handle:

  • Connection Management: HTTP clients and connection pooling
  • Error Handling: Timeouts, retries, circuit breakers
  • Data Transformation: Request/response mapping
  • Caching: Response caching when appropriate
External Service Integration Pattern
@Component
public class PricingEngineServiceInvoker {
    
    @Autowired
    private PropertyHandler propertyHandler;
    
    public FxRate getExchangeRate(String fromCurrency, String toCurrency, 
                                  BigDecimal amount, Integer orgId) {
        try {
            // Build service URL
            String host = propertyHandler.getProperty("pe.serivce.host");
            String port = propertyHandler.getProperty("pe.serivce.port");
            String urlTemplate = propertyHandler.getProperty("pe.serivce.url.template");
            String serviceUrl = String.format(urlTemplate, host, port, "PricingEngineService");
            
            // Create SOAP request
            GetExchangeRateRequest request = new GetExchangeRateRequest();
            request.setFromCurrency(fromCurrency);
            request.setToCurrency(toCurrency);
            request.setAmount(amount);
            request.setOrganizationId(orgId);
            
            // Call service with timeout
            PricingEngineService service = createServiceClient(serviceUrl);
            GetExchangeRateResponse response = service.getExchangeRate(request);
            
            if (response.getStatus().getCode().equals("SUCCESS")) {
                return response.getFxRate();
            } else {
                throw new NGOPBaseException("Pricing service error: " + response.getStatus().getMessage());
            }
            
        } catch (Exception e) {
            // Fallback to cached rates or default pricing
            LOG.error("Pricing engine unavailable, using fallback", e);
            return getFallbackRate(fromCurrency, toCurrency, amount, orgId);
        }
    }
    
    private FxRate getFallbackRate(String fromCurrency, String toCurrency, 
                                   BigDecimal amount, Integer orgId) {
        // Fallback logic for when external service is down
        return cacheService.getLastKnownRate(fromCurrency, toCurrency, orgId);
    }
}

Integration Challenges

๐Ÿšซ Service Dependencies

Many critical functions depend on external services being available

๐Ÿšซ Network Timeouts

Financial networks can be slow - timeouts are common

๐Ÿšซ Data Consistency

No distributed transactions - eventual consistency only

๐Ÿšซ Error Propagation

External service errors can cascade through the system

Deployment Topology

Production Environment

Production Deployment
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   Load Balancer โ”‚    โ”‚   Load Balancer โ”‚
โ”‚   (Customer)    โ”‚    โ”‚   (Admin)       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚                       โ”‚
         โ–ผ                       โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   JBoss EAP     โ”‚    โ”‚   JBoss EAP     โ”‚
โ”‚   Node 1        โ”‚    โ”‚   Node 2        โ”‚
โ”‚   Customer      โ”‚    โ”‚   Admin +       โ”‚
โ”‚   Portal        โ”‚    โ”‚   Business      โ”‚
โ”‚                 โ”‚    โ”‚   Services      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚                       โ”‚
         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ”‚
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚     SQL Server Always On        โ”‚
    โ”‚     Availability Group          โ”‚
    โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚
    โ”‚  โ”‚   Primary   โ”‚ โ”‚  Secondary  โ”‚โ”‚
    โ”‚  โ”‚   Node      โ”‚ โ”‚   Node      โ”‚โ”‚
    โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Application Server Configuration

  • JBoss EAP 7.0: Not the latest, but stable and supported
  • Java 8: Required for compatibility with legacy dependencies
  • Connection Pooling: C3P0 for database connections
  • Session Clustering: Infinispan for distributed sessions

Scaling Characteristics

๐Ÿ“ˆ

Vertical Scaling

Primarily scales up (bigger servers) rather than out (more servers)

๐Ÿ’พ

Database Bottleneck

SQL Server is usually the limiting factor, not the application servers

โšก

Cache-Heavy

Infinispan cache reduces database load significantly

Technical Debt as Features

๐ŸŽฏ Perspective Shift

What looks like "technical debt" often represents solved business problems. Understanding the context helps you work with the system, not against it.

Common "Issues" and Their Business Context

1. Hardcoded Organization Logic

Organization-Specific Code
// This looks like a code smell, but...
if (orgCode.equals("CD")) {
    // Currencies Direct specific logic
    useComplexComplianceRules();
} else if (orgCode.equals("TorFX")) {
    // TorFX specific logic
    useSimplifiedKYC();
}

Why it exists: Different financial regulations per organization. Each client has unique compliance requirements that can't be generalized.

2. SOAP Instead of REST

Why it exists:

  • Financial services industry standard when built
  • Strong typing and contracts required for compliance
  • WSDL provides clear API documentation
  • Better tooling for financial messaging standards

3. Monolithic Deployment

Why it exists:

  • Easier to audit for financial compliance
  • ACID transactions across all operations
  • Small team could manage everything
  • Reduced operational complexity

4. Custom Authentication

Why it exists:

  • Pre-dates modern auth frameworks
  • Specific multi-tenant requirements
  • Integration with legacy CRM systems
  • Custom audit trail requirements

Working With Legacy Decisions

โš ๏ธ Do's and Don'ts

DO:

  • Understand the business context before criticizing
  • Work within existing patterns
  • Make small, incremental improvements
  • Document your reasoning

DON'T:

  • Rewrite entire subsystems "to modernize"
  • Break existing APIs without migration plans
  • Ignore compliance and audit requirements
  • Assume newer is always better

๐Ÿ’ก The Bottom Line

Dione's architecture reflects 10+ years of solving real business problems in financial services. It may not be "modern," but it works, it's profitable, and it serves customers reliably. Your job is to understand it, work with it, and improve it incrementally while respecting the business context that shaped it.

๐Ÿ“ Chapter Quiz

Test your understanding of Dione's architecture with these questions:

Question 1: What is the primary data flow pattern in Dione?

Question 2: Why does Dione use SOAP instead of REST APIs?

Question 3: What principle should guide working with Dione's architecture?