Do we have support for Outbound Channel Adapter in Spring Integration with annotation based? Please share link for example which supports.
See Programming Tips in the Reference Manual, where we have a sample for XMPP chat message sending:
#Bean
#ServiceActivator(inputChannel = "input")
public MessageHandler sendChatMessageHandler(XMPPConnection xmppConnection) {
ChatMessageSendingMessageHandler handler = new ChatMessageSendingMessageHandler(xmppConnection);
DefaultXmppHeaderMapper xmppHeaderMapper = new DefaultXmppHeaderMapper();
xmppHeaderMapper.setRequestHeaderNames("*");
handler.setHeaderMapper(xmppHeaderMapper);
return handler;
}
The same technique is applied for the FtpMessageHandler.
Also see Annotation Support there as well.
Related
I have to listen a queue using spring integration flow and intgeration sqs. Once message is received from queue it should trigger a integration flow. Below is the things which I am trying but everythings fine in but afater receiving test it is not triggering any Integration flow. Please let me know where I am doing wrong:
UPDATED as per comment from Artem
Adapter for SQS.
#Bean
public MessageProducerSupport sqsMessageDrivenChannelAdapter() {
SqsMessageDrivenChannelAdapter adapter = new SqsMessageDrivenChannelAdapter(amazonSQSAsync, "Main");
adapter.setOutputChannel(inputChannel());
adapter.setAutoStartup(true);
adapter.setMessageDeletionPolicy(SqsMessageDeletionPolicy.NEVER);
adapter.setMaxNumberOfMessages(10);
adapter.setVisibilityTimeout(5);
return adapter;
}
Queue configured:
#Bean
public MessageChannel inputChannel() {
return new DirectChannel();
}
Now the main integration flow trigger point:
#Bean
public IntegrationFlow inbound() {
return IntegrationFlows.from("inputChannel").transform(i -> "TEST_FLOW").get();
}
}
Appreciate any type of help.
The sqsMessageDrivenChannelAdapter() must be declared as a #Bean
The inbound() must be declared as a #Bean
This one fully does not make sense IntegrationFlows.from(MessageChannels.queue()). What is the point to start the flow from anonymous channel? Who and how is going to produce messages to that channel?
Make yourself familiar with different channels: https://docs.spring.io/spring-integration/docs/current/reference/html/core.html#channel-implementations
Pay attention that QueueChannel must be consumed via polling endpoint.
Right, there is a default poller auto-configured by Spring Boot, but it is based on a single thread in the TaskScheduler and has a polling period as 10 millis.
I wouldn't recommend to hand off SQS messages to the QueueChannel: when consumer fails, you lose the data. It is better to process those messages in the consumer thread.
Otherwise your intention is not clear in the provided code.
Can you, please, share with us what error you get or anything else?
You also can turn on DEBUG logging level for org.springframework.integration to see how your messages are processed.
I'm trying to learn how to handle MQTT Messages in Spring-Integration.
Have created a converter, that subscribes with a single MqttPahoMessageDrivenChannelAdapter per MQTT Topic for consuming and converting the messages.
The problem is our data provider is planning to "speed-up" publishing messages on his side. So instead of having a few(<=10) topics each of which has messages with about 150 fields it is planned to publish each of those fields to the separate MQTT topic.
This means my converter would have to consume ca. 1000 mqtt topics, but I do not know whether:
Is spring-integration still a good choice for it. Cause afaik. the mentioned adapter uses the PAHO MqttClient that will consume the messages from all of the topics it is subscribed to in one single thread and creating 1000 instances of those adapters is an overkill.
If we stick further to spring-integration and use the provided components, would it be a good idea to create a single inbound adapter for all of the fields, that previously were in messages of one topic but moving the conversion away from the adapter bean to a separate bean ( that does the conversion) connected with an executer-channel to the adapter and thus executing the conversion of those fields on some threadpool in parallel.
Thanks in advance for your answers!
I think your idea makes sense.
For that purpose you need to implement a passthrough MqttMessageConverter and provide an MqttMessage as a payload and topic as a header:
public class PassThroughMqttMessageConverter implements MqttMessageConverter {
#Override
public Message<?> toMessage(String topic, MqttMessage mqttMessage) {
return MessageBuilder.withPayload(mqttMessage)
.setHeader(MqttHeaders.RECEIVED_TOPIC, topic)
.build();
}
#Override
public Object fromMessage(Message<?> message, Class<?> targetClass) {
return null;
}
#Override
public Message<?> toMessage(Object payload, MessageHeaders headers) {
return null;
}
}
So, you really will be able to perform a target conversion downstream, after a mentioned ExecutorChannel in the custom transformer.
You also may consider to implement a custom MqttPahoClientFactory (an extension of the DefaultMqttPahoClientFactory may work as well) and provide a custom ScheduledExecutorService to be injected into the MqttClient you are going create in the getClientInstance().
I am using following to define my integration flow:
#Bean
public IntegrationFlow pollingFlow(MessageSource<Object> jdbcMessageSource) {
return IntegrationFlows.from(jdbcMessageSource,
c -> c.poller(Pollers.fixedRate(250, TimeUnit.MILLISECONDS)
.maxMessagesPerPoll(1)
.transactional()))
.split()
.channel(taskSourceChannel())
.get();
}
I would like to make call to service activator that reads from taskSourceChannel as transactional. Also, I want to use following with my transaction.
#Bean
public TransactionSynchronizationFactory transactionSynchronizationFactory() {
ExpressionEvaluatingTransactionSynchronizationProcessor syncProcessor
= new ExpressionEvaluatingTransactionSynchronizationProcessor();
syncProcessor.setAfterCommitChannel(successChannel());
syncProcessor.setAfterRollbackChannel(failureChannel());
return new DefaultTransactionSynchronizationFactory(syncProcessor);
}
The taskSourceChannel is an executor channel.
#Bean
public MessageChannel taskSourceChannel() {
return new ExecutorChannel(executor());
}
How can I add transaction support after split while using TransactionSynchronizationFactory. I don't want to make polling transacational. The only solution I can think of is putting transactional on activator but that won't solve my problem. I would like to make it applicable to any service activator uses this channel.
You question is not so clear, but you definitely need to consider to add transaction into the service activator. Although you don't show what is the subscriber for that taskSourceChannel, but you need to think do not have several subscribers on it.
Nevertheless I think your point is to apply TX into the service activator on this taskSourceChannel and everything after that one.
For this purpose Spring Integration provides a TransactionHandleMessageAdvice. See more info the Reference Manual: https://docs.spring.io/spring-integration/reference/html/messaging-endpoints-chapter.html#tx-handle-message-advice.
The TransactionSynchronizationFactory is only used from the AbstractPollingEndpoint implementations. However you can still utilize it in your transactional context relying on the TransactionSynchronizationManager.registerSynchronization().
A fragment from doc
A Message Endpoint represents the "filter" of a pipes-and-filters
architecture. As mentioned earlier, the endpoint’s primary role is to
connect application code to the messaging framework and to do so in a
non-invasive manner. In other words, the application code should
ideally have no awareness of the message objects or the message
channels.
Transformers, Filters, Service Activators are all Message Endpoints.
What I don't understand is why they are called so as an application actually can send messages into input channels and these "endpoints" are used in the middle of the chain. In other words, the app is aware about a channel, and not about endpoints.
Example:
#SpringBootApplication
#IntegrationComponentScan
public class SendToInputChannel {
#Bean
public IntegrationFlow flow() {
return IntegrationFlows.from("input")
.handle(System.out::println).get();
}
public static void main(String[] args) throws IOException {
ConfigurableApplicationContext ctx = SpringApplication.run(SendToInputChannel.class, args);
MessageChannel inputChannel = ctx.getBean("input", MessageChannel.class);
for (int i = 0; i < 10; i++) {
inputChannel.send(MessageBuilder.withPayload(i)
.build());
}
ctx.close();
}
}
Ekaterina, It all started from the Enterprise Integration Patterns (EIP) book and Spring Integration (SI) is effectively a Reference Implementation of the EIP. We were trying to stay pretty close to "that script". So as you can see from this excerpt - Message Endpoint is used to connect an application to a messaging channels. In other words SI in itself is a messaging framework since it provides internal channels to which various Filters/Endpoints could be connected.
Keep in mind that MessageChannel is an interface and could represent not only the internal channels implemented in SI. For example one can implement a MessageChannel interface that provides some proxy to a JMS queue or anything else, while Filters/Endpoints will remain the same/unchanged.
I can go on, but I hope that is enough for now, but fee free to follow up.
In my application, sending the messages to Tibco Queue with the help of Spring JMS Integration Outbound Gateway. We are having configuration file to load the Connection factory and all the information during server start up.
But when we try to retrieve the messages from Inbound Gateway, the call gets into the doReceive() of GenericMessagingTemplate class and not returned from that method.
Below is the configuration of our application
The Gateway Class as:
#MessagingGateway
public Interface MessageGateway
{
#Gateway(requestChannel="InboundChannel")
public Object listent(#Headers Map<String,Object> cusHeader, #Payload Object obj)
}
Below is the config and registers listener class:
public Class Msgconfig {
#Bean
public MessageChannel InboundChannel(){
return new DirectChannel();
}
#Bean
#ServiceActivator(inputChannel ="InboundChannel")
public AbstractMessageHandler listenMessage() {
// having the logic of DefaultMessageListenerContainer class to load connection factory and setting the message listener
// Have the logic of ChannelPublishingJmsMessageListener class to set the request channel
}
}
I have Custom Inbound class which overrides the handleMessageInternal() method which is actually used for handling the messages.
My client app or test call will call the MessageGateway.listen which has to return the JMS response which is not returning anything.
Can someone help me on this
The AbstractMessageHandler indeed doesn't return anything. It is one-way component. If you would like to return something from downstream you have to use request-reply component. In the Spring Integration all of them are extension of the AbstractReplyProducingMessageHandler. However that's full unclear why you should go so low level - the simple POJO with the method to return anything for the gateway call is fully enough. You still can use that #ServiceActivator annotation: https://docs.spring.io/spring-integration/docs/5.0.0.RELEASE/reference/html/configuration.html#annotations