Event-Driven Architecture: Integrating Legacy FLEXCUBE Banking Systems with Modern REST Services
The Challenge
Oracle FLEXCUBE is one of the most widely used core banking systems globally, but its SOAP-based integration model was designed for a batch-processing era. Modern banking demands real-time transaction processing, RESTful APIs, and event-driven workflows. Bridging these two worlds without disrupting existing operations was the core challenge.
System Architecture
The integration layer follows a hexagonal architecture pattern, isolating the core business logic from both the legacy FLEXCUBE system and modern REST consumers:
┌──────────────┐
│ REST API │
│ (Consumers) │
└──────┬───────┘
│
┌──────▼───────┐
│ API GW │
└──────┬───────┘
│
┌──────▼───────┐
│ Orchestrator│
└──────┬───────┘
│
┌─────────▼──────────┐
│ Kafka Cluster │
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ FLEXCUBE Adapter │
│ (SOAP Bridge) │
└─────────┬──────────┘
│
┌──────▼───────┐
│ FLEXCUBE │
│ (Core Bank) │
└──────────────┘
The Kafka Backbone
Apache Kafka serves as the transaction backbone, providing durability, ordering guarantees, and replayability — all non-negotiable in financial systems.
Transaction Event Schema
Each financial transaction is modeled as an event with strict schema:
{
"eventId": "txn_8a3f2b1c",
"eventType": "FUNDS_TRANSFER_INITIATED",
"source": "REST_API",
"timestamp": "2024-11-28T14:32:10.123Z",
"payload": {
"transactionRef": "TXN20241128001",
"amount": 1500000.00,
"currency": "INR",
"fromAccount": "1234567890",
"toAccount": "0987654321",
"narration": "INTER-BANK TRANSFER"
},
"metadata": {
"correlationId": "corr_abc123",
"idempotencyKey": "idem_xyz789"
}
}
Idempotency & Exactly-Once Semantics
Financial systems cannot tolerate duplicate transactions. The solution was a multi-layered idempotency strategy:
@Component
public class IdempotencyHandler {
private final RedisTemplate<String, String> redis;
public boolean isDuplicate(String idempotencyKey) {
return redis.opsForValue()
.setIfAbsent(idempotencyKey, "PROCESSED",
Duration.ofHours(24));
}
}
Each event carries an idempotency key. Before processing, the adapter checks Redis for existing keys. The TTL is set to 24 hours — well beyond any reasonable replay window.
FLEXCUBE SOAP Bridge
The bridge translates between Kafka events and FLEXCUBE's SOAP operations. This was the most delicate part of the system:
@Service
public class FlexcubeSoapBridge {
private final Jaxb2Marshaller marshaller;
private final WebServiceTemplate wsTemplate;
public TransactionResponse submitTransaction(
TransactionEvent event) {
var request = new FLEXCUBERequest();
request.setTransactionRef(event.getTransactionRef());
request.setAmount(event.getAmount());
// ... map fields
try {
var response = (FLEXCUBEResponse) wsTemplate
.marshalSendAndReceive(request);
return handleResponse(response);
} catch (SoapFaultClientException e) {
// Route to DLT for manual reconciliation
kafkaTemplate.send("flexcube-dlt", event);
throw new RetryableException(e);
}
}
}
Error Handling & Dead Letter Queues
Not all transactions succeed on the first attempt. A sophisticated retry mechanism with exponential backoff routes failed messages through a Dead Letter Topic (DLT):
Monitoring & Observability
With millions in daily transaction value, observability was paramount. Each event is traced through the system using distributed tracing:
management:
tracing:
sampling:
probability: 1.0 # 100% sampling for financial tracing
metrics:
export:
prometheus:
enabled: true
Custom metrics track:
Results
The integration layer processes millions in daily transaction value with 99.9% uptime over 18 months. The event-driven architecture reduced end-to-end transaction time from batch-level (hours) to sub-second, and the DLT pattern ensures zero transaction loss even during FLEXCUBE outages.