The Problem
Lets say you run a web shop where the orders are processed automatically by apache camel. The items which are selled are assembled from make and buy items.
Make items have to be produced in your shop-floor and buy items have to be bought at one of your suppliers.
Ideally you would like to have a mechanism which splits up your order into two lists:
- One list of items which have to be produced and
- another list which with items which should be purchased.
Every list should then be forwarded to a different route within apache camel (where either manufacturing instructions or purchases are created and forwarded to the supplier).
The Solution
The solution to this problem is called 'content based message routing'. There is a fully functional example of such an example in our github repository. The next few paragraphs will give you an idea how this code works.
Datamodel
The data model is simple.
We have an abstract base class called Item which is the parent of the BuyItem and the PurchaseItem class. An Order represents an order which comes from the webshop and it consists of a list of MakeItems and BuyItems along with some utility methods.
Routes
Apache camel provides a woute called 'direct:webshop' which is able to process such orders. Its purpose is to read out the Items, to pack them into separate exchanges and to set the ItemType header information which is processed in the next step. Finally it forwards the newly created exchange to another route called 'direct:itemprocessor'. This is where the actual magic happens:
.choice().when(header("ItemType").isEqualToIgnoreCase("MakeItem")) // Check if the Item is a makeitem
.to("direct:factory") // Then build it
.when(header("ItemType").isEqualToIgnoreCase("BuyItem")) // Check if the Item is a BuyItem
.to("direct:purchase") // Then purchase it
.otherwise() // otherwise
.log("~~~~~~~ DOING NOTHING WITH ${body} ~~~~~~~") // do nothing
.end();
Depending on the header field ItemType is sends the Item either to the 'direct:factory' route or to the 'direct:purchase' route where just a log message is written. This would be the place where the type-specific business logic would be placed.
Testrun
The following order:
pump_assembly.addItem(new BuyItem("GearMotor", "An electromotor", 45))
pump_assembly.addItem(new MakeItem("PumpHousing-UpperPart", "Molded steel housing", 4))
pump_assembly.addItem(new MakeItem("Shaft", "40 mm steel shaft", 1))
pump_assembly.addItem(new BuyItem("RubberFeet", "Rubber feet to damp vibrations", 0.1))
pump_assembly.addItem(new BuyItem("RubberFeet", "Rubber feet to damp vibrations", 0.1))
pump_assembly.addItem(new BuyItem("Bearing", "Ring bearing", 0.75))
pump_assembly.addItem(new MakeItem("PumpHousing-LowerPart", "Molded steel housing", 2));
produces the following output:
The factory is producing :MakeItem(name=PumpHousing-UpperPart, description=Molded steel housing, hoursToBuild=4)
The factory is producing :MakeItem(name=Shaft, description=40 mm steel shaft, hoursToBuild=1)
Buyer purchases the following item :BuyItem(name=RubberFeet, description=Rubber feet to damp vibrations, price=0.1)
Buyer purchases the following item :BuyItem(name=RubberFeet, description=Rubber feet to damp vibrations, price=0.1)
Buyer purchases the following item :BuyItem(name=Bearing, description=Ring bearing, price=0.75)
The factory is producing :MakeItem(name=PumpHousing-LowerPart, description=Molded steel housing, hoursToBuild=2)
Bingo - Thats exactly what we where looking for.
Happy coding