第2章 ルート構築の基本原則

概要

Apache Camel は、ルートの中で繋ぎ合わせられる複数のプロセッサーおよびコンポーネントを提供します。本章では、提供されるビルディングブロックを使用してルートを構築する原則を説明します。

2.1. パイプライン処理

概要

Apache Camel では、パイプライン処理はルート定義でノードを接続するための主要なパラダイムです。パイプラインの概念は、おそらく UNIX オペレーティングシステムのユーザーには最も馴染のあるものでしょう。オペレーティングシステムのコマンドを結合するために使用しているからです。たとえば、ls | more はディレクトリー一覧 ls をページスクロールのユーティリティー more にパイプするコマンドの例です。パイプラインの基本的な概念は、あるコマンドの 出力 が次の 入力 に読み込まれることです。ルートにおいては、あるプロセッサーからの Out メッセージが次のプロセッサーの In メッセージにコピーされることに相当します。

プロセッサーノード

最初のエンドポイントを除き、ルートのすべてのノードは プロセッサー で、org.apache.camel.Processor インターフェイスを継承します。つまり、プロセッサーが DSL ルートの基本ビルディングブロックを設定します。たとえば、filter()delayer()setBody()setHeader()、および to() などの DSL コマンドはすべてプロセッサーを表します。プロセッサーがどのように接続しあってルートを設定するかを考えるときに、2 つの異なる処理アプローチを区別することが重要になります。

最初のアプローチは、図2.1「In メッセージを変更するプロセッサー」 にあるように、プロセッサーが単純にエクスチェンジの In メッセージを変更する方法です 。この場合、エクスチェンジの Out メッセージは null のままになります。

図2.1 In メッセージを変更するプロセッサー

In メッセージを変更するプロセッサー

以下のルートは、BillingSystem ヘッダーを追加 (または変更) して現在の In メッセージを修正する setHeader() コマンドを示しています。

from("activemq:orderQueue")
    .setHeader("BillingSystem", xpath("/order/billingSystem"))
    .to("activemq:billingQueue");

2 つ目のアプローチは、図2.2「Out メッセージを作成するプロセッサー」 にあるように、プロセッサーが処理の結果として Out メッセージを作成する方法です。

図2.2 Out メッセージを作成するプロセッサー

Out メッセージを作成するプロセッサー

以下のルートは、文字列 DummyBody が含まれるメッセージボディーを持った Out メッセージを作成する transform() コマンドを示しています。

from("activemq:orderQueue")
    .transform(constant("DummyBody"))
    .to("activemq:billingQueue");

constant("DummyBody") は定数式を表します。transform() の引数の型は式である必要があるため、文字列 DummyBody を直接渡すことはできません。

InOnly エクスチェンジのパイプライン

図2.3「InOnly エクスチェンジのサンプルパイプライン」 は、 InOnly エクスチェンジのプロセッサーパイプラインの例を示しています。プロセッサー A は In メッセージを変更し、プロセッサー B および C は Out メッセージを作成します。ルートビルダーが、図に示されているようにプロセッサー同士を繋ぎ合わせます。特にプロセッサー B と C は パイプライン の形式で繋がれています。つまり、エクスチェンジをプロセッサー C に読み込ませる前にプロセッサー B の Out メッセージが In メッセージに移動され、エクスチェンジをプロデューサーエンドポイントに読み込ませる前にプロセッサー C の Out メッセージが In メッセージに移動されています。したがって、図2.3「InOnly エクスチェンジのサンプルパイプライン」 に示されるようにプロセッサーの出力と入力は連続したパイプラインに結合されています。

図2.3 InOnly エクスチェンジのサンプルパイプライン

InOnly エクスチェンジのパイプラインサンプル

Apache Camel はデフォルトでパイプラインパターンを使用するため、特別な構文を使用してルートにパイプラインを作成する必要はありません。たとえば、以下のルートは userdataQueue キューからメッセージを取り出し、(テキスト形式で顧客アドレスを生成するために) Velocity テンプレートを通してメッセージをパイプ処理し、生成されたテキストアドレスをキュー envelopeAddresses に送信します。

from("activemq:userdataQueue")
    .to(ExchangePattern.InOut, "velocity:file:AdressTemplate.vm")
    .to("activemq:envelopeAddresses");

Velocity エンドポイントである velocity:file:AddressTemplate.vm は、ファイルシステム内の Velocity テンプレートファイルの file:AddressTemplate.vm の場所を指定します。この to() コマンドは、エクスチェンジを Velocity エンドポイントに送信する前に、エクスチェンジパターンをInOut に変更し、その後 InOnly に戻します。Velocity エンドポイントの詳細は、Apache Camel コンポーネントリファレンスガイドVelocity を参照してください。

InOut エクスチェンジのパイプライン

図2.4「InOut エクスチェンジのサンプルパイプライン」 は、通常リモートプロシージャーコール (RPC) のセマンティクスをサポートするときに使用する、 InOut エクスチェンジ用のプロセッサーパイプラインの例を示しています。プロセッサー A、B、および C はパイプライン形式で結合され、各プロセッサーの出力が次の入力に読み込まれます。プロデューサーエンドポイントによって生成された最後の Out メッセージは、コンシューマーエンドポイントまで遡って、元のリクエストへの返信として提供されます。

図2.4 InOut エクスチェンジのサンプルパイプライン

InOut エクスチェンジのサンプルパイプライン

InOut 交換パターンをサポートするには、ルートの最後のノード (プロデューサーエンドポイントかその他の種類のプロセッサーかに限らず) が Out メッセージを作成することが 必須 です。そうでない場合は、コンシューマーエンドポイントに接続するクライアントがハングし、リプライメッセージを無期限に待ち続けることになります。すべてのプロデューサーエンドポイントが Out メッセージを作成するわけではないことに注意してください。

受信 HTTP リクエストを処理し、支払い要求を処理する以下のルートを見てみましょう。

from("jetty:http://localhost:8080/foo")
    .to("cxf:bean:addAccountDetails")
    .to("cxf:bean:getCreditRating")
    .to("cxf:bean:processTransaction");

受信支払い要求は、Web サービスのパイプライン、cxf:bean:addAccountDetailscxf:bean:getCreditRating、および cxf:bean:processTransaction を介して渡すことで処理されます。最後の Web サービス processTransaction が生成する応答 (Out メッセージ) は、Jetty エンドポイント経由で返信されます。

パイプラインがエンドポイントのシーケンスで設定される場合は、以下の代替構文を使用することもできます。

from("jetty:http://localhost:8080/foo")
    .pipeline("cxf:bean:addAccountDetails", "cxf:bean:getCreditRating", "cxf:bean:processTransaction");

InOptionalOut エクスチェンジのパイプライン

InOptionalOut エクスチェンジのパイプラインは、図2.4「InOut エクスチェンジのサンプルパイプライン」 のパイプラインと基本的に同じです。InOutInOptionalOut の相違点は、 InOptionalOut 交換パターンのエクスチェンジが応答として null Out メッセージを使用することが可能であることです。つまり、InOptionalOut エクスチェンジの場合、nullOut メッセージが、パイプラインの次のノードの In メッセージにコピーされます。一方、InOut エクスチェンジの場合、nullOut メッセージは破棄され、代わりに現在のノードの元の In メッセージが、次のノードの In メッセージにコピーされます。