camel-scalaの基本的なDSL



# 前提
- 基本文法をJavaDSLとScalaDSLの比較。
- JavaDSLはApacheCamel本家からコピってちょっと改変しているので動作確認まではしていない。
- Java:1.7.0_25
- Scala:2.11.6
- Camel:2.14.0<br/> 執筆途中から2.15.0へVup RouteBuilderの派生元が変わっている。<br />```org.apache.camel.scala.dsl.builder.RouteBuilder```→<br />```org.apache.camel.scala.dsl.builder.ScalaRouteBuilder```


## Route定義
- scala は クラスのメンバーとしてRouteとなるDSLを定義する。<br />Routeを記述している ***DSLはクラスの最下部に定義する*** 必要がある。
- java は configureメソッド内にRouteとなるDSLを定義する。
- from は ```"Route定義" ==>```、to は ```-->("Route 定義")```で記述する。<br />
- java は ```;```まで、scalaは```{}```内がRoute定義となる。
- java scalaともに```RouteBuilder```を継承するのは同じだけど、 **パッケージが違う** ので注意。<br/>※camel-scala2.15.0からは```org.apache.camel.scala.dsl.builder.RouteBuilder```は@deprecatedとなり、```org.apache.camel.scala.dsl.builder.ScalaRouteBuilder```を使うようにする。


```java
import org.apache.camel.builder.RouteBuilder;

class MyRouteBuilder extends RouteBuilder {
    public void configure() {
        from("direct:a")
            .to("direct:b");
    }
}
```

```scala
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)```とも書けるが、違いはよく分からない

```java
from("direct:filter")
    .filter(body().isEqualTo("foo"))
        .to("mock:foo")
    .end()
    .to("mock:result");
```

```scala
"direct:filter" ==> {
  filter(body(_) == "foo") {
    -->("mock:foo")
  }
  -->("mock:result")
}
```

## choice - when - otherwise　(if - elseif - else)
- if elseに使う。if のみの場合はchoiceは省略できる。( = fileter)
- scalaDSLでは、```end()``` の代わりにブロック内が条件合致時の処理。
- 条件の記述方法はfilterと(多分)同じ。

```java
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");
```
```scala
"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の長さでループ出来る。<br/>※loop内でSeqの長さを変えてもloopする回数は変わらない。

```java
from("direct:b")
    .loop(header("loop"))
        .to("mock:result");
```

```scala
"direct:b" ==> {
  loop(_.in("loop"))
    -->("mock:result")
}
```

## try - catch
- attemp - handle - ensureで記述する
- multi catchは対応していない


```java
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();
```

```scala
  "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の値は引き継がれる。<br />Routeが長く肥大化してくると、Headerも肥大化しやすいので実装時に注意が必要。
- DSLで取得する場合は```_.in("header key")``` (or ```header("header key")```)で取得出来る。
- DSLで設定する場合は```setHeader("header key", [value])```で設定出来る。

### Body
メッセージ本体。

- fromでRouteが呼ばれた時にはBody部にメッセージが詰められている。
 - fileコンポーネント(```file://directory?fileName=foo.txt``` みたいの)だとファイルの中身
 - activemqコンポーネント(```activemq:queueName:QUEUE```)だとQueueの中身
- DSLで取得する場合は```body(_)```で取得出来る。
- DSLで設定する事は基本的には出来ない。(ただし応用すれば？出来る。)

# サンプルコード
https://github.com/ktr-type23/experiment-camel-scala.git

- Scala:2.11.6
- Camel:2.15.0