ISSUES with Monitor folder, consume WebService and send files via FTP Outbound channel

116 views Asked by At

I'm having bad time dealing with a simple application that must monitor a folder for new files, take each file and consume RESTful service ( one of my other apps) and send the response files using spring integration FTP Outbound channel adapter

It has following structure:

enter image description here

Initializer:

package com.ftpoutbound;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

import com.ftpoutbound.client.FtpoutboundApp;
public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(FtpoutboundApp.class);
    }

}

I define beans in FtpoutboundApp:

package com.ftpoutbound.client;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.context.ApplicationContext;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.ftp.outbound.FtpMessageHandler;
import org.springframework.integration.ftp.session.DefaultFtpSessionFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.client.RestTemplate;

import com.ftpoutbound.monitor.MonitorDirectory;

@Configuration
@SpringBootApplication
@ComponentScan({ "com.ftpoutbound" })
@IntegrationComponentScan
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
@EnableScheduling
public class FtpoutboundApp implements ApplicationContextAware {

    final static Logger logger = Logger.getLogger(FtpoutboundApp.class);

    @Autowired
    private MonitorDirectory monitor;

    @Autowired
    MyGateway gateway;

    @Value("${remotedirectory}")
    private String remotedirectory;

    @Value("${remotehost}")
    private String remotehost;

    @Value("${remoteport}")
    private int remoteport;

    @Value("${remoteuser}")
    private String remoteuser;

    @Value("${remotepassword}")
    private String remotepassword;

    @Value("${outbound214sname}")
    private String outbound214sname;

    public static void main(String[] args) {
        SpringApplication.run(FtpoutboundApp.class, args);
    }

    public void createGateway(File file214) {
        try {
            gateway.sendToFtp(file214);
            file214.delete();
        } catch (Exception e) {
            logger.error("ERROR APP OUTBOUND\n");
            logger.error(e);
        }
    }

    @Bean
    public SessionFactory<FTPFile> ftpSessionFactory() {
        DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
        sf.setHost(remotehost);
        sf.setPort(remoteport);
        sf.setUsername(remoteuser);
        sf.setPassword(remotepassword);
        return new CachingSessionFactory<FTPFile>(sf);
    }

    @Bean
    @ServiceActivator(inputChannel = "ftpChannel")
    public MessageHandler handler() {
        FtpMessageHandler handler = new FtpMessageHandler(ftpSessionFactory());
        handler.setRemoteDirectoryExpression(new LiteralExpression(remotedirectory));
        handler.setFileNameGenerator(new FileNameGenerator() {

            @Override
            public String generateFileName(Message<?> message) {
                String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
                String time = new SimpleDateFormat("HHmmssssssss").format(new Date());
                return outbound214sname + "." + date + time;
            }
        });
        return handler;
    }

    @MessagingGateway
    public interface MyGateway {

        @Gateway(requestChannel = "ftpChannel")
        void sendToFtp(File file);
    }

    @EventListener
    public void afterApplicationReady(ApplicationReadyEvent event) {
        try {
            logger.info("INICIO DE MONITOREO DE ARCHIVOS HG");
            monitor.startMonitoring();
        } catch (IOException e) {
            logger.error("ERROR EN MONITOREO  DE FOLDER ENTRADA ARCHIVOS HG:\n" + e);
        } catch (InterruptedException e) {
            logger.error("INTERRUPCIƓN EN MONITOREO  DE FOLDER ENTRADA ARCHIVOS HG:\n" + e);
        }
    }

    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    }

}

The monitor started from the FtpoutboundApp: I'm using SCHEDULED annotation since Watchservice was not working either

package com.ftpoutbound.monitor;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.ftpoutbound.client.FtpoutboundApp;
import com.ftpoutbound.restfulclient.httpPost;

@Component
public class MonitorDirectory {

    final static Logger logger = Logger.getLogger(MonitorDirectory.class);

    @Autowired
    private httpPost httppost;

    @Value("${inboundhgfilesfolder}")
    private String inboundhgfilesfolder;

    @Value("${inboundhgfilesfolderbak}")
    private String inboundhgfilesfolderbak;

    @Value("${hglin}")
    private String hglin;

    @Scheduled(fixedRate = 10000)
    public void startMonitoring() throws IOException, InterruptedException {
        try {
            listFiles();
        } catch (Exception e) {
            logger.error("ERROR MONITOREANDO FOLDER");
            logger.error(e);
        }
    }

    public void listFiles() throws Exception {
        File directory = new File(inboundhgfilesfolder);
        File[] fList = directory.listFiles();
        for (File file : fList) {
            String fileName = file.getName();
            if (file.isFile()) {
                readFile(fileName);
                Thread.sleep(1000);
            }
        }
    }

    public void readFile(String fileName) throws IOException {

        String hgFile = fileName.substring(0, 7);
        if (hgFile.equals(hglin)) {

            InputStream input = new FileInputStream(inboundhgfilesfolder + fileName);
            StringBuilder builder = new StringBuilder();
            int ch;
            while ((ch = input.read()) != -1) {
                builder.append((char) ch);
            }
            try {
                httppost.get214fromRestful(builder.toString());
            } catch (Exception e) {
                logger.error("ERROR EN POST REQUEST DESDE APP OUTBOUND:\n" + e);
            }
        }
        moveFile(fileName);
    }

    public void moveFile(String fileName) {

        Path source = Paths.get(inboundhgfilesfolder + fileName);
        Path newdir = Paths.get(inboundhgfilesfolderbak + fileName);
        try {
            Files.move(source, newdir);
        } catch (IOException e) {
            logger.error("ERROR MOVIENDO ARCHIVO:\n" + e);
        }
    }
}

And the HTTPclient that consumes the RESTful app

package com.ftpoutbound.restfulclient;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.ftpoutbound.client.FtpoutboundApp;

@Component
public class httpPost {

    final static Logger logger = Logger.getLogger(httpPost.class);

    @Value("${restful214url}")
    private String restful214url;

    @Value("${outbound214sfolder}")
    private String outbound214sfolder;

    @Autowired
    private FtpoutboundApp ftpoutbound;

    public void get214fromRestful(String hgfile) throws Exception {
        logger.info("OBTENIENDO 214");
        logger.info("DIRECCION" + restful214url);
        logger.info("ARCHIVO" + hgfile);

        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.postForObject(restful214url, hgfile, String.class);

        File file = createFile214local(result.toString());
        logger.info("RESULTADO DE POST:");
        logger.info(result.toString());

        ftpoutbound.createGateway(file);

    }

    private File createFile214local(String hgfile) {

        logger.info("ESCRIBIENDO 214");
        File file = new File(outbound214sfolder + "214.tmp");
        try {
            file.createNewFile();
            FileWriter fw = new FileWriter(file.getAbsoluteFile());
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write(hgfile);
            bw.close();

        } catch (IOException e) {
            logger.error("ERROR ESCRIBIENDO FILE:\n->" + e);
        }

        return file;
    }

}

but the app seems not working, it freezes before consuming the RESTful in:

            logger.info("OBTENIENDO 214");
            logger.info("DIRECCION" + restful214url);
            logger.info("ARCHIVO" + hgfile);

I noticed these lines are printed twice in the log, still not sure if this is a threads issue or what causes the APP to not even finish the deployment in the server, I have another similar App (except that one doesn't consume RESTful) and it works OK, another FTPInbound channel Adapter and it works OK, but I have some days figuring what I'm missing or What's the best way to do this.

Believe me, Help will be extremely appreciated.

1

There are 1 answers

0
viruskimera On BEST ANSWER

The issue was that my outbound channel configuration class was implementing ApplicationContextAware and it was causing the RestTemplate to freezes the App when consuming my Microservices App, so I changed to extend SpringBootServletInitializer and implement WebApplicationInitializerand it worked.