Skip to content

Commit aeb43f3

Browse files
JMS-in-gateway: destination to requestDestination (#3494)
* JMS-in-gateway: destination to requestDestination Related to https://stackoverflow.com/questions/66174779/what-is-the-dsl-version-of-int-jmsinbound-gateway-request-destination In Java DSL, the `JmsInboundGatewaySpec` expose a `destination()` option which is not correlated what we have in XML with a `request-destination` and what we have with a `replyQueue` option * Deprecate an existing `destination()` option in the `JmsInboundGatewaySpec` in favor of newly introduced `requestDestination()` * Clean up a bit `jms.adoc` and add some code block-switch sections to show Java & Kotlin DSLs along side with existing XML configs * Fix typo. Co-authored-by: Gary Russell <[email protected]>
1 parent b1cb906 commit aeb43f3

File tree

3 files changed

+169
-28
lines changed

3 files changed

+169
-28
lines changed

spring-integration-jms/src/main/java/org/springframework/integration/jms/dsl/JmsInboundGatewaySpec.java

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ public S shutdownContainerOnStop(boolean shutdown) {
197197
* @param <S> the target {@link JmsListenerContainerSpec} implementation type.
198198
* @param <C> the target {@link AbstractMessageListenerContainer} implementation type.
199199
*/
200-
public static class JmsInboundGatewayListenerContainerSpec<S extends JmsListenerContainerSpec<S, C>, C extends AbstractMessageListenerContainer>
200+
public static class JmsInboundGatewayListenerContainerSpec<S extends JmsListenerContainerSpec<S, C>,
201+
C extends AbstractMessageListenerContainer>
201202
extends JmsInboundGatewaySpec<JmsInboundGatewayListenerContainerSpec<S, C>> {
202203

203204
private final S spec;
@@ -212,24 +213,55 @@ protected JmsInboundGatewayListenerContainerSpec(S spec) {
212213
* @param destination the destination
213214
* @return the spec.
214215
* @see JmsListenerContainerSpec#destination(Destination)
216+
* @deprecated since 5.5 in favor of {@link #requestDestination(Destination)}
215217
*/
218+
@Deprecated
216219
public JmsInboundGatewayListenerContainerSpec<S, C> destination(Destination destination) {
217-
this.spec.destination(destination);
220+
return requestDestination(destination);
221+
}
222+
223+
/**
224+
* Specify a request destination for incoming messages.
225+
* @param requestDestination the destination
226+
* @return the spec.
227+
* @see JmsListenerContainerSpec#destination(Destination)
228+
* @since 5.5
229+
*/
230+
public JmsInboundGatewayListenerContainerSpec<S, C> requestDestination(Destination requestDestination) {
231+
this.spec.destination(requestDestination);
218232
return _this();
219233
}
220234

221235
/**
222236
* @param destinationName the destinationName
223237
* @return the spec.
224238
* @see JmsListenerContainerSpec#destination(String)
239+
* @deprecated since 5.5 in favor of {@link #requestDestination(String)}
225240
*/
241+
@Deprecated
226242
public JmsInboundGatewayListenerContainerSpec<S, C> destination(String destinationName) {
227-
this.spec.destination(destinationName);
243+
return requestDestination(destinationName);
244+
}
245+
246+
/**
247+
* Specify a request destination for incoming messages.
248+
* @param requestDestinationName the destination name
249+
* @return the spec.
250+
* @see JmsListenerContainerSpec#destination(String)
251+
* @since 5.5
252+
*/
253+
public JmsInboundGatewayListenerContainerSpec<S, C> requestDestination(String requestDestinationName) {
254+
this.spec.destination(requestDestinationName);
228255
return _this();
229256
}
230257

231-
public JmsInboundGatewayListenerContainerSpec<S, C> configureListenerContainer(
232-
Consumer<S> configurer) {
258+
/**
259+
* Specify a {@link Consumer} to accept a {@link JmsListenerContainerSpec} for further configuration.
260+
* @param configurer the {@link Consumer} to accept a {@link JmsListenerContainerSpec}
261+
* for further configuration.
262+
* @return the spec
263+
*/
264+
public JmsInboundGatewayListenerContainerSpec<S, C> configureListenerContainer(Consumer<S> configurer) {
233265
Assert.notNull(configurer, "'configurer' must not be null");
234266
configurer.accept(this.spec);
235267
return _this();

spring-integration-jms/src/test/java/org/springframework/integration/jms/dsl/JmsTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ protected Object handleRequestMessage(Message<?> requestMessage) {
444444
}
445445

446446
}))
447-
.destination("jmsPipelineTest")
447+
.requestDestination("jmsPipelineTest")
448448
.configureListenerContainer(c ->
449449
c.transactionManager(mock(PlatformTransactionManager.class))))
450450
.filter(payload -> !"junk".equals(payload))

src/reference/asciidoc/jms.adoc

Lines changed: 131 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,17 @@ Spring Integration provides channel adapters for receiving and sending JMS messa
66
You need to include this dependency into your project:
77

88
====
9+
[source, xml, subs="normal", role="primary"]
910
.Maven
10-
[source, xml, subs="normal"]
1111
----
1212
<dependency>
1313
<groupId>org.springframework.integration</groupId>
1414
<artifactId>spring-integration-jms</artifactId>
1515
<version>{project-version}</version>
1616
</dependency>
1717
----
18-
18+
[source, groovy, subs="normal", role="secondary"]
1919
.Gradle
20-
[source, groovy, subs="normal"]
2120
----
2221
compile "org.springframework.integration:spring-integration-jms:{project-version}"
2322
----
@@ -52,7 +51,44 @@ The inbound channel adapter requires a reference to either a single `JmsTemplate
5251
The following example defines an inbound channel adapter with a `Destination` reference:
5352

5453
====
55-
[source,xml]
54+
[source, java, role="primary"]
55+
.Java DSL
56+
----
57+
@Bean
58+
public IntegrationFlow jmsInbound(ConnectionFactory connectionFactory) {
59+
return IntegrationFlows.from(
60+
Jms.inboundAdapter(connectionFactory)
61+
.destination("inQueue"),
62+
e -> e.poller(poller -> poller.fixedRate(30000)))
63+
.handle(m -> System.out.println(m.getPayload()))
64+
.get();
65+
}
66+
----
67+
[source, kotlin, role="secondary"]
68+
.Kotlin DSL
69+
----
70+
@Bean
71+
fun jmsInbound(connectionFactory: ConnectionFactory) =
72+
integrationFlow(
73+
Jms.inboundAdapter(connectionFactory).destination("inQueue"),
74+
{ poller { Pollers.fixedRate(30000) } })
75+
{
76+
handle { m -> println(m.payload) }
77+
}
78+
----
79+
[source, java, role="secondary"]
80+
.Java
81+
----
82+
@Bean
83+
@InboundChannelAdapter(value = "exampleChannel", poller = @Poller(fixedRate = "30000"))
84+
public MessageSource<Object> jmsIn(ConnectionFactory connectionFactory) {
85+
JmsDestinationPollingSource source = new JmsDestinationPollingSource(new JmsTemplate(connectionFactory));
86+
source.setDestinationName("inQueue");
87+
return source;
88+
}
89+
----
90+
[source, xml, role="secondary"]
91+
.XML
5692
----
5793
<int-jms:inbound-channel-adapter id="jmsIn" destination="inQueue" channel="exampleChannel">
5894
<int:poller fixed-rate="30000"/>
@@ -72,19 +108,7 @@ However, if your JMS `ConnectionFactory` has a different bean name, you need to
72108
If `extract-payload` is set to `true` (the default), the received JMS Message is passed through the `MessageConverter`.
73109
When relying on the default `SimpleMessageConverter`, this means that the resulting Spring Integration Message has the JMS message's body as its payload.
74110
A JMS `TextMessage` produces a string-based payload, a JMS `BytesMessage` produces a byte array payload, and the serializable instance of a JMS `ObjectMessage` becomes the Spring Integration message's payload.
75-
If you prefer to have the raw JMS message as the Spring Integration message's payload, set `extract-payload` to `false`, as the following example shows:
76-
77-
====
78-
[source,xml]
79-
----
80-
<int-jms:inbound-channel-adapter id="jmsIn"
81-
destination="inQueue"
82-
channel="exampleChannel"
83-
extract-payload="false"/>
84-
<int:poller fixed-rate="30000"/>
85-
</int-jms:inbound-channel-adapter>
86-
----
87-
====
111+
If you prefer to have the raw JMS message as the Spring Integration message's payload, set the `extractPayload` option to `false`.
88112

89113
Starting with version 5.0.8, a default value of the `receive-timeout` is `-1` (no wait) for the `org.springframework.jms.connection.CachingConnectionFactory` and `cacheConsumers`, otherwise it is 1 second.
90114
The JMS Inbound Channel Adapter crates a `DynamicJmsTemplate` based on the provided `ConnectionFactory` and options.
@@ -119,7 +143,54 @@ The `message-driven-channel-adapter` requires a reference to either an instance
119143
The following example defines a message-driven channel adapter with a `Destination` reference:
120144

121145
====
122-
[source,xml]
146+
[source, java, role="primary"]
147+
.Java DSL
148+
----
149+
@Bean
150+
public IntegrationFlow jmsMessageDrivenRedeliveryFlow() {
151+
return IntegrationFlows
152+
.from(Jms.messageDrivenChannelAdapter(jmsConnectionFactory())
153+
.destination("inQueue"))
154+
.channel("exampleChannel")
155+
.get();
156+
}
157+
----
158+
[source, kotlin, role="secondary"]
159+
.Kotlin DSL
160+
----
161+
@Bean
162+
fun jmsMessageDrivenFlowWithContainer() =
163+
integrationFlow(
164+
Jms.messageDrivenChannelAdapter(jmsConnectionFactory())
165+
.destination("inQueue")) {
166+
channel("exampleChannel")
167+
}
168+
----
169+
[source, java, role="secondary"]
170+
.Java
171+
----
172+
@Bean
173+
public JmsMessageDrivenEndpoint jmsIn() {
174+
JmsMessageDrivenEndpoint endpoint = new JmsMessageDrivenEndpoint(container(), listener());
175+
return endpoint;
176+
}
177+
@Bean
178+
public AbstractMessageListenerContainer container() {
179+
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
180+
container.setConnectionFactory(cf());
181+
container.setDestinationName("inQueue");
182+
return container;
183+
}
184+
185+
@Bean
186+
public ChannelPublishingJmsMessageListener listener() {
187+
ChannelPublishingJmsMessageListener listener = new ChannelPublishingJmsMessageListener();
188+
listener.setRequestChannelName("exampleChannel");
189+
return listener;
190+
}
191+
----
192+
[source, xml, role="secondary"]
193+
.XML
123194
----
124195
<int-jms:message-driven-channel-adapter id="jmsIn" destination="inQueue" channel="exampleChannel"/>
125196
----
@@ -203,7 +274,46 @@ As with the inbound channel adapter, the easiest way to configure this adapter i
203274
The following configuration produces an adapter that receives Spring Integration messages from the `exampleChannel`, converts those into JMS messages, and sends them to the JMS destination reference whose bean name is `outQueue`:
204275

205276
====
206-
[source,xml]
277+
[source, java, role="primary"]
278+
.Java DSL
279+
----
280+
@Bean
281+
public IntegrationFlow jmsOutboundFlow() {
282+
return f -> f
283+
.handle(Jms.outboundAdapter(cachingConnectionFactory())
284+
.destinationExpression("headers." + SimpMessageHeaderAccessor.DESTINATION_HEADER)
285+
.configureJmsTemplate(t -> t.id("jmsOutboundFlowTemplate")));
286+
}
287+
----
288+
[source, kotlin, role="secondary"]
289+
.Kotlin DSL
290+
----
291+
@Bean
292+
fun jmsOutboundFlow() =
293+
integrationFlow {
294+
handle(Jms.outboundAdapter(jmsConnectionFactory())
295+
.apply {
296+
destinationExpression("headers." + SimpMessageHeaderAccessor.DESTINATION_HEADER)
297+
deliveryModeFunction<Any> { DeliveryMode.NON_PERSISTENT }
298+
timeToLiveExpression("10000")
299+
configureJmsTemplate { it.explicitQosEnabled(true) }
300+
}
301+
)
302+
}
303+
----
304+
[source, java, role="secondary"]
305+
.Java
306+
----
307+
@Bean
308+
@ServiceActivator(inputChannel = "exampleChannel")
309+
public MessageHandler jmsOut() {
310+
JmsSendingMessageHandler handler = new JmsSendingMessageHandler(new JmsTemplate(connectionFactory));
311+
handler.setDestinationName("outQueue");
312+
return handler;
313+
}
314+
----
315+
[source, xml, role="secondary"]
316+
.XML
207317
----
208318
<int-jms:outbound-channel-adapter id="jmsOut" destination="outQueue" channel="exampleChannel"/>
209319
----
@@ -263,8 +373,7 @@ The default is 'true'.
263373

264374
Similarly, for an inbound-gateway, the 'extract-reply-payload' property applies to the Spring Integration message that is to be converted into a reply JMS Message.
265375
If you want to pass the whole Spring Integration message (as the body of a JMS ObjectMessage), set value this to 'false'.
266-
By default, it is also 'true' that the Spring Integration message payload is converted into a JMS Message (for example, a
267-
`String` payload becomes a JMS TextMessage).
376+
By default, it is also 'true' that the Spring Integration message payload is converted into a JMS Message (for example, a `String` payload becomes a JMS TextMessage).
268377

269378
As with anything else, gateway invocation might result in error.
270379
By default, a producer is not notified of the errors that might have occurred on the consumer side and times out waiting for the reply.
@@ -306,7 +415,7 @@ To revert to the previous behavior, set the `shutdownContainerOnStop` on the `Jm
306415
=== Outbound Gateway
307416

308417
The outbound gateway creates JMS messages from Spring Integration messages and sends them to a 'request-destination'.
309-
It thens handle the JMS reply message either by using a selector to receive from the 'reply-destination' that you configure or, if no 'reply-destination' is provided, by creating JMS `TemporaryQueue` instances.
418+
It then handles the JMS reply message either by using a selector to receive from the 'reply-destination' that you configure or, if no 'reply-destination' is provided, by creating JMS `TemporaryQueue` instances.
310419

311420
[[jms-outbound-gateway-memory-caution]]
312421
[CAUTION]

0 commit comments

Comments
 (0)