if i don't want to use dsl to write the code which build connection between jms and spring integration channel, how does it do - spring-integration

In this link, the author use java domain specific language to build connection from spring integration channel to activeMQ. If i don't want to use java dsl and I just want to use general java method. how should I do?
#Bean
public IntegrationFlow outboundFlow(ActiveMQConnectionFactory connectionFactory) {
return IntegrationFlows
.from(requests())
.handle(Jms.outboundAdapter(connectionFactory).destination("requests"))
.get();
}
https://github.com/spring-projects/spring-batch/blob/master/spring-batch-samples/src/main/java/org/springframework/batch/sample/remotepartitioning/aggregating/WorkerConfiguration.java

The Jms.outboundAdapter(connectionFactory) is a syntax sugar wrapper around JmsSendingMessageHandler.
The .handle() is an equivalent of the #ServiceActivator.
So, what you need with plain Java is like this:
#Bean
#ServiceActivator(inputChannel="requests")
public MessageHandler jmsMessageHandler((ActiveMQConnectionFactory connectionFactory) {
JmsSendingMessageHandler handler = new JmsSendingMessageHandler(new JmsTemplate(connectionFactory));
handler.setDestinationName("requests");
return handler;
}
See some explanation in the Docs: https://docs.spring.io/spring-integration/docs/current/reference/html/overview.html#programming-tips
And more about JmsSendingMessageHandler: https://docs.spring.io/spring-integration/docs/current/reference/html/jms.html#jms-outbound-channel-adapter

Related

Spring integration org.springframework.integration.MessageTimeoutException handling

I have following spring integration flow:
#Bean
public IntegrationFlow innerInFlow(#Value("${jms.concurrency:10}") String concurrency) {
return IntegrationFlows
.from(Jms.messageDrivenChannelAdapter(
Jms.container(connectionFactory, innerQueue)
.concurrency(concurrency)
.taskExecutor(taskExecutor()).get())
.extractPayload(true))
.transform(Transformers.deserializer())
.route(eventRouter())
.get();
}
And after routing
#Bean
public IntegrationFlow findPersonClienFlow(FindClientHandler findClientHandler) {
return IntegrationFlows.from(findPersonClienChannel())
.transform(findClientHandler, "queryToFindClientRequest")
.handle(Jms.outboundGateway(connectionFactory).requestDestination(cifRequestQueue)
.replyDestination(cifResponseQueue).get())
.get();
}
}
In the Jms.outboundGateway I have org.springframework.integration.MessageTimeoutException and I cant understand how I can handle this error?
Thank you.
I believe the MessageTimeoutException is there because the other side doesn't send you a reply into the cifResponseQueue.
You can configure there a receiveTimeout(), but it is 5 secs by default anyway.
Also you can configure a RequestHandlerRetryAdvice or ExpressionEvaluatingRequestHandlerAdvice on this Jms.outboundGateway() to really handle this exception some specific way, using an advice(...) of the ConsumerEndpointSpec.
See Docs on the matter: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints-chapter.html#message-handler-advice-chain
UPDATE
Also as Gary pointed you can catch an exception from the Jms.messageDrivenChannelAdapter() level using its errorChannel() and some flow subscribed to this channel.

How can I specify a Poller for a queue channel using java-dsl?

I want to consume messages from a Queue channel using java-dsl, but Integrations.from doesn't have a signature allowing me to specify a Poller.
How can I achieve this?
Ex.:
#Bean
IntegrationFlow flow() {
return IntegrationFlows.from(this.channel())
.handle(...)
.get();
}
#Bean
MessageChannel channel() {
return MessageChannels.queue().get();
}
Well, actually it is an endpoint responsibility to provide poller properties.
If you are familiar with an XML configuration you should remember that to poll from <queue> we should configure <poller> sub-element for <service-activator> etc.
The same approach is applied in Java DSL as well. The next endpoint definition should be with desired poller:
IntegrationFlows.from(this.channel())
.handle(..., e -> e.poller(Pollers...))
.get();
I've had trouble for some reason setting a poller on the endpoint definition as Artem described - for some reason it gets ignored. You can always set a default poller. This has worked for me:
#Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata poller() {
return Pollers.fixedRate(500).get();
}

Spring integration DSL creating JMS MessageDriver Channel Adapter in java 1.7

I am trying to create a integration flow for JMS MessageDriverChannelAdapter through which I need to send message to the Kafka server. But I really
stuck when I am trying to convert the the xml tag to dsl specific code, not able to convert the xml to required DSL. Can any one please provide
any pointer to it as I am not able to proceed over here.
I have created a MessageListenerContainer like this........
String brokerUrl = "tcp://101.11.102.125:31316";
String topic = "sometpoic";
String kafkaBrokerUrl = "101.11.102.125:1012";
String kafkaTopic = "kafka_Topic";
#Bean
public DefaultMessageListenerContainer listenerContainer() {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
ActiveMQConnectionFactory conFactory = new ActiveMQConnectionFactory();
ActiveMQTopic mqTopic = new ActiveMQTopic(topic);
conFactory.setBrokerURL(brokerUrl);
container.setConnectionFactory(conFactory);
container.setDestination(mqTopic);
container.setSessionTransacted(true);
return container;
}
These are my input and output channels........
#Bean
public MessageChannel jmsInChannel() {
return MessageChannels.publishSubscribe().get();
}
#Bean
public MessageChannel jmsOutChannel() {
return MessageChannels.publishSubscribe().get();
}
And this is my JMS adapter flow............
#Bean
public IntegrationFlow jmsMessageDrivenFlow() {
return IntegrationFlows
.from(Jms.messageDriverChannelAdapter(listenerContainer())
.autoStartup(true))
.channel(jmsInChannel())
.get();
}
Now I need to create a header-enricher like this but not able to covert this into DSL.
<int:header-enricher input-channel="jmsInChannel" output-channel="jmsOutChannel">
<int:header name="kafkaBrokerUrl" value="${kafka.url}"></int:header>
<int:header name="kafkaTopic" value="${kafka.topic}"></int:header>
and I need to create a service-activator and call a kafka producer method form a different class like this in xml....
<int:service-activator input-channel="jmsOutChannel" ref="KafkaProducer" method="produceToJmsKafka"/>
<bean id="KafkaProducer" class="com.david.jms.JmsKafkaProducer"/>
So how to convert these above xml code to similar DSL specific code.
After getting the compilation error I have tried like this...
#SuppressWarnings("unchecked")
#Bean
public IntegrationFlow jmsMessageDrivenFlow() {
return IntegrationFlows
.from(Jms.messageDriverChannelAdapter(listenerContainer())
.autoStartup(true))
.channel(jmsInChannel())
.enrichHeaders(new MapBuilder()
.put("brokerid", brokerid)
.put("topic", topic)
.put("source", source)
.put("fileType", fileType))
.handle("KafkaProducer", "produceToJmsKafka")
.get();
}
#Bean
public JmsProducer KafkaProducer() {
return new JmsProducer();
}
That may be like this:
#Value("${kafka.url}")
private String kafkaBrokerUrl;
#Value("${kafka.topic}")
private String kafkaTopic;
....
#Bean
public IntegrationFlow jmsMessageDrivenFlow() {
return IntegrationFlows
.from(Jms.messageDriverChannelAdapter(listenerContainer())
.autoStartup(true))
.channel(jmsInChannel())
.enrichHeaders(new StringStringMapBuilder()
.put("kafkaBrokerUrl", kafkaBrokerUrl)
.put("kafkaTopic", kafkaTopic))
.handle("KafkaProducer", "produceToJmsKafka")
.get();
}
From here I don't see reason to have those MessageChannel beans, especially like publishSubscribe().
From other side since DSL 1.1 we provide the implementation for Spring Integration Kafka Adapters.

Spring integration DSL creating JMS Outbound Adapter in java 1.7

I am trying to create a integration flow for JMS OutboundAdapter through which I need to send message to the ActiveMQTopic. But I really
stuck when I am trying to convert the the xml tag to dsl specific code, not able to convert some xml tag to required DSL. Can any ony one please provide
any pointer to it as I am not able to proceed.
This is my Connection factory and Active MQTopic bean
#Bean
public ActiveMQConnectionFactory ConnectionFactory() {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
factory.setBrokerURL(brokerUrl);
return factory;
}
#Bean
public ActiveMQTopic mqTopic() {
return new ActiveMQTopic(jmstopic);
}
This is my QueueChannel and integration flow that I have made...........
#Bean
public QueueChannel jmsOutChannel(){
return new QueueChannel();
}
#Bean
public IntegrationFlow jmsOutboundFlow() {
return IntegrationFlows.from(jmsOutChannel())
.handle(Jms.outboundAdapter(ConnectionFactory())
.destination(mqTopic()))
.get();
}
But I need to convert these below xml into required DSL. Not able to add a poller in my flow.
<int-jms:outbound-channel-adapter id="jmsOutbound" channel="jmsOutChannel" destination="jmsQueue"
connection-factory="connectionFactory" pub-sub-domain="true">
<int:poller fixed-delay="10000" receive-timeout="0"/>
</int-jms:outbound-channel-adapter>
<int:channel id="jmsOutChannel" >
<int:queue capacity="10"/>
</int:channel>
I've edited a bit your question, especially in the last code snippet to figure out what you really need to convert.
First of all pay attention, please, that you don't specify capacity="10" for the jmsOutChannel() #Bean. It is very easy - ctor argument. So, please, try to follow with your code yourself: we can't do all the work for you.
Now regarding the <poller> and DSL. As you see in the XML configuration variant the <poller> is as a part of <int-jms:outbound-channel-adapter> configuration, the Java DSL doesn't invent anything new on the matter and PollerMetadata is tied with the Endpoint configuration there, too:
#Bean
public IntegrationFlow jmsOutboundFlow() {
return IntegrationFlows.from(jmsOutChannel())
.handle(Jms.outboundAdapter(ConnectionFactory())
.destination(mqTopic()),
new Consumer<GenericEndpointSpec<JmsSendingMessageHandler>>() {
void accept(GenericEndpointSpec<JmsSendingMessageHandler> spec) {
spec.poller(Pollers.fixedDelay(10000)
.receiveTimeout(0));
}
})
.get();
}
Something like that.

Spring integration Java DSL : creating jms Message Driver Channel Adapter

I'm having issues with the following Message Driver Channel Adapter
#Bean
public IntegrationFlow jmsInboundFlow() {
return IntegrationFlows.from(Jms.messageDriverChannelAdapter(this.jmsConnectionFactory)
.outputChannel(MessageChannels.queue("inbound").get())
.destination("test"))
.get();
}
#Bean
public IntegrationFlow channelFlow() {
return IntegrationFlows.from("inbound")
.transform("hello "::concat)
.handle(System.out::println)
.get();
}
I'm getting an error about "Dispatcher has no subscribers for channel". What's the preferred configuration for sending the message payload to another integration flow?
With that Java DSL channel auto-creation you should be careful. For example that .outputChannel(MessageChannels.queue("inbound").get()) doesn't populate a MessageChannel bean to the bean factory. But from other side IntegrationFlows.from("inbound") does that.
To fix your issue I suggest to extract #Bean for your inbound channel, or just rely on the DSL:
return IntegrationFlows.from(Jms.messageDriverChannelAdapter(this.jmsConnectionFactory)
.destination("test"))
.channel(MessageChannels.queue("inbound").get())
.get();
Feel free to raise a GH-issue to fix JavaDocs on that .outputChannel() or remove it alltogether, since it is confused.

Resources