This adapter bridges the Open Bank Project (OBP) API and Core Banking Systems (CBS) using RabbitMQ for messaging. The architecture is designed with clear separation of concerns to maximize reusability and minimize bank-specific customization.
- Separation of Concerns: CBS-specific code is isolated from generic OBP message handling
- Plugin Architecture: Multiple CBS implementations can coexist
- Observability First: Telemetry is a first-class concern, separate from business logic
- Functional Programming: Uses Cats Effect for pure functional effects
- Type Safety: Leverages Scala's type system to prevent errors at compile time
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β OBP-API β
β (RabbitMQ Client) β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β RabbitMQ Messages
β (obp.request / obp.response)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ADAPTER - NORTH SIDE β
β (Generic, Reusable) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β RabbitMQ Consumer/Producer (messaging/) β β
β β - Queue management β β
β β - Message routing β β
β β - Correlation ID tracking β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β OBP Message Models (models/) β β
β β - CallContext, OutboundAdapterCallContext β β
β β - InboundAdapterCallContext β β
β β - BankCommons, AccountCommons, etc. β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Message Handlers (handlers/) β β
β β - Route messages by type (obp.getBank, etc.) β β
β β - Orchestrate CBS calls β β
β β - Build responses β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β LocalAdapter Interface
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ADAPTER - INTERFACE LAYER β
β (contracts/) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β trait LocalAdapter { β
β def getBank(...): IO[LocalAdapterResult[BankCommons]] β
β def getBankAccount(...): IO[...] β
β def makePayment(...): IO[...] β
β // ... all CBS operations β
β } β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β Implementation
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ADAPTER - SOUTH SIDE β
β (CBS-Specific, Customizable) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β REST CBS β β SOAP CBS β β Mock CBS β β
β β Adapter β β Adapter β β Adapter β β
β β β β β β β β
β β implements β β implements β β implements β β
β β LocalAdapter β β LocalAdapter β β LocalAdapter β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
β β β β β
β ββββββββββββββββββββ΄βββββββββββββββββββ β
β β β
ββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β HTTP/SOAP/DB/etc.
βΌ
βββββββββββββββββββ
β Core Banking β
β System β
βββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CROSS-CUTTING CONCERNS β
β (telemetry/) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β trait Telemetry { β
β - Message metrics β
β - CBS operation metrics β
β - Performance monitoring β
β - Error tracking β
β - Distributed tracing β
β } β
β β
β Implementations: β
β - ConsoleTelemetry (dev) β
β - PrometheusTelemetry (production) β
β - DatadogTelemetry (production) β
β - NoOpTelemetry (testing) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
src/main/scala/com/tesobe/obp/adapter/
βββ config/ # Configuration (generic)
β βββ Config.scala # RabbitMQ, CBS, app config
β
βββ models/ # OBP Message Models (generic)
β βββ OBPModels.scala # All OBP data types
β
βββ messaging/ # RabbitMQ handling (generic)
β βββ RabbitMQConsumer.scala
β βββ RabbitMQProducer.scala
β βββ MessageRouter.scala
β
βββ handlers/ # Message handlers (generic)
β βββ BankHandlers.scala
β βββ AccountHandlers.scala
β βββ TransactionHandlers.scala
β βββ CustomerHandlers.scala
β
βββ interfaces/ # Contracts (generic)
β βββ LocalAdapter.scala # THE interface CBS must implement
β
βββ cbs/ # CBS implementations (bank-specific)
β βββ implementations/
β βββ RestLocalAdapter.scala # HTTP REST implementation
β βββ SoapLocalAdapter.scala # SOAP implementation
β βββ MockLocalAdapter.scala # Testing/demo
β βββ YourBankAdapter.scala # Bank-specific impl
β
βββ telemetry/ # Observability (generic framework)
β βββ Telemetry.scala # Interface
β βββ ConsoleTelemetry.scala
β βββ PrometheusTelemetry.scala
β βββ CompositeTelemetry.scala # Combine multiple
β
βββ AdapterMain.scala # Main entry point
Purpose: Define what operations a CBS must support
Bank Developers: Implement this trait for your specific CBS
trait LocalAdapter {
def name: String
def version: String
// Core operations
def getBank(bankId: String, callContext: CallContext): IO[LocalAdapterResult[BankCommons]]
def getBankAccount(...): IO[LocalAdapterResult[BankAccountCommons]]
def makePayment(...): IO[LocalAdapterResult[TransactionCommons]]
// ... 30+ operations covering OBP functionality
}Key Points:
- All methods return
IO[LocalAdapterResult[T]]for pure functional effects LocalAdapterResultis a sealed trait withSuccessandErrorcasesCallContextcontains correlation ID, user info, auth context- Bank-specific logic stays in your implementation
Purpose: Observability and monitoring
Operations Teams: Choose or implement telemetry backend
trait Telemetry {
// Message lifecycle
def recordMessageReceived(...)
def recordMessageProcessed(...)
def recordMessageFailed(...)
// CBS operations
def recordCBSOperationStart(...)
def recordCBSOperationSuccess(...)
def recordCBSOperationFailure(...)
// Business metrics
def recordPaymentSuccess(...)
def recordAccountCreated(...)
// Tracing
def startSpan(...): IO[String]
def endSpan(...)
}Key Points:
- Telemetry is injected, not hardcoded
- Multiple implementations can coexist
- NoOp implementation for testing
- Console implementation for development
OBP-API sends message to RabbitMQ (obp.request queue)
β
RabbitMQConsumer receives message
β
Telemetry.recordMessageReceived()
β
MessageRouter extracts message type (e.g., "obp.getBank")
β
Route to appropriate Handler (e.g., BankHandlers)
β
Handler calls LocalAdapter.getBank()
β
LocalAdapter implementation makes CBS call
β
Response wrapped in LocalAdapterResult
β
Handler builds InboundAdapterCallContext
β
RabbitMQProducer sends response to obp.response queue
β
Telemetry.recordMessageProcessed()
If CBS call fails:
β
LocalAdapterResult.Error returned
β
Telemetry.recordCBSOperationFailure()
β
Handler builds error InboundAdapterCallContext
β
Error response sent to OBP with proper error codes
β
Telemetry.recordMessageFailed()
package com.tesobe.obp.adapter.cbs.implementations
import com.tesobe.obp.adapter.interfaces._
import com.tesobe.obp.adapter.models._
import cats.effect.IO
class MyBankAdapter(
baseUrl: String,
apiKey: String,
telemetry: Telemetry
) extends LocalAdapter {
override def name: String = "MyBank-REST-Adapter"
override def version: String = "1.0.0"
override def getBank(bankId: String, callContext: CallContext): IO[LocalAdapterResult[BankCommons]] = {
for {
// Start telemetry
_ <- telemetry.recordCBSOperationStart("getBank", callContext.correlationId)
// Make CBS HTTP call
result <- httpClient.get(s"$baseUrl/banks/$bankId")
.map(response =>
// Map CBS response to OBP BankCommons
LocalAdapterResult.success(
BankCommons(
bankId = response.id,
shortName = response.name,
fullName = response.fullName,
// ... map all fields
),
callContext
)
)
.handleErrorWith(error =>
IO.pure(LocalAdapterResult.error(
"BANK_NOT_FOUND",
error.getMessage,
callContext
))
)
// End telemetry
_ <- telemetry.recordCBSOperationSuccess("getBank", callContext.correlationId, duration)
} yield result
}
// Implement all other LocalAdapter methods...
}// In AdapterMain.scala or config
val localAdapter: LocalAdapter = config.cbsType match {
case "mybank" => new MyBankAdapter(config.baseUrl, config.apiKey, telemetry)
case "mock" => new MockLocalAdapter(telemetry)
case _ => throw new IllegalArgumentException(s"Unknown CBS type: ${config.cbsType}")
}export MYBANK_CBS_URL=https://cbs.mybank.com/api
export MYBANK_CBS_API_KEY=secret123
export RABBITMQ_HOST=localhost
export RABBITMQ_REQUEST_QUEUE=obp.request
export RABBITMQ_RESPONSE_QUEUE=obp.response
java -jar obp-rabbit-cats-adapter.jarRabbitMQ Configuration:
RABBITMQ_HOST- RabbitMQ server hostRABBITMQ_PORT- RabbitMQ server port (default: 5672)RABBITMQ_USERNAME- Username for authenticationRABBITMQ_PASSWORD- Password for authenticationRABBITMQ_REQUEST_QUEUE- Queue to consume messages fromRABBITMQ_RESPONSE_QUEUE- Queue to send responses to
CBS Configuration: Your bank-specific local adapter will define what configuration it needs.
Telemetry Configuration:
TELEMETRY_TYPE- Telemetry implementation (console/prometheus/datadog/noop)ENABLE_METRICS- Enable metrics collection (true/false)
Test local adapter implementations in isolation:
class MyBankAdapterSpec extends CatsEffectSuite {
test("getBank returns bank when CBS responds successfully") {
val adapter = new MyBankAdapter(mockHttpClient, NoOpTelemetry)
val result = adapter.getBank("bank-id", CallContext("corr-123"))
result.map {
case LocalAdapterResult.Success(bank, _, _) =>
assertEquals(bank.bankId, "bank-id")
case _ => fail("Expected success")
}
}
}Test with mock RabbitMQ and mock CBS:
test("adapter processes obp.getBank message end-to-end") {
// Set up mock RabbitMQ, mock CBS, real handlers
// Send message, verify response
}Use MockLocalAdapter for development without real CBS:
class MockLocalAdapter extends LocalAdapter {
def getBank(...) = IO.pure(
LocalAdapterResult.success(
BankCommons(
bankId = "mock-bank",
shortName = "Mock",
fullName = "Mock Bank for Testing"
),
callContext
)
)
}-
Message Processing:
- Messages received/processed/failed per minute
- Processing duration (p50, p95, p99)
- Queue depth
-
CBS Operations:
- Operation success/failure rate
- Operation duration by type
- Retry count
- Error rate by error code
-
Business Metrics:
- Payments processed
- Accounts created
- Transaction volume
-
System Health:
- Memory usage
- CPU usage
- Connection status (RabbitMQ, CBS)
All logs include:
- Correlation ID (for request tracing)
- Timestamp
- Log level
- Component name
- Message
Example:
[INFO][CID: 1flssoftxq0cr1nssr68u0mioj] Message received: type=obp.getBank queue=obp.request
[INFO][CID: 1flssoftxq0cr1nssr68u0mioj] CBS operation started: getBank
[INFO][CID: 1flssoftxq0cr1nssr68u0mioj] CBS operation success: getBank duration=45ms
[INFO][CID: 1flssoftxq0cr1nssr68u0mioj] Message processed: type=obp.getBank duration=52ms
FROM openjdk:11-jre-slim
COPY target/obp-rabbit-cats-adapter.jar /app/adapter.jar
CMD ["java", "-jar", "/app/adapter.jar"]apiVersion: apps/v1
kind: Deployment
metadata:
name: obp-adapter
spec:
replicas: 3
template:
spec:
containers:
- name: adapter
image: obp-rabbit-cats-adapter:latest
env:
- name: RABBITMQ_HOST
value: rabbitmq-service
- name: MYBANK_CBS_URL
value: https://cbs.internal
resources:
requests:
memory: "512Mi"
cpu: "500m"β
Only implement LocalAdapter trait - Clear contract
β
No RabbitMQ knowledge needed - Already handled
β
No OBP message format knowledge needed - Already handled
β
Focus on CBS integration - Your domain expertise
β
Telemetry included - Observability for free
β
Standard RabbitMQ setup - Same for all banks
β
Pluggable telemetry - Use your monitoring stack
β
Clear metrics - Know what's happening
β
Health checks - Easy monitoring
β
Containerizable - Deploy anywhere
β
Reusable core - Generic message handling
β
Multiple CBS support - One adapter, many banks
β
Consistent interface - All adapters work the same
β
Type-safe - Compiler catches errors
β
Functional - Pure, testable, composable
- Implement your local adapter - Extend
LocalAdaptertrait - Configure environment - Set CBS credentials and endpoints
- Choose telemetry backend - Console for dev, Prometheus for prod
- Deploy and monitor - Use provided metrics
- Iterate - Add more CBS operations as needed
- GitHub: OBP-Rabbit-Cats-Adapter
- Documentation: OBP Wiki
- Community: OBP Rocket Chat