1.2. 基本的な Java DSL 構文
DSL とは
ドメイン固有言語 (DSL) は、特別な目的のために設計されたミニ言語です。DSL は論理的に完全である必要はありませんが、選択したドメインで適切に問題を記述するのに十分な表現力が必要になります。通常、DSL には専用のパーサー、インタープリター、またはコンパイラーは 必要ありません。DSL コンストラクトがホスト言語 API のコンストラクトに適切にマッピングされていれば、DSL は既存のオブジェクト指向ホスト言語の上に便乗できます。
架空の DSL で以下の一連のコマンドを考えてみましょう。
command01; command02; command03;
これらのコマンドは、以下のような Java メソッド呼び出しにマップできます。
command01().command02().command03()
ブロックを Java メソッド呼び出しにマップすることもできます。以下に例を示します。
command01().startBlock().command02().command03().endBlock()
DSL 構文は、ホスト言語 API のデータ型によって暗黙的に定義されます。たとえば、Java メソッドの戻り値の型によって、次 (DSL の次のコマンドと同等) をアクティブに呼び出すことのできるメソッドが決定します。
ルータールール構文
Apache Camel は、ルーティングルールを定義する ルーター DSL を定義します。この DSL を使用して、RouteBuilder.configure()
実装のボディーにルールを定義できます。図1.1「ローカルルーティングルール」 は、ローカルルーティングルールを定義する基本的な構文の概要を示しています。
図1.1 ローカルルーティングルール
ローカルルールは、常に from("EndpointURL")
メソッドで開始します。このメソッドは、ルーティングルールのメッセージのソース (コンシューマーエンドポイント) を指定します。その後、ルールに任意の長いプロセッサーチェーンを追加できます (例: filter()
)。通常、to("EndpointURL")
メソッドでルールを終了します。このメソッドは、ルールを通過するメッセージのターゲット (producer endpoint) を指定します。ただし、常に to()
でルールを終了する必要はありません。メッセージのターゲットをルールに指定する別の方法もあります。
特別なプロセッサータイプ (intercept()
、exception()
、または errorHandler()
など) でルールを開始することで、グローバルルーティングルールを定義することもできます。グローバルルールはこのガイドの対象範囲外です。
コンシューマーおよびプロデューサー
ローカルルールは、常に from("EndpointURL")
を使用してコンシューマーエンドポイントを定義して開始します。そして (常にではありませんが) 通常は、to("EndpointURL")
を使用してプロデューサーエンドポイントを定義して終了します。エンドポイント URL である EndpointURL は、デプロイ時に設定された任意のコンポーネントを使用できます。たとえば、ファイルエンドポイント file:MyMessageDirectory
、Apache CXF エンドポイント cxf:MyServiceName
、または Apache ActiveMQ エンドポイント activemq:queue:MyQName
を使用できます。全てのコンポーネント型を網羅するリストは、Apache Camel Component Reference を参照してください。
エクスチェンジ
エクスチェンジ オブジェクトは、メタデータで拡張されたメッセージで構成されます。エクスチェンジはメッセージがルーティングルールを介して伝搬される際に使われる標準形式であるため、Apache Camel において最も重要です。エクスチェンジの主な構成要素は次のとおりです。
Inメッセージ - エクスチェンジによってカプセル化された現在のメッセージです。エクスチェンジがルートを通過するにつれて、このメッセージは変更される場合があります。そのため、ルート開始時の In メッセージは、通常ルート終了時の Inメッセージとは 異なります。
org.apache.camel.Message
タイプは、以下の部分を含むメッセージの汎用モデルを提供します。- ボディー
- ヘッダー
- アタッチメント
これはメッセージの 汎用 モデルであることを理解することが重要です。Apache Camel は、さまざまなプロトコルおよびエンドポイントをサポートします。したがって、メッセージのボディーまたはヘッダーの形式を標準化することは できません。たとえば、JMS メッセージのボディー形式は、HTTP メッセージまたは Web サービスメッセージのボディーとは全く異なります。このため、ボディーとヘッダーは
Object
タイプと宣言されます。ボディーとヘッダーの元のコンテンツは、エクスチェンジインスタンスを作成するエンドポイントによって決定されます (つまり、from()
コマンドに指定されたエンドポイント)。out メッセージ - 返信メッセージまたは変換されたメッセージの一時的な保持領域です。特定の処理ノード (特に
to()
コマンド) は、In メッセージをリクエストとして処理し、これをプロデューサーエンドポイントに送信し、そのエンドポイントからのリプライを受信することで、現在のメッセージを変更できます。リプライメッセージは、エクスチェンジの Out メッセージスロットに挿入されます。通常、現在のノードで Out メッセージが設定された場合、Apache Camel はエクスチェンジを次のように変更してからルートの次のノードに渡します: In メッセージを破棄し、Out メッセージを In メッセージのスロットに移動します。そのため、リプライは最新のメッセージになります。Apache Camel がノード同士をルート内で接続する方法の詳細は、「パイプライン処理」 を参照してください。
ただし、Out メッセージが異なる方法で扱われる特殊なケースが 1 つあります。ルート開始時のコンシューマーエンドポイントがリプライメッセージを期待している場合、ルートの最終端にある Out メッセージはコンシューマーエンドポイントのリプライメッセージとみなされます (さらに、この場合、最終ノードが Out メッセージを作成 しなければならず、さもなくばコンシューマーエンドポイントはハングしてしまいます)。
メッセージ交換パターン (MEP) - 以下のように、ルート内でのエクスチェンジとエンドポイント間のやり取りに影響を与えます。
- コンシューマーエンドポイント - 元となるエクスチェンジを作成するコンシューマーエンドポイントは、MEP の初期値を設定します。初期値は、コンシューマーエンドポイントがリプライするか (例: InOut MEP)、リプライしないか (例: InOnly MEP) を示します。
-
プロデューサーエンドポイント - MEP は、エクスチェンジがルートで通過するプロデューサーエンドポイントに影響します (例: エクスチェンジが
to()
ノードを通過する場合)。たとえば、現在の MEP が InOnly の場合、to()
ノードはエンドポイントからのリプライを受け取ることを期待しません。場合によっては、エクスチェンジのプロデューサーエンドポイントとのやり取りをカスタマイズするために、現在の MEP を変更する必要があります。詳細は、「エンドポイント」 を参照してください。
- エクスチェンジプロパティー - 現在のメッセージのメタデータが含まれる名前付きプロパティーのリスト。
メッセージ交換パターン
Exchange
オブジェクトを使用すると、メッセージ処理を異なる メッセージ交換パターン に簡単に一般化することができます。たとえば、非同期プロトコルは、コンシューマーエンドポイントからプロデューサーエンドポイントに流れる単一のメッセージで構成される MEP を定義する場合があります (InOnly MEP)。一方、RPC プロトコルは、リクエストメッセージとリプライメッセージで構成される MEP を定義する場合があります (InOut MEP)。現在、Apache Camel は以下の MEP をサポートします。
-
InOnly
-
RobustInOnly
-
InOut
-
InOptionalOut
-
OutOnly
-
RobustOutOnly
-
OutIn
-
OutOptionalIn
これらのメッセージ交換パターンは、列挙型の定数 org.apache.camel.ExchangePattern
によって表されます。
グループ化されたエクスチェンジ
複数のエクスチェンジインスタンスをカプセル化した 1 つのエクスチェンジがあると便利な場合もあります。これに対応する為、グループ化されたエクスチェンジ を使用できます。グループ化されたエクスチェンジは、基本的 Exchange.GROUPED_EXCHANGE
エクスチェンジプロパティーに格納されている Exchange
オブジェクトの java.util.List
が含まれるエクスチェンジインスタンスです。グループ化されたエクスチェンジの使用例は、「Aggregator」 を参照してください。
プロセッサー
プロセッサー は、ルートを通過するエクスチェンジのストリームにアクセスして変更することができるルート内のノードです。プロセッサーは、動作を変更する 式 や 述語 の引数を取ることができます。たとえば、図1.1「ローカルルーティングルール」 で示されたルールには、xpath()
述語を引数とする filter()
プロセッサーが含まれます。
式および述語
式 (文字列またはその他のデータ型への評価) および述語 (true または false への評価) は、組み込みプロセッサー型の引数として頻繁に発生します。たとえば、以下のフィルタールールは、ヘッダー foo
の値が bar
と等しい場合にのみ In メッセージを伝播します。
from("seda:a").filter(header("foo").isEqualTo("bar")).to("seda:b");
header("foo").isEqualTo("bar")
ではフィルターが述語によって修飾されます。メッセージの内容に基づいてより高度な述語や式を作成するために、式言語および述語言語のいずれかを使用できます (パートII「ルーティング式と述語言語」 を参照)。