Spring Integration - Inbound file endpoint. How to process a file correctly.

我怕爱的太早我们不能终老 提交于 2019-12-23 18:30:04

问题


I have a Spring integration flow as following.

<int-file:inbound-channel-adapter id="filesIn"
        directory="file:${incomingDir}" 
        filename-pattern="*.txt" 
        prevent-duplicates="true">
    <int:poller id="poller" fixed-delay="5000"/>
    </int-file:inbound-channel-adapter>

    <int:splitter input-channel="filesIn" 
        ref="filesSplitterService"
        method="splitFilesToReportContent"
        output-channel="reportProcessIn"
     />

     <int:channel id="reportProcessIn"/>

     <int:chain input-channel="reportProcessIn" output-channel="reportProcessOut">    
        <int:service-activator ref="reportProcessorService" method="readReportMetaData" />
        <int:service-activator ref="reportProcessorService" method="saveReportFileInFileSystem" />
        <int:service-activator ref="reportProcessorService" method="saveReportMetaDataInDB" />
    </int:chain>

     <int:channel id="reportProcessOut"/>


    <bean id="filesSplitterService" class="com.app.integration.FilesSplitter"/>

    <bean id="reportProcessorService" class="com.app.reporting.integration.ReportProcessor"/>

Incoming file is splitted by one service and make a List of ReportContent.

Then service chain takes each element of the ReportContent and works on them to read_report_meta_data from the file content (like report id, report type), save report content string to a file in the appropriate directory, and save report meta data in a database. The flow is working fine except there seems to have a loose end.

I get the following exception.

org.springframework.integration.MessageDeliveryException: Dispatcher has no subscribers

  1. I don't need to aggregate the splitted elements. Flow is completed as far as I am concerned after saving meta data in the database.

  2. However I would like to move the original file, the master file I splitted into report files, to some other directory after working with it. How could I incorporate that logic? File:outbound-channel seems to be the way to do it, but I don't understand how to.

  3. Is there a way to avoid saveReportFileInSystem and saveReportMetaDataInDB operations based on some meta-data read in readReportMetaData operation.

For convenience, I have given below the structure of my service classes.

class : FilesSplitter

public List<ReportContent> splitFilesToReportContent(File file){
} 

class : ReportProcessor

public ReportContent readReportMetaData(ReportContent reportContent) {


}



public ReportContent saveReportFileInFileSystem(ReportContent reportContent) {


    }

public ReportContent saveReportMetaDataInDB(ReportContent reportContent) {


    }

One thing to note is that I am not using message headers. I didn't yet feel the necessity to use to but I am okay to use. I am new to spring integration so, any advice to improve this flow would be helpful.


回答1:


1. I get the following exception... org.springframework.integration.MessageDeliveryException

I suppose you have missed file:outbound-channel-adapter definition here.

2. However I would like to move the original file, the master file I splitted into report files, to some other directory after working with it. How could I incorporate that logic?

As written in 14.3.4 File Outbound Channel Adapter your should use delete-source-files attribute for outbound-channel-adapter but(!)

...attribute will only have an effect if the inbound Message has a File payload or if the FileHeaders.ORIGINAL_FILE header value contains either the source File instance or a String representing the original file path.

So, in you reportProcessorService you should deal with raw messages anyway. You don't have source file as a payload anymore. Thus, only one option is to set properly FileHeaders.ORIGINAL_FILE header value.

3. Is there a way to avoid saveReportFileInSystem and saveReportMetaDataInDB operations based on some meta-data read in readReportMetaData operation?

Yes, there is. Use after readReportMetaData in the chain EIP either PayloadTypeRouter (if it's possible becorse its simple) or Configuring (Generic) Router




回答2:


We usually have Dispatcher has no subscribers when there is really no subscribers for the SubscribableChannel (like yours reportProcessOut) or those subscribers has been stopped, which can treat as a "no subscribers", too.

We usually recommend to the send the <service-activator> result to the nullChannel, if you aren't interested in that result. That is the case when you can't achieve your task with just standard one-way component - <outbound-channel-adapter>.

However I would like to move the original file, the master file I splitted into report files,

You can do that with the second one-way subscriber for the <publish-subscriber-channel> as a filesIn. And achiever that with standard File.renameTo() function. I don't reason to blow your mind with something like <int-file:outbound-channel-adapter>. You are on the file system already. So, just use its capabilities. We need adapters for files, when we deal with remote files like FTP, SFTP.

You can use Map<String, Object> headers as a second parameter for your 3service methods and Framework will inject the proper object for you from the request Message<?>.

See @Andriy Kryvtsun 's answer regarding "avoid saveReportFileInSystem".

As an alternative you can use the <filter> to skip and drop messages which should not be saved by some reason.



来源:https://stackoverflow.com/questions/35775105/spring-integration-inbound-file-endpoint-how-to-process-a-file-correctly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!