2018-11-16 15:00:30 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2014-2019 Lightbend Inc. <https://www.lightbend.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package akka.stream.javadsl
|
|
|
|
|
|
|
|
|
|
import akka.annotation.ApiMayChange
|
|
|
|
|
import akka.japi.{ Pair, Util, function }
|
|
|
|
|
import akka.stream._
|
2019-02-17 21:00:02 +01:00
|
|
|
import akka.event.LoggingAdapter
|
|
|
|
|
import akka.util.ConstantFun
|
2018-11-16 15:00:30 +01:00
|
|
|
|
|
|
|
|
import scala.annotation.unchecked.uncheckedVariance
|
|
|
|
|
import scala.collection.JavaConverters._
|
|
|
|
|
import java.util.concurrent.CompletionStage
|
|
|
|
|
|
|
|
|
|
import scala.compat.java8.FutureConverters._
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* API MAY CHANGE
|
|
|
|
|
*/
|
|
|
|
|
@ApiMayChange
|
|
|
|
|
object FlowWithContext {
|
2019-02-21 14:24:35 +01:00
|
|
|
|
|
|
|
|
def create[In, Ctx](): FlowWithContext[In, Ctx, In, Ctx, akka.NotUsed] = {
|
|
|
|
|
new FlowWithContext(scaladsl.FlowWithContext[In, Ctx])
|
2018-11-16 15:00:30 +01:00
|
|
|
}
|
2019-02-21 14:24:35 +01:00
|
|
|
|
2019-02-12 17:05:07 +01:00
|
|
|
/**
|
|
|
|
|
* Creates a FlowWithContext from a regular flow that operates on `Pair<data, context>` elements.
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def fromPairs[In, CtxIn, Out, CtxOut, Mat](under: Flow[Pair[In, CtxIn], Pair[Out, CtxOut], Mat]): FlowWithContext[In, CtxIn, Out, CtxOut, Mat] = {
|
2019-02-09 15:25:39 +01:00
|
|
|
new FlowWithContext(scaladsl.FlowWithContext.fromTuples(scaladsl.Flow[(In, CtxIn)].map { case (i, c) => Pair(i, c) }.viaMat(under.asScala.map(_.toScala))(scaladsl.Keep.right)))
|
2018-11-16 15:00:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2019-01-15 16:53:02 +01:00
|
|
|
* A flow that provides operations which automatically propagate the context of an element.
|
|
|
|
|
* Only a subset of common operations from [[Flow]] is supported. As an escape hatch you can
|
|
|
|
|
* use [[FlowWithContext.via]] to manually provide the context propagation for otherwise unsupported
|
|
|
|
|
* operations.
|
|
|
|
|
*
|
|
|
|
|
* An "empty" flow can be created by calling `FlowWithContext[Ctx, T]`.
|
|
|
|
|
*
|
2018-11-16 15:00:30 +01:00
|
|
|
* API MAY CHANGE
|
|
|
|
|
*/
|
|
|
|
|
@ApiMayChange
|
2019-02-21 14:24:35 +01:00
|
|
|
final class FlowWithContext[-In, -CtxIn, +Out, +CtxOut, +Mat](delegate: scaladsl.FlowWithContext[In, CtxIn, Out, CtxOut, Mat]) extends GraphDelegate(delegate) {
|
2019-01-15 16:53:02 +01:00
|
|
|
/**
|
|
|
|
|
* Transform this flow by the regular flow. The given flow must support manual context propagation by
|
|
|
|
|
* taking and producing tuples of (data, context).
|
|
|
|
|
*
|
|
|
|
|
* This can be used as an escape hatch for operations that are not (yet) provided with automatic
|
|
|
|
|
* context propagation here.
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.via]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def via[Out2, CtxOut2, Mat2](viaFlow: Graph[FlowShape[Pair[Out @uncheckedVariance, CtxOut @uncheckedVariance], Pair[Out2, CtxOut2]], Mat2]): FlowWithContext[In, CtxIn, Out2, CtxOut2, Mat] = {
|
2019-01-15 16:53:02 +01:00
|
|
|
val under = asFlow().via(viaFlow)
|
2018-11-16 15:00:30 +01:00
|
|
|
FlowWithContext.fromPairs(under)
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-21 12:05:21 +01:00
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.withAttributes]].
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.withAttributes]]
|
|
|
|
|
*/
|
|
|
|
|
override def withAttributes(attr: Attributes): FlowWithContext[In, CtxIn, Out, CtxOut, Mat] =
|
|
|
|
|
viaScala(_.withAttributes(attr))
|
|
|
|
|
|
2019-01-15 16:53:02 +01:00
|
|
|
/**
|
|
|
|
|
* Creates a regular flow of pairs (data, context).
|
|
|
|
|
*/
|
|
|
|
|
def asFlow(): Flow[Pair[In, CtxIn], Pair[Out, CtxOut], Mat] @uncheckedVariance =
|
2018-11-16 15:00:30 +01:00
|
|
|
scaladsl.Flow[Pair[In, CtxIn]]
|
|
|
|
|
.map(_.toScala)
|
2019-01-15 16:53:02 +01:00
|
|
|
.viaMat(delegate.asFlow)(scaladsl.Keep.right)
|
2019-02-09 15:25:39 +01:00
|
|
|
.map { case (o, c) => Pair(o, c) }
|
2018-11-16 15:00:30 +01:00
|
|
|
.asJava
|
|
|
|
|
|
2019-01-15 16:53:02 +01:00
|
|
|
// remaining operations in alphabetic order
|
2018-11-16 15:00:30 +01:00
|
|
|
|
2019-01-15 16:53:02 +01:00
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.collect]].
|
|
|
|
|
*
|
|
|
|
|
* Note, that the context of elements that are filtered out is skipped as well.
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.collect]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def collect[Out2](pf: PartialFunction[Out, Out2]): FlowWithContext[In, CtxIn, Out2, CtxOut, Mat] =
|
2019-01-15 16:53:02 +01:00
|
|
|
viaScala(_.collect(pf))
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.filter]].
|
|
|
|
|
*
|
|
|
|
|
* Note, that the context of elements that are filtered out is skipped as well.
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.filter]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def filter(p: function.Predicate[Out]): FlowWithContext[In, CtxIn, Out, CtxOut, Mat] =
|
2019-01-15 16:53:02 +01:00
|
|
|
viaScala(_.filter(p.test))
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.filterNot]].
|
|
|
|
|
*
|
|
|
|
|
* Note, that the context of elements that are filtered out is skipped as well.
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.filterNot]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def filterNot(p: function.Predicate[Out]): FlowWithContext[In, CtxIn, Out, CtxOut, Mat] =
|
2019-01-15 16:53:02 +01:00
|
|
|
viaScala(_.filterNot(p.test))
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.grouped]].
|
|
|
|
|
*
|
|
|
|
|
* Each output group will be associated with a `Seq` of corresponding context elements.
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.grouped]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def grouped(n: Int): FlowWithContext[In, CtxIn, java.util.List[Out @uncheckedVariance], java.util.List[CtxOut @uncheckedVariance], Mat] =
|
2019-01-15 16:53:02 +01:00
|
|
|
viaScala(_.grouped(n).map(_.asJava).mapContext(_.asJava))
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.map]].
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.map]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def map[Out2](f: function.Function[Out, Out2]): FlowWithContext[In, CtxIn, Out2, CtxOut, Mat] =
|
2019-01-15 16:53:02 +01:00
|
|
|
viaScala(_.map(f.apply))
|
2018-11-16 15:00:30 +01:00
|
|
|
|
2019-02-21 14:24:35 +01:00
|
|
|
def mapAsync[Out2](parallelism: Int, f: function.Function[Out, CompletionStage[Out2]]): FlowWithContext[In, CtxIn, Out2, CtxOut, Mat] =
|
2019-02-09 15:25:39 +01:00
|
|
|
viaScala(_.mapAsync[Out2](parallelism)(o => f.apply(o).toScala))
|
2019-01-15 16:53:02 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.mapConcat]].
|
|
|
|
|
*
|
|
|
|
|
* The context of the input element will be associated with each of the output elements calculated from
|
|
|
|
|
* this input element.
|
|
|
|
|
*
|
|
|
|
|
* Example:
|
|
|
|
|
*
|
|
|
|
|
* ```
|
|
|
|
|
* def dup(element: String) = Seq(element, element)
|
|
|
|
|
*
|
|
|
|
|
* Input:
|
|
|
|
|
*
|
|
|
|
|
* ("a", 1)
|
|
|
|
|
* ("b", 2)
|
|
|
|
|
*
|
|
|
|
|
* inputElements.mapConcat(dup)
|
|
|
|
|
*
|
|
|
|
|
* Output:
|
|
|
|
|
*
|
|
|
|
|
* ("a", 1)
|
|
|
|
|
* ("a", 1)
|
|
|
|
|
* ("b", 2)
|
|
|
|
|
* ("b", 2)
|
|
|
|
|
* ```
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.mapConcat]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def mapConcat[Out2](f: function.Function[Out, _ <: java.lang.Iterable[Out2]]): FlowWithContext[In, CtxIn, Out2, CtxOut, Mat] =
|
2019-02-09 15:25:39 +01:00
|
|
|
viaScala(_.mapConcat(elem => Util.immutableSeq(f.apply(elem))))
|
2018-11-16 15:00:30 +01:00
|
|
|
|
2019-01-15 16:53:02 +01:00
|
|
|
/**
|
|
|
|
|
* Apply the given function to each context element (leaving the data elements unchanged).
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def mapContext[CtxOut2](extractContext: function.Function[CtxOut, CtxOut2]): FlowWithContext[In, CtxIn, Out, CtxOut2, Mat] = {
|
2019-01-15 16:53:02 +01:00
|
|
|
viaScala(_.mapContext(extractContext.apply))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.sliding]].
|
|
|
|
|
*
|
|
|
|
|
* Each output group will be associated with a `Seq` of corresponding context elements.
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.sliding]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def sliding(n: Int, step: Int = 1): FlowWithContext[In, CtxIn, java.util.List[Out @uncheckedVariance], java.util.List[CtxOut @uncheckedVariance], Mat] =
|
2019-01-15 16:53:02 +01:00
|
|
|
viaScala(_.sliding(n, step).map(_.asJava).mapContext(_.asJava))
|
|
|
|
|
|
2019-02-17 21:00:02 +01:00
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.log]].
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.log]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def log(name: String, extract: function.Function[Out, Any], log: LoggingAdapter): FlowWithContext[In, CtxIn, Out, CtxOut, Mat] =
|
2019-02-09 15:25:39 +01:00
|
|
|
viaScala(_.log(name, e => extract.apply(e))(log))
|
2019-02-17 21:00:02 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.log]].
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.log]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def log(name: String, extract: function.Function[Out, Any]): FlowWithContext[In, CtxIn, Out, CtxOut, Mat] =
|
2019-02-17 21:00:02 +01:00
|
|
|
this.log(name, extract, null)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.log]].
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.log]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def log(name: String, log: LoggingAdapter): FlowWithContext[In, CtxIn, Out, CtxOut, Mat] =
|
2019-02-17 21:00:02 +01:00
|
|
|
this.log(name, ConstantFun.javaIdentityFunction[Out], log)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Context-preserving variant of [[akka.stream.javadsl.Flow.log]].
|
|
|
|
|
*
|
|
|
|
|
* @see [[akka.stream.javadsl.Flow.log]]
|
|
|
|
|
*/
|
2019-02-21 14:24:35 +01:00
|
|
|
def log(name: String): FlowWithContext[In, CtxIn, Out, CtxOut, Mat] =
|
2019-02-17 21:00:02 +01:00
|
|
|
this.log(name, ConstantFun.javaIdentityFunction[Out], null)
|
|
|
|
|
|
2019-02-21 14:24:35 +01:00
|
|
|
def asScala: scaladsl.FlowWithContext[In, CtxIn, Out, CtxOut, Mat] = delegate
|
2018-11-16 15:00:30 +01:00
|
|
|
|
2019-02-09 15:25:39 +01:00
|
|
|
private[this] def viaScala[In2, CtxIn2, Out2, CtxOut2, Mat2](f: scaladsl.FlowWithContext[In, CtxIn, Out, CtxOut, Mat] => scaladsl.FlowWithContext[In2, CtxIn2, Out2, CtxOut2, Mat2]): FlowWithContext[In2, CtxIn2, Out2, CtxOut2, Mat2] =
|
2019-01-15 16:53:02 +01:00
|
|
|
new FlowWithContext(f(delegate))
|
2018-11-16 15:00:30 +01:00
|
|
|
}
|