I have a simple mule flow that streams a csv file to a custom java component. I need to be able to handle large files so don't want to use a Transformer that reads the file to memory.
Currently, I get the following error: "Failed to delete file "C:\temp\input\inputCSV.csv" as part of the file move operation. The file was being deleted because AutoDelete was set on the file connector."
Changing the mule XML config Autodelete="false" and specifying a destination directory for the 'processed' file results in a similar error. Could someone tell me how to stream the file and postpone autodeletion until the file has been read fully?
I'm calling .close() on my mule payloadStream, when I'm done, but mule seems to be completing the file deletion too early!
Here's the flow XML config...
<?xml version="1.0" encoding="UTF-8"?>
<mule 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.5.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
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">
<spring:beans>
<spring:import resource="classpath*:/spring/config.xml" />
<spring:import resource="classpath*:/spring/extras/Rule-preprocessor-config.xml" />
</spring:beans>
<file:connector name="fileInput" streaming="true"
autoDelete="true"
moveToPattern="#[message.inboundProperties['originalFilename']]"
doc:name="File">
<!-- <service-overrides messageFactory="org.mule.transport.file.FileMuleMessageFactory" /> -->
</file:connector>
<flow name="stringflowFlow2x" doc:name="stringflowFlow2x">
<file:inbound-endpoint connector-ref="fileInput"
path="/temp/input" doc:name="inputCsv" responseTimeout="10000" fileAge="10000" />
<component class="com.benji.FileImportPreProcessor" doc:name="JavaPreProcessorLogic"/>
<logger message="Finished!" level="INFO" doc:name="Logger"/>
</flow>
</mule>
When on streaming mode, Mule will wrap the stream with a ReceiverFileInputStream. It will take care of the file removal or movement when the stream is closed. And this is the point, you should not call the close on the input stream. The stream itself will call it whenever EOF is hit.
I understand this a little differently: See considerations https://docs.mulesoft.com/mule-user-guide/v/3.6/file-transport-reference
If streaming is enabled a ReceiverFileInputStream is used as the payload for each file that is processed. This input stream’s close() method takes care of moving the file or deleting it. Streams are closed by transformers reading the input stream. If you process the stream in your own component implementation make sure to properly close the stream after reading.
Therefore I don't think mule handles this for you unless you use a transformer which is usually highly likely....but in my case some initial validation meant I had not even started to consider the payload meant I was ending the process before transforming the payload (and therefore not reading and closing the file stream)
You should you object-to-byte-array transformer in File connector itself. It will take care of closing the stream after reading the input stream.
Related
I used Microsoft EWS api SyncFolderItems to get mail changes, but got ErrorInvalidSyncStateData after several successful api calls.
The given SyncState request parameter is correct because it is the reponse from the last successful call.
The error response looks the same to the document shows
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<t:ServerVersionInfo MajorVersion="8" MinorVersion="0"
MajorBuildNumber="628" MinorBuildNumber="0"
xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types" />
</soap:Header>
<soap:Body>
<SyncFolderItemsResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types"
xmlns="https://schemas.microsoft.com/exchange/services/2006/messages">
<m:ResponseMessages>
<m:SyncFolderItemsResponseMessage ResponseClass="Error">
<m:MessageText>Synchronization state data is corrupt or otherwise invalid.</m:MessageText>
<m:ResponseCode>ErrorInvalidSyncStateData</m:ResponseCode>
<m:DescriptiveLinkKey>0</m:DescriptiveLinkKey>
<m:SyncState />
<m:IncludesLastItemInRange>true</m:IncludesLastItemInRange>
</m:SyncFolderItemsResponseMessage>
</m:ResponseMessages>
</SyncFolderItemsResponse>
</soap:Body>
</soap:Envelope>
I use the above api to synchronize mails to my local storage. If I got ErrorInvalidSyncStateData, all I can do is delete all mails in my storage, and then re-synchronize mails (starting from empty SyncState).
I'm wondering if there is a better way to handle the error if someone has the experience using SyncFolderItems api.
Thank you.
There are few methods to avoid the above error. If you follow them you won't get the error.
Ensuring that the sync state value you are sending matches the sync state value returned during a previous synchronization.
Ensuring that you are not sending the sync state for the folder hierarchy when you attempt to sync items, and vice versa.
Ensuring that you are sending the sync state for the correct root folder.
Ensuring that the same root folder is specified in each request.
Ensuring that the previous request did not specify a root folder of
null, while the current request includes a root folder of root. Null
and root are not treated the same.
[Microsoft Documentation]: https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/handling-synchronization-related-errors-in-ews-in-exchange
I have 3 S3 buckets:
input-files
in-progress
processed-files
The "input-files" bucket contains a list of CSV files and I want to get each input file (filename format: filename-timestamp) from the bucket one at a time and move it to the "in-progress" bucket and when the workflow is complete I want to move it to "processed-files" bucket. On error all file processing needs to stop.
In my flow I can get the content of the csv file but there is no reference to file name so not sure how I can implement the above because I can't specify the file that needs to be moved.
How can I implement the processing steps outlined above?
XML flow:
<?xml version="1.0" encoding="UTF-8"?>
<mule 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="EE-3.8.1"
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">
<flow name="CsvToMongo" >
<poll doc:name="Poll">
<s3:get-object-content config-ref="Amazon_S3__Configuration" bucketName="test-file-bucket" key="input-files/TestData.csv" mimeType="application/csv" doc:name="Amazon S3"/>
</poll>
<object-to-string-transformer encoding="UTF-8" mimeType="application/csv" doc:name="Object to String"/>
<logger message="#['**** Start writing CSV to database...']" level="INFO" doc:name="Logger: Start Process"/>
</flow>
</mule>
Software being used:
Anypoint Studio 6.2
Mule 3.8.1
Thanks
An approach that I used recently was to configure an Amazon Simple Queue Service (SQS) queue to receive S3 events from a bucket. (Configure the bucket to send events to the SQS queue).
Then in my Mule flow, my input source is an SQS poller.
The structure of the S3 event is well documented at AWS and is a JSON string (convert it to JSON object to use it) and contains all the relevant information that I needed to identify the actual file name.
It's working quite nicely.
I am trying to use Mule 3.2.0 s Collection Aggregator. I tried using Mule Studio but seems it is still not available in Mule studio for configuration though the icon does appear in the "Flow Control" section.
My use case is -
I get a message from a VM Inbound endpoint. I now want to pass that to 3 different flows - all using the same request object but performing different operations - say A,B,C. All of them update their respective databases but they are all part of a common Order_ID(somethig internal to our application). The 3 processes may take different processing times but once done each of them return the same success response. I want to use an aggregator which will aggregate all these responses without timing out and then forward that to a Java component or another VM Endpoint for further processing.
The Mule documentation for Collection Aggregator doesn't seem to be very informative so if some one who has used Collection Agg can help me out with the xml config for the above scenario it will be very helpful
Instead of Collection Aggregator use All message processor. It sends the same message to every processor inside it and aggregates the results after they finish.
http://www.mulesoft.org/documentation/display/MULE3USER/Routing+Message+Processors#RoutingMessageProcessors-All
Sample config: (I send "foo" to the vm endpoint)
<flow name="main" processingStrategy="asynchronous">
<vm:inbound-endpoint path="in"/>
<all>
<flow-ref name="flow1"/>
<flow-ref name="flow2"/>
</all>
<logger message="#[payload:]" level="INFO"/>
</flow>
<flow name="flow1">
<append-string-transformer message="bar1"/>
</flow>
<flow name="flow2">
<append-string-transformer message="bar2"/>
</flow>
Console output:
INFO 2012-08-15 17:26:01,749 [main.stage1.02] org.mule.api.processor.LoggerMessageProcessor: [foobar1, foobar2]
HTH
I would go with to use ALL component and the endpoint you use should be request-response (two-way where the flow waits for the response).
Thus the ALL component will aggregate the response an then returns you a CopyOnWriteArrayList with all the response from the flows A,B and C. This Array list you can transform in any desired way using a custom transformer by extending AbstractTransformer in your java class.
Cheers,
Naveen Raj
Hello WSO2 community and hello Stackoverflow,
my testing of the SOA suite starting from the ESB is going good: now the ESB recognises external services, create correct proxies that return correct results.
SOLVED
About that, I have two issues: the first is that the "try it"
functionality raises the exception:
"Cannot find dispatch method for {http://schemas.xmlsoap.org/soap/envelope/}Envelope
[tagOpened]/soapenv:Text[tagClosed]"
when i try to send a SOAP enveloped created for the mock service of
the web service proxied.
Anyway, if I try the proxy service from an external client (created on
Netbeans) it works great.
ANSWER
For the first part, the reason is most probably the cross domain issue as try-it is sending messages through a java script stub from
the browser. You will notice that this works great when the service
itself is hosted in the ESB itself, because the request passes through
the same domain. This is why, although, it works perfectly through a
normal client invocation, it does not work through try-it.
The second issue is that I'm not able to orchestrate two services. My objective is sending the input of the first service to the second service, and then to the user.
I'm working on the tutorial Tharindu Mathew suggested: everything now makes sense to me except on one thing: the XSLT transformation.
Here is the out sequence the tutorial suggests you to create:
<outSequence xmlns="http://ws.apache.org/ns/synapse">
<switch source="get-property('STATE')">
<case regex="PERSON_INFO_REQUEST">
<log level="full">
<property name="sequence" value="outSequence - STATE 01 - response from PersonInfoService" />
</log>
<xslt key="xslt">
<property name="amount" expression="get-property('ORG_AMOUNT')" />
</xslt>
<log level="full">
<property name="sequence" value="outSequence - STATE 01 - request for CreditService" />
</log>
<property name="STATE" value="CREDIT_REQUEST" />
<send>
<endpoint key="CreditEpr" />
</send>
</case>
<case regex="CREDIT_REQUEST">
<log level="full">
<property name="sequence" value="outSequence - STATE 02 - response from CreditService" />
</log>
<send />
</case>
</switch>
</outSequence>
Now, focusing on the XSLT node of the first case of the switch, you can see that there's just a get for the amount property.
So that I think we have an XML from the in sequence that states the ID, and this get on the amount property (and I don't know what it does).
The tutorial then suggests:
To create the request to this CrediService, we use the following XSLT with the XSLT mediator. Note, we are using the ORG_ID that we stored in this XSLT as a XSLT parameter and using the XSLT mediator as well.
And here is the XSLT showed in the tutorial:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/02/xpath-functions"
xmlns:ns="http://samples.esb.wso2.org"
xmlns:ax21="http://samples.esb.wso2.org/xsd"
exclude-result-prefixes="ns fn">
<xsl:param name="amount"/>
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//ns:getResponse" />
</xsl:template>
<xsl:template match="ns:getResponse" xmlns:ns="http://samples.esb.wso2.org">
<sam:credit xmlns:sam="http://samples.esb.wso2.org" xmlns:xsd="http://samples.esb.wso2.org/xsd">
<sam:info>
<xsd:amount><xsl:value-of select="$amount"/></xsd:amount>
<xsd:personInfo>
<xsd:address><xsl:value-of select="ns:return/ax21:address"/></xsd:address>
<xsd:id><xsl:value-of select="ns:return/ax21:id"/></xsd:id>
<xsd:name><xsl:value-of select="ns:return/ax21:name"/></xsd:name>
</xsd:personInfo>
</sam:info>
</sam:credit>
</xsl:template>
</xsl:stylesheet>
I was asked to put a similar file into the resources directory of WSO2 ESB, but this file is never used in the tutorial:
Copy the personToCredit.xslt in the sample zip to resources directory of WSO2 ESB.
---------LITTLE PARENTHESIS-----------
The WSDL file was not used either after it was stated:
Copy the CreditProxy.wsdl in the sample zip to the resources directory of the WSO2 ESB.
I cannot find the WSDL file in the Configuration/Governance Registry, and I don't know how to address it, so I chose to specify it inline instead.
---------LITTLE PARENTHESIS END-----------
This sentence is followed by the XSLT file text. My main question now is:
Where should I put this XSLT? I do not know where to put the XSLT mediator, neither how to build it.
Should I rely on registries?
A perfect answer could be the code of the out sequence, and the specified connection with the XSLT mediator suggested.
OverTheBitStair
Hi OverTheBitStair (nice nick!),
For the first part, the reason is most probably the cross domain issue as try-it is sending messages through a java script stub from the browser. You will notice that this works great when the service itself is hosted in the ESB itself, because the request passes through the same domain. This is why, although, it works perfectly through a normal client invocation, it does not work through try-it.
For the second part, the short answer is yes, it is possible. In terms of the ESB, we refer to it as a light-weight orchestration engine in addition to being a mediation engine. This means for light-weight and short-lived (<1 day) processes we can solve the orchestration requirements using the ESB without bringing in the Business Process Server.
To do this, we use this method called service chaining. What it does is introduce a method to get some output out of the initial service invocation and use it in a subsequent invocation. The article WSO2 ESB by example - Service Chaining should help you with implementation details on what you are looking for.
Hope this helps.
If you create a service chaining scenario where your proxy service calls two other services and return the result to the caller of the proxy service, it would look something like this:
Caller --> Proxy Service -- seq_A --> Service1 -- seq_B --> Service2 -- seq_C --> (proxy serviced response) --> Caller
In this case, seq_A would be the in sequence of the proxy service, seq_C the out sequence of the proxy service and seq_B another named sequence.
Input, i.e. the message body, to seq_A would be the input to proxy service. seq_A would contain a send mediator at the end and at that point in the sequence the message context would be the input to Service1. The send mediator also points to seq_B to be executed for the reply.
At start of seq_B the message body contains the output from Service1. If you want to keep some message data from before the service call you need to save that in properties in the context.
At the end of seq_B you would have a send mediator; at that point the message body should contain the input to Service2, The send mediator would in this case not need to point to an explicit reply sequence, if seq_C is the out sequence of the proxy service - that one will be used by default then.
When seq_C is executing the message body at that point is the response from Service2. Again, if you need to use/combine with some data prior to the call to Service2, you need that to be saved into properties.
Depending on the particular needs for the input and transformations needed at each step it can be fairly straightforward or a bit cumbersome to handle.
What also should taken into consideration is what needs to happen in error scenarios, as this may add some additional complexity, depending on the requirements.
I am creating some services using JAX-RS that need to take in arbitrarily complex objects as arguments, not just primitives like integers and strings. A discussion on the CXF mailing list says to just use a wrapper object as a single parameter in this case.
My concern is how to document the input format to the service? If creating a service that looks something like the following:
#POST
#Produces("application/json")
#Consumes("application/json")
#Path("oneParam")
public ComplexObject2 myServiceMethod(ComplexObject1 obj) {
Foo f = obj.foo
Bar b = obj.bar
...
}
the auto-generated WADL that CXF produces will only produce the following:
<resource path="/oneParam">
<method name="POST">
<request>
<representation mediaType="application/json"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
</resource>
This contains no information on what the request or response actually contains. Sergey on the CXF mailing list said it was possible to link a schema to the representation, but how am I supposed to do that? And how do I create the XSD?
(P.S. Using POST for idempotent resources might not be RESTful, but it's not important here as we are in essence doing RPC using Json. This is more or less a 1:1 clone of an existing SOAP based api.)
It is possible to link an XSD file into a WADL file and then to reference an XML element in the representation for requests and responses. However, as it is XML schema it doesn't apply to JSON representations.
To link an XSD into a WADL file, create a grammars element at the top of the file before the main resources element.
<grammars>
<include href="myapp.xsd"/>
</grammars>
Then add a reference to an XML element as follows (using a modified version of your example):
<resource path="/oneParam">
<method name="POST">
<request>
<representation mediaType="application/xml" element="myapp:oneParamRequest" />
</request>
<response>
<representation mediaType="application/xml" element="myapp:oneParamResponse" />
</response>
</method>
</resource>
The prefix myapp is defined in the XSD and can be used in the WADL file as well.
I don't know to to configure CXF to do this automatically. My experience with Jersey is similar and we use the generated WADL as a starting point for hand-editing later.