My requirement is to process a file at an inbound endpoint
Use Case 1- Failure in processing the file
If the file fails processing due to some exception like a validation error move the file to a separate directory different from the source. Delete the original file in the source directory
Use Case 2 -Successful processing
If the file processing is successful done , let the file remain in the source directory.
I tried the following , the file is moved to failed directory but the source file is not deleted as required in Use Case 1.
<flow name="InValidFlow1" doc:name="InValidFlow1">
<file:inbound-endpoint responseTimeout="10000" doc:name="File" path="c:\filelanding\in2" pollingFrequency="100" connector-ref="input_2" moveToDirectory="c:\filelanding\in2" moveToPattern="#[header:originalFilename]-#[function:dateStamp]-Processed">
<file:filename-regex-filter pattern="(?!.*Processed|.*Failed)(.*)" caseSensitive="false"/>
</file:inbound-endpoint>
<test:component waitTime="20000"></test:component>
<custom-transformer class="com.XXX.XXX.service.ExceptionService" doc:name="Java"/>
<file:outbound-endpoint responseTimeout="10000" doc:name="File" path="c:\filelanding\out2" connector-ref="output_2"/>
<exception-strategy ref="fot_exception_strategy_single" doc:name="Reference Exception Strategy"/>
</flow>
<file:connector name="error_output_1" outputPattern="#[header:originalFilename]" doc:name="File"/>
<choice-exception-strategy name="fot_exception_strategy_single">
<catch-exception-strategy when="#[exception.causedBy(java.lang.RuntimeException)]" doc:name="Catch Exception Strategy">
<!-- Mark the status as failed-->
<file:outbound-endpoint connector-ref="error_output_1" responseTimeout="10000" doc:name="File" path="c:\filelanding\backup2" outputPattern="#[header:originalFilename]-#[function:dateStamp]-Failed" >
</file:outbound-endpoint>
</catch-exception-strategy>
</choice-exception-strategy>
Do i need to override any existing mule functionality to achieve this behavior. The source folder on failure shouldn't contain the file. The destination folder should have the file marked with "Failed" status.
For use case 1, in your exception strategy use the value in originalFilename in a MEL expression component to move the file to wherever you want.
You can use org.mule.util.FileUtils.moveFileWithCopyFallback() for that matter.
PS. #[header:originalFilename] is old style expression syntax, on Mule 3.3 and above use MEL #[message.inboundProperties.originalFilename].
Related
Using Mule 4.4 community edition .
I am reading a file using mule's sftp connector :
<dependency>
<groupId>org.mule.connectors</groupId>
<artifactId>mule-sftp-connector</artifactId>
<version>1.4.1</version>
<classifier>mule-plugin</classifier>
</dependency>
Running code in dedug mode , after the file is read , I can still see the file on sftp location ( which is good ) , however it disappears after file read .... ( see below code )
<sftp:config name="SFTP_Config" doc:name="SFTP Config"
timeBetweenSizeCheck="30" timeBetweenSizeCheckUnit="SECONDS">
<sftp:connection host="myHost" port="22" username="myUser" password="myPassword" />
</sftp:config>
<until-successful maxRetries="1" doc:name="Until Successful" millisBetweenRetries="30000">
<sftp:read doc:name="Read employee file" config-ref="SFTP_Config" path="${sftp.inputDir}\employee.unl" timeBetweenSizeCheck="-1" outputMimeType="application/csv; streaming=true; header=false; separator=|" outputEncoding="UTF-8">
<non-repeatable-stream />
</sftp:read>
</until-successful>
<choice doc:name="is the file empty ?" >
<when expression="sizeOf(payload) == 0">
<raise-error doc:name="Raise error on empty file " type="FILE_NOT_PRESENT_OR_EMPTY" description="Employee File empty "/>
</when>
<otherwise >
<logger level="INFO" doc:name="Payload not empty" message=" #[sizeOf(payload)]" category="employee"/>
</otherwise>
</choice>
So when the code enters the choice condition I can see the file is somehow no longer available on SFTP drive ...
I have tested this code in debug mode to verify when the file is getting deleted / disappearing.
Not sure why this would happen ?
why is the file getting deleted after code enters into the choice condition ?
I've got a few .properties files containing some data. How do I write a specific value of a property from one of the property files to a variable?
There are the following three approaches to perform on this problem statement.
1.Reading a properties file using ${Key} expression
2.Reading a properties file using ![p[‘Key’]] expression
3.Reading a properties file using p() function from DataWeave
While according to your need, I have used the first approach. Please go through the following code. I think this will resolve your problem.
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
<context:property-placeholder location="propread.properties"/>
<flow name="propreadFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/propread" doc:name="HTTP"/>
<logger message=""Flow Started"" level="INFO" doc:name="Logger"/>
<set-variable variableName="prop" value="${prop.read}" doc:name="Variable"/>
<logger message="#[flowVars.prop]" level="INFO" doc:name="Logger"/>
</flow>
</mule>
Please create one property file under src/main/resources with the name propread.properties and copy this ( prop.read=HelloMule ) into the file and run the above code. You will get the solution.
We process XML-Files from the Filesystem and once they've been process, they will be moved to another directory. Another system monitors this output folder and takes all newly created files for further process.
If we define the moveToPattern and moveToDirecory properties, the input file will be first copied to destinations and then deleted from input folder. This works properly on small files but takes longer on huge files which causes to incomplete file on output folder for some seconds.
Our solution is to let the file be copied with .tmp extension and then rename it to the final name and delete the input file.
So the Flow looks like below:
Input-File --> Processing --> Output-File with .tmp --> Rename --> Delete Input-File
The Problem is through using this custom-transformer for renaming the file after the file:endpoint the flow remains active and all Messages won't be garbage collected and causes a OutOfMemory Exception.
A Memory Dump shows a huge number of DefaultMuleMessage object which proofs my assumption.
has anybody an Idea to resolve this Problem?
<file:connector name="inputFileConnector" autoDelete="false" doc:name="File" streaming="true" validateConnections="true" />
<file:connector name="temporaryFileOutputConnectorConfig" outputPattern="#[message.outboundProperties['transportFileName']].tmp" autoDelete="false" streaming="false" validateConnections="true" doc:name="File" />
<file:endpoint path="${outputDir}/${queuePrefix}#[message.outboundProperties.'queue_number' ]/#[message.outboundProperties.'approvalSubDir']" name="OutputConnectorEndpoint" responseTimeout="10000" doc:name="File"/>
<flow name="Queue_Flow" processingStrategy="synchronous" initialState="stopped" >
<file:inbound-endpoint path="${inputDir}" responseTimeout="10000" pollingFrequency="5000" connector-ref="inputFileConnector" doc:name="File">
.
.
.
<flow-ref name="OutStrategyFile" doc:name="Out Strategy File"/>
</flow>
<sub-flow name="OutStrategyFile">
<file:outbound-endpoint connector-ref="temporaryFileOutputConnectorConfig" responseTimeout="10000" ref="OutputConnectorEndpoint" doc:name="Write temporary file"/>
<custom-transformer class="com.fileutil.FileRenamer" doc:name="Rename file to final location">
<spring:property name="fileUtils" ref="fileUtils"/>
</custom-transformer>
<custom-transformer class="com.fileutil.DeleteOriginalInputMessage" doc:name="Delete Original input message"/>
</sub-flow>
I am having a flow as follows
<flow name="MyMainFlow">
<flow-ref name="MySubFlow" >
</flow>
<sub-flow name="MySubFlow">
------
</sub-flow>
While testing with Munit I am getting class not found exception . Due to some reasons I am not allowed to test through mule files . Is there any way where I could test sub-flow with Munit?
I was able to test a sub flow using the following flow and sub-flow:
<flow name="main">
<vm:inbound-endpoint path="in"/>
<flow-ref name="MySubFlow" />
<vm:outbound-endpoint path="out"/>
</flow>
<sub-flow name="MySubFlow">
<append-string-transformer message=" Received"/>
</sub-flow>
and the following munit test:
<munit:test name="test" description="Create your test here">
<munit:set payload-ref="#[string: Hello world!]"/>
<munit:assert-not-null/>
</munit:test>
You can do a flow ref to a sub flow
https://github.com/mulesoft/munit/blob/munit-3.5.x/munit-integration-tests/src/test/munit/assertion-munit-test.xml#L83
The class not found exception is related with your test classpath, can we have a stacktrace?
Subflow can be tested from parent flow which called by using the flow -ref.
you can try with latest versions of munit 3.5.2-m2 version.
In MuleStudio a simple rename script deletes files after a while. This is how the script looks like:
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:ftp="http://www.mulesoft.org/schema/mule/ftp" xmlns:file="http://www.mulesoft.org/schema/mule/file" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" version="CE-3.4.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.mulesoft.org/schema/mule/ftp http://www.mulesoft.org/schema/mule/ftp/current/mule-ftp.xsd">
<flow name="ftp_ping_pong_testFlow1" doc:name="ftp_ping_pong_testFlow1" initialState="started" processingStrategy="queued-asynchronous">
<file:inbound-endpoint path="C:\ftp_ping_pong_test\src\test\in\" responseTimeout="10000" doc:name="File" fileAge="1000" pollingFrequency="1200">
<file:filename-regex-filter pattern="^.*\.csv$" caseSensitive="true"/>
</file:inbound-endpoint>
<file:outbound-endpoint path="C:\ftp_ping_pong_test\src\test\in\" outputPattern="#[message.inboundProperties['originalFilename']].temp" responseTimeout="10000" doc:name="File"/>
</flow>
<flow name="ftp_ping_pong_testFlow2" doc:name="ftp_ping_pong_testFlow2">
<file:inbound-endpoint path="C:\ftp_ping_pong_test\src\test\in\" responseTimeout="10000" doc:name="File" fileAge="1000" pollingFrequency="1200">
<file:filename-regex-filter pattern="^.*\.temp$" caseSensitive="true"/>
</file:inbound-endpoint>
<file:outbound-endpoint path="C:\ftp_ping_pong_test\src\test\in\" outputPattern="#[message.inboundProperties['originalFilename'].replace('.temp','')]" responseTimeout="10000" doc:name="File"/>
</flow>
</mule>
The script does nothing else but renames the file, than names it back. It makes no difference if I raise the fileAge or if I change the processing strategy or if I run it in MuleStudio or Mule Standalone. What is strange that it works for ~300 iterations but then it gets confused.
The error log what I get looks like:
WARN 2013-12-19 12:43:15,815 [Finalizer] org.mule.transport.file.FileMessageReceiver: Failure trying to remove file C:\ftp_ping_pong_test\src\test\in\145278.csv.temp from list of files under processing
I have already lost a week with this issue, so any help would be much appreciated :)
Update:
I created two different apps. Here they are:
<?xml version="1.0" encoding="UTF-8"?>
<mule Links removed by Stackoverflow">
<file:connector name="File_Connector_CSV" autoDelete="true" streaming="false" validateConnections="true" doc:name="File" readFromDirectory="C:\Users\gabor.bodo\MuleStudio\workspace\ftp_ping_pong_test\src\test\in" writeToDirectory="C:\Users\gabor.bodo\MuleStudio\workspace\ftp_ping_pong_test\src\test\out"/>
<flow name="ftp_ping_pong_testFlow1" doc:name="ftp_ping_pong_testFlow1" initialState="started" processingStrategy="synchronous">
<file:inbound-endpoint path="C:\Users\gabor.bodo\MuleStudio\workspace\ftp_ping_pong_test\src\test\in\" responseTimeout="10000" doc:name="File" fileAge="1000" pollingFrequency="1200" connector-ref="File_Connector_CSV" >
<file:filename-regex-filter pattern="^.*\.csv$" caseSensitive="true"/>
</file:inbound-endpoint>
<file:outbound-endpoint outputPattern="#[message.inboundProperties['originalFilename']].temp" responseTimeout="10000" doc:name="File" path="C:\Users\gabor.bodo\MuleStudio\workspace\ftp_ping_pong_test\src\test\out"/>
</flow>
</mule>
And the second:
<?xml version="1.0" encoding="UTF-8"?>
<mule links removed by Stackoverflow">
<file:connector name="File" writeToDirectory="C:\Users\gabor.bodo\MuleStudio\workspace\ftp_ping_pong_test\src\test\in" readFromDirectory="C:\Users\gabor.bodo\MuleStudio\workspace\ftp_ping_pong_test\src\test\out" autoDelete="true" streaming="false" validateConnections="true" doc:name="File"/>
<flow name="ftp_ping_pong_player2Flow1" doc:name="ftp_ping_pong_player2Flow1">
<file:inbound-endpoint path="C:\Users\gabor.bodo\MuleStudio\workspace\ftp_ping_pong_test\src\test\out" responseTimeout="10000" doc:name="File" connector-ref="File">
<file:filename-regex-filter pattern="^.*\.temp$" caseSensitive="true"/>
</file:inbound-endpoint>
<file:outbound-endpoint path="C:\Users\gabor.bodo\MuleStudio\workspace\ftp_ping_pong_test\src\test\in\" outputPattern="#[message.inboundProperties['originalFilename'].replace('.temp','')]" responseTimeout="10000" doc:name="File" connector-ref="File"/>
</flow>
</mule>
I ran the test with 7 test files, and as usual the files started to disappear. From the combine logs, here is the last appearance of one of the files:
INFO 2013-12-20 17:58:13,843 [[ping_pong_player1].File_Connector_CSV.receiver.01] org.mule.transport.file.FileMessageReceiver: Lock obtained on file: C:\ftp_ping_pong_test\src\test\in\09.csv
INFO 2013-12-20 17:58:14,519 [[ping_pong_player1].File_Connector_CSV.receiver.01] org.mule.transport.file.FileConnector: Writing file to: C:\ftp_ping_pong_test\src\test\out\09.csv.temp
INFO 2013-12-20 17:58:14,812 [[ping_pong_player2].File.receiver.01] org.mule.transport.file.FileMessageReceiver: Lock obtained on file: C:\ftp_ping_pong_test\src\test\out\09.csv.temp
INFO 2013-12-20 17:58:15,437 [[ping_pong_player2].File.dispatcher.402] org.mule.transport.file.FileConnector: Writing file to: C:\ftp_ping_pong_test\src\test\in\09.csv
After these log entries this file simply disappeared without any no further trace in logs.
I have observed that even if in MuleStudio there is a default value defined for File Age, the value is not represented in the XML file, this is why Player2, has no File Age defined.
I can about a possible scenario:
- Player1, reads the csv file and creates the temp. Player 2 reads the temp and writes back the csv. Player1 deletes the csv, believing it is still the original file. In this case Player1 is too slow, lets Player2 intervene and this can happen if Player2 has no File Age. - I have to retest this with File Age value settings accordingly.But it does not explain why happens this very rarely.
Thanks,
Gabor
Update
I know your feeling. When you add the File Connector, uncheck Auto Delete in the General tab:
Finally, I managed to figure out what was the problem after countless of experiments.
It seems that when mule is launching an application the File Age property will be checked only once, and not for each flow separately (maybe it is normal but I did not expect this behaviour). Even with different flows, it doesn't matter what is the File Age property as long as it is less than the standard kick time of Mule (says 5000 ms, but actually it is 50000 ms - someone added one zero in plus somewhere).
So what happened, that Player1 and Player2 were always trying to read, copy and delete all the files in the same time. It was just a question of when until the scenario described by me above happened.
The solution now works well, by making two separate applications with big enough FileAge (Attention that it is not enough that you have a FileAge defined in MuleStudio, it has to be in the XML as well!).
Hope it saves time for someone and thanks for all the good intention!