Case of Study
REPLACING
Why?
Responsive
Message Driven
Elastic
Resilient
Stream Composition: Single Shapes
Stream Composition: Composite Shapes
Stream Composition: Partial Flow Graphs
Event Inbound Flow
<int:channel id="eventInboundChannel" />
<int:chain input-channel="eventInboundChannel" output-channel="eventPreProcessingChannel">
<int:transformer ref="eventHeaderEnricher" method="applyHeaders"/>
<int:filter ref="payloadValidationFilter" method="accept" discard-channel="validationFailureSuppressedChannel"/>
</int:chain>
<int:channel id="validationFailureSuppressedChannel" />
<int:chain auto-startup="true" input-channel="validationFailureSuppressedChannel" output-channel="eventSuppressedChannel">
<int:header-enricher>
<int:header name="suppressedReason" value="ValidationFailure"/>
</int:header-enricher>
</int:chain>
<int:channel id="eventPreProcessingChannel" />
<int:header-value-router input-channel="eventPreProcessingChannel" header-name="eventRefreshRequest"
default-output-channel="eventProcessingChannel">
<int:mapping value="true" channel="eventRefreshChannel"/>
</int:header-value-router>
Event Inbound Channel defined using Spring
trait EventInboundFlow extends ValidationFailureSuppressedFlow with EventSuppressedPublisherFlow {
this: Gateway with EventPipelineBeans =>
private val payloadFilterFlow = filterPartialFlowGraph(payloadValidationFilter.accept(_))
private val eventRefreshFilterFlow = filterPartialFlowGraph(_.isContained(MessageUtil.EVENT_REFRESH_REQUEST_HEADER))
lazy val eventInboundFlow = FlowGraph.partial() { implicit b =>
val headerEnricherFlow = b.add(partialFlow(eventHeaderEnricher.applyHeaders(_)))
val payloadFilter = b.add(payloadFilterFlow)
val erf = b.add(eventRefreshFilterFlow)
val validationSuppressed = b.add(validationFailureSuppressedFlow)
headerEnricherFlow ~> payloadFilter
payloadFilter.out(0) ~> erf
payloadFilter.out(1) ~> validationSuppressed
UniformFanOutShape(headerEnricherFlow.inlet, erf.out(0), erf.out(1), validationSuppressed.outlet)
}.named("eventInboundFlow")
}
Event Inbound Flow: Coding
trait EventInboundFlow extends ValidationFailureSuppressedFlow with EventSuppressedPublisherFlow {
this: Gateway with EventPipelineBeans =>
private val payloadFilterFlow = filterPartialFlowGraph(payloadValidationFilter.accept(_))
private val eventRefreshFilterFlow = filterPartialFlowGraph(_.isContained(MessageUtil.EVENT_REFRESH_REQUEST_HEADER))
lazy val eventInboundFlow = FlowGraph.partial() { implicit b =>
val headerEnricherFlow = b.add(partialFlow(eventHeaderEnricher.applyHeaders(_)))
val payloadFilter = b.add(payloadFilterFlow)
val erf = b.add(eventRefreshFilterFlow)
val validationSuppressed = b.add(validationFailureSuppressedFlow)
headerEnricherFlow ~> payloadFilter
payloadFilter.out(0) ~> erf
payloadFilter.out(1) ~> validationSuppressed
UniformFanOutShape(headerEnricherFlow.inlet, erf.out(0), erf.out(1), validationSuppressed.outlet)
}.named("eventInboundFlow")
}
"Event Inbound Flow" should {
val eventRefreshHeaders = Map(MessageUtil.EVENT_REFRESH_REQUEST_HEADER -> Boolean.box(true))
"Have every message with the header 'eventRefreshRequest' and value 'true' in filterOut and empty stream in notFilterOut" in withMessageSource(eventRefreshHeaders) { source => messages =>
val (filterOut, notFilterOut, suppressedOut) = flowGraph(source)
val filterResult = Await.result(filterOut, 1000.millis)
// Should be an Empty stream
intercept[NoSuchElementException] {
Await.result(notFilterOut, 1000.millis)
}
intercept[NoSuchElementException] {
Await.result(suppressedOut, 1000.millis)
}
filterResult.getHeaders should (contain key (MessageUtil.EVENT_REFRESH_REQUEST_HEADER) and contain value (true))
}
}
Event Inbound Flow: Unit Test