How to configure a trigger in spring integration flow to get value from a method invoking message source? - spring-integration

How to configure a trigger in spring integration flow to get value from a method invoking message source and start it in another flow ?
#Bean
public IntegrationFlow integrationFlow() {
return IntegrationFlows.from(messageSource,channelSpec -> channelSpec.poller(Pollers.trigger(new SomeTrigger())).handle(...).get()
}
#Bean
public MessageSource<?> messageSource() {
MethodInvokingMessageSource source = new MethodInvokingMessageSource();
source.setObject(new Random());
source.setMethod("nextInt");
}
#Bean
public IntegrationFlow someOtherFlow() {
return IntegrationFlows.from("messageChannel")
///some logic to trigger and get the value of random int
}

The MessageSource has receive() method, so you can do just this:
#Bean
public MessageSource<?> randomIntSource() {
MethodInvokingMessageSource source = new MethodInvokingMessageSource();
source.setObject(new Random());
source.setMethodName("nextInt");
return source;
}
#Bean
public IntegrationFlow someOtherFlow() {
return IntegrationFlows.from("messageChannel")
.handle(randomIntSource(), "receive")
.handle(System.out::println)
.get();
}
pay attention to the .handle(randomIntSource(), "receive").

Related

spring integration http inbound gateway parameters

I have a SpringBoot 2.2.6 application and I would like to set an endpoint with spring-integration therefore I have the follow configuration:
#Bean
public MessageChannel reply() {
return new DirectChannel();
}
#Bean
public IntegrationFlow inbound(TestTransformer testTransformer) {
return IntegrationFlows.from(Http.inboundGateway("/foo")
.requestMapping(m -> m.methods(HttpMethod.GET))
.replyChannel("reply")
.requestPayloadType(String.class))
.channel("httpRequest")
.get();
}
#Bean
#ServiceActivator(inputChannel = "httpRequest", outputChannel = "reply")
public Function<Message<?>, String> handler() {
return new Function<Message<?>, String>() {
public String apply(Message<?> message) throws MessagingException {
log.info("myHandler: " + message.getPayload());
log.info("myHandler: " + message.getHeaders());
return "ok";
}
};
}
Now if I call the enpoint passing params as http://localhost:8080/MyApp/foo?q=test&q1=test2 I receive the parameters in a JSON form.
Is possible to receive something like #PathVariable in the MVC for example writing:
return IntegrationFlows.from(Http.inboundGateway("/foo/{name}")
I have tried it but doesn't work and I canno't find any docs talking about that (at least with java bean configuration)
Thanks
Maybe:
#Bean
public IntegrationFlow test(TestTransformer testTransformer, Jackson2JsonObjectMapper obj) {
return IntegrationFlows.from(Http.inboundGateway("/foo/{name}")
.requestMapping(m -> m.methods(HttpMethod.GET))
.payloadExpression("#pathVariables.name")
.replyChannel("reply")
.requestPayloadType(String.class))
.transform(testTransformer)
.transform(new ObjectToJsonTransformer(obj))
.channel("httpRequest")
.get();
}
is more usefull... The docs is full of xml config and I read it but I'm not able to trasnform them all into java DSL

Spring Integration Wiretap with Annotations (4.3 Spring Integration)

I have a Spring Integration (4.3) application and i have a JMS receiver which sends the received message to a ServiceActivator.
I am trying to Wiretap a channel, and send the JMS message to Logger (which in this case is Service Activator as well)
I get a strange behavior with the code below.
Every odd message sent (first, third) - it only goes to the logger.
Every even message sent (second, fourth, etc) - only goes to the ServiceActivator that is supposed to do some work and in the future sent the message downstream.
Here are logs
2018-07-23 16:14:43.278 INFO 16532 --- [ container-1] zzz : MSG1
Received via barChannel: MSG2
How can i change my code so all messages go both to the logger and the ServiceActivator that is supposed to do the work?
Thanks a lot in advance
#Bean
public ConnectionFactory jmsConnectionFactory() {
return new ActiveMQConnectionFactory("tcp://localhost:61616");
}
#Bean
public JmsMessageDrivenEndpoint inbound() {
JmsMessageDrivenEndpoint jmsMessageDrivenEndpoint = new JmsMessageDrivenEndpoint(container(), listener());
jmsMessageDrivenEndpoint.setSessionAcknowledgeMode("transacted");
jmsMessageDrivenEndpoint.setAutoStartup(true);
return jmsMessageDrivenEndpoint;
}
#Bean
public DefaultMessageListenerContainer container() {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(jmsConnectionFactory());
container.setDestinationName("foo.bar");
return container;
}
#Bean
public ChannelPublishingJmsMessageListener listener() {
ChannelPublishingJmsMessageListener listener = new ChannelPublishingJmsMessageListener();
listener.setRequestChannelName("myLogChannel");
return listener;
}
#ServiceActivator(inputChannel = "myLogChannel")
public void bar(String in) {
System.out.println("Received via barChannel: " + in);
}
#Bean
public MessageChannel TappingChannel(MessageChannel myLogChannel) {
DirectChannel d = new DirectChannel();
d.addInterceptor(new WireTap("myLogChannel"));
return d;
}
#Bean
#ServiceActivator(inputChannel = "myLogChannel")
public MessageHandler logger() {
LoggingHandler loggingHandler = new LoggingHandler(LoggingHandler.Level.INFO.name());
loggingHandler.setLoggerName("zzz");
return loggingHandler;
}
#Bean
public MessageChannel myLogChannel() {
return new DirectChannel();
}
EDIT: Here is the original code that works
#Bean
public MessageChannel toRouter() {
return new DirectChannel();
}
#Bean
public ConnectionFactory jmsConnectionFactory() {
return new ActiveMQConnectionFactory("tcp://localhost:61616");
}
#Bean
public JmsMessageDrivenEndpoint inbound(ConnectionFactory jmsConnectionFactory) {
return new JmsMessageDrivenEndpoint(container(jmsConnectionFactory), listener());
}
#Bean
public DefaultMessageListenerContainer container(ConnectionFactory jmsConnectionFactory) {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(jmsConnectionFactory);
container.setDestinationName("foo.bar");
return container;
}
#Bean
public ChannelPublishingJmsMessageListener listener() {
ChannelPublishingJmsMessageListener listener = new ChannelPublishingJmsMessageListener();
listener.setRequestChannelName("toRouter");
return listener;
}
#ServiceActivator(inputChannel = "toRouter")
public void bar(String in) {
System.out.println("Received via barChannel: " + in);
}
I want to do the Wiretap logging on this code
You have a mess in your config.
First of all you have two #ServiceActivator for the same myLogChannel DirectChannel.
By default it uses a round-robin dispatching strategy. That's why you see that odd/even behavior between your two consumers on the same channel.
You separate TappingChannel doesn't bring any value and it is out of use at all. No one sends message to this channel: you send to the listener.setRequestChannelName("myLogChannel"); directly though... Therefore a WireTap isn't performed at all as well.
I'm not sure how to help you since it isn't clear what you are going to use as a main channel and what should be used from the wire-tap.
UPDATE
So, you need to configure that new WireTap("myLogChannel") on this toRouter channel.

Dynamic http inbound gateway using spring-integration-dsl

I am trying to create and register runtime Integration flow for HTTP inbound gateway using Java DSL as code provided below
#Autowired
private IntegrationFlowContext flowContext;
public static void main(String[] args) {
SpringApplication.run(RestClientDemoApplication.class, args);
}
#ServiceActivator(inputChannel="httpRequest")
public String upCase(String in) {
System.out.println("message received" + in);
return in.toUpperCase();
}
#Bean
public MessageChannel directChannel(){
return MessageChannels.direct().get();
}
/*#Bean
public IntegrationFlow inbound() {
return IntegrationFlows.from(Http.inboundGateway("/foo")
.requestMapping(m -> m.methods(HttpMethod.POST))
.requestPayloadType(String.class).replyChannel(directChannel()))
.channel("httpRequest")
.get();
}
*/
#Override
public void run(String... args) throws Exception {
IntegrationFlow flow;
IntegrationFlowRegistration theFlow;
flow = IntegrationFlows.from(Http.inboundGateway("/foo")
.requestMapping(m -> m.methods(HttpMethod.POST))
.requestPayloadType(String.class).replyChannel(directChannel()))
.channel("httpRequest")
.get();
theFlow = this.flowContext.registration(flow).register();
}
In this case my request url ("/foo") is not mapping with the server as when I send the message from the HTTP client then no message is received on server side.
but when I uncomment the above bean (inbound) i.e creating a Bean for Integration flow and comment the flow creation and register code(remove runtime integration flow code) in run method
as below it work fine:
#Autowired
private IntegrationFlowContext flowContext;
public static void main(String[] args) {
SpringApplication.run(RestClientDemoApplication.class, args);
}
#ServiceActivator(inputChannel="httpRequest")
public String upCase(String in) {
System.out.println("message received" + in);
return in.toUpperCase();
}
#Bean
public MessageChannel directChannel(){
return MessageChannels.direct().get();
}
#Bean
public IntegrationFlow inbound() {
return IntegrationFlows.from(Http.inboundGateway("/foo")
.requestMapping(m -> m.methods(HttpMethod.POST))
.requestPayloadType(String.class).replyChannel(directChannel()))
.channel("httpRequest")
.get();
}
#Override
public void run(String... args) throws Exception {
/*IntegrationFlow flow;
IntegrationFlowRegistration theFlow;
flow = IntegrationFlows.from(Http.inboundGateway("/foo")
.requestMapping(m -> m.methods(HttpMethod.POST))
.requestPayloadType(String.class).replyChannel(directChannel()))
.channel("httpRequest")
.get();
theFlow = this.flowContext.registration(flow).register();*/
}
My HTTP outbound gateway Code is as follow
flow = IntegrationFlows.from(directChannel()).handle(Http.outboundGateway("https://localhost:8448/foo")
.httpMethod(HttpMethod.POST).expectedResponseType(String.class)).channel("httpReply").get();
theFlow = this.flowContext.registration(flow).register();
Please help me with the above issue or provide a solution to create Http inbound gateway at runtime if this approach is not appropriate.
This is not possible yet: https://jira.spring.io/browse/INT-4436.
Unfortunately there is no simple workaround for your to go ahead, unless you could expose just only one REST endpoint and do routing inside the IntegrationFlow according the accepted HTTP request.

How to wire tap a message channel in java dsl?

I am trying Java dsl in spring integration. I am trying to wiretap a channel. But getting error,
#ContextConfiguration
#EnableIntegration
#IntegrationComponentScan
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(DemoApplication.class);
CustomGtwy service = ctx.getBean(CustomGtwy.class);
service.pushMessage("Manoj");
}
#Bean
public MessageChannel loggerChannel(){
return MessageChannels.direct().get();
}
#Bean
public MessageChannel pushAssetIdChannel() {
return MessageChannels.direct()
.interceptor(new WireTap(loggerChannel()))
.get();
}
#Bean
public IntegrationFlow pushAssetIdFlow() {
return IntegrationFlows.from("pushAssetIdChannel")
.handle(new GenericHandler() {
#Override
public String handle(Object arg0, Map arg1) {
// TODO Auto-generated method stub
return "Success";
}})
.get();
}
#MessagingGateway
public interface CustomGtwy{
#Gateway(requestChannel="pushAssetIdChannel")
String pushMessage(String s);
}
#Bean
public IntegrationFlow logger(){
return IntegrationFlows.from("loggerChannel").handle(new GenericHandler() {
#Override
public String handle(Object arg0, Map arg1) {
// TODO Auto-generated method stub
return "Success";
}}).channel("nullChannel").get();
}
}
In the above code, if i try to put message in the pushAssetIdChannel, i am getting Dispatcher has no subscribers for channel 'unknown.channel.name'
If the interceptor is not there, it is working.
Not sure what's going on with your case, but that works for me with the latest 1.0.2 version:
#ContextConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#DirtiesContext
public class SO31348246Tests {
#Autowired
private MessageChannel pushAssetIdChannel;
#Test
public void testIt() {
this.pushAssetIdChannel.send(new GenericMessage<>("foo"));
}
#Configuration
#EnableIntegration
public static class ContextConfiguration {
#Bean
public MessageChannel loggerChannel() {
return MessageChannels.direct().get();
}
#Bean
public MessageChannel pushAssetIdChannel() {
return MessageChannels.direct()
.interceptor(new WireTap(loggerChannel()))
.get();
}
#Bean
public IntegrationFlow pushAssetIdFlow() {
return IntegrationFlows.from("pushAssetIdChannel")
.handle(System.out::println)
.get();
}
#Bean
public IntegrationFlow logger() {
return IntegrationFlows.from("loggerChannel")
.handle((p, h) -> {
System.out.println(p);
return p;
})
.channel("nullChannel")
.get();
}
}
}
I see both SOUTs in logs.
UPDATE
Your class works for me after fixing #ContextConfiguration to the normal #Configuration annotation :-).
Without the last one the framework considers your DemoApplication as lite configuration, just because you have there #Bean methods, but it does not do it like the full one and doesn't proxy it to allow to use bean method reference like you do with loggerChannel() in the WireTap constructor.
So, with lite we jsut invoke that method and get a fresh MessageChannel object, but it isn't a bean in the application context. That's why you end up with the Dispatcher has no subscribers.

Spring integration DSL creating Sftp Inbound Adapter in java 1.7

I am creating a sftp inbound flow in spring dsl but when I am trying to test this in junit the mesage is coming null. I think the sftp ibound adapter is not starting properly, but not sure. So I am not able to go further. Can any ony one please provide any pointer to it as I am not able to proceed.
This is my flow....
#Bean
public IntegrationFlow sftpInboundFlow() {
return IntegrationFlows
.from(Sftp.inboundAdapter(this.sftpSessionFactory)
.preserveTimestamp(true).remoteDirectory(remDir)
.regexFilter(".*\\.txt$")
.localFilenameExpression("#this.toUpperCase()")
.localDirectory(new File(localDir))
.remoteFileSeparator("/"),
new Consumer<SourcePollingChannelAdapterSpec>() {
#Override
public void accept(
SourcePollingChannelAdapterSpec e) {
e.id("sftpInboundAdapter")
.autoStartup(true)
.poller(Pollers.fixedRate(1000)
.maxMessagesPerPoll(1));
}
})
.channel(MessageChannels.queue("sftpInboundResultChannel"))
.get();
}
This is my session Factory...
#Autowired
private DefaultSftpSessionFactory sftpSessionFactory;
#Bean
public DefaultSftpSessionFactory sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(
true);
factory.setHost("111.11.12.143");
factory.setPort(22);
factory.setUser("sftp");
factory.setPassword("*******");
return factory;
}
This is my Pollable channel..
#Autowired
private PollableChannel sftpInboundResultChannel;
#Bean
public PollableChannel sftpChannel() {
return new QueueChannel();
}
And this is my Test method..
#Test
public void testSftpInboundFlow() {
Message<?> message = ((PollableChannel) sftpInboundResultChannel).receive(1000); //Not receiving any message
System.out.println("message====" + message);
Object payload = message.getPayload();
File file = (File) payload;
message = this.sftpInboundResultChannel.receive(1000);
file = (File) message.getPayload();
}

Resources