前提
- 基本文法をJavaDSLとScalaDSLの比較。
- JavaDSLはApacheCamel本家からコピってちょっと改変しているので動作確認まではしていない。
- Java:1.7.0_25
- Scala:2.11.6
- Camel:2.14.0
執筆途中から2.15.0へVup RouteBuilderの派生元が変わっている。org.apache.camel.scala.dsl.builder.RouteBuilder
→org.apache.camel.scala.dsl.builder.ScalaRouteBuilder
Route定義
- scala は クラスのメンバーとしてRouteとなるDSLを定義する。
Routeを記述している DSLはクラスの最下部に定義する 必要がある。 - java は configureメソッド内にRouteとなるDSLを定義する。
- from は
"Route定義" ==>
、to は-->("Route 定義")
で記述する。
- java は
;
まで、scalaは{}
内がRoute定義となる。 - java scalaともに
RouteBuilder
を継承するのは同じだけど、 パッケージが違う ので注意。
※camel-scala2.15.0からはorg.apache.camel.scala.dsl.builder.RouteBuilder
は@deprecatedとなり、org.apache.camel.scala.dsl.builder.ScalaRouteBuilder
を使うようにする。
import org.apache.camel.builder.RouteBuilder;
class MyRouteBuilder extends RouteBuilder {
public void configure() {
from("direct:a")
.to("direct:b");
}
}
import org.apache.camel.scala.dsl.builder.RouteBuilder
class MyRouteBuilder extends RouteBuilder {
from("direct:a") {
to("direct:b")
}
// from - to を記号を使っても書ける。
// こっちの方がscalaっぽい気がする。
"direct:aa" ==> {
-->("direct:bb")
}
}
以下、特筆が無ければ以下の前提で記述する
- JavaDSLはconfigureメソッド内。
- ScalaDSLのfrom - to は
==>
-->
形式
filter (if)
- if文のみで else文は書けない
- headerのオブジェクトの有無でも判断出来る
- headerやbodyがBooleanの場合は、式を省略することが出来る
- booleanを返すprocessorを引数に渡すことが出来る
- Scalaの場合、
header("key")
を_.in(key)
とも書けるが、違いはよく分からない
from("direct:filter")
.filter(body().isEqualTo("foo"))
.to("mock:foo")
.end()
.to("mock:result");
"direct:filter" ==> {
filter(body(_) == "foo") {
-->("mock:foo")
}
-->("mock:result")
}
choice - when - otherwise (if - elseif - else)
- if elseに使う。if のみの場合はchoiceは省略できる。( = fileter)
- scalaDSLでは、
end()
の代わりにブロック内が条件合致時の処理。 - 条件の記述方法はfilterと(多分)同じ。
from("direct:if-else-body")
.choice()
.when(body().isEqualTo("foo")).to("mock:foo")
.when(body().isEqualTo("bar")).to("mock:bar").stop()
.otherwise().to("mock:otherwise")
.end()
.to("mock:result");
"direct:if-else-body" ==> {
choice {
when(body(_) == "foo") {
-->("mock:foo")
}
when(body(_) == "bar") {
-->("mock:bar")
stop
}
otherwise {
-->("mock:otherwise")
}
}
-->("mock:result")
}
loop (for or while)
- 回数は固定で途中でブレイク出来ない
- 固定回数の場合は引数にそのまま数値を記述出来る
- 条件式は
_.in("key").asInstansOf[Seq[Any]].length
とか書けば、Seqの長さでループ出来る。
※loop内でSeqの長さを変えてもloopする回数は変わらない。
from("direct:b")
.loop(header("loop"))
.to("mock:result");
"direct:b" ==> {
loop(_.in("loop"))
-->("mock:result")
}
try - catch
- attemp - handle - ensureで記述する
- multi catchは対応していない
from("direct:direct:attempt-handle")
.doTry()
.process(new ProcessorFail())
.to("mock:result")
.doCatch(IllegalStateException.class, NullPointerException.class)
.to("mock:illegalstate-or-nullpointer-exception")
.doCatch(Exception.class)
.to("mock:exception")
.doFinally()
.to("mock:finally")
.end();
"direct:attempt-handle" ==> {
attempt {
process(occurException)
-->("mock:result")
} handle (classOf[IllegalStateException]) apply {
-->("mock:illegal-state-exception")
} handle (classOf[Exception]) apply {
-->("mock:exception")
} ensure {
-->("mock:finally")
}
}
Tips
HeaderとBody
誤解を恐れずいえば、Exchange(箱)の中はInメッセージ(HTTPで言えば、Request)とOutメッセージ(同 Response)に分かれている。
また、InとOutはそれぞれ、HeaderとBodyでデータを保持してる。
Header
-
Map[String, Any]
のような物。 - J2EEでいうと、Sessionオブジェクトのような存在。
-
direct
やseda
コンポネントで別Routeを呼んだ場合、Headerの値は引き継がれる。
Routeが長く肥大化してくると、Headerも肥大化しやすいので実装時に注意が必要。 - DSLで取得する場合は
_.in("header key")
(orheader("header key")
)で取得出来る。 - DSLで設定する場合は
setHeader("header key", [value])
で設定出来る。
Body
メッセージ本体。
- fromでRouteが呼ばれた時にはBody部にメッセージが詰められている。
- fileコンポーネント(
file://directory?fileName=foo.txt
みたいの)だとファイルの中身 - activemqコンポーネント(
activemq:queueName:QUEUE
)だとQueueの中身
- fileコンポーネント(
- DSLで取得する場合は
body(_)
で取得出来る。 - DSLで設定する事は基本的には出来ない。(ただし応用すれば?出来る。)
サンプルコード
- Scala:2.11.6
- Camel:2.15.0