I am using the following fork and join pattern in my flow.Parallel processing works just fine. However, I have issues with exception handling. I want to implement an exception strategy for the processing happening on VM response inbound endpoint of the router. However, it seems my nothing happens when I am trying to write to response, from within the catch exception strategy block. When there is an exception, I am able to see the log statement from the catch block, but the response on browser just hangs.
Please suggest.
<flow name="forkAndJoinFlow" doc:name="forkAndJoinFlow">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="81" path="lowestprice" doc:name="HTTP"/>
<not-filter doc:name="Not">
<wildcard-filter pattern="*favicon*" caseSensitive="true"/>
</not-filter>
<request-reply>
<all>
<vm:outbound-endpoint path="shop1"/>
<vm:outbound-endpoint path="shop2"/>
</all>
<vm:inbound-endpoint path="response">
<message-properties-transformer>
<add-message-property key="MULE_CORRELATION_GROUP_SIZE" value="2" />
</message-properties-transformer>
<collection-aggregator />
</vm:inbound-endpoint>
</request-reply>
<expression-transformer evaluator="groovy" expression="java.util.Collections.min(payload)" doc:name="Expression"/>
<object-to-string-transformer doc:name="Object to String"/>
<logger level="WARN" message="#[string:Lowest price: #[payload]]" doc:name="Logger"/>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<logger message="EXCEPTION:#[payload]" level="INFO" doc:name="Logger"></logger>
<!--Nothing happens after this-->
<object-to-string-transformer doc:name="Object to String"></object-to-string-transformer></catch-exception-strategy>
</flow>
<flow name="shop1Flow" doc:name="shop1Flow">
<vm:inbound-endpoint path="shop1" doc:name="VM"/>
<logger level="INFO" message="SHOP1 Flow..." doc:name="Logger"/>
<expression-transformer evaluator="groovy" expression="new java.lang.Double(1000.0 * Math.random()).intValue()" doc:name="Expression"/>
<logger level="WARN" message="#[string:Price from shop 1: #[payload]]" doc:name="Logger"/>
</flow>
<flow name="shop2Flow" doc:name="shop2Flow">
<vm:inbound-endpoint path="shop2" doc:name="VM"/>
<logger level="INFO" message="SHOP2 Flow..." doc:name="Logger"/>
<expression-transformer evaluator="groovy" expression="new java.lang.Double(1000.0 * Math.random()).intValue()" doc:name="Expression"/>
<logger level="WARN" message="#[string:Price from shop 2: #[payload]]" doc:name="Logger"/>`enter code here`
</flow>
</mule>
Related
I've a mule flow where I configured Request Reply scope. The flow is like below:
<flow name="RequestReplyFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/test" doc:name="HTTP" />
<set-payload value="#['Sample Payload']" doc:name="Set Payload" />
<request-reply doc:name="Request-Reply">
<vm:outbound-endpoint exchange-pattern="one-way" path="request" doc:name="VM" />
<vm:inbound-endpoint exchange-pattern="one-way" path="reply" doc:name="VM" />
</request-reply>
</flow>
and
<flow name="RequestReplyFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="request" doc:name="VM" />
<logger message="Executing with payload: #[payload]" level="INFO" doc:name="Logger" />
<component class="org.ram.BusinessComponent" doc:name="Java" />
<rollback-exception-strategy maxRedeliveryAttempts="5" doc:name="Rollback Exception Strategy">
<logger message="Will attempt redelivery" level="INFO" doc:name="Logger" />
</rollback-exception-strategy>
</flow>
I configure rollback-exception-strategy on the request VM inbound endpoint.
When the component org.ram.BusinessComponent throws an exception, what I expected is the message is redelivered to the inbound VM endpoint but it did not happen. Why?
Can anyone please solve the issue?
If you are using rollback exception strategy instead of default exception strategy for unhandled exceptions, then you just have to specify the redirection manually in the "rollback-exception-strategy" by adding the "vm:outbound-endpoint" with the "reply" path, note that the maxRedeliveryAttempts was changed to "0" because your vm is not transactional:
<flow name="RequestReplyFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="request" doc:name="VM" />
<logger message="Executing with payload: #[payload]" level="INFO" doc:name="Logger" />
<component class="org.ram.BusinessComponent" doc:name="Java" />
<rollback-exception-strategy maxRedeliveryAttempts="0" doc:name="Rollback Exception Strategy">
<logger message="Will attempt redelivery" level="INFO" doc:name="Logger" />
<vm:outbound-endpoint exchange-pattern="one-way" path="reply" doc:name="VM" />
</rollback-exception-strategy>
</flow>
When the vm is transactional then the value maxRedeliveryAttempts=5 makes sense because in that case Mule attempts message redelivery five (5) times. Then you can specify the redirection manually in the "rollback-exception-strategy" by adding the "vm:outbound-endpoint" with the "reply" path inside the "on-redelivery-attempts-exceeded" child element:
<flow name="RequestReplyFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="request" doc:name="VM" />
<logger message="Executing with payload: #[payload]" level="INFO" doc:name="Logger" />
<component class="org.ram.BusinessComponent" doc:name="Java" />
<rollback-exception-strategy maxRedeliveryAttempts="0" doc:name="Rollback Exception Strategy">
<logger message="Will attempt redelivery" level="INFO" doc:name="Logger" />
<on-redelivery-attempts-exceeded>
<logger message="redelivery attempt exceeded" level="INFO" doc:name="Logger" />
<vm:outbound-endpoint exchange-pattern="one-way" path="reply" doc:name="VM" />
</on-redelivery-attempts-exceeded>
</rollback-exception-strategy>
</flow>
<flow name="listobjects">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="listobjects" contentType="text/plain" doc:name="HTTP"/>
<s3:list-objects config-ref="Amazon_S3" bucketName="demo" doc:name="Amazon S3" maxKeys="5" />
<!-- <payload-type-filter expectedType="java.util.List" doc:name="Payload"/> -->
<foreach collection="#[payload]" doc:name="For Each">
<!-- <foreach doc:name="For Each file"> -->
<logger message=" inside foreach...... #[payload.getKey()] ...." level="INFO" doc:name="Logger" />
<s3:get-object-content config-ref="Amazon_S3" bucketName="demo" key="#[payload.getKey()]" doc:name="Amazon S3"/>
<object-to-byte-array-transformer/>
<file:outbound-endpoint path="C:\output" responseTimeout="10000" doc:name="File" outputPattern="#[payload.getKey()] "></file:outbound-endpoint>
</foreach>
</flow>
I have bucket name called demo.
In that bucket I have 3 pdf files. I want to download all files and put it in c:\output folder.
I hit my url like http://localhost:8081/listobjects.
But I got the error:
Could not find a transformer to transform "CollectionDataType{type=org.mule.module.s3.simpleapi.SimpleAmazonS3AmazonDevKitImpl$S3ObjectSummaryIterable, itemType=com.amazonaws.services.s3.model.S3ObjectSummary, mimeType='/'}" to "SimpleDataType{type=org.mule.api.transport.OutputHandler, mimeType='/'}". (org.mule.api.transformer.TransformerException) (org.mule.api.transformer.TransformerException). Message payload is of type: SimpleAmazonS3AmazonDevKitImpl$S3ObjectSummaryIterable
The error occurs because after the foreach processor the payload is an instance of an S3 class, and you haven't specified any Content-Type to return. So Mule tries to transform the S3 instance to the default SimpleDataType and fails.
One way to solve it is simply to add something like
<set-property propertyName="Content-Type" value="application/json" doc:name="Content-Type" />
<set-payload value="{'result': 'ok'}"/>
at the end to make it explicit.
Also note that in your flow after running:
<object-to-byte-array-transformer/>
the S3 payload is gone, so #[payload.getKey()] will fail in the next processor:
<file:outbound-endpoint path="C:\output" responseTimeout="10000" doc:name="File" outputPattern="#[payload.getKey()] "></file:outbound-endpoint>
I've run this without problems:
<flow name="listobjects">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8083" path="listobjects" contentType="text/plain" doc:name="HTTP"/>
<s3:list-objects config-ref="Amazon_S3" bucketName="mule_test" doc:name="Amazon S3" maxKeys="5" />
<foreach collection="#[payload]" doc:name="For Each">
<logger message=" inside foreach...... #[payload.getKey()] ...." level="INFO" doc:name="Logger" />
<set-variable variableName="fileKey" value="#[payload.getKey()]" doc:name="Variable" />
<s3:get-object-content config-ref="Amazon_S3" bucketName="#[payload.getBucketName()]" key="#[payload.getKey()]" doc:name="Amazon S3"/>
<object-to-byte-array-transformer/>
<file:outbound-endpoint path="/tmp" responseTimeout="10000" doc:name="File" outputPattern="#[flowVars.fileKey] "></file:outbound-endpoint>
</foreach>
<set-property propertyName="Content-Type" value="application/json" doc:name="Content-Type" />
<set-payload value="{'result': 'ok'}"/>
</flow>
In Mule flow how can I re-use choice-exception-stretegy across several flows?
I tried the following, but it throws error when I run mule application.
<mule ....>
<choice-exception-strategy doc:name="My_exception_strategy">
<catch-exception-strategy when="exception.causedBy(java.net.SocketTimeoutException)" doc:name="Strategy1">
<logger message="message 1" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
<catch-exception-strategy when="exception.causedBy(java.lang.Throwable)" doc:name="Strategy2">
<logger message="message 2" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</choice-exception-strategy>
<flow name="Test1" doc:name="Test1" processingStrategy="synchronous">
<logger message="message 3" level="INFO" doc:name="Logger"/>
<outbound-endpoint ref="myendpoint" doc:name="MyEndPoint"/>
<exception-strategy ref="My_exception_strategy" doc:name="Reference Exception Strategy"/>
<set-variable variableName="somevalue" value="#[something]" doc:name="statusCode"/>
</flow>
</mule>
There are two issues with the config you have posted.
There is a "set-variable" after the exception strategy. No other processors are expected after the "exception-strategy".
The exception strategy is not named. The attribute "name" is missing for the exception strategy.
Try the following flow .
<mule ....>
<choice-exception-strategy name="my_exception_strategy" doc:name="My_exception_strategy">
<catch-exception-strategy when="exception.causedBy(java.net.SocketTimeoutException)" doc:name="Strategy1">
<logger message="message 1" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
<catch-exception-strategy when="exception.causedBy(java.lang.Throwable)" doc:name="Strategy2">
<logger message="message 2" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</choice-exception-strategy>
<flow name="Test1" doc:name="Test1" processingStrategy="synchronous">
<logger message="message 3" level="INFO" doc:name="Logger"/>
<outbound-endpoint ref="myendpoint" doc:name="MyEndPoint"/>
<exception-strategy ref="my_exception_strategy" doc:name="Reference Exception Strategy"/>
</flow>
</mule>
Hope this helps.
How can I get Mule to download just attachments using pop3? I tried following the example at http://www.mulesoft.org/documentation/display/current/POP3+Transport+Reference as closely as possible, but I keep getting two files: one with the e-mail body and one with the actual attachment. Here's the flow I'm using:
<pop3:connector name="pop3Connector" checkFrequency="5000" doc:name="POP3"/>
<expression-transformer name="returnAttachments" doc:name="Expression">
<return-argument evaluator="attachments-list" expression="*" />
</expression-transformer>
<file:connector name="fileName" doc:name="File">
<file:expression-filename-parser/>
</file:connector>
<flow name="incoming-orders" doc:name="incoming-orders">
<pop3s:inbound-endpoint host="pop.gmail.com" port="995" user="myuser%40mydomain" password="mypassword" responseTimeout="10000" doc:name="POP3" transformer-refs="returnAttachments" />
<collection-splitter doc:name="Collection Splitter"/>
<file:outbound-endpoint path="C:/popthreetest" outputPattern="#[function:datestamp].dat" doc:name="File">
<expression-transformer>
<return-argument expression="payload.inputStream" evaluator="groovy" />
</expression-transformer>
</file:outbound-endpoint>
</flow>
Thanks!
edit:
Here's the final flow based on #David Dossot's answer. I have an added complexity in that I'm reading in a JSON file that specifies attachment names and an arbitrary destinations for the attachment. I included the replaceAll because I was getting an error about an invalid character in the path file:///C:\.
<pop3:connector name="pop3Connector" checkFrequency="5000" doc:name="POP3"/>
<expression-transformer name="returnAttachments" doc:name="Expression">
<return-argument evaluator="attachments-list" expression="*" />
</expression-transformer>
<file:connector name="DestinationsFileConnector" doc:name="File" autoDelete="false" streaming="true" validateConnections="true">
<file:expression-filename-parser/>
</file:connector>
<file:endpoint path="C:/popthreetest/" name="DestinationsFileEndpoint" responseTimeout="10000" doc:name="File" connector-ref="DestinationsFileConnector">
<file:filename-regex-filter pattern="destinations\.json" caseSensitive="true"/>
</file:endpoint>
<mulerequester:config name="DestinationsMuleRequestorConnector" doc:name="Mule Requester"/>
<flow name="incoming-orders" doc:name="incoming-orders">
<pop3s:inbound-endpoint host="pop.gmail.com" port="995" user="myusername%40mydomain" password="mypassword" responseTimeout="10000" doc:name="POP3" transformer-refs="returnAttachments" />
<collection-splitter doc:name="Collection Splitter"/>
<set-variable variableName="MessagePart" value="#[message.payload]" doc:name="MessagePart"/>
<logger message="Got #[message.payload.dataSource.name]." level="INFO" doc:name="Logger"/>
<mulerequester:request config-ref="DestinationsMuleRequestorConnector" resource="DestinationsFileEndpoint" doc:name="GetDestinations"/>
<json:json-to-object-transformer returnClass="java.util.HashMap" doc:name="JSON to Object"/>
<choice doc:name="Choice">
<when expression="#[message.payload.get(MessagePart.dataSource.name) != null]">
<set-payload value="#[message.payload.get(MessagePart.dataSource.name)]" doc:name="Destination List"/>
<foreach doc:name="For Each">
<logger message="Saving to #[message.payload]." level="INFO" doc:name="Logger"/>
<set-variable variableName="DestinationPath" value="#[java.nio.file.Paths.get(message.payload).getParent().toString().replaceAll('\\\\', '/')]" doc:name="DestinationPath"/>
<set-variable variableName="DestinationPattern" value="#[java.nio.file.Paths.get(message.payload).getFileName()]" doc:name="DestinationPattern"/>
<logger message="Saving to #[DestinationPattern] in #[DestinationPath]." level="INFO" doc:name="Logger"/>
<set-payload value="#[MessagePart]" doc:name="MessagePart"/>
<file:outbound-endpoint path="#[DestinationPath]" outputPattern="#[DestinationPattern]" doc:name="File">
<expression-transformer>
<return-argument expression="payload.inputStream" evaluator="groovy"/>
</expression-transformer>
</file:outbound-endpoint>
</foreach>
</when>
<otherwise>
<logger message="Did not find destination(s) for #[MessagePart.dataSource.name]." level="INFO" doc:name="Logger"/>
</otherwise>
</choice>
</flow>
For completeness, here's the JSON file:
{
"attachment-name.txt": [
"C:/popthreetest/firstDestination.txt"
, "C:/path/to/secondDestination.txt"
, "C:\\popthreetest\\destination\\using-backslashes.txt"
]
}
An email with attachment is a multi-part email into which attachments are parts but also the body. Hence Mule can only download "the whole package" and give the different parts to you.
You should be able to filter the body part after the collection-splitter based on the name of the part.
Alternatively, you could use a MEL expression to drop the first element of the collection, which is typically the body (Mule uses this technique internally to set the message payload: https://github.com/mulesoft/mule/blob/mule-3.x/transports/email/src/main/java/org/mule/transport/email/transformers/EmailMessageToString.java#L50 )
I am having the following problem concerning asynchronous (or one-way) vm inbound endpoints. In the tests below, it seems that the number of one-way inbound endpoints is limited to 20 per vmconnector. My question is: Is there a setting on the vmconnector or a way programmatically to configure the vmconnector to remove this limitation?
I am using Mule 3.3.1 CE.
Thanks.
test1 (will fail to reach secondFlow unless the 21nd endpoint uses vmConn2):
<mule ..>
<stdio:connector name="stdioConn" messageDelayTime="1000" promptMessage="prompt >"/>
<vm:connector name="vmConn"/>
<vm:connector name="vmConn2"/>
<flow name="FirstFlow">
<stdio:inbound-endpoint system="IN" connector-ref="stdioConn"/>
<vm:outbound-endpoint exchange-pattern="one-way" path="path21" connector-ref="vmConn"/>
</flow>
<flow name="SecondFlow">
<composite-source doc:name="Composite Source">
<vm:inbound-endpoint exchange-pattern="one-way" path="path1" connector-ref="vmConn"/>
<vm:inbound-endpoint exchange-pattern="one-way" path="path2" connector-ref="vmConn"/>
<vm:inbound-endpoint exchange-pattern="one-way" path="path3" connector-ref="vmConn"/>
....
<vm:inbound-endpoint exchange-pattern="one-way" path="path20" connector-ref="vmConn"/>
<vm:inbound-endpoint exchange-pattern="one-way" path="path21" connector-ref="vmConn"/>
</composite-source>
<logger message="MESSAGE RECEIVED!" level="INFO" doc:name="Logger"/>
</flow>
test2 (same test with 21 flows):
<flow name="Flow1" >
<stdio:inbound-endpoint system="IN" connector-ref="stdioConn"/>
<vm:outbound-endpoint exchange-pattern="one-way" path="path21" connector-ref="vmConn" />
</flow>
<flow name="Flow2">
<vm:inbound-endpoint exchange-pattern="one-way" path="path1" connector-ref="vmConn" doc:name="VM" />
<logger message="MESSAGE RECEIVED!" level="INFO" doc:name="Logger" />
</flow>
<flow name="Flow3">
<vm:inbound-endpoint exchange-pattern="one-way" path="path2" connector-ref="vmConn" doc:name="VM" />
<logger message="MESSAGE RECEIVED!" level="INFO" doc:name="Logger" />
</flow>
...
<flow name="Flow21">
<vm:inbound-endpoint exchange-pattern="one-way" path="path20" connector-ref="vmConn" doc:name="VM" />
<logger message="MESSAGE RECEIVED!" level="INFO" doc:name="Logger" />
</flow>
<flow name="Flow22">
<vm:inbound-endpoint exchange-pattern="one-way" path="path21" connector-ref="vmConn" doc:name="VM" />
<logger message="MESSAGE RECEIVED!" level="INFO" doc:name="Logger" />
</flow>
Any vm connector has a thread pool of message receivers. Once the receiver are exhausted new vm inbound endpoint want be able to process messages.
To address it you should increase the number of message receivers configuring threading profiles properly