0

Using Spring FTP Integration and Annotation configuration, I downloaded files from the FTP server. After downloaded still our application is trigger to connect the server and find the any newly added files, if any files added it will download from the server. But I don't need to maintain the FTP server session alive and disconnect the server after first connection or first time downloaded.

Code :

public class FtpServices {

    @Bean(name="ftpSessionFactory")
    public DefaultFtpSessionFactory ftpSessionFactory() {
        System.out.println("session");

        DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
        sf.setHost("localhost");
        sf.setPort(21);
        sf.setUsername("user");
        sf.setPassword("password");

        return sf;
    }

    @Bean
    public FtpInboundFileSynchronizer ftpInboundFileSynchronizer() {
        System.out.println("2");
        FtpInboundFileSynchronizer fileSynchronizer = new FtpInboundFileSynchronizer(ftpSessionFactory());
        fileSynchronizer.setDeleteRemoteFiles(false);
        fileSynchronizer.afterPropertiesSet();
        fileSynchronizer.setRemoteDirectory("/test/");
       // fileSynchronizer.setFilter(new FtpSimplePatternFileListFilter("*.docx"));
        fileSynchronizer.setFilter(filter);
        return fileSynchronizer;
    }

    @Bean()
    @InboundChannelAdapter(value="ftpChannel", poller = @Poller(fixedDelay = "50", maxMessagesPerPoll = "1"))
    public FtpInboundFileSynchronizingMessageSource ftpMessageSource() {
        System.out.println(3);
        FtpInboundFileSynchronizingMessageSource source =
                new FtpInboundFileSynchronizingMessageSource(ftpInboundFileSynchronizer());
        source.setLocalDirectory(new File("D:/Test-downloaded/"));
        //source.stop();
        return source;
    }

    @Bean
    @ServiceActivator(inputChannel = "ftpChannel", requiresReply="false")
    public MessageHandler handler() {
        System.out.println(4);
        MessageHandler handler =  new MessageHandler() {

            @Override
            public void handleMessage(Message<?> message) throws MessagingException {
                System.out.println(message.getPayload()+" @ServiceActivator");
                System.out.println(" Message Header :"+message.getHeaders());
            }
        };
        return handler;
    }

    @Bean(name = PollerMetadata.DEFAULT_POLLER)
    public PollerMetadata defaultPoller() {

        PollerMetadata pollerMetadata = new PollerMetadata();
        pollerMetadata.setTrigger(triggerOnlyOnce());
        return pollerMetadata;
    }

}

and also I override the AbtractFTPSessionFactory.java to test FTP server connection and disconnection process.

protected void postProcessClientAfterConnect(T t) throws IOException {
    System.out.println("After connect");
}

protected void postProcessClientBeforeConnect(T client) throws IOException {
    System.out.println("Before connect");
}

Console :

    INFO : org.springframework.context.support.DefaultLifecycleProcessor - Starting beans in phase -2147483648
    INFO : org.springframework.context.support.DefaultLifecycleProcessor - Starting beans in phase 0
    Before connect
    After connect
    D:\Test-downloaded\demo 1.txt @ServiceActivator
     Message Header :{id=e4a1fd7f-0bbf-9692-f70f-b0ac68b4dec4, timestamp=1477317086272}
    D:\Test-downloaded\demo.txt @ServiceActivator
     Message Header :{id=9115ee92-12b4-bf1f-d592-9c13bf7a27fa, timestamp=1477317086324}
    Before connect
    After connect
    Before connect
    After connect
    Before connect
    After connect
    Before connect
    After connect
    Before connect
    After connect
    Before connect
    After connect

Thanks.

1 Answers1

1

That is really a purpose of any @InboundChannelAdapter: poll the target system for new data periodically.

To do that once we sometimes suggest OnlyOnceTrigger:

public class OnlyOnceTrigger implements Trigger {

    private final AtomicBoolean done = new AtomicBoolean();

    @Override
    public Date nextExecutionTime(TriggerContext triggerContext) {
           return !this.done.getAndSet(true) ? new Date() : null;
    }

}

But this might not work for your case, because there might not be desired files in the source FTP directory yet.

Therefore we have to poll until you will receive required files and .stop() an adapter when that condition is met.

For this purpose you can use any downstream logic to determine the state or consider to implement AbstractMessageSourceAdvice to be injected to the PollerMetadata of the @Poller: http://docs.spring.io/spring-integration/reference/html/messaging-channels-section.html#conditional-pollers

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Its working fine, but still it triggering the AbstractMessageSourceAdvice subclass and after some business logic, I'm returning false from beforeReceive(MessageSource> source), so it's not triggering FTP server. is it affect the our application performance. – Chethan kumar B N Oct 25 '16 at 06:59
  • Well, not so much, but avoid that triggering altogether you can consider stopping Inbound Channel Adapter endpoint – Artem Bilan Oct 25 '16 at 11:01
  • If local directory has old files, then the our application is not connecting to FTP server. if not that means our local directory is empty, then it's working fine. is their any reason for that? and how to overcome this. – Chethan kumar B N Nov 03 '16 at 06:27
  • For that purpose you can consider to use persistent `localFilter`, which will skip already processed files after restart and will go to FTP. – Artem Bilan Nov 03 '16 at 10:48