spring cloud AWS sendAndReceive - spring

I need to send and receive SQS message as I do it in rabbitmq. So I need to do that synchronously.
The issue is, if I use #SqsListener in spring boot,the method never invoked if it has a signature other than (String s). Any other signature does not simply work, method is not triggering.
My config is:
#Bean
public QueueMessagingTemplate queueMessagingTemplate() {
return new QueueMessagingTemplate(amazonSQSAsync());
}
#Bean
public AmazonSQSAsync amazonSQSAsync() {
return AmazonSQSAsyncClientBuilder.standard().withRegion(Regions.US_EAST_1)
.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(awsAccessKey, awsSecretKey)))
.build();
}
#Bean
public SimpleMessageListenerContainer simpleMessageListenerContainer() {
SimpleMessageListenerContainer msgListenerContainer = simpleMessageListenerContainerFactory()
.createSimpleMessageListenerContainer();
msgListenerContainer.setMessageHandler(queueMessageHandler());
return msgListenerContainer;
}
#Bean
public SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory() {
SimpleMessageListenerContainerFactory msgListenerContainerFactory = new SimpleMessageListenerContainerFactory();
msgListenerContainerFactory.setAmazonSqs(amazonSQSAsync());
return msgListenerContainerFactory;
}
#Bean
public QueueMessageHandler queueMessageHandler() {
QueueMessageHandlerFactory queueMsgHandlerFactory = new QueueMessageHandlerFactory();
queueMsgHandlerFactory.setAmazonSqs(amazonSQSAsync());
QueueMessageHandler queueMessageHandler = queueMsgHandlerFactory.createQueueMessageHandler();
List<HandlerMethodArgumentResolver> list = new ArrayList<>();
HandlerMethodArgumentResolver resolver = new PayloadArgumentResolver(new MappingJackson2MessageConverter());
list.add(resolver);
list.add( new HeaderMethodArgumentResolver(null, null));
queueMessageHandler.setArgumentResolvers(list);
return queueMessageHandler;
}
and receiver is:
#SqsListener(value = {"${cloud.aws.end-point.uri}"}, deletionPolicy = SqsMessageDeletionPolicy.ALWAYS)
public void receive(String message) {
System.out.println("Inside receive: " + message);
}
If this method has any other signature, it will not even be triggered. What should I do to retrieve a raw aws Message here to use in AwsSQSResponder?

Have you tried the #Payload annotation?
#SqsListener(value = {"${cloud.aws.end-point.uri}"}, deletionPolicy = SqsMessageDeletionPolicy.ALWAYS)
public void receive(#Payload String message) {
System.out.println("Inside receive: " + message);
}

Related

Issue with RabbitMQ Delay message in spring boot

I am facing an issue in Rabbit MQ regarding x-delay while connecting to spring boot. I need to schedule the messages for a variable delay according to the message type. It can be one of the units MINUTE, DAY, WEEK, MONTH, and so on…
Below is my configuration class :
private final RabbitProperties rabbitProperties;
private final Environment environment;
#Bean
public Queue rabbitMQueue() {
return new Queue(environment.getProperty(RABBITMQ_QUEUE_NAME), false);
}
#Bean
public Exchange rabbitExchange() {
String exchangeName = "test_exchange";
Map<String, Object> exchangeArgs = new HashMap<>();
exchangeArgs.put("x-delayed-type", exchangeType.toLowerCase());
exchangeArgs.put("x-delayed-message",true);
exchangeArgs.put("x-message-ttl",9922);
log.info("Loading {} exchange with name {}.", exchangeType, exchangeName);
switch (exchangeType){
default: return new CustomExchange(exchangeName, exchangeType, true, false, exchangeArgs);
case "DIRECT" : return directExchange(exchangeName, exchangeArgs);
}
}
private Exchange directExchange(String exchangeName, Map<String, Object> exchangeArgs) {
// log.info("Generating directExchange");
// DirectExchange directExchange = new DirectExchange(exchangeName,true, false, exchangeArgs);
// directExchange.setDelayed(true);
// return directExchange;
return ExchangeBuilder.directExchange(exchangeName).withArguments(exchangeArgs)
.delayed()
.build();
}
#Bean
public Binding rabbitBinding(final Queue rabbitMQueue, final Exchange rabbitExchange){
log.info("Exchange to bind : {}", rabbitExchange.getName());
return BindingBuilder
.bind(rabbitMQueue)
.to(rabbitExchange)
.with(environment.getProperty(RABBITMQ_ROUTING_KEY)).noargs();
}
#Bean
public AmqpTemplate amqpTemplate(final ConnectionFactory rabbitMQConnectionFactory,
final MessageConverter rabbitMessageConvertor,
final Exchange rabbitExchange){
RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitMQConnectionFactory);
rabbitTemplate.setMessageConverter(rabbitMessageConvertor);
rabbitTemplate.setExchange(rabbitExchange.getName());
return rabbitTemplate;
}
#Bean
public ConnectionFactory rabbitMQConnectionFactory(){
Boolean isUriBased = environment.getProperty(URI_BASED_CONNECTION_ENABLED, Boolean.class);
CachingConnectionFactory connectionFactory;
if(!Objects.isNull(isUriBased) && isUriBased){
connectionFactory = new CachingConnectionFactory();
connectionFactory.setUri(environment.getProperty(RABBITMQ_URI));
}
else{
connectionFactory = new CachingConnectionFactory(rabbitProperties.getHost(), rabbitProperties.getPort());
connectionFactory.setUsername(rabbitProperties.getUsername());
connectionFactory.setPassword(rabbitProperties.getPassword());
}
return connectionFactory;
}
#Bean
public MessageConverter rabbitMessageConvertor(){
return new Jackson2JsonMessageConverter();
}
And publisher code :
public boolean sendMessage(String tenant, T message, int delay){
MyQueueMessage<T> myQueueMessage = getQueueMessage(tenant, message);
try{
amqpTemplate.convertAndSend(exchangeName, routingKey, myQueueMessage, messagePostProcessor -> {
// MessageProperties messageProperties = messagePostProcessor.getMessageProperties();
messagePostProcessor.getMessageProperties().setHeader("x-message-ttl", 5011);
messagePostProcessor.getMessageProperties().setHeader(MessageProperties.X_DELAY, 5012);
messagePostProcessor.getMessageProperties().setDelay(5013);
messagePostProcessor.getMessageProperties().setReceivedDelay(5014);
log.info("Setting delay in properties : {}", messagePostProcessor.getMessageProperties().getHeader(MessageProperties.X_DELAY).toString());
return messagePostProcessor;
});
} catch (Exception e){
return false;
}
return true;
}
And receiver :
#RabbitListener(queues = "INVOICE")
public void receiveMessage(Message message){
log.info("Message Received : " + message.toString() + " with delay " + message.getMessageProperties().getDelay());
}
}
Issue :
The value
message.getMessageProperties().getDelay()
comes as NULL in the receiver and the message is also not delayed. It’s getting received instantly.
Did I miss anything?
Please note that I am using docker, rabbitmq-management-3, and have already installed the rabbitmq_delayed_message_exchange plugin.

aws sns to sqs, message not getting converted

I am trying to configure an SNS producer with SQS consumer, built with a Spring boot app. I have tried leveraging Spring cloud and just using JMS API, with both ways I cant seem to get my consumer to convert the message for me to read. With Spring cloud I get an error saying that the "payload is not a valid notification. Code below: Any help much appreciated
SNS configuration:
#Bean
public AmazonSNS snsClient() {
AmazonSNS snsClient = AmazonSNSClientBuilder.standard()
.withEndpointConfiguration(<endpoint-stuff)).build();
return snsClient;
}
#Bean
public NotificationMessagingTemplate notificationMessagingTemplate(
AmazonSNS amazonSNS) {
return new NotificationMessagingTemplate(amazonSNS);
}
producer code:
#Autowired
NotificationMessagingTemplate messagingTemplate;
public void send() throws Exception {
MessageDto message = new MessageDto();
message.setMessageA("Hello");
message.setMessageB("Again");
messagingTemplate.sendNotification("my_topic",message,"Test");
}
SQS consumer configuration:
#Bean
public SimpleMessageListenerContainer simpleMessageListenerContainer()
{
SimpleMessageListenerContainer msgListenerContainer =
simpleMessageListenerContainerFactory()
.createSimpleMessageListenerContainer();
msgListenerContainer.setMessageHandler(queueMessageHandler());
return msgListenerContainer;
}
#Bean
public SimpleMessageListenerContainerFactory
simpleMessageListenerContainerFactory() {
SimpleMessageListenerContainerFactory msgListenerContainerFactory =
new SimpleMessageListenerContainerFactory();
msgListenerContainerFactory.setAmazonSqs(amazonSQSClient());
return msgListenerContainerFactory;
}
#Bean
public QueueMessageHandler queueMessageHandler() {
QueueMessageHandlerFactory queueMsgHandlerFactory = new
QueueMessageHandlerFactory();
queueMsgHandlerFactory.setAmazonSqs(amazonSQSClient());
QueueMessageHandler queueMessageHandler =
queueMsgHandlerFactory.createQueueMessageHandler();
//List<HandlerMethodArgumentResolver> list = new ArrayList<>();
//HandlerMethodArgumentResolver resolver = new
//PayloadArgumentResolver(new MappingJackson2MessageConverter());
//list.add(resolver);
//queueMessageHandler.setArgumentResolvers(list);
return queueMessageHandler;
}
#Lazy
#Bean(name = "amazonSQS", destroyMethod = "shutdown")
public AmazonSQSAsync amazonSQSClient() {
AwsClientBuilder.EndpointConfiguration endpointConfiguration = new
AwsClientBuilder.EndpointConfiguration(
"<url>, "<region");
AmazonSQSAsync awsSQSAsync =
AmazonSQSAsyncClientBuilder.standard()
.withEndpointConfiguration(endpointConfiguration)
.build();
return awsSQSAsync;
}
SQS listener:
#SqsListener(value = "my_queue", deletionPolicy =
SqsMessageDeletionPolicy.ON_SUCCESS)
public void consume(final #NotificationMessage MessageDto event) {
LOGGER.info("Message received {}
{}",event.getMessageA(),event.getMessageB());
}
stack trace:
Caused by:
org.springframework.messaging.converter.MessageConversionException:
Payload: '<payload here>' is not a valid notification
at
org.springframework.cloud.aws.messaging.support.
converter.NotificationRequestConverter.fromMessage
(NotificationRequestConverter.java:69)
at

Spring Cloud AWS SQS SendTo annotation with property placeholder

This issue suggests that the #SendTo annotation supports property placeholders, but I can't get it to work. Here's some simplified code snippets of what I'm trying to do (easier than trying to explain with words). I'm on spring-cloud-aws version 1.2.1.
This works:
#Component
public class InputQueueListener {
#Value("${replyQueueProperty}")
private String replyQueue;
#Autowired
private QueueMessagingTemplate messagingTemplate;
#SqsListener(value = "${inputQueueProperty}", deletionPolicy = SqsMessageDeletionPolicy.NEVER)
private void receiveMessage(final Message message, final Acknowledgment acknowledgment, #Header("ApproximateReceiveCount") final int receiveCount) throws Exception {
final Reply reply = doStuff(message);
messagingTemplate.convertAndSend(replyQueue, reply);
}
}
And this works:
#Component
public class InputQueueListener {
#SqsListener(value = "${inputQueueProperty}", deletionPolicy = SqsMessageDeletionPolicy.NEVER)
#SendTo("replyQueueActualName")
private Reply receiveMessage(final Message message, final Acknowledgment acknowledgment, #Header("ApproximateReceiveCount") final int receiveCount) throws Exception {
final Reply reply = doStuff(message);
return reply;
}
}
But this does not work:
#Component
public class InputQueueListener {
#SqsListener(value = "${inputQueueProperty}", deletionPolicy = SqsMessageDeletionPolicy.NEVER)
#SendTo("${replyQueueProperty}")
private Reply receiveMessage(final Message message, final Acknowledgment acknowledgment, #Header("ApproximateReceiveCount") final int receiveCount) throws Exception {
final Reply reply = doStuff(message);
return reply;
}
}
This fails with a NonExistentQueue exception. But the queue exists, and the first two methods send messages to it just fine.
What am I missing?! I have checked for typos a million times, I'm pretty sure that's not it :)
Just in case, this is my configuration:
#Bean
public QueueMessagingTemplate queueMessagingTemplate(final AmazonSQSAsync amazonSqs, final ResourceIdResolver resourceIdResolver) {
final QueueMessagingTemplate queueMessagingTemplate = new QueueMessagingTemplate(amazonSqs, resourceIdResolver);
return queueMessagingTemplate;
}
#Lazy
#Bean(name = "amazonSQS", destroyMethod = "shutdown")
public AmazonSQSAsync amazonSQSClient() {
final AmazonSQSAsync awsSQSAsyncClient;
awsSQSAsyncClient = AmazonSQSAsyncClientBuilder
.standard()
.withRegion(Regions.fromName(System.getProperty("cloud.aws.region.static")))
.withCredentials(new DefaultAWSCredentialsProviderChain())
.build();
return awsSQSAsyncClient;
}
#Bean
public QueueMessageHandler queueMessageHandler(final AmazonSQSAsync amazonSqs) {
final QueueMessageHandlerFactory queueMsgHandlerFactory = new QueueMessageHandlerFactory();
queueMsgHandlerFactory.setAmazonSqs(amazonSqs);
final QueueMessageHandler queueMessageHandler = queueMsgHandlerFactory.createQueueMessageHandler();
return queueMessageHandler;
}
#Bean
public SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory(final AmazonSQSAsync amazonSqs) {
final SimpleMessageListenerContainerFactory msgListenerContainerFactory = new SimpleMessageListenerContainerFactory();
msgListenerContainerFactory.setAmazonSqs(amazonSqs);
msgListenerContainerFactory.setMaxNumberOfMessages(5);
msgListenerContainerFactory.setWaitTimeOut(20);
return msgListenerContainerFactory;
}
#Bean
public SimpleMessageListenerContainer simpleMessageListenerContainer(final QueueMessageHandler messageHandler, final SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory) {
final SimpleMessageListenerContainer msgListenerContainer = simpleMessageListenerContainerFactory.createSimpleMessageListenerContainer();
msgListenerContainer.setMessageHandler(messageHandler);
return msgListenerContainer;
}
#Bean
public DynamicQueueUrlDestinationResolver destinationResolver(final AmazonSQSAsync amazonSqs, final ResourceIdResolver resourceIdResolver) {
DynamicQueueUrlDestinationResolver destinationResolver = new DynamicQueueUrlDestinationResolver(amazonSqs, resourceIdResolver);
return destinationResolver;
}
#Bean
public QueueMessageHandlerFactory queueMessageHandlerFactory(final AmazonSQSAsync amazonSqs) {
QueueMessageHandlerFactory factory = new QueueMessageHandlerFactory();
factory.setAmazonSqs(amazonSqs);
return factory;
}

Unexpected message - no endpoint registered with connection interceptor while communicating with multiple servers

#Configuration
#Component
public class GatewayAqrConfig {
#Autowired
ConnectorService connectorService;
#Autowired
MasterService masterService;
private HashMap<ConnectorPK, GatewayAqr> connectorMap;
#Bean
#Scope(value = "prototype")
public AbstractClientConnectionFactory clientCF(Connector connector , Master master) {
TcpNetClientConnectionFactory clientConnectionFactory = new TcpNetClientConnectionFactory(connector.getAqrIpAddr(), connector.getAqrIpPortNo());
clientConnectionFactory.setSingleUse(false);
MyByteArraySerializer obj = new MyByteArraySerializer(master.getAqrMsgHeaderLength(), master.getAqrId());
clientConnectionFactory.setSerializer(obj);
clientConnectionFactory.setDeserializer(obj);
clientConnectionFactory.setSoKeepAlive(true);
TcpMessageMapper tcpMessageMapper = new TcpMessageMapper();
tcpMessageMapper.setCharset("ISO-8859-1");
clientConnectionFactory.setMapper(tcpMessageMapper);
clientConnectionFactory.setBeanName(connector.getAqrIpAddr() + ":" + connector.getAqrIpPortNo());
clientConnectionFactory.afterPropertiesSet();
clientConnectionFactory.start();
return clientConnectionFactory;
}
#Bean
#Scope(value = "prototype")
public TcpSendingMessageHandler tcpOutGateway(AbstractClientConnectionFactory connectionFactory) {
TcpSendingMessageHandler messageHandler = new TcpSendingMessageHandler();
messageHandler.setConnectionFactory(connectionFactory);
messageHandler.setClientMode(true);
messageHandler.setTaskScheduler(getTaskScheduler());
messageHandler.setStatsEnabled(true);
messageHandler.afterPropertiesSet();
messageHandler.start();
return messageHandler;
}
#Bean
#Scope(value = "prototype")
public TcpReceivingChannelAdapter tcpInGateway(AbstractClientConnectionFactory connectionFactory) {
TcpReceivingChannelAdapter messageHandler = new TcpReceivingChannelAdapter();
messageHandler.setConnectionFactory(connectionFactory);
messageHandler.setClientMode(true);
messageHandler.setOutputChannel(receive());
messageHandler.setAutoStartup(true);
messageHandler.setTaskScheduler(getTaskScheduler());
messageHandler.afterPropertiesSet();
messageHandler.start();
return messageHandler;
}
#Bean
#Scope(value = "prototype")
public TaskScheduler getTaskScheduler() {
TaskScheduler ts = new ThreadPoolTaskScheduler();
return ts;
}
#Bean
public MessageChannel receive() {
QueueChannel channel = new QueueChannel();
return channel;
}
#Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata poller() {
return new PollerMetadata();
}
#Bean
#Transactional
public HashMap<ConnectorPK, GatewayAqr> gatewayAqr() throws Exception {
connectorMap = new HashMap();
Connector connector = null;
ConnectorPK connectorPK = null;
Master master = null;
TcpConnectionSupport connectionSupport = null;
// 1. Get List of Connections configured in Database
List<Connector> connectors = connectorService.getConnections();
if (connectors.size() > 0) {
for (int i = 0; i < connectors.size(); i++) {
// 2. Get the connection details
connector = connectors.get(i);
connectorPK = aqrConnector.getConnectorpk();
master = masterService.findById(connectorPK.getAcuirerId());
try {
// 3. Create object of TcpNetClientConnectionFactory for each Acquirer connection
AbstractClientConnectionFactory clientConnectionFactory = clientCF(aqrConnector, aqrMaster);
// 4. Create TcpSendingMessageHandler for the Connection
TcpSendingMessageHandler outHandler = tcpOutGateway(clientConnectionFactory);
// 5. Create TcpReceivingChannelAdapter object for the Connection and assign it to receive channel
TcpReceivingChannelAdapter inHandler = tcpInGateway(clientConnectionFactory);
// 6. Generate the GatewayAqr object
GatewayAqr gatewayAqr = new GatewayAqr(clientConnectionFactory, outHandler, inHandler);
// 7. Put in the MAP acuirerPK and Send MessageHandler object
connectorMap.put(aqrConnectorPK, gatewayAquirer);
} catch (Exception e) {
}
} // for
} // if
return connectorMap;
}
}
*********************************************************************************************************************************
#EnableIntegration
#IntegrationComponentScan(basePackageClasses = {GatewayEventConfig.class,GatewayAqrConfig.class })
#Configuration
#ComponentScan(basePackages = {"com.iz.zw.gateway.impl", "com.iz.zw.configuration"})
#Import({GatewayEventConfig.class,GatewayAquirerConfig.class})
public class GatewayConfig {
#Autowired
private GatewayAsyncReply<Object, Message<?>> gatewayAsyncReply;
#Autowired
private GatewayCorrelationStrategy gatewayCorrelationStrategy;
#Autowired
private HashMap<ConnectorPK, GatewayAqr> gatewayAqrs;
#Autowired
ConnectorService connectorService;
#Autowired
GatewayResponseDeserializer gatewayResponseDeserializer;
#MessagingGateway(defaultRequestChannel = "send")
public interface Gateway {
void waitForResponse(TransactionMessage transaction);
}
#Bean
public MessageChannel send() {
DirectChannel channel = new DirectChannel();
return channel;
}
#Bean
#ServiceActivator(inputChannel = "send")
public BarrierMessageHandlerWithLateGoodResponse barrier() {
BarrierMessageHandlerWithLateGoodResponse barrier = new BarrierMessageHandlerWithLateGoodResponse(25000, this.gatewayCorrelationStrategy);
barrier.setAsync(true);
barrier.setOutputChannel(out());
barrier.setDiscardChannel(lateGoodresponseChannel());
return barrier;
}
#ServiceActivator(inputChannel = "out")
public void printMessage(Message<?> message) {
System.out.println("in out channel");
}
#Transformer(inputChannel = "receive", outputChannel = "process")
public TransactionMessage convert(byte[] response) {
logger.debug("Response Received", Arrays.toString(response));
TransactionMessage transactionMessage = gatewayResponseDeserializer.deserializeResponse(response);
System.out.println("Response : " + response);
return transactionMessage;
}
#ServiceActivator(inputChannel = "process")
#Bean
public MessageHandler releaser() {
return new MessageHandler() {
#Override
public void handleMessage(Message<?> message) throws MessagingException {
try {
gatewayAsyncReply.put(message);
barrier().trigger(message);
} catch (GatewayLateGoodMessageException exception) {
System.out.println("Late good response..!");
gatewayAsyncReply.get(message);
lateGoodresponseChannel().send(message);
}
}
};
}
#Bean
public MessageChannel process() {
QueueChannel channel = new QueueChannel();
return channel;
}
#Bean
public MessageChannel out() {
DirectChannel channel = new DirectChannel();
return channel;
}
#Bean
public MessageChannel lateGoodresponseChannel() {
QueueChannel channel = new QueueChannel();
return channel;
}
#ServiceActivator(inputChannel="lateGoodresponseChannel")
public void handleLateGoodResponse(Message<?> message) {
String strSTAN = null;
String strResponse = null;
Message<?> respMessage = null;
if(message instanceof TransactionMessage){
strSTAN = ((TransactionMessage)message).getStan();
respMessage = gatewayAsyncReply.get(strSTAN);
if (null != respMessage) {
strResponse = (String) message.getPayload();
}
}
logger.info("Late Good Response: " + strResponse);
}
}
*********************************************************************************************************************************
#Configuration
public class GatewayEventConfig {
private static final Logger logger = LoggerFactory.getLogger(GatewayEventConfig.class);
#Bean
public ApplicationEventListeningMessageProducer tcpEventListener() {
ApplicationEventListeningMessageProducer producer = new ApplicationEventListeningMessageProducer();
producer.setEventTypes(new Class[] {TcpConnectionOpenEvent.class, TcpConnectionCloseEvent.class, TcpConnectionExceptionEvent.class});
producer.setOutputChannel(tcpEventChannel());
producer.setAutoStartup(true);
producer.setTaskScheduler(getEventTaskScheduler());
producer.start();
return producer;
}
#Bean
public TaskScheduler getEventTaskScheduler() {
TaskScheduler ts = new ThreadPoolTaskScheduler();
return ts;
}
#Bean
public MessageChannel tcpEventChannel() {
return new QueueChannel();
}
#Transactional
#ServiceActivator(inputChannel = "tcpEventChannel")
public void tcpConnectionEvent(TcpConnectionEvent event) {
System.out.println("In publishing" + event.toString());
String strConnectionFactory = event.getConnectionFactoryName();
if (strConnectionFactory.equals("connection1")) {
//send some message to connector
} else {
// send message to another connector
}
}
}
this is my configuration files, my application tries to connect to 2 servers as soon as it starts.
I have made 2 configurations for 2 servers as above class
GatewayAqrConfig1 and GatewayConfig1 classes are used for first server connection
GatewayAqrConfig2 and GatewayConfig2 classes are used for second server connection
Using event I am connecting to server and sending a connection set up message, if server is already started and If I have started my application,
it gets the event, connects and sends the message but I am not getting the response instead I am getting the WARNING as below
**WARN TcpNetConnection:186 - Unexpected message - no endpoint registered with connection interceptor:**
i.e connection does not registers the listener properly
but if I am starting my application first and then servers I am getting responses perfectly, As I am connecting to servers
I could not restart it ? My application should connect to server which is already started ? what could be the problem ?
Version used:
Spring integration Version : 4.3.1
Spring version : 4.3.2
JDK 1.8 on JBOSS EAP 7
That WARN message means that, somehow, an inbound message was received without a TcpReceivingChannelAdapter having been registered with the connection factory. Client mode should make no difference.
Having looked at your code a little more, the prototype beans should be ok, as long as you use those objects (especially TcpMessageHandler directly rather than via the framework).
It's not obvious to me how that can happen, given your configuration; the listener is registered when you call setConnectionFactory on the receiving adapter.
If you can reproduce it with a trimmed-down project and post it someplace, I will take a look.

Get String from Spring FTP streaming Inbound Channel Adapter

I have the following code which works OK retrieving files from FTP server into a stream, but I need to get String of each file, seems I need to use the Transformer passing a charset but what I'm missing? How exactly to get the content String of each file transferred?
Thanks a lot in advance
#SpringBootApplication
#EnableIntegration
public class FtpinboundApp extends SpringBootServletInitializer implements WebApplicationInitializer {
final static Logger logger = Logger.getLogger(FtpinboundApp.class);
public static void main(String[] args) {
SpringApplication.run(FtpinboundApp.class, args);
}
#Bean
public SessionFactory<FTPFile> ftpSessionFactory() {
DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
sf.setHost("X.X.X.X");
sf.setPort(21);
sf.setUsername("xxx");
sf.setPassword("XXX");
return new CachingSessionFactory<FTPFile>(sf);
}
#Bean
#ServiceActivator(inputChannel = "stream")
public MessageHandler handler() {
return new MessageHandler() {
#Override
public void handleMessage(Message<?> message) throws MessagingException {
System.out.println("trasnferred file:" + message.getPayload());
}
};
}
#Bean
#InboundChannelAdapter(value = "stream", poller = #Poller(fixedRate = "1000"))
public MessageSource<InputStream> ftpMessageSource() {
FtpStreamingMessageSource messageSource = new FtpStreamingMessageSource(template(), null);
messageSource.setRemoteDirectory("/X/X/X");
messageSource.setFilter(new FtpPersistentAcceptOnceFileListFilter(new SimpleMetadataStore(), "streaming"));
return messageSource;
}
#Bean
#Transformer(inputChannel = "stream", outputChannel = "data")
public org.springframework.integration.transformer.Transformer transformer() {
return new StreamTransformer("UTF-8");
}
#Bean
public FtpRemoteFileTemplate template() {
return new FtpRemoteFileTemplate(ftpSessionFactory());
}
#Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(5000));
return pollerMetadata;
}
}
Use a StreamTransformer to get the whole file as a single string, or a FileSplitter to get a message for each line.
EDIT (filter config)
#Bean
#InboundChannelAdapter(channel = "stream")
public MessageSource<InputStream> ftpMessageSource() {
FtpStreamingMessageSource messageSource = new FtpStreamingMessageSource(template(), null);
messageSource.setRemoteDirectory("ftpSource/");
messageSource.setFilter(filter());
return messageSource;
}
public FileListFilter<FTPFile> filter() {
CompositeFileListFilter<FTPFile> filter = new CompositeFileListFilter<>();
filter.addFilter(new FtpSimplePatternFileListFilter("*.txt"));
filter.addFilter(acceptOnceFilter());
return filter;
}
#Bean
public FtpPersistentAcceptOnceFileListFilter acceptOnceFilter() {
FtpPersistentAcceptOnceFileListFilter filter = new FtpPersistentAcceptOnceFileListFilter(meta(),
"streaming"); // keys will be, e.g. "streamingfoo.txt"
filter.setFlushOnUpdate(true);
return filter;
}
#Bean
public ConcurrentMetadataStore meta() {
PropertiesPersistingMetadataStore meta = new PropertiesPersistingMetadataStore();
meta.setBaseDirectory("/tmp/foo");
meta.setFileName("ftpStream.properties");
return meta;
}
EDIT2 - remove remote file with an advice
#ServiceActivator(inputChannel = "data", adviceChain = "after")
#Bean
public MessageHandler handle() {
return System.out::println;
}
#Bean
public ExpressionEvaluatingRequestHandlerAdvice after() {
ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
advice.setOnSuccessExpression(
"#template.remove(headers['file_remoteDirectory'] + headers['file_remoteFile'])");
advice.setPropagateEvaluationFailures(true);
return advice;
}

Resources