This site is in English. Use your browser's built-in translate feature to read it in your language.

Content-Based Router Pattern

Overview

The Content-Based Router pattern is a sophisticated message routing pattern in enterprise integration architectures that examines message content, headers, or properties to dynamically determine the appropriate destination for each message. Unlike static routing rules, the Content-Based Router makes intelligent routing decisions at runtime by analyzing the actual message payload, enabling flexible and adaptive message flow control based on business logic, data characteristics, and contextual information.

Theoretical Foundation

The Content-Based Router pattern is grounded in decision tree algorithms and rule-based systems theory, specifically addressing the challenge of dynamic message classification and intelligent routing in distributed systems. The pattern embodies the principle of "content-driven dispatch" - making routing decisions based on actual message data and business semantics rather than predetermined static configurations.

Core Principles

1. Intelligent Content Analysis

The Content-Based Router performs sophisticated examination of message characteristics: - Payload inspection - analyzing message content structure, data types, and values - Header analysis - examining message metadata, routing hints, and context information - Business rule evaluation - applying complex business logic to determine appropriate destinations - Pattern matching - using regular expressions, XPath, JSONPath, or custom matchers to identify content patterns

2. Dynamic Destination Selection

Based on content analysis, the router selects appropriate destinations: - Single destination routing - directing messages to one specific endpoint - Multi-destination routing - sending messages to multiple endpoints based on content - Conditional routing - applying different routing logic based on content characteristics - Priority-based routing - selecting destinations based on message priority or urgency

3. Business Logic Integration

The pattern enables sophisticated business-driven routing: - Customer segmentation - routing based on customer type, geography, or business value - Product categorization - directing messages based on product types or categories - Regulatory compliance - routing based on jurisdictional or compliance requirements - Service level agreements - routing based on SLA requirements or service tiers

4. Scalability and Performance

The Content-Based Router optimizes routing performance: - Efficient content parsing - minimizing overhead of content inspection - Rule caching - caching frequently used routing rules and patterns - Parallel evaluation - evaluating multiple routing conditions concurrently - Short-circuit optimization - stopping evaluation once a matching rule is found

Why Content-Based Routers are Essential in Integration Architecture

1. Business Process Flexibility

In dynamic business environments, content-based routing enables: - Workflow automation - automatically routing work items based on content characteristics - Exception handling - directing error conditions or special cases to appropriate handlers - Approval workflows - routing requests to correct approval chains based on amount, type, or risk - Escalation management - routing time-sensitive or high-value transactions to priority queues

2. Multi-Tenant and Multi-Channel Support

For complex enterprise architectures: - Tenant isolation - routing messages to tenant-specific processing pipelines - Channel differentiation - handling web, mobile, API, and batch requests differently - Geographic routing - directing messages based on customer location or data residency - Brand segmentation - routing messages based on brand affiliation or business unit

3. Legacy System Integration

When integrating diverse legacy systems: - Format adaptation - routing messages to systems that support specific data formats - Protocol mediation - directing messages to appropriate protocol handlers - Capability matching - routing to systems based on their processing capabilities - Load distribution - balancing load across systems with different capacity characteristics

4. Microservices Architecture

In microservices environments: - Service specialization - routing to services optimized for specific data types or operations - Version management - routing to appropriate service versions based on message schema - Feature flagging - routing to different service implementations based on feature flags - A/B testing - distributing traffic to different service variants for testing

Benefits in Integration Contexts

1. Operational Efficiency

2. Business Agility

3. System Resilience

4. Customer Experience Enhancement

Integration Architecture Applications

1. Enterprise Service Bus (ESB)

Content-Based Routers in ESB architectures provide: - Service endpoint selection - routing to appropriate service implementations - Message transformation routing - directing to transformation services based on content - Error handling routing - sending errors to specialized error processing services - Audit and compliance routing - directing sensitive messages to audit services

2. API Gateway and Management

In API gateway implementations: - Backend service routing - directing API calls to appropriate backend services - Rate limiting routing - routing high-volume clients to specialized handling - Authentication routing - directing to different authentication services based on client type - Version compatibility routing - routing to compatible service versions

3. Event-Driven Architecture

For event processing systems: - Event type routing - directing different event types to specialized processors - Stream partitioning - routing events to appropriate stream partitions - Consumer group routing - directing events to specific consumer groups - Priority event handling - routing critical events to high-priority processors

4. Data Pipeline and Analytics

In data processing workflows: - Data source routing - directing data based on source system characteristics - Quality-based routing - routing high-quality data to real-time systems, low-quality to batch processing - Compliance routing - directing sensitive data to compliant processing pipelines - Analytics routing - routing operational data to analytical systems

Implementation Patterns

1. Simple Content Inspection Router

// Basic content-based routing using message analysis
@Component
public class ContentInspectionRouter {

    public String determineRoute(MessageDto message) {
        // Route based on message type
        if (message.getMessageType() == MessageType.PAYMENT) {
            return routePaymentMessage(message);
        } else if (message.getMessageType() == MessageType.CUSTOMER_UPDATE) {
            return routeCustomerMessage(message);
        } else if (message.getMessageType() == MessageType.ORDER) {
            return routeOrderMessage(message);
        }

        return "default-processor";
    }

    private String routePaymentMessage(MessageDto message) {
        PaymentDto payment = message.getPayload(PaymentDto.class);

        // Route high-value payments to secure processor
        if (payment.getAmount().compareTo(new BigDecimal("10000")) > 0) {
            return "high-value-payment-processor";
        }

        // Route international payments to specialized processor
        if (!payment.getCurrency().equals("EUR")) {
            return "international-payment-processor";
        }

        return "standard-payment-processor";
    }

    private String routeCustomerMessage(MessageDto message) {
        CustomerUpdateDto customer = message.getPayload(CustomerUpdateDto.class);

        // Route VIP customers to priority processor
        if (customer.getCustomerTier() == CustomerTier.VIP) {
            return "vip-customer-processor";
        }

        // Route by geographic region
        String region = customer.getAddress().getCountry();
        return switch (region) {
            case "FI", "SE", "NO", "DK" -> "nordic-customer-processor";
            case "DE", "FR", "ES", "IT" -> "eu-customer-processor";
            default -> "international-customer-processor";
        };
    }

    private String routeOrderMessage(MessageDto message) {
        OrderDto order = message.getPayload(OrderDto.class);

        // Route based on order characteristics
        if (order.isExpressDelivery()) {
            return "express-order-processor";
        }

        if (order.getItems().size() > 10) {
            return "bulk-order-processor";
        }

        return "standard-order-processor";
    }
}

2. Rule-Based Content Router

// Advanced routing using configurable business rules
@Component
public class RuleBasedContentRouter {

    @Autowired
    private RoutingRuleEngine ruleEngine;

    @Autowired
    private MessageContentAnalyzer contentAnalyzer;

    public RoutingDecision routeMessage(Message message) {
        MessageContext context = contentAnalyzer.analyzeMessage(message);

        List<RoutingRule> applicableRules = ruleEngine.getApplicableRules(context);

        for (RoutingRule rule : applicableRules) {
            if (rule.evaluate(context)) {
                return RoutingDecision.builder()
                    .destination(rule.getDestination())
                    .ruleId(rule.getId())
                    .confidence(rule.getConfidence())
                    .metadata(rule.getMetadata())
                    .build();
            }
        }

        return RoutingDecision.defaultRoute();
    }
}

@Service
public class RoutingRuleEngine {

    private final List<RoutingRule> rules;

    public List<RoutingRule> getApplicableRules(MessageContext context) {
        return rules.stream()
            .filter(rule -> rule.isApplicable(context))
            .sorted(Comparator.comparing(RoutingRule::getPriority).reversed())
            .collect(Collectors.toList());
    }
}

public interface RoutingRule {
    boolean isApplicable(MessageContext context);
    boolean evaluate(MessageContext context);
    String getDestination();
    String getId();
    int getPriority();
    double getConfidence();
    Map<String, Object> getMetadata();
}

public class CustomerTypeRoutingRule implements RoutingRule {
    private final CustomerType targetCustomerType;
    private final String destination;
    private final int priority;

    @Override
    public boolean evaluate(MessageContext context) {
        return context.getCustomerType() == targetCustomerType;
    }

    @Override
    public String getDestination() {
        return destination;
    }

    // Additional methods...
}

3. JSON/XML Content Path Router

// Content routing using path expressions for structured data
@Component
public class PathBasedContentRouter {

    @Autowired
    private JsonPathEvaluator jsonPathEvaluator;

    @Autowired
    private XPathEvaluator xPathEvaluator;

    public String routeByContentPath(String messageContent, String contentType) {
        if ("application/json".equals(contentType)) {
            return routeJsonContent(messageContent);
        } else if ("application/xml".equals(contentType) || "text/xml".equals(contentType)) {
            return routeXmlContent(messageContent);
        }

        return "default-processor";
    }

    private String routeJsonContent(String jsonContent) {
        try {
            // Route based on event type
            String eventType = jsonPathEvaluator.evaluate(jsonContent, "$.eventType");
            if ("user.created".equals(eventType)) {
                return "user-onboarding-processor";
            } else if ("order.placed".equals(eventType)) {
                return "order-processing-service";
            }

            // Route based on data characteristics
            Integer amount = jsonPathEvaluator.evaluate(jsonContent, "$.order.totalAmount");
            if (amount != null && amount > 1000) {
                return "high-value-processor";
            }

            // Route based on customer segment
            String segment = jsonPathEvaluator.evaluate(jsonContent, "$.customer.segment");
            if ("ENTERPRISE".equals(segment)) {
                return "enterprise-processor";
            }

        } catch (Exception e) {
            log.warn("Error evaluating JSON path for routing", e);
        }

        return "default-processor";
    }

    private String routeXmlContent(String xmlContent) {
        try {
            // Route based on XML element values
            String messageType = xPathEvaluator.evaluate(xmlContent, "/message/@type");
            String priority = xPathEvaluator.evaluate(xmlContent, "/message/header/priority/text()");

            if ("urgent".equalsIgnoreCase(priority)) {
                return "urgent-processor";
            }

            if ("invoice".equals(messageType)) {
                String amount = xPathEvaluator.evaluate(xmlContent, "/message/body/invoice/amount/text()");
                if (amount != null && Double.parseDouble(amount) > 5000) {
                    return "large-invoice-processor";
                }
                return "standard-invoice-processor";
            }

        } catch (Exception e) {
            log.warn("Error evaluating XPath for routing", e);
        }

        return "default-processor";
    }
}

4. Multi-Criteria Content Router

// Complex routing based on multiple content criteria
@Component
public class MultiCriteriaContentRouter {

    public List<String> determineDestinations(ComplexMessage message) {
        List<String> destinations = new ArrayList<>();

        RoutingCriteria criteria = analyzeCriteria(message);

        // Primary destination based on message type and priority
        destinations.add(determinePrimaryDestination(criteria));

        // Additional destinations based on content characteristics
        destinations.addAll(determineSecondaryDestinations(criteria));

        // Compliance and audit destinations
        destinations.addAll(determineComplianceDestinations(criteria));

        return destinations.stream().distinct().collect(Collectors.toList());
    }

    private RoutingCriteria analyzeCriteria(ComplexMessage message) {
        return RoutingCriteria.builder()
            .messageType(message.getType())
            .priority(message.getPriority())
            .customerTier(extractCustomerTier(message))
            .geographicRegion(extractRegion(message))
            .dataClassification(extractDataClassification(message))
            .complianceRequirements(extractComplianceRequirements(message))
            .messageSize(message.getPayload().length())
            .urgency(calculateUrgency(message))
            .build();
    }

    private String determinePrimaryDestination(RoutingCriteria criteria) {
        if (criteria.getUrgency() == Urgency.CRITICAL) {
            return "critical-processor";
        }

        if (criteria.getCustomerTier() == CustomerTier.ENTERPRISE) {
            return "enterprise-processor";
        }

        // Route based on message type and region
        return criteria.getMessageType().toString().toLowerCase() + "-" + 
               criteria.getGeographicRegion().toString().toLowerCase() + "-processor";
    }

    private List<String> determineSecondaryDestinations(RoutingCriteria criteria) {
        List<String> destinations = new ArrayList<>();

        // Analytics destinations
        if (criteria.getMessageType().isAnalyticsEligible()) {
            destinations.add("analytics-collector");
        }

        // Monitoring destinations
        if (criteria.getUrgency().ordinal() >= Urgency.HIGH.ordinal()) {
            destinations.add("priority-monitor");
        }

        // Backup destinations for high-value messages
        if (criteria.getCustomerTier() == CustomerTier.VIP) {
            destinations.add("vip-backup-processor");
        }

        return destinations;
    }

    private List<String> determineComplianceDestinations(RoutingCriteria criteria) {
        List<String> destinations = new ArrayList<>();

        // GDPR compliance
        if (criteria.getGeographicRegion().isEURegion() && 
            criteria.getDataClassification().isPersonalData()) {
            destinations.add("gdpr-compliance-processor");
        }

        // Financial compliance
        if (criteria.getMessageType().isFinancial() && 
            criteria.getComplianceRequirements().contains(ComplianceType.FINANCIAL)) {
            destinations.add("financial-compliance-processor");
        }

        // Audit requirements
        if (criteria.getDataClassification().requiresAudit()) {
            destinations.add("audit-logger");
        }

        return destinations;
    }
}

Apache Camel Implementation

1. Simple Content-Based Router

@Component
public class SimpleContentBasedRouterRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("direct:contentBasedRoute")
            .routeId("content-based-router")
            .log("Analyzing message content for routing")
            .choice()
                .when(jsonpath("$.messageType == 'PAYMENT'"))
                    .to("direct:routePayment")
                .when(jsonpath("$.messageType == 'ORDER'"))
                    .to("direct:routeOrder")
                .when(jsonpath("$.messageType == 'CUSTOMER'"))
                    .to("direct:routeCustomer")
                .when(header("urgent").isEqualTo("true"))
                    .to("direct:urgentProcessor")
                .otherwise()
                    .to("direct:defaultProcessor")
            .end();

        from("direct:routePayment")
            .log("Routing payment message")
            .choice()
                .when(jsonpath("$.amount > 10000"))
                    .to("direct:highValuePaymentProcessor")
                .when(jsonpath("$.currency != 'EUR'"))
                    .to("direct:internationalPaymentProcessor")
                .otherwise()
                    .to("direct:standardPaymentProcessor")
            .end();

        from("direct:routeOrder")
            .log("Routing order message")
            .choice()
                .when(jsonpath("$.expressDelivery == true"))
                    .to("direct:expressOrderProcessor")
                .when(jsonpath("$.items.length() > 10"))
                    .to("direct:bulkOrderProcessor")
                .otherwise()
                    .to("direct:standardOrderProcessor")
            .end();
    }
}

2. Header and Content Combined Router

@Component
public class HeaderContentRouterRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("direct:combinedContentRouter")
            .routeId("header-content-router")
            .log("Routing based on headers and content")
            .choice()
                // Route based on customer tier (header) and message content
                .when(and(header("customerTier").isEqualTo("VIP"), 
                         jsonpath("$.priority == 'HIGH'")))
                    .to("direct:vipHighPriorityProcessor")

                // Route based on region and message type
                .when(and(header("region").in("EU", "NORDICS"), 
                         jsonpath("$.messageType == 'COMPLIANCE'")))
                    .to("direct:euComplianceProcessor")

                // Route based on content size and type
                .when(and(jsonpath("$.data.length() > 1000"), 
                         header("messageType").isEqualTo("BATCH")))
                    .to("direct:largeBatchProcessor")

                // Route based on customer segment from content
                .when(jsonpath("$.customer.segment == 'ENTERPRISE'"))
                    .to("direct:enterpriseProcessor")

                // Default routing
                .otherwise()
                    .to("direct:standardProcessor")
            .end();
    }
}

3. XPath-Based XML Content Router

@Component
public class XPathContentRouterRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("direct:xmlContentRouter")
            .routeId("xpath-content-router")
            .log("Routing XML content based on XPath expressions")
            .choice()
                // Route based on document type
                .when(xpath("/document/@type = 'invoice'"))
                    .to("direct:routeInvoice")

                // Route based on priority
                .when(xpath("/document/header/priority/text() = 'urgent'"))
                    .to("direct:urgentProcessor")

                // Route based on customer type
                .when(xpath("//customer/@type = 'enterprise'"))
                    .to("direct:enterpriseProcessor")

                // Route based on amount
                .when(xpath("//amount/text() > 5000"))
                    .to("direct:highValueProcessor")

                .otherwise()
                    .to("direct:defaultXmlProcessor")
            .end();

        from("direct:routeInvoice")
            .choice()
                .when(xpath("//invoice/amount/text() > 10000"))
                    .to("direct:largeInvoiceProcessor")
                .when(xpath("//invoice/@type = 'credit'"))
                    .to("direct:creditInvoiceProcessor")
                .otherwise()
                    .to("direct:standardInvoiceProcessor")
            .end();
    }
}

4. Dynamic Content Router with Rules

@Component
public class DynamicContentRouterRoute extends RouteBuilder {

    @Autowired
    private ContentRoutingService routingService;

    @Override
    public void configure() throws Exception {
        from("direct:dynamicContentRouter")
            .routeId("dynamic-content-router")
            .log("Applying dynamic content routing rules")
            .process(exchange -> {
                Object messageBody = exchange.getIn().getBody();
                Map<String, Object> headers = exchange.getIn().getHeaders();

                RoutingDecision decision = routingService.determineRoute(messageBody, headers);

                exchange.getIn().setHeader("routingDecision", decision);
                exchange.getIn().setHeader("primaryDestination", decision.getPrimaryDestination());
                exchange.getIn().setHeader("secondaryDestinations", decision.getSecondaryDestinations());
            })
            .log("Primary destination: ${header.primaryDestination}")
            .recipientList(header("primaryDestination"))
            .choice()
                .when(header("secondaryDestinations").isNotNull())
                    .process(exchange -> {
                        List<String> secondaryDestinations = 
                            exchange.getIn().getHeader("secondaryDestinations", List.class);

                        if (secondaryDestinations != null && !secondaryDestinations.isEmpty()) {
                            String destinations = String.join(",", secondaryDestinations);
                            exchange.getIn().setHeader("additionalDestinations", destinations);
                        }
                    })
                    .recipientList(header("additionalDestinations"))
                        .parallelProcessing()
                        .stopOnException()
            .end();
    }
}

@Service
public class ContentRoutingService {

    public RoutingDecision determineRoute(Object messageBody, Map<String, Object> headers) {
        MessageAnalysisResult analysis = analyzeMessage(messageBody, headers);

        String primaryDestination = determinePrimaryRoute(analysis);
        List<String> secondaryDestinations = determineSecondaryRoutes(analysis);

        return RoutingDecision.builder()
            .primaryDestination(primaryDestination)
            .secondaryDestinations(secondaryDestinations)
            .analysisResult(analysis)
            .build();
    }

    private MessageAnalysisResult analyzeMessage(Object messageBody, Map<String, Object> headers) {
        // Implement message analysis logic
        return MessageAnalysisResult.builder()
            .messageType(extractMessageType(messageBody, headers))
            .priority(extractPriority(messageBody, headers))
            .customerInfo(extractCustomerInfo(messageBody, headers))
            .contentCharacteristics(analyzeContent(messageBody))
            .build();
    }
}

5. Multi-Destination Content Router

@Component
public class MultiDestinationContentRouterRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("direct:multiDestinationRouter")
            .routeId("multi-destination-content-router")
            .log("Routing to multiple destinations based on content")
            .process(exchange -> {
                List<String> destinations = new ArrayList<>();

                // Always route to primary processor
                destinations.add("direct:primaryProcessor");

                // Add audit destination for sensitive data
                if (containsSensitiveData(exchange.getIn().getBody())) {
                    destinations.add("direct:auditProcessor");
                }

                // Add compliance destination for regulated industries
                if (isRegulatedIndustry(exchange.getIn().getHeaders())) {
                    destinations.add("direct:complianceProcessor");
                }

                // Add analytics destination for business events
                if (isBusinessEvent(exchange.getIn().getBody())) {
                    destinations.add("direct:analyticsProcessor");
                }

                String recipientList = String.join(",", destinations);
                exchange.getIn().setHeader("recipientList", recipientList);
            })
            .log("Sending to destinations: ${header.recipientList}")
            .recipientList(header("recipientList"))
                .parallelProcessing()
                .stopOnException();
    }

    private boolean containsSensitiveData(Object body) {
        // Implementation to detect sensitive data
        if (body instanceof Map) {
            Map<?, ?> data = (Map<?, ?>) body;
            return data.containsKey("ssn") || data.containsKey("creditCard") || 
                   data.containsKey("personalData");
        }
        return false;
    }

    private boolean isRegulatedIndustry(Map<String, Object> headers) {
        String industry = (String) headers.get("industry");
        return "FINANCIAL".equals(industry) || "HEALTHCARE".equals(industry) || 
               "PHARMACEUTICAL".equals(industry);
    }

    private boolean isBusinessEvent(Object body) {
        if (body instanceof Map) {
            Map<?, ?> data = (Map<?, ?>) body;
            String eventType = (String) data.get("eventType");
            return eventType != null && (eventType.startsWith("business.") || 
                   eventType.contains("transaction"));
        }
        return false;
    }
}

Best Practices

1. Content Analysis Optimization

2. Routing Rule Management

3. Error Handling and Fallbacks

4. Performance and Scalability

5. Security and Compliance

The Content-Based Router pattern is fundamental for building intelligent, adaptive integration solutions that can make sophisticated routing decisions based on message content, enabling flexible and business-driven message flows in complex enterprise architectures.

← Back to All Patterns