Content Based Router

概要

Content Base Routerは、メッセージをその内容に基づいて、適切な後続の処理にルーティングします。

Java言語などにおける、if - then - elseswitch - caseに該当します。


Content Base Router

基本

基本的なSpring XMLは次の通り、<choice> - <when> - <otherwise> で、条件が複数ある場合は<when>を複数繰り返します。

<when>には、<simple>${header.type} == 'A'</simple>のような条件と実行する処理を記述します。 ここでは、Simple言語を用いて、ヘッダtypeの値により処理を分けています。

    <camelContext xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="direct:start"/>
            <!-- (1)  -->
            <log message="(1) type = ${header.type}" />
            <choice>
                <when>
                    <simple>${header.type} == 'A'</simple>
                    <log message="(2) Adding ${body} ..." />
                </when>
                <when>
                    <simple>${header.type} == 'D'</simple>
                    <log message="(3) Deleting ${body} ..." />
                </when>
                <otherwise>
                    <log message="(4) Unknown Type: ${header.type}" />
                </otherwise>
            </choice>
            <log message="(5) end." />
            <to uri="mock:result"/>
        </route>
    </camelContext>

このSpring XMLに対して、ヘッダtypeに、A Dおよび?を設定したメッセージを流通します。

    @Test
    @DirtiesContext
    public void testHeaderType() throws Exception {  
        // 入力データ送信
        template.sendBodyAndHeader("direct:start", "No.1 data", "type", "A");
        template.sendBodyAndHeader("direct:start", "No.2 data", "type", "D");
        template.sendBodyAndHeader("direct:start", "No.3 data", "type", "?");
    }

実行結果は次のようになります。

[main] (1) type = A
[main] (2) Adding No.1 data ...
[main] (5) end.
[main] (1) type = D
[main] (3) Deleting No.2 data ...
[main] (5) end.
[main] (1) type = ?
[main] (4) Unknown Type: ?
[main] (5) end.

応用

複雑な条件

上記では、ヘッダの値により条件を設定していましたが、もう少し複雑な条件を使用したい場合は、<simple>のかわりに、<method>を使用してJavaのメソッドで条件を設定することも可能です。

次のような、Exchaneを受け取ってヘッダの値を確認するクラスを作成します。

package com.buildria.camel.example.eip.cbr;

import org.apache.camel.Exchange;

public class HeaderChecker {

    /**
     * ヘッダ"type"の値が"A"であるかチェックします。
     * 
     * @param exchange Exchange
     * @return  ヘッダ"type"の値が"A"の場合<code>true</code>
     */
    public boolean isTypeA(Exchange exchange) {
     // ヘッダ"type"の値を取得
        String type = exchange.getIn().getHeader("type", String.class);
       // "A"か"a"ならtrue
        return "A".equalsIgnoreCase(type);
    }
}

SpringXMLでは、<simple>のかわりに、<method>で実行するクラスとメソッドを指定します。

    <camelContext xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="direct:start"/>
            <log message="(1) type = ${header.type}" />
            <choice>
                <when>
                   <!-- HeaderChecker#isTypeA()が真の場合 -->
                    <method ref="HeaderChecker" method="isTypeA" />
                    <log message="(2) Adding ${body} ..." />
                </when>
                <otherwise>
                   <!-- 真でない場合 -->
                    <log message="(3) Unknown Type: ${header.type}" />
                </otherwise>
            </choice>
            <log message="(4) end." />
            <to uri="mock:result"/>
        </route>
    </camelContext>
    
    <!-- ロジックの定義 -->
    <bean id="HeaderChecker" class="com.buildria.camel.example.eip.cbr.HeaderChecker" />

このとき、同様のデータを流すと、ヘッダtypeがAの場合、(2)が実行されます。

[main] (1) type = A
[main] (2) Adding No.1 data ...
[main] (4) end.
[main] (1) type = D
[main] (3) Unknown Type: D
[main] (4) end.
[main] (1) type = ?
[main] (3) Unknown Type: ?
[main] (4) end.

何らかのロジックの結果により処理を分岐する場合は、<method>を使うよりも、<process><bean>で処理結果をヘッダに設定し、その値で分岐するほうがわかりやすいかもしれません。

関連項目