SAP CPI Dynamic Router with External Rule Set using Simple Expressions

SAP CPI Dynamic Router with External Rule Set using Simple Expressions

Intro

Routing in CPI can get messy. As more routing branches are added, maintaining them becomes a headache, especially when conditions get complex or frequently change.


Background / Problem

I've explored a few ways to reduce this pain.

One is convention-based processDirect routing, e.g. building endpoint dynamically from headers like: /PD_$​{header.mestyp}_$​{header.rcvprn}. It’s simple and router-free, but can’t handle complex routing conditions.

Another is using value mapping for routing, lookup a field to get the processDirect path. See link at [Ref 1] & [Ref 2]. But VM has serious limits:

  • Only supports single field matching

  • No clean way to do AND logic without messy field concatenation

  • Can’t return multiple matching rows

  • No support for rich conditions like contains, startsWith, greaterThan, etc.

If you try to simulate those rich conditions in VM, it gets hacky, need to embed pseudo-logic in values, then decode with Groovy. That’s fragile and hard to maintain.

You could build your own rule engine, but that becomes a long-term maintenance trap. You’ll keep adding custom operators, fixing your own rule evaluation engine, and it won’t be standard. I wouldn’t go that route.


Inspiration

While revisiting the Dynamic Router pattern from Gregor Hohpe’s EIP book and Apache Camel, I realized: CPI should be able to support dynamic, flexible routing, if the conditions are externalized and evaluated at runtime.

The core idea of a true Dynamic Router:

  • Rules are externally maintained

  • Easy to add/remove/update

  • Supports rich conditions (not just equals)

  • Still simple to implement

Camel is the backbone of CPI, so I turned to Camel’s Simple Expression language.

Research

Found from Apache Camel Dynamic Router Component, do make use of simple expression as predicate/rules, so feel this should be the approach, work along with this direction, and not against it.

After revisit a great blog [Ref 3] by Eng Swee, found out able to use evaluate() method to read some simple expression to get value using Groovy, however, it doesn't return single true or false.

Until at [Ref 4] Camel SimpleBuilder JavaDoc, found the method: matches()


Discovery

With SimpleBuilder.matches(), I can evaluate conditions like below with headers/properties in Groovy to Boolean true/false. Please note that for matches() method, Both ("and", "or") is not working, have to use actual operator (&&, II). Need double equal sign.

This opened up new possibilities and a clean path: I can store rules as just two fields:

  • endpoint (processDirect path)

  • condition (simple expression)

Evaluate them in Groovy using matches(). If it returns true, route to that endpoint.


How it work: Dynamic Simple Expression matches()

You can build "Simple Expression Tester" to test simple expression from Postman.

Step 1: Build an iFlow like below. Allowed Header(s) must be *

Step 2: Add the script testSimpleExpression.groovy that do evaluate() and matches() on some Simple Expression:

Step 3: Positive Test Run. Header class & type matched the condition, result = true

Step 4: Negative Test Run. Changed class from A to B, then result = false

Step 5: Tried with some other method like startsWith() still work. I not tried all possible method, however believe as long as the method work in Camel Simple Expression, will work in this iFlow too.

Dynamic Router with External Rule Set (Simple Expression)

After testing and a few iterations, this worked well. So now ready to build a mini rule engine that is simple, dynamic, and avoids all the earlier pain points.

Step 1: Below will be our rule set in JSON, telling the processDirect endpoint and condition. The name field is just as an identifier for the rule.

Step 2: Build below 'Dynamic Router' iflow. For demo purpose, the sender is HTTP adapter. In actual you may change to processDirect. Allowed Header(s) must be *

Step 3: That "getPDSimpleRule" script, for now you can just use content modifier set static JSON rule set to property "simpleRule". We going to change to Partner Directory later.

Step 4: Script "doDynamicRouting". This script loop each rule, if condition matched, set the endpoint in property, also do logging in custom headers for traceability.

Step 5: For demo, build 2 different receivers with processDirect. Each with sender address: /PD_SO_A and /PD_PO_B.

Positive Test Run (Go to ReceiverA)

Positive Test Run (Go to ReceiverB)

Negative Test Run (When no rule matches)

Where To Store The Rule Set?

One possible way is to store Json rule set in Partner Directory. SAP CPI do have UI to upload JSON to Partner Directory. Below are steps to upload JSON to Partner Directory:

Step 1: At CPI Monitor, go to 'Partner Directory'

Step 2: Click '+' to add:

Step 3: Maintain like below, browse to JSON rule set file, then 'Create'.

Step 4: After maintain, you should see like below:

Step 5: Replace the step 'getPDSimpleRule' with below script:

Step 6: If future need to maintain the JSON rule set, come here, Edit..

then just Browse and upload updated JSON rule files.

Closing Summary

This approach doesn’t aim to replace complex rule engines, but for many real-world routing needs, it strikes the right balance: flexible, simple, and maintainable. If you’ve struggled with hardcoded routers or limited value mappings in CPI, this might be a cleaner path forward.

What do you think about this approach?

If you’ve tackled similar routing challenges in CPI, I’d be curious how you approached it. Feel free to share your thoughts, improvements, or alternative ideas.

Disclaimer: This is a pattern I sparked from EIP pattern(Dynamic Router) and made workable in CPI, but it hasn’t been used in real production environments yet. Use it at your own discretion.

References:

[Ref 1] IDOC Dispatching - Use case for the ProcessDirect Adapter from Ariel Bravo Ayala

[Ref 2] SAP Cloud Integration IDoc Receiver Handler from Ayush Aggarwal

[Ref 3] Using Camel's Simple in CPI Groovy scripts from Eng Swee Yeoh

[Ref 4] Class SimpleBuilder JavaDoc & Dynamic Router Component from Apache Camel

[Ref 5] EIPinCPI - Dynamic Router & EIPinCPI - Message Dispatcher  from Bhalchandra Wadekar

[Ref 6] Get to know Camel’s Simple expression language in SAP Cloud Integration from Morten Wittrock

[Ref 7] DynamicRouter EIP from Enterprise Integration Patterns (https://www.enterpriseintegrationpatterns.com/)

Wouter van Heddeghem

Senior SAP S/4HANA Finance Consultant + Dutch + French + Spanish + English. 718,000 SAP Followers. I promote SAP jobseekers for free on LinkedIn.

1w

Great post ! Yee Loon Khoo

Ayush Aggarwal

SAP Integration Suite Expert (CPI, API, BTP) | Ariba CIG | SAP Certified | 11+ yrs | Building Scalable & Cloud-First Integrations

1w

Love how you externalized routing logic using Camel simple expressions, elegant and scalable. The clarity around VM limitations and how this approach overcomes them is gold. Thanks for referencing my post too — honored! 👏

Peter Jonker

Senior SAP ABAP, XI, PI, PO, CPI, BTP, Integration Suite consultant

1w

Very nice approach. I am going to try it since I am right now facing a challenge where the routing with value mapping is not sufficient. Thanks Yee Loon

To view or add a comment, sign in

Others also viewed

Explore topics