0

This is my flows LS-GET(SFTP outbound gateway: download files from a remote SFTP server.) and MessagingGateway.

    @MessagingGateway
    public interface IntegratedRemoteFileProcessMessagingGateway {
    
      @Gateway(requestChannel = "getFlows.input")
      void getFlows(final String remoteDirectory);
    
      @Gateway(requestChannel = "moveFlows.input")
      void moveFlows(final String remoteDirectory);
   }

    @Bean
    public QueueChannelSpec getOutputChannel() {
        return MessageChannels.queue();
    }
    
    @Bean
    public IntegrationFlow getFlows() {
        return f -> f
                .enrichHeaders(h -> h
                        .headerExpression("originalPayload", "payload.toString()")
                        .headerExpression(FileHeaders.REMOTE_DIRECTORY, "payload.toString()"))
                .log(LoggingHandler.Level.INFO, "eu.haee", "'Header originalPayload=' + headers[originalPayload]")
                .handle(Sftp.outboundGateway(sessionFactory, Command.LS.getCommand(), "payload")
                        .autoCreateDirectory(false)
                        .autoCreateLocalDirectory(false)
                        .charset("UTF-8")
                        .filter(new SftpSimplePatternFileListFilter("*.xml"))
                        .options(Option.NAME_ONLY, Option.RECURSIVE))
                .split()
                .log(LoggingHandler.Level.INFO, "eu.haee", "'LS Payload= ' + payload.toString()")
                .enrichHeaders(h -> h
                        .headerExpression("originalRemoteFile", "payload.toString()")
                        .headerExpression(FileHeaders.REMOTE_FILE, "payload.toString()"))
                .handle(Sftp.outboundGateway(sessionFactory, Command.GET.getCommand(), "headers['originalPayload'] + headers['file_remoteFile']")
                        .autoCreateLocalDirectory(false)
                        .charset("UTF-8")
                        .fileNameExpression("headers['file_remoteFile']")
                        .localDirectory(new File(flowsConfiguration.localDirectory()))
                        .localFilenameExpression(new FunctionExpression<Message<?>>(m -> {
                            IntegrationMessageHeaderAccessor accessor = new IntegrationMessageHeaderAccessor(m);
                            final String remoteFileName = (String) accessor.getHeader("file_remoteFile");
                            final int extensionIndex = remoteFileName.lastIndexOf('.');
                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss.SSSSS", Locale.GERMAN);
                            return String.format("%s_MYC(%s-%d)%s", remoteFileName.substring(0, extensionIndex), 
                                    ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("Europe/Berlin")).format(formatter), 
                                    (new SecureRandom()).nextInt(99999), 
                                    remoteFileName.substring(extensionIndex));
                        }))
                        .options(Option.PRESERVE_TIMESTAMP)
                        .remoteFileSeparator("/"))
                .channel("getOutputChannel");
    }

This is my spring-batch tasklet and Junit. MessagingGateway injected via tasklet constructor.

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        for (Endpoint endpoint : endpoints) {
            final String remoteDirectory = endpoint.getEpConUri();
            logger.info("ProcessRemoteFilesFlowsTasklet {} dealer at {} remote files process starting", 
                    endpoint.getId().getDlrCd(), remoteDirectory);
            flowsMessagingGateway.getFlows(remoteDirectory);
        }
        return RepeatStatus.FINISHED;
    }
@Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        controlChannel.send(new GenericMessage<>("@getPoller.start()"));
        logger.info("GetPollerRemoteFilesFlowsTasklet poller starting...");
        return RepeatStatus.FINISHED;
    }
@Autowired
    private IntegratedRemoteFileProcessMessagingGateway flowsMessagingGateway;
        
    @Autowired
    private EndpointRepository endpointRepository;
        
    @Test
    public void getFlows() {
        flowsMessagingGateway.getFlows("/c07va00011/iris/import/");
        Uninterruptibles.sleepUninterruptibly(60, TimeUnit.SECONDS);
    }

When I execute getFlows test code. I met exception. but file downloaded to my local computer. I have no idea. I've tried many variants but didn't get any progress.

org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'application.getFlows.input'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers, failedMessage=GenericMessage [payload=/c07va00011/iris/import/, headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@2e64ae1a, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@2e64ae1a, id=bd393cb7-42d0-03b2-674d-40e3cf9211de, timestamp=1609844917799}]
...
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:139)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:106)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:72)
    ... 145 common frames omitted

@EnableIntegration placed every spring-integration related configuration classes. @IntegrationComponentScan also placed my main flow configuration class (with string arrays of package names to scan). If @EnableIntegration annotation located in multiple classes what happens?

Should I merge all spring-batch and spring-integration configuration classes into one?

Also, I've tested ControlBus(Send messages to the poller in the spring-batch tasklet) and got the same exception.

11:57:36.481 [main] ERROR o.s.batch.core.step.AbstractStep - Encountered an error executing step startGetPollerRemoteFilesStep in job integratedFilesProcessJob2
org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'application.controlChannel'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers, failedMessage=GenericMessage [payload=@getPoller.start(), headers={id=539a27d0-9bce-062d-8664-53aae14b5680, timestamp=1609930656454}]

@Lazy, @DependsOn also not working. (@Lazy added to the ControlBus, @DependsOn added in the spring service class: Spring-batch jobs also manually starts/stops by rest API calls.)

@Autowired
    public BatchFileServiceConfiguration(JobBuilderFactory jobBuilderFactory,
            StepBuilderFactory stepBuilderFactory,
            PropertyConfiguration propertyConfiguration,
            @Qualifier("sourceBatchTransactionManager") PlatformTransactionManager sourceBatchTransactionManager,
            @Qualifier("sourceBatchEntityManagerFactory") EntityManagerFactory sourceBatchEntityManagerFactory,
            @Qualifier("processFileTaskExecutor") TaskExecutor processFileTaskExecutor,
            BatchEndpointRepository batchEndpointRepository,
            RemoteFileProcessMessagingGateway remoteFileProcessMessagingGateway,
            @Lazy @Qualifier("controlChannel") MessageChannel controlChannel) {
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
        this.propertyConfiguration = propertyConfiguration;
        this.sourceBatchTransactionManager = sourceBatchTransactionManager;
        this.sourceBatchEntityManagerFactory = sourceBatchEntityManagerFactory;
        this.processFileTaskExecutor = processFileTaskExecutor;
        this.batchEndpointRepository = batchEndpointRepository;
        this.remoteFileProcessMessagingGateway = remoteFileProcessMessagingGateway;
        this.controlChannel = controlChannel;

@Service
@DependsOn({"lsFlows", "getFlows", "moveFlows", "moveFailedFlows", "getPollableFlows"})
public class FileServiceImpl implements FileService {

These exceptions were never occurred in the spring-integration stand-alone applications.

KiSong Kim
  • 68
  • 5
  • Confirm, please, that you have an `@EnableIntegration` somewhere on your `@Configuration` classes. Otherwise it would only be possible to determine the problem if you can share with us a simple project to let us to reproduce an play with. What you show so far is correct. `Dispatcher has no subscribers for channel 'application.getFlows.input'` - probably you declare an `IntegrtionFlow` bean in the child application context... – Artem Bilan Jan 05 '21 at 15:22
  • @EnableIntegration placed every spring-integration related configuration classes. – KiSong Kim Jan 06 '21 at 11:25
  • The `controlChannel` configuration is not shown in the question and it is that extra bit which doesn't help to understand the problem. Since it looks like there is too many parts of your application which we don't see here, it is hard to determine what is going on. Therefore my question: would you mind to share with us a simple reproducible project. Otherwise it is just impossible for us to see what is going on. Probably when you configure your test you miss some `@Configuration` to add... – Artem Bilan Jan 06 '21 at 15:40
  • Yes. `controlChannel` is not my question. It just added after this question posted to check spring-batch job behavior. I have 6 other methods in the `MessageGateway` and all of them work well. The debugging logger shows that the same integration flows ran twice from the one unit test method run. (Exception on the first one but the second one is ok) I'll check this point. Always thanks and happy new year. – KiSong Kim Jan 06 '21 at 18:20

0 Answers0