Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (C) 2015-2020 Lightbend Inc.
*/
package akka.stream.scaladsl
import akka.NotUsed
import akka.stream.{ BidiShape, _ }
import akka.stream.impl.{ LinearTraversalBuilder, Timers, TraversalBuilder }
import scala.concurrent.duration.FiniteDuration
final class BidiFlow[-I1, +O1, -I2, +O2, +Mat](
override val traversalBuilder: TraversalBuilder,
override val shape: BidiShape[I1, O1, I2, O2])
extends Graph[BidiShape[I1, O1, I2, O2], Mat] {
def asJava[JI1 <: I1, JO1 >: O1, JI2 <: I2, JO2 >: O2, JMat >: Mat]: javadsl.BidiFlow[JI1, JO1, JI2, JO2, JMat] =
new javadsl.BidiFlow(this)
/**
* Add the given BidiFlow as the next step in a bidirectional transformation
* pipeline. By convention protocol stacks are growing to the left: the right most is the bottom
* layer, the closest to the metal.
* {{{
* +----------------------------+
* | Resulting BidiFlow |
* | |
* | +------+ +------+ |
* I1 ~~> | | ~O1~> | | ~~> OO1
* | | this | | bidi | |
* O2 <~~ | | <~I2~ | | <~~ II2
* | +------+ +------+ |
* +----------------------------+
* }}}
* The materialized value of the combined [[BidiFlow]] will be the materialized
* value of the current flow (ignoring the other BidiFlow’s value), use
* [[BidiFlow#atopMat atopMat]] if a different strategy is needed.
*/
def atop[OO1, II2, Mat2](bidi: Graph[BidiShape[O1, OO1, II2, I2], Mat2]): BidiFlow[I1, OO1, II2, O2, Mat] =
atopMat(bidi)(Keep.left)
/**
* Add the given BidiFlow as the next step in a bidirectional transformation
* pipeline. By convention protocol stacks are growing to the left: the right most is the bottom
* layer, the closest to the metal.
* {{{
* +----------------------------+
* | Resulting BidiFlow |
* | |
* | +------+ +------+ |
* I1 ~~> | | ~O1~> | | ~~> OO1
* | | this | | bidi | |
* O2 <~~ | | <~I2~ | | <~~ II2
* | +------+ +------+ |
* +----------------------------+
* }}}
* The `combine` function is used to compose the materialized values of this flow and that
* flow into the materialized value of the resulting BidiFlow.
*/
def atopMat[OO1, II2, Mat2, M](bidi: Graph[BidiShape[O1, OO1, II2, I2], Mat2])(
combine: (Mat, Mat2) => M): BidiFlow[I1, OO1, II2, O2, M] = {
val newBidi1Shape = shape.deepCopy()
val newBidi2Shape = bidi.shape.deepCopy()
// We MUST add the current module as an explicit submodule. The composite builder otherwise *grows* the
// existing module, which is not good if there are islands present (the new module will "join" the island).
val newTraversalBuilder =
TraversalBuilder
.empty()
.add(traversalBuilder, newBidi1Shape, Keep.right)
.add(bidi.traversalBuilder, newBidi2Shape, combine)
.wire(newBidi1Shape.out1, newBidi2Shape.in1)
.wire(newBidi2Shape.out2, newBidi1Shape.in2)
new BidiFlow(
newTraversalBuilder,
BidiShape(newBidi1Shape.in1, newBidi2Shape.out1, newBidi2Shape.in2, newBidi1Shape.out2))
}
/**
* Add the given Flow as the final step in a bidirectional transformation
* pipeline. By convention protocol stacks are growing to the left: the right most is the bottom
* layer, the closest to the metal.
* {{{
* +---------------------------+
* | Resulting Flow |
* | |
* | +------+ +------+ |
* I1 ~~> | | ~O1~> | | |
* | | this | | flow | |
* O2 <~~ | | <~I2~ | | |
* | +------+ +------+ |
* +---------------------------+
* }}}
* The materialized value of the combined [[Flow]] will be the materialized
* value of the current flow (ignoring the other Flow’s value), use
* [[BidiFlow#joinMat joinMat]] if a different strategy is needed.
*/
def join[Mat2](flow: Graph[FlowShape[O1, I2], Mat2]): Flow[I1, O2, Mat] = joinMat(flow)(Keep.left)
/**
* Add the given Flow as the final step in a bidirectional transformation
* pipeline. By convention protocol stacks are growing to the left: the right most is the bottom
* layer, the closest to the metal.
* {{{
* +---------------------------+
* | Resulting Flow |
* | |
* | +------+ +------+ |
* I1 ~~> | | ~O1~> | | |
* | | this | | flow | |
* O2 <~~ | | <~I2~ | | |
* | +------+ +------+ |
* +---------------------------+
* }}}
* The `combine` function is used to compose the materialized values of this flow and that
* flow into the materialized value of the resulting [[Flow]].
*/
def joinMat[Mat2, M](flow: Graph[FlowShape[O1, I2], Mat2])(combine: (Mat, Mat2) => M): Flow[I1, O2, M] = {
val newBidiShape = shape.deepCopy()
val newFlowShape = flow.shape.deepCopy()
// We MUST add the current module as an explicit submodule. The composite builder otherwise *grows* the
// existing module, which is not good if there are islands present (the new module will "join" the island).
val resultBuilder = TraversalBuilder
.empty()
.add(traversalBuilder, newBidiShape, Keep.right)
.add(flow.traversalBuilder, newFlowShape, combine)
.wire(newBidiShape.out1, newFlowShape.in)
.wire(newFlowShape.out, newBidiShape.in2)
val newShape = FlowShape(newBidiShape.in1, newBidiShape.out2)
new Flow(LinearTraversalBuilder.fromBuilder(resultBuilder, newShape, Keep.right), newShape)
}
/**
* Turn this BidiFlow around by 180 degrees, logically flipping it upside down in a protocol stack.
*/
def reversed: BidiFlow[I2, O2, I1, O1, Mat] =
new BidiFlow(traversalBuilder, BidiShape(shape.in2, shape.out2, shape.in1, shape.out1))
/**
* Transform only the materialized value of this BidiFlow, leaving all other properties as they were.
*/
def mapMaterializedValue[Mat2](f: Mat => Mat2): BidiFlow[I1, O1, I2, O2, Mat2] =
new BidiFlow(traversalBuilder.transformMat(f.asInstanceOf[Any => Any]), shape)
/**
* Change the attributes of this [[Source]] to the given ones and seal the list
* of attributes. This means that further calls will not be able to remove these
* attributes, but instead add new ones. Note that this
* operation has no effect on an empty Flow (because the attributes apply
* only to the contained processing operators).
*/
override def withAttributes(attr: Attributes): BidiFlow[I1, O1, I2, O2, Mat] =
new BidiFlow(traversalBuilder.setAttributes(attr), shape)
/**
* Add the given attributes to this Source. Further calls to `withAttributes`
* will not remove these attributes. Note that this
* operation has no effect on an empty Flow (because the attributes apply
* only to the contained processing operators).
*/
override def addAttributes(attr: Attributes): BidiFlow[I1, O1, I2, O2, Mat] =
withAttributes(traversalBuilder.attributes and attr)
/**
* Add a ``name`` attribute to this Flow.
*/
override def named(name: String): BidiFlow[I1, O1, I2, O2, Mat] =
addAttributes(Attributes.name(name))
/**
* Put an asynchronous boundary around this `BidiFlow`
*/
override def async: BidiFlow[I1, O1, I2, O2, Mat] =
super.async.asInstanceOf[BidiFlow[I1, O1, I2, O2, Mat]]
/**
* Put an asynchronous boundary around this `BidiFlow`
*
* @param dispatcher Run the graph on this dispatcher
*/
override def async(dispatcher: String): BidiFlow[I1, O1, I2, O2, Mat] =
super.async(dispatcher).asInstanceOf[BidiFlow[I1, O1, I2, O2, Mat]]
/**
* Put an asynchronous boundary around this `BidiFlow`
*
* @param dispatcher Run the graph on this dispatcher
* @param inputBufferSize Set the input buffer to this size for the graph
*/
override def async(dispatcher: String, inputBufferSize: Int): BidiFlow[I1, O1, I2, O2, Mat] =
super.async(dispatcher, inputBufferSize).asInstanceOf[BidiFlow[I1, O1, I2, O2, Mat]]
}
object BidiFlow {
private[this] val _identity: BidiFlow[Any, Any, Any, Any, NotUsed] =
BidiFlow.fromFlows(Flow[Any], Flow[Any])
def identity[A, B]: BidiFlow[A, A, B, B, NotUsed] = _identity.asInstanceOf[BidiFlow[A, A, B, B, NotUsed]]
/**
* A graph with the shape of a flow logically is a flow, this method makes
* it so also in type.
*/
def fromGraph[I1, O1, I2, O2, Mat](graph: Graph[BidiShape[I1, O1, I2, O2], Mat]): BidiFlow[I1, O1, I2, O2, Mat] =
graph match {
case bidi: BidiFlow[I1, O1, I2, O2, Mat] => bidi
case bidi: javadsl.BidiFlow[I1, O1, I2, O2, Mat] => bidi.asScala
case other =>
new BidiFlow(other.traversalBuilder, other.shape)
}
/**
* Wraps two Flows to create a ''BidiFlow''. The materialized value of the resulting BidiFlow is determined
* by the combiner function passed in the second argument list.
*
* {{{
* +----------------------------+
* | Resulting BidiFlow |
* | |
* | +----------------------+ |
* I1 ~~> | Flow1 | ~~> O1
* | +----------------------+ |
* | |
* | +----------------------+ |
* O2 <~~ | Flow2 | <~~ I2
* | +----------------------+ |
* +----------------------------+
* }}}
*
*/
def fromFlowsMat[I1, O1, I2, O2, M1, M2, M](flow1: Graph[FlowShape[I1, O1], M1], flow2: Graph[FlowShape[I2, O2], M2])(
combine: (M1, M2) => M): BidiFlow[I1, O1, I2, O2, M] = {
val newFlow1Shape = flow1.shape.deepCopy()
val newFlow2Shape = flow2.shape.deepCopy()
new BidiFlow(
TraversalBuilder
.empty()
.add(flow1.traversalBuilder, newFlow1Shape, Keep.right)
.add(flow2.traversalBuilder, newFlow2Shape, combine),
BidiShape(newFlow1Shape.in, newFlow1Shape.out, newFlow2Shape.in, newFlow2Shape.out))
}
/**
* Wraps two Flows to create a ''BidiFlow''. The materialized value of the resulting BidiFlow is Unit.
*
* {{{
* +----------------------------+
* | Resulting BidiFlow |
* | |
* | +----------------------+ |
* I1 ~~> | Flow1 | ~~> O1
* | +----------------------+ |
* | |
* | +----------------------+ |
* O2 <~~ | Flow2 | <~~ I2
* | +----------------------+ |
* +----------------------------+
* }}}
*
*/
def fromFlows[I1, O1, I2, O2, M1, M2](
flow1: Graph[FlowShape[I1, O1], M1],
flow2: Graph[FlowShape[I2, O2], M2]): BidiFlow[I1, O1, I2, O2, NotUsed] =
fromFlowsMat(flow1, flow2)(Keep.none)
/**
* Create a BidiFlow where the top and bottom flows are just one simple mapping
* operator each, expressed by the two functions.
*/
def fromFunctions[I1, O1, I2, O2](outbound: I1 => O1, inbound: I2 => O2): BidiFlow[I1, O1, I2, O2, NotUsed] =
fromFlows(Flow[I1].map(outbound), Flow[I2].map(inbound))
/**
* If the time between two processed elements *in any direction* exceed the provided timeout, the stream is failed
* with a [[scala.concurrent.TimeoutException]].
*
* There is a difference between this operator and having two idleTimeout Flows assembled into a BidiStage.
* If the timeout is configured to be 1 seconds, then this operator will not fail even though there are elements flowing
* every second in one direction, but no elements are flowing in the other direction. I.e. this operator considers
* the *joint* frequencies of the elements in both directions.
*/
def bidirectionalIdleTimeout[I, O](timeout: FiniteDuration): BidiFlow[I, I, O, O, NotUsed] =
fromGraph(new Timers.IdleTimeoutBidi(timeout))
}