I'm trying to write test application using twitter connector.
The flow is next:
Load retweets;
Here I'm getting a list of retweets and I want to transform them one by one. I'm using for-each, but earlier I used collection-splitter.
How I understand, outside foreach block I should have already transformated payload, but in this place I'm getting the same result as at the beginning.
Here is my flow:
<flow name="twits">
<http:listener config-ref="HTTP_Listener_Configuration" path="/twits" doc:name="HTTP"/>
<twitter:get-retweets statusId="111111111111" config-ref="Twitter" doc:name="Twitter"/>
<foreach>
<transformer ref="ReTwitTransformer"/>
</foreach>
<json:object-to-json-transformer doc:name="Object to JSON"/>
</flow>
So the problem is at 3 step, I can't set transformed data into message payload. I already had tried to use set-payload but without success.
The Foreach scope returns the original message after processing each element. Your transformations will not be retained.
In this case, you might try the Batch Processing module (EE) or just use a Collection Splitter (CE) as you tried previously.
Also, I noticed you're using an HTTP listener to start things off. If you actually need the collection of transformed retweets back as an HTTP response, you'll have to add a bit more:
If you use the Batch module, you'll need to pair it with a Request Reply router in order to get the collection of successful records back synchronously. Just put a Batch Execute for the Request, and a VM inbound endpoint for the Reply. Then just put a VM outbound endpoint in the Batch On Complete step.
If you use a Collection Splitter, you'll need a Collection Aggregator after the transformation occurs. You might wait until after aggregation to do the object-to-json-transformer.
Related
I am wordering about how to implement a counter which is will increase 1 step when flow is called. For example:
I have a flow named: http://localhost:8080/doSomething and a variable counter.
The counter variable will increase by 1 when I hit enter in doSomething service
Many thanks
If you need to store runtime data that is available across the application, you can store the data as objects in the Registry.
Here is an example
To set the value
<scripting:component doc:name="Groovy">
<scripting:script engine="Groovy">
<![CDATA[muleContext.getRegistry().registerObject("Count", new Integer(14))]]>
</scripting:script>
</scripting:component>
To read the value
<logger message="Count #[app.registry.get('Count')]" level="INFO" doc:name="Logger"/>
Initialize a variable with integer value 1 in mule app registry in the starting of your flow as below:
<expression-component doc:name="Expression"><![CDATA[#[app.registry.put('counter',1)]]]></expression-component>
To increment the value use:
<expression-component doc:name="Expression"><![CDATA[#[app.registry.put('counter',app.registry['counter']+1)]]]></expression-component>
To retrieve final value of the counter flag, use the expression:
#[app.registry.get('counter')]
You need a persistent storage solution. Variables in Mule do not live across invocations. Mule has a concept of Object Stores: https://docs.mulesoft.com/mule-user-guide/v/3.7/mule-object-stores
If you are a Mule Enterprise customer, analytics may be included in your subscription.
If you are just trying to collect statistics, then I suggest you to consider using MuleSoft Insight. You will be able to setup Custom Business Events in your flows and track important information. Finally, you can use Insight Dashboard on CloudHub to get appropriate stats by applying various filters.
You can have object store in your flow which can store your counter(number of hits on to your flow) either in memory or in a persistent store. You can then retrieve the counter and increase it on subsequent hit to your flow.
https://docs.mulesoft.com/mule-user-guide/v/3.9/object-store-module-reference
properties file:
#torun='GSD11','GSD12'
torun='GSD11'
<flow name="deleteInvoiceFlow" doc:name="deleteInvoiceFlow">
<http:inbound-endpoint exchange-pattern="request-response" host="${hostname}" port="${port}" path="deleteInvoice" doc:name="HTTP"/>
<invoke object-ref="client" method="deleteInvoice" methodArguments="${torun}" methodArgumentTypes="java.lang.String" />
</flow>
<spring:bean id="client" name="client" class="com.util.DeleteTable"/>
Java: DeleteTable:
public String deleteInvoice(#Payload String deleteCompany) throws SQLException{
It works well for single parameter from the properties as shown above in properties file. But If i run application with below companies in properties
`torun='GSD11','GSD12'
it gives error message as
1 (java.lang.ArrayIndexOutOfBoundsException). Message payload is of type: String
How do I enable to receive parameteras array?
the Mule message's Payload is a Object. Thus allowing it to handle any kind of object.
If you check the MuleMessage interface you'll see it.
In your code above your sending whatever comes from your inbound endpoint (http) to your spring bean, and you are assuming it's going to be a string.
Now the payload can certainly change in an http inbound endpoint depending on what type of request you receive (get/post/put/etc) so be careful with that.
Going back to your question, if you're positive the payload is going to be an array you can just change the firm of your method to that. If not I'll advise you change it to object and validate what's coming and cast accordingly.
HTH
Mule docs says:
http://www.mulesoft.org/documentation/display/current/Invoke+Component+Reference
methodArguments="#[1], #[2]"
methodArgumentTypes="java.lang.Float, java.lang.Float"
but my list is random and it grows to 100s to 1000s, I don't want to put 1000s of argument types.
As a workaround solution I am loading the mule-app.propertes in java component and reading the property content.
public String deleteInvoice(){
Properties prop = new Properties();
InputStream input = DeleteTable.class.getClassLoader().getResourceAsStream("mule-app.properties");
prop.load(input);
return prop.getProperty("torun");
}
I'm using very simple flow, where I have tried to set message attribute( for SQS) in flowVars, so that it will be reflected in my SQS Queue. I have used this link https://github.com/mulesoft/sqs-connector/blob/master/src/test/resources/automation-test-flows.xml for references(In the link they referred by using flow vars). But i'm getting the error like
"Could not find a transformer to transform "SimpleDataType{type=java.lang.String,mimeType='*/*'}" to "SimpleDataType{type=java.util.Map, mimeType='*/*'}". (org.mule.api.transformer.TransformerException)"
Pleasse find my config xml
<flow name="sqsFlow1" doc:name="sqsFlow1">
<sqs:receive-messages config-ref="Amazon_SQS" doc:name="Amazon SQS (Streaming)" numberOfMessages="5" visibilityTimeout="11"/>
<set-variable variableName="setMessageAtt" value="[name:"John"]" doc:name="Variable"/>
sqs:send-message config-ref="Amazon_SQS1" doc:name="Amazon SQS" >
<sqs:message-attributes ref="#[flowVars.setMessageAtt]"/>
</sqs:send-message>
</flow>
I understand the value which I try to return as String, but it is expecting Map. Is there any way we can change the string vaue in to Map inside flow variable itself ( Via MEL). If not, how we can handle the scenario. I have tried multiple scenario , but it is not working.
Your help is required.
Thanks in advance.
In mule you can represent a Map as: #[key1 : value1, key2 : value2, . . .]
For example, with mel:
#[['title':'value','description':'value','status':'404','bit': false]]
is equivalent to
Map<String, Object>
I hope to help;
I am experimenting with using Mule 3.4.0CE to provide a RESTful API and evaluating both the Jersey and Rest-router modules to handle this. That is mostly going well but I am not finding very much in terms of concrete/complete examples of implementing RESTful APIs in Mule.
At present I have simple GET and PUT endpoints for an entity working using the rest-router. The PUT flow is successfully passing stuff through to JDBC but I am fizzy about how to handle the case where the entity already exists.
I am ok with relying on SqlException to catch the pk constraint violation and have an exception strategy handling that:
<catch-exception-strategy when="#[exception.causedBy(java.sql.SQLException) and exception.getCauseException().getMessage().contains('Duplicate entry')]" doc:name="Duplicate_entry1">
<set-payload value="The request cannot be processed, the error is #[exception.getSummaryMessage()]" doc:name="Set Payload"/> <!-- [1] -->
<set-property propertyName="http.status" value="400" doc:name="Property"/> <!-- [2] -->
</catch-exception-strategy>
but am confused about 2 things:
1) Catching a more specific Exception?
I am able to get the exception strategy to match on java.sql.SQLException but would rather match on the root cause of com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException. Using that class and the various forms of casusedBy(), causedExactlyBy() and casueMatches() dont seem to find anything other than the outer SQLException.
and
2) How to return a simple json encoded payload in response to this error?
What I would like to do inside the catch-exception-strategy is to create a map of KV pairs something like status="error" and error_message="entity XX already exists" and have that json encoded as the mule payload/ response.
I am embarrassed that I cant seem to get my head around a way to do that simply with MEL or the various components in MuleStudio. Looking for pointers or docs on how to do this. I am resisting building a custom component to return the map I want and have that json encoded on the way out of Mule.
For 1) In your when clause you can make use of containsType() method of org.mule.util.ExceptionUtils (build on top of Apache ExceptionUtils class). It checks whole stacktrace for presence of specific exception.
If you don't want to provide fully qualified class name in MEL (for ExceptionUtils), you can use global imports feature, described in last part of MEL Cheat Sheet.
I have made two blog posts (here & here) about RESTful services on Mule. Maybe, you find them useful.
For 2) You can look into <json:object-to-json-transformer doc:name=“Object to JSON”/>
http://mule3.wordpress.com/2012/10/14/mule-object-to-json/
http://svn.muleforge.org/json-support/trunk/src/main/java/org/mule/module/json/transformers/JsonToObject.java
http://www.mulesoft.org/docs/site/current/apidocs/org/mule/module/json/transformers/package-summary.html
http://www.mulesoft.org/documentation/display/current/Native+Support+for+JSON#NativeSupportforJSON-Examples
Below is my file inbound endpoint configuration. It is processing all .edi files available at the specified path.
<file:inbound-endpoint path="D:\test docs\in"
pollingFrequency="3000" responseTimeout="10000" doc:name="Incoming File">
<file:filename-regex-filter pattern="(.*).edi"
caseSensitive="false" />
I send an event to this endpoint from spring application as below
muleClient.dispatch("file://D:/test docs/in", inputFileName,
null);
I am passing the input file name as message1.edi. I want to restrict file inbound point to process single file whose name is sent as payload object in dispatch().
Is it possible with file inbound endpoint?
Muleclient.dispatch() is an async method. I want to pause the current thread till i get reply from dispatch(). As of now i am using thread.sleep(). Is there any better approach?
I may be missing the point :-) however I don't think the dispatch is what you want to use.
To trigger the event on the mule file listener, copy your message1.edi to the file folder file://D:/test docs/in
mule will pickup the file and process.
Alternativly, I don't think the mule file endpoint support dynamically changing the regex, if you want to dynamically change the file then trigger your flow with muleClient.dispatch("file://D:/test docs/in", inputFileName, null); and use a groovy component to read an process the file named in the trigger
def fileContent = new File("file://D:/test docs/in/" + inputFileName).text
return fileContent
Adjust according if not text files.
There is no need for an inbound endpoint. You need to use a the request method of the MuleClient to get a custom file content on demand:
muleClient.request('file://D:/test docs/in', -1);
sorry i could have posted the whole mule flow code.
Below is my mule flow:
<flow name="ediTransformationFlow" doc:name="ediTransformationFlow">
<file:inbound-endpoint path="D:\smooks\test docs\in"
pollingFrequency="3000" responseTimeout="10000" doc:name="Incoming File"
transformer-refs="SmooksTransformer" moveToDirectory="D:\smooks\test docs\history"
moveToPattern="#[header:originalFilename]">
<file:filename-regex-filter pattern="(.*).edi"
caseSensitive="false" />
</file:inbound-endpoint>
<file:outbound-endpoint path="D:\smooks\test docs\out" responseTimeout="10000"
doc:name="Outgoing File" outputPattern="#[header:originalFilename].xml"/>
</flow>
My requirement is:
From spring controller I will send .edi file name to file inbound endpoint. It will read the file from D:\smooks\test docs\in folder, transforms it to xml file.
File outbound end point places the xml file in D:\smooks\test docs\out folder.
In spring controller i should be able to read the xml file and create a dom source.
xmlDocument = builder.parse(documentRootPath + outputFileName);
Source source = new DOMSource(xmlDocument);
To request mule from spring controller i am using mule client
muleClient.dispatch("file://D:/smooks/test docs/in", inputFileName,null);
message = muleClient.request("file://D:/smooks/test docs/out",
100000);