Stream 移行ガイド / Play2.6【翻訳】

[Play framework 2.5.x ： Stream 移行ガイド](https://www.playframework.com/documentation/2.5.x/StreamsMigration25) を google 翻訳した。（websocket/Commet/EventSource は使ってないので未訳）

------------------------
# Streams移行ガイド

Play 2.5では、データとレスポンスの本体をどのようにストリームするかが大きく変わっています。

  1. Play 2.5では、 **ストリーミング用のAkkaストリーム** が使用されます。以前のバージョンのPlayでは、 `WebSocket`、`Chunks` など、いくつかの特別な種類のストリーミングだけでなく、ストリーミングにiteratees を使用していました。

    Akkaストリームに変更する主なメリットは2つあります。まず、JavaユーザーはPlayの全機能セットにアクセスできるようになりました。ボディーパーサとフィルタを記述できます。次に、ストリーミングライブラリはPlay全体でより一貫性があります。

  2. Play 2.5は **バイトのパケットを保持するために `ByteString`** を使用します。以前は、Playはバイト配列（ `byte[]` / `ArrayByte`）を使っていました。

    `ByteString` クラスはJavaの `String` のように不変ですので、安全で使いやすいです。 `String` と同様に、構築時にデータをコピーするため、パフォーマンスコストは小さくなりますが、これは安価な連結および部分文字列演算とのバランスが取れています。

  3. Play 2.5は **レスポンスボディに新しい `HttpEntity` タイプ** を持っています。これまでのレスポンスボディは、単純なバイトストリームでした。 HTTPボディは `HttpEntity`の一種です： `Strict`、 `Streamed`、` Chunked` です。

    Playにどのタイプのエンティティを使用するかを伝えることで、アプリケーションはPlayのHTTP応答の送信方法をより詳細に制御できます。また、Playが本体をどのように配信するのかを簡単に最適化することもできます。

## 変更の概要

Play APIの次の部分が更新されました：

- 結果（ `Result`本体、` chunked` / `feed` /` stream`メソッド）
- アクション（ `EssentialAction`）
- ボディパーサー（ `BodyParser`）
- WebSocket（ `WebSocket`）
- サーバー送信イベント（ `EventSource`）

以下のタイプが変更されました：

| **目的** | **古いタイプ** | **新しいタイプ**   |
|---------|--------------|----------------|
| バイト保持 | `byte []` / `配列[Byte]` | `ByteString` |
| ストリーム生成 | `Enumerator`、` WebSocket.Out`、 `Chunks.Out`、` EventSource.Out` | `Source` |
| ストリームを別のストリームに変換する| `Enumeratee`  |  `Flow` |
| ストリームを単一の値に変換する| `Iteratee`  |  `Accumulator`
| ストリームを消費する| `Iteratee`  |  `Sink`

## 移行方法（API別）

次のセクションでは、APIのさまざまな部分を使用するコードを移行する方法の概要を示します。

### チャンク結果の移行（ `chunked`、` Results.Chunked`）

Play 2.4 では、Scalaで `Enumerator` 、そしてJavaで `Results.Chunked` オブジェクトを使用してチャンク結果を作成します。 Play 2.5では、これらのAPIの部分は引き続き使用できますが、廃止されました。

新しいAPIに移行する場合は、 `StatusHeader` オブジェクトで `chunked` メソッドを呼び出し、チャンクのストリームにAkka Streams `Source` オブジェクトを提供することで、チャンク結果を作成できます。

より高度なユーザは、明示的に `HttpEntity.Chunked` オブジェクトを作成し、それを `Result` オブジェクトコンストラクタに渡すことを好むかもしれません。

* `Enumerator` を `Source` に移行する方法については、`Enumerator` を `Source` に移行する」を参照してください。

### ストリーミング結果の移行（ `feed`、`stream` ）（Scalaのみ）

Play 2.4では、Scalaユーザは `Enumerator` を `feed` メソッドまたは `stream` メソッドに渡すことで結果をストリーミングできます。 （Javaユーザは、チャンクされた結果とは別に、結果をストリーミングする方法がありませんでした）。 `feed` メソッドは、 `Enumerator` のデータをストリーミングして接続を閉じました。 `stream` メソッドは、HTTPバージョンの接続と `Content-Length` ヘッダの有無に応じて、結果をストリーミングまたはチャンクして、おそらく接続を閉じました。

Play 2.5では、 `stream`メソッドが削除され、 `feed` メソッドは廃止されました。 `feed` メソッドを新しいAPIに移行するかどうかを選択することができます。 `stream` メソッドを使うとコードを変更する必要があります。

新しいAPIは、 `Result` オブジェクトを直接作成し、その本体を表す `HttpEntity` を選択することです。ストリーミングされた結果の場合、 `HttpEntity.Streamed` クラスを使用することができます。 `Streamed`
 クラスは `Source` を本体とし、オプションの `Content-Length` ヘッダ値をとります。 `Source` の内容はクライアントに送られます。エンティティに `Content-Length` ヘッダがある場合、接続はオープンのままになります。そうでなければ、ストリームの終わりを知らせるために閉じられます。

* `Enumerator` を `Source` に移行する方法については、「`Enumerator` を `Source` に移行する」を参照してください。


### 未訳部分

```
### Migrating WebSockets (`WebSocket`)
#### Migrating Scala WebSockets
#### Migrating Java WebSockets
### Migrating Comet
#### Migrating Java Comet
#### Migrating Scala Comet
### Migrating Server-Sent events (`EventSource`)
#### Migrating Java Server-Sent events
#### Migrating Scala Server-Sent events
```

### カスタムアクションの移行（ `EssentialAction` ）（Scalaのみ）

Scalaのほとんどのユーザーは、アクションに `Action` クラスを使用します。 `Action` クラスはロジックを実行して結果を送る前に常にボディを完全に解析する `EssentialAction` の一種です。 ユーザは独自のカスタムEssentialActionを書いてリクエストボディーを段階的に処理するようなことをすることができます。

Play 2.4 アプリケーションで通常の `Action` を使用している場合は、マイグレーションは必要ありません。 しかし、もしあなたが `EssentialAction` を書いたのであれば、それを Play 2.5 の新しいAPIに移す必要があります。 「EssentialAction」の動作は同じですが、シグネチャは Play 2.4 から変更されました：

```scala
trait EssentialAction extends (RequestHeader => Iteratee[Array[Byte], Result])
```

to a new signature in Play 2.5:

```scala
trait EssentialAction extends (RequestHeader => Accumulator[ByteString, Result])
```

移行するには、 `Iteratee` を `Accumulator` と `Array[Byte]` を `ByteString` で置き換える必要があります。

* IterateeをAccumulatorに移行する方法については、「IterateesをSinks and Accumulatorsに移行する」を参照してください。
* `Array[Byte]` を `ByteString` に移行する方法については、「ByteStringsへのバイト配列の移行」を参照してください。

###カスタムボディパーサーの移行（ `BodyParser` ）（Scalaのみ）

Play 2.4アプリケーションに独自のBodyParserを持っているScalaユーザーの場合は、新しいPlay 2.5 APIに移行する必要があります。 `BodyParser`型シグネチャは、Play 2.4では次のようになります。

```scala
trait BodyParser[+A] extends (RequestHeader => Iteratee[Array[Byte], Either[Result, A]])
```

In Play 2.5 it has changed to use Akka Streams types:

```scala
trait BodyParser[+A] extends (RequestHeader => Accumulator[ByteString, Either[Result, A]])
```

移行するには、 `Iteratee` を `Accumulator` と `Array[Byte]` を `ByteString` で置き換える必要があります。

* Iteratee を Accumulator に移行する方法については、「IterateesをSinks and Accumulatorsに移行する」を参照してください。
* [Array [Byte]]をByteStringに移行する方法については、「ByteStringsへのバイト配列の移行」を参照してください。

### `Result` ボディーの移行（Scalaのみ）

`Result` オブジェクトは、結果本体と接続クローズフラグの表現方法が変更されました。 `body: Enumerator[Array[Byte]], connection: Connection`  から `body: HttpEntity` に取り替えることになりました。 `HttpEntity` 型にはボディに関する情報と接続を閉じる方法に関する暗黙の情報が含まれています。

`Source` とオプションの `Content-Length` と `Content-Type` ヘッダを含む `Streamed` エンティティを使って、既存の `Enumerator` を移行できます。

```scala
val bodyPublisher: Publisher[ByteString] = Streams.enumeratorToPublisher(bodyEnumerator)
val bodySource: Source[ByteString, _] = Source.fromPublisher(bodyPublisher)
val entity: HttpEntity = HttpEntity.Streamed(bodySource)
new Result(headers, entity)
```

これらの型への移行の詳細については、 `Enumerator`s の移行と `ByteString` への移行の節を参照してください。

* Iteratee を Accumulator に移行する方法については、「IterateesをSinks and Accumulatorsに移行する」を参照してください。
* [Array [Byte]]をByteStringに移行する方法については、「ByteStringsへのバイト配列の移行」を参照してください。

`Result`ボディのストリームはまったく必要ないかもしれません。 そうであれば、ボディに `Strict`エンティティを使えます。


```scala
new Result(headers, HttpEntity.Strict(bytes))
```

## 移行する方法（型別）

このセクションでは、バイト配列とストリームを新しいAkka Streams APIに移行する方法について説明します。

Akka StreamsはAkkaプロジェクトの一部です。 PlayはAkka Streamsを使用してストリーミング機能を提供します。一連のバイトやその他のオブジェクトを送受信します。 Akkaプロジェクトには、Akkaストリームに関する多くの優れたドキュメントがあります。 PlayでAkka Streamsを使用する前に、利用可能な情報を確認するためにAkka Streamsのドキュメントを調べることをお勧めします。

* [Documentation for Java](http://doc.akka.io/docs/akka/2.4.4/java/stream/index.html)
* [Documentation for Scala](http://doc.akka.io/docs/akka/2.4.4/scala/stream/index.html)

APIドキュメントは、Akka APIの主要なドキュメントの `akka.stream` パッケージの下にあります：

* [Akka Javadoc](http://doc.akka.io/japi/akka/2.4.4/)
* [Akka Scala](http://doc.akka.io/api/akka/2.4.4/)

最初にAkka Streamsを使い始めるときは、 **Basics のフローの操作** セクションを見ることをお勧めします。 Akka Streams APIの最も重要な部分を紹介します。

* [Basics for Java](http://doc.akka.io/docs/akka/2.4.4/java/stream/stream-flows-and-basics.html)
* [Basics for Scala](http://doc.akka.io/docs/akka/2.4.4/scala/stream/stream-flows-and-basics.html)

一度にアプリケーション全体を変換する必要はありません。 アプリケーションの一部は繰り返し使用でき、他の部分はAkkaストリームを使用します。 Akka Streamsは [reactive streams](http://reactive-streams.org) の実装を提供し、Playのiterateesライブラリも反応ストリームの実装を提供します。その結果、Play の iteratees は Akka Streams に簡単にラップすることができます。

###バイト配列（ `byte[]` / `Array[Byte]`）を `ByteString`に移行する

[Java](http://doc.akka.io/japi/akka/2.4.4/index.html) と [Scala](http://doc.akka.io/api/akka/2.4.4/akka/util/ByteString.html) の `ByteString`のAPIドキュメントを参照してください。

例：

Scala:

```scala
// Get the empty ByteString (this instance is cached)
ByteString.empty
// Create a ByteString from a String
ByteString("hello")
ByteString.fromString("hello")
// Create a ByteString from an Array[Byte]
ByteString(arr)
ByteString.fromArray(arr)
```

Java:

```java
// Get the empty ByteString (this instance is cached)
ByteString.empty();
// Create a ByteString from a String
ByteString.fromString("hello");
// Create a ByteString from an Array[Byte]
ByteString.fromArray(arr);
```
### `*.Outs` を `Source` に移行する

Playでは、元の `WebSocket.Out` クラス、 `Chunks.Out` クラス、 `EventSource.Out` クラスではなく、 `Source` を使用してイベントを生成します。 これらのクラスは使用が簡単でしたが、柔軟性がなく、[back](http://doc.akka.io/docs/akka/2.4.4/java/stream/stream-flows-and-basics.html#back-pressure-explained) [pressure](http://doc.akka.io/docs/akka/2.4.4/scala/stream/stream-flows-and-basics.html#back-pressure-explained) を適切に実装しませんでした。

`*.Out` クラスは、ストリームを生成するすべての `Source` で置き換えることができます。 `Source` を作成する方法はたくさんあります ([Java](http://doc.akka.io/docs/akka/2.4.4/java/stream/stream-flows-and-basics.html#Defining_sources__sinks_and_flows)/[Scala](http://doc.akka.io/docs/akka/2.4.4/scala/stream/stream-flows-and-basics.html#Defining_sources__sinks_and_flows))。

`*.Out` を単純なオブジェクトに置き換えて、バック・プレッシャーを心配することなく、メッセージを書いたり閉じることができたら、 `Source.actorRef` メソッドを使うことができます：

```java
Source<ByteString, ?> source = Source.<ByteString>actorRef(256, OverflowStrategy.dropNew())
  .mapMaterializedValue(sourceActor -> {
    sourceActor.tell(ByteString.fromString("hello"), null);
    sourceActor.tell(ByteString.fromString("world"), null);
    sourceActor.tell(new Status.Success(NotUsed.getInstance()), null);
    return null;
  });
```

Scala:

```scala
val source = Source.actorRef[ByteString](256, OverflowStrategy.dropNew).mapMaterializedValue { sourceActor =>
  sourceActor ! ByteString("hello")
  sourceActor ! ByteString("world")
  sourceActor ! Status.Success(()) // close the source
}
```


### `Enumerator` を `Source` に移行する

Playは多くの場所で `Enumerator` を使用して値のストリームを生成します。

**ステップ1：** 移行APIを使用する（利用可能な場合）

`Results.chunked` または `Results.feed` を使用する場合は、引き続き既存のメソッドを使用できます。 これらのメソッドは廃止されました。したがって、とにかくコードを変更したい場合があります。

**ステップ2：** アダプタを使用して `Enumerator` を `Source` に変換する

既存の `Enumerator` を `Streams.enumeratorToPublisher` を使用してリアクティブストリーム `Publisher` に変換した後、 [`Source.fromPublisher`](http://doc.akka.io/api/akka/2.4.4/akka/stream/scaladsl/Source$.html#fromPublisher[T]\(Publisher[T]\):Source[T,NotUsed]) を使用してパブリッシャをソースに変換することで、既存の列挙子をソースに変換できます。

```scala
val enumerator: Enumerator[T] = ...
val source = Source.fromPublisher(Streams.enumeratorToPublisher(enumerator))
```

**ステップ3：** （オプション）ソースに書き直す

列挙子ファクトリメソッドの一般的なマッピングの一覧を次に示します。

| **Iteratees** | **Akka Streams** | **Notes** |
|--------|--------|--------|
| `Enumerator.apply(a)` | `Source.single(a)` | |
| `Enumerator.apply(a, b)` | `Source.apply(List(a, b)))` | |
| `Enumerator.enumerate(seq)` | `Source.apply(seq)` | `seq` must be immutable |
| `Enumerator.repeat` | `Source.repeat` | 繰り返し要素は、Akkaストリームで毎回評価されません |
| `Enumerator.empty` | `Source.empty` | |
| `Enumerator.unfold` | `Source.unfold` | |
| `Enumerator.generateM` | `Source.unfoldAsync` | |
| `Enumerator.fromStream` | `StreamConverters.fromInputStream` | |
| `Enumerator.fromFile` | `StreamConverters.fromInputStream` | `java.io.File`のための` InputStream`を作成しなければなりません。 |

### `Iteratee` を `Sink`s と `Accumulator`s に移行する

**ステップ1：** アダプタを使用して変換する

既存の `Iteratee` を `Streams.iterateeToSubscriber` を使ってリアクティブストリーム `Subscriber` に変換してから `Sink` に変換し、 [`Sink.fromSubscriber`](http://doc.akka.io/api/akka/2.4.4/akka/stream/scaladsl/Sink$.html#fromSubscriber[T](Subscriber[T]):Sink[T,NotUsed]) を使ってシンクに変換することができます。例えば：

```scala
val iteratee: Iteratee[T, U] = ...
val (subscriber, resultIteratee) = Streams.iterateeToSubscriber(iteratee)
val sink = Sink.fromSubscriber(subscriber)
```

`Accumulator` を返す必要がある場合は、代わりに [`Streams.iterateeToAccumulator`](https://www.playframework.com/documentation/2.5.x/api/scala/play/api/libs/streams/Streams$.html#iterateeToAccumulator[T,U](Iteratee[T,U]):Accumulator[T,U]) が使えます。

**ステップ2：** （オプション）`Sink` に書き直す

iterateeファクトリメソッドの一般的なマッピングのリストを次に示します。

| **Iteratees** | **Akka Streams** | **Notes** |
| --------|---|---|
| `Iteratee.fold` | `Sink.fold` | |
| `Iteratee.head` | `Sink.headOption` | |
| `Iteratee.getChunks` | `Sink.seq` | |
| `Iteratee.foreach` | `Sink.foreach` | |
| `Iteratee.ignore` | `Sink.ignore` | |
| `Done` | `Sink.cancelled` | マテリアライズされた値は、結果を生成するためにマップすることができます。アキュムレータを使用する場合は、代わりに `Accumulator.done` を使用できます。 |


### `Enumeratees` の `Processor` への移行

**ステップ1：** アダプタを使用して変換する

[`Flow.fromProcessor`](http://doc.akka.io/api/akka/2.4.4/akka/stream/scaladsl/Flow$.html#fromProcessor[I,O]\(\(\)⇒Processor[I,O]\):Flow[I,O,NotUsed]) を使用して、既存の `Enumeratee` を `Flow` に変換し、その後、 `Flow.fromProcessor` を使用して `Processor` を `Flow` に変換できます。たとえば、次のようになります。

```scala
val enumeratee: Enumeratee[A, B] = ...
val flow = Flow.fromProcessor(() => Streams.enumerateeToProcessor(enumeratee))
```

**ステップ2 :** (オプション） `Flow` への書き換え

列挙型ファクトリメソッドの一般的なマッピングのリストを次に示します。

| **Iteratees** | **Akka Streams** | **Notes** |
| --------|----|----|
| `Enumeratee.map` | `Flow.map` | |
| `Enumeratee.mapM` | `Flow.mapAsync` | Akka Streamsの並列性、つまり一度に並列にマップされる要素の数を指定する必要があります。 |
| `Enumeratee.mapConcat` | `Flow.mapConcat` | |
| `Enumeratee.filter` | `Flow.filter` | |
| `Enumeratee.take` | `Flow.take` | |
| `Enumeratee.takeWhile` | `Flow.takeWhile` | |
| `Enumeratee.drop` | `Flow.drop` | |
| `Enumeratee.dropWhile` | `Flow.dropWhile` | |
| `Enumeratee.collect` | `Flow.collect` | |

--------------------------

[Apache License 2.0](https://github.com/playframework/playframework/blob/master/LICENSE)