-
Notifications
You must be signed in to change notification settings - Fork 645
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Jms passthrough envelope #1212
Jms passthrough envelope #1212
Changes from all commits
12782b4
13ecc48
30ba5fc
9911170
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright (C) 2016-2018 Lightbend Inc. <http://www.lightbend.com> | ||
*/ | ||
|
||
package akka.stream.alpakka.jms | ||
|
||
object JmsProducerMessage { | ||
|
||
sealed trait Envelope[+M <: JmsMessage, +PassThrough] { | ||
def passThrough: PassThrough | ||
} | ||
|
||
def message[M <: JmsMessage, PassThrough](message: M, passThrough: PassThrough): Envelope[M, PassThrough] = | ||
Message(message, passThrough) | ||
|
||
def passThroughMessage[M <: JmsMessage, PassThrough](passThrough: PassThrough): Envelope[M, PassThrough] = | ||
PassThroughMessage(passThrough) | ||
|
||
final case class Message[+M <: JmsMessage, +PassThrough](message: M, passThrough: PassThrough) | ||
extends Envelope[M, PassThrough] | ||
|
||
final case class PassThroughMessage[+M <: JmsMessage, +PassThrough](passThrough: PassThrough) | ||
extends Envelope[M, PassThrough] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,11 +7,14 @@ | |
import akka.Done; | ||
import akka.NotUsed; | ||
import akka.actor.ActorSystem; | ||
import akka.japi.Pair; | ||
import akka.stream.ActorMaterializer; | ||
import akka.stream.KillSwitch; | ||
import akka.stream.Materializer; | ||
import akka.stream.alpakka.jms.*; | ||
import akka.stream.alpakka.jms.JmsProducerMessage.*; | ||
import akka.stream.javadsl.Flow; | ||
import akka.stream.javadsl.Keep; | ||
import akka.stream.javadsl.Sink; | ||
import akka.stream.javadsl.Source; | ||
import akka.testkit.javadsl.TestKit; | ||
|
@@ -778,6 +781,75 @@ public void failAfterRetry() throws Exception { | |
}); | ||
} | ||
|
||
@Test | ||
public void passThroughMessageEnvelopes() throws Exception { | ||
withServer( | ||
ctx -> { | ||
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ctx.url); | ||
// #run-flexi-flow-producer | ||
Flow<Envelope<JmsTextMessage, String>, Envelope<JmsTextMessage, String>, NotUsed> | ||
jmsProducer = | ||
JmsProducer.flexiFlow( | ||
JmsProducerSettings.create(connectionFactory).withQueue("test")); | ||
|
||
List<String> data = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"); | ||
List<Envelope<JmsTextMessage, String>> input = new ArrayList<>(); | ||
for (String s : data) { | ||
input.add(JmsProducerMessage.message(JmsTextMessage.create(s), s)); | ||
} | ||
|
||
CompletionStage<List<String>> result = | ||
Source.from(input) | ||
.via(jmsProducer) | ||
.map(Envelope::passThrough) | ||
.runWith(Sink.seq(), materializer); | ||
// #run-flexi-flow-producer | ||
assertEquals(data, result.toCompletableFuture().get()); | ||
}); | ||
} | ||
|
||
@Test | ||
public void passThroughEmptyMessageEnvelopes() throws Exception { | ||
withServer( | ||
ctx -> { | ||
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ctx.url); | ||
|
||
Pair<KillSwitch, CompletionStage<List<String>>> switchAndItems = | ||
JmsConsumer.textSource( | ||
JmsConsumerSettings.create(connectionFactory) | ||
.withBufferSize(10) | ||
.withQueue("test")) | ||
.toMat(Sink.seq(), Keep.both()) | ||
.run(materializer); | ||
|
||
// #run-flexi-flow-pass-through-producer | ||
Flow<Envelope<JmsTextMessage, String>, Envelope<JmsTextMessage, String>, NotUsed> | ||
jmsProducer = | ||
JmsProducer.flexiFlow( | ||
JmsProducerSettings.create(connectionFactory).withQueue("test")); | ||
|
||
List<String> data = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"); | ||
List<Envelope<JmsTextMessage, String>> input = new ArrayList<>(); | ||
for (String s : data) { | ||
input.add(JmsProducerMessage.passThroughMessage(s)); | ||
} | ||
|
||
CompletionStage<List<String>> result = | ||
Source.from(input) | ||
.via(jmsProducer) | ||
.map(Envelope::passThrough) | ||
.runWith(Sink.seq(), materializer); | ||
// #run-flexi-flow-pass-through-producer | ||
|
||
assertEquals(data, result.toCompletableFuture().get()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to assert that none of these pass-through envelopes are published? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I'll add an assertion for that |
||
|
||
Thread.sleep(500); | ||
|
||
switchAndItems.first().shutdown(); | ||
assertTrue(switchAndItems.second().toCompletableFuture().get().isEmpty()); | ||
}); | ||
} | ||
|
||
private static ActorSystem system; | ||
private static Materializer materializer; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1126,6 +1126,60 @@ class JmsConnectorsSpec extends JmsSpec with MockitoSugar { | |
// Due to buffering, it will finish re-connecting before stream finishes. | ||
connectCount shouldBe 5 | ||
} | ||
|
||
"pass through message envelopes" in withServer() { ctx => | ||
val connectionFactory = new ActiveMQConnectionFactory(ctx.url) | ||
|
||
//#run-flexi-flow-producer | ||
val jmsProducer = JmsProducer.flexiFlow[JmsTextMessage, String]( | ||
JmsProducerSettings(connectionFactory).withQueue("test") | ||
) | ||
|
||
val data = List("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k") | ||
val in = data.map(t => JmsProducerMessage.Message(JmsTextMessage(t), t)) | ||
|
||
val result = Source(in).via(jmsProducer).map(_.passThrough).runWith(Sink.seq) | ||
//#run-flexi-flow-producer | ||
|
||
result.futureValue shouldEqual data | ||
|
||
val sentData = | ||
JmsConsumer | ||
.textSource(JmsConsumerSettings(connectionFactory).withBufferSize(10).withQueue("test")) | ||
.take(data.size) | ||
.runWith(Sink.seq) | ||
|
||
sentData.futureValue shouldEqual data | ||
} | ||
|
||
"pass through empty envelopes" in { | ||
val connectionFactory = mock[ConnectionFactory] | ||
val connection = mock[Connection] | ||
val session = mock[Session] | ||
val producer = mock[MessageProducer] | ||
val message = mock[TextMessage] | ||
|
||
when(connectionFactory.createConnection()).thenReturn(connection) | ||
when(connection.createSession(anyBoolean(), anyInt())).thenReturn(session) | ||
when(session.createProducer(any[javax.jms.Destination])).thenReturn(producer) | ||
when(session.createTextMessage(any[String])).thenReturn(message) | ||
|
||
//#run-flexi-flow-pass-through-producer | ||
val jmsProducer = JmsProducer.flexiFlow[JmsTextMessage, String]( | ||
JmsProducerSettings(connectionFactory).withQueue("topic") | ||
) | ||
|
||
val data = List("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k") | ||
val in = data.map(t => JmsProducerMessage.PassThroughMessage(t)) | ||
|
||
val result = Source(in).via(jmsProducer).map(_.passThrough).runWith(Sink.seq) | ||
//#run-flexi-flow-pass-through-producer | ||
|
||
result.futureValue shouldEqual data | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer to mock this one instead so you can actually collect the messages that are published vs the messages that are not published. You can achieve the same with creating a consumer to validate your messages as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean mocking the connection factory (and session etc) and asserting that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's what I'm thinking. Thanks! |
||
|
||
verify(session, never()).createTextMessage(any[String]) | ||
verify(producer, never()).send(any[javax.jms.Destination], any[Message], any[Int], any[Int], any[Long]) | ||
} | ||
} | ||
|
||
"publish and subscribe with a durable subscription" in withServer() { ctx => | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may want to document the use case for
PassThroughMessage
similar to the Scaladocs in the Kafka case, or document it in the main documentation. Otherwise it may not be clear when and why to use this class.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I'll add a section in the docs explaining that this allows to ack messages consumed without producing, and without the need for fan-out flows.