Camel Choice by Example

IAmYourFaja picture IAmYourFaja · Dec 18, 2013 · Viewed 20.1k times · Source

I have 2 POJOs:

public class Witch {
    private Broom broom;
    private List<Spell> spells;

    // constructors, getters/setters, etc.
}

public class ValidatedWitches {
    private List<Witch> goodWitches
    private List<Witch> badWitches;

    // constructors, getters/setters, etc.
}

I have a Camel processor I wrote that will produce a ValidatedWitches instance (which again, consists of 2 List<Witch>):

public class WitchValidator implements Processor {
    @Override
    public void process(Exchange exchange) {
        List<Witch> witchesToValidate = (List<Witch>)exchange.getIn().getBody();

        ValidatedWitches validated = validate(witchesToValidate);

        exchange.getOut().setBody(validated);
    }

    private ValidatedWitches validate(List<Witch> toValidate) {
        // For each witch, determines if it is a good witch, or a bad witch,
        // and places it on an appropriate list.
        List<Witch> good = new ArrayList<Witch>();
        List<Witch> bad = new ArrayList<Witch>();

        // etc...

        return new ValidatedWitches(good, bad);
    }
}

I now want to route my list of good witches 1 way, and my list of bad witches another way:

<route id="witch-route">
    <!-- Everything before my WitchValidator component... -->

    <to uri="bean:witchValidator?method=process" />

    <choice>
        <when>
            <simple>???</simple>
            <to uri="direct:goodWitches" />
        </when>
        <when>
            <simple>???</simple>
            <to uri="direct:badWitches" />
        </when>
    </choice>
</route>

What can I put inside my <choice> to take the ValidatedWitches.getGoodWitches() and route them to direct:goodWitches, and to take the ValidatedWitches.getBadWitches() and route them to direct:badWitches?

Answer

bgossit picture bgossit · Dec 19, 2013

A <choice> is either one or the other, so in your example you can only reach one destination URI. Therefore you may need to add a <split> before the <choice> so that you have two separate messages being evaluated.

See splitter for your options there, for example you may want to create your own POJO with a method that returns a list of two ValidatedWitches objects - one with the "goodWitches" collection populated only and one with the "badWitches" collection populated only.

There are many predicate options available, but an easy one would be to check if each array was empty.

Then your route could look something like this:

<to uri="bean:witchValidator?method=process" />
<split>
    <method beanType="SPLITTER_CLASS_NAME" method="SPLITTER_METHOD" />
    <choice>
        <when>
            <simple>${body.goodWitches.size} > 0</simple>
            <to uri="direct:goodWitches" />
        </when>
        <when>
            <simple>${body.badWitches.size} > 0</simple>
            <to uri="direct:badWitches" />
        </when>
    </choice>
</split>

Key points:

  • Splitter should return a collection of two or more objects
  • Choice needs to be able to distinguish between the split objects