MEL Expression Issues - mule

I have defined a global function as below
<configuration doc:name="Configuration">
<expression-language autoResolveVariables="true">
<import class="java.text.SimpleDateFormat" />
<global-functions>
def convertDate(shiftDate){
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return dateFormat.format(shiftDate);
}
</global-functions>
</expression-language>
</configuration>
But when calling via logger nothing seems to happen
<logger message="Convert Date #[convertDate(xpath://address/#timestamp)]" level="DEBUG" doc:name="Logger"/>
The xpath expression xpath://address/#timestamp yields 2014-10-29T15:23:07
But before the logger I see
xpath-branch:/address/#timestamp is: org.dom4j.tree.DefaultAttribute#6452310a [Attribute: name timestamp value "2014-10-29T15:23:07"]
The error message is as below
org.mule.api.expression.InvalidExpressionException: [Error: unexpected end of statement]
[Near : {... convertDate(xpath://address/#payloadID) ....}]
What am I doing wrong here? Many Thanks.

You're mixing MEL and the old style of expressions.
This is old style: xpath://address/#payloadID
This is MEL: xpath('//address/#payloadID').value
So you need to use:
<logger
message="Convert Date #[convertDate(xpath('//address/#payloadID').value)]"
level="DEBUG" />
See: http://www.mulesoft.org/documentation/display/current/Mule+Expression+Language+Tips#MuleExpressionLanguageTips-XPathSupport

Related

How to raise a Custom Error With Internal payload (error.errorMessage.payload) in MUnit

A little description of the flow: I have a flow that is making an HTTP call to a REST Webservice. There are a couple of errors that we get as statusCode=500 but with different "errorCodes" inside the response body. This request connector is wrapped inside a try block with multiple on-error-continue based on the content of the response body in its "when" attribute. eg: error.errorMessage.payload.errorCode==CODE_A. Adding an image and source code of the flow below
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">
<http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config" doc:id="dee432d7-a176-448c-a1ac-a374a86fa85b" >
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>
<flow name="test2Flow" doc:id="be602af1-cfcf-46f1-a312-ea6a5544503b" >
<http:listener doc:name="Listener" doc:id="f160fa61-15be-4744-b823-973e20740e73" config-ref="HTTP_Listener_config" path="/test"/>
<logger level="INFO" doc:name="Some logic before request" doc:id="6354a117-e918-4937-a1d9-df4ae0ef6386" message="Some logic before request"/>
<try doc:name="Try" doc:id="15bd106a-c116-4d87-958e-8ad698026739" >
<http:request method="GET" doc:name="Request" doc:id="a046919e-f149-45d6-9a70-db37cac0540f" url="http://example.com/some-resource" />
<error-handler >
<on-error-continue enableNotifications="true" logException="true" doc:name="when error.errorMessage.payload.errorCode==CODE_A" doc:id="20fc0575-da65-41b4-81f7-d364227b1639" when='error.errorMessage.payload.errorCode=="CODE_A"'>
<logger level="INFO" doc:name="Some logic for CODE_A" doc:id="a699ccd0-952c-415f-b288-4ea027f2cff2" message="Some logic for CODE_A" />
</on-error-continue>
<on-error-continue enableNotifications="false" logException="false" doc:name="when error.errorMessage.payload.errorCode==CODE_B" doc:id="63dc8aa5-5fae-4235-a4ae-a80903a76362" when='error.errorMessage.payload.errorCode=="CODE_B"' >
<logger level="INFO" doc:name="Some logic for CODE_B" doc:id="9364ff1e-4bcd-48d5-a37a-a207828cda9d" message="Some logic for CODE_B" />
</on-error-continue>
</error-handler>
</try>
<logger level="INFO" doc:name="Some logic After request" doc:id="fd754198-d6b5-40dd-b23f-c8619faee7e6" message="Some logic After request" />
</flow>
</mule>
What I am trying to do: I am trying to write MUnit to verify if the correct error-handler block is executed based on response. However, I do not see any option to mock an error with its errorMessage part filled.
What I am looking for: I am trying to find out one of these
Anyway to mock error with errorMessage using the simple mock-when'sthen-return element. I do not think it is possible, but if there is a way please let me know.
Maybe there is a way to use a Java class for raising complex errors. I am thinking if I can use mock-when'sthen-call to call a flow and then raise an error using it.
Any other way to do it.
Note:
Mule version: 4.3.0 MUnit version: 2.3.0
I can not make change in the REST webservice, I do not own that.
I am trying to avoid any code change, For example, I can ignore status code in the message validator and do the error handling using response directly, with something like choice. But I will do it as the last resort
You can try using something like this when mocking error for HTTP requests:
Create the following DW file:
httpError.dwl
var detailMessage = 'Internal server error'
var myJsonResponse = '{"errorCode":"ERROR_A"}'
var typedValue = java!org::mule::runtime::api::metadata::TypedValue::new(myJsonResponse, java!org::mule::runtime::api::metadata::DataType::JSON_STRING)
var errorMessage = java!org::mule::runtime::api::message::Message::of(typedValue)
var errorType = java!org::mule::extension::http::api::error::HttpError::INTERNAL_SERVER_ERROR
---
java!org::mule::extension::http::api::request::validator::ResponseValidatorTypedException::new(detailMessage, errorType, errorMessage)
In your MUnit test suite file, create the following flow:
<flow name="munit-set-error-code-event-flow" doc:id="3b7e266c-2f3b-4105-8fdb-8ea44d5f128e" >
<munit:set-event doc:name="Generate error" doc:id="4ee8b870-6c8b-4570-bc70-7ec0086a1bca" cloneOriginalEvent="true">
<munit:error id="HTTP:INTERNAL_SERVER_ERROR" exception="#[${file::httpError.dwl}]" />
</munit:set-event>
</flow>
And, finally, in your actual MUnit test flow, configure the then-call option to call the above flow. Eg:
<munit:test name="test-test-suite-testFlowTest" doc:id="5670a9cd-758a-4f2c-a55f-57b48a9f3b41" description="Test" timeOut="1200000">
<munit:behavior >
<munit-tools:mock-when doc:name="Mock when" doc:id="466fd55c-80b4-4e27-82ed-f561223a3b4f" processor="http:request">
<munit-tools:with-attributes >
<munit-tools:with-attribute whereValue="08c4fba6-ef4b-4006-bd7d-deb1fd0f5304" attributeName="doc:id" />
</munit-tools:with-attributes>
<munit-tools:then-call flow="munit-set-error-code-event-flow" />
</munit-tools:mock-when>
</munit:behavior>
<munit:execution >
<flow-ref doc:name="Flow-ref to testFlow" doc:id="c57b3265-b453-432c-88fd-db2df7125fdc" name="testFlow"/>
</munit:execution>
</munit:test>
Although I'm not sure if this is something recommended to do, it should work for what you want to achieve.
Let me know if it works.

Json to object and Mule expression

I have a json file which the link is https://gist.githubusercontent.com/Rajeun/b550fe17181610f5c0f0/raw/7ba82c6c1135d474e0bedc8b203d3cf16e196038/file.json
i want to do a test on the boolean "sent". there is my xml file.
<http:request-config name="HTTP_Request_Configuration"
host="gist.githubusercontent.com" port="443" protocol="HTTPS"
doc:name="HTTP Request Configuration" />
<flow name="testFlow">
<poll doc:name="Poll">
<http:request config-ref="HTTP_Request_Configuration"
path="Rajeun/b550fe17181610f5c0f0/raw/7ba82c6c1135d474e0bedc8b203d3cf16e196038/file.json"
method="GET" doc:name="HTTP" />
</poll>
<json:json-to-object-transformer
returnClass="java.lang.Object" doc:name="JSON to Object" />
<choice doc:name="Choice">
<when expression="#[payload.sent] == true )">
<logger message="its ok" level="INFO" doc:name="Logger"/>
</when>
<otherwise>
<logger message="Error" level="INFO" doc:name="Logger"/>
</otherwise>
</choice>
</flow>
errors:
ERROR 2015-03-25 16:29:59,871 [[push1].testFlow.stage1.02] org.mule.exception.DefaultMessagingExceptionStrategy:
********************************************************************************
Message : Failed to transform from "json" to "java.lang.Object"
Code : MULE_ERROR-109
--------------------------------------------------------------------------------
Exception stack is:
1. Unexpected character ('"' (code 34)): was expecting comma to separate OBJECT entries
at [Source: java.io.InputStreamReader#1a09a5b; line: 5, column: 4] (org.codehaus.jackson.JsonParseException)
org.codehaus.jackson.JsonParser:1433 (null)
2. Failed to transform from "json" to "java.lang.Object" (org.mule.api.transformer.TransformerException)
org.mule.module.json.transformers.JsonToObject:132 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transformer/TransformerException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
org.codehaus.jackson.JsonParseException: Unexpected character ('"' (code 34)): was expecting comma to separate OBJECT entries
at [Source: java.io.InputStreamReader#1a09a5b; line: 5, column: 4]
at org.codehaus.jackson.JsonParser._constructError(JsonParser.java:1433)
at org.codehaus.jackson.impl.JsonParserMinimalBase._reportError(JsonParserMinimalBase.java:521)
at org.codehaus.jackson.impl.JsonParserMinimalBase._reportUnexpectedChar(JsonParserMinimalBase.java:442)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
i don't know what is the problem please any help !!
The expression should be <when expression="#[payload.sent == true ]"> and this is working for me ..
also as afelisatti mentioned, there should be a comma after email attribute in JSON payload
There's is no comma after the "email" in that JSON file so the transformation fails, that's what the error message is saying. I believe the correct format would be
{
"token" : 123,
"tel" : 456,
"email" : "Rm9vYmFyIQ==",
"sent" : true
}
Remove
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object" />
and use an json based mule expression #[json:sent]

mule expression transformer exception

I have a payload like
{"jcr:createdBy":"admin","jcr:content":{"sling:resourceType":"contentpage","addressdetails":{"state":"vic"}}}
I want to change the value of state. I have tried the below,
<expression-transformer
expression="#[message.payload.jcr:content.addressdetails.state = 'NSW';message.payload]"
doc:name="Expression" />
but this throws an exception, invalid expression.
I believe its because of : in jcr:createdBy. How should I handle this?
Try <json:json-to-object-transformer returnClass="java.util.HashMap" /> before expression like following :-
<json:json-to-object-transformer returnClass="java.util.HashMap" />
<expression-transformer expression="#[message.payload.jcr.content:addressdetails.state = 'NSW';message.payload]" doc:name="Expression" />

Mule ESB problems with interceptor-stack

I'm new to Mule and having trouble with using interceptor-stack elements.
The following seems like it is taken right out of their documentation here: http://www.mulesoft.org/documentation/display/33X/Using+Interceptors
<interceptor-stack name="default">
<logging-interceptor/>
<timer-interceptor/>
</interceptor-stack>
<flow name="MyFlowFlow1" doc:name="MyFlowFlow1">
<interceptor-stack ref="default"/> <!--this is line 15 -->
<logger level="INFO" message="Got here"/>
</flow>
but I get an exception saying it's invalid.
Can someone tell me what I'm doing wrong?
org.xml.sax.SAXParseException; lineNumber: 15; columnNumber: 43; cvc-complex-type.2.4.a: Invalid content was found starting with element 'interceptor-stack'. One of '{"http://www.mulesoft.org/schema/mule/core":annotations, "http://www.mulesoft.org/schema/mule/core":description, "http://www.mulesoft.org/schema/mule/core":abstract-message-source, "http://www.mulesoft.org/schema/mule/core":abstract-inbound-endpoint, "http://www.mulesoft.org/schema/mule/core":abstract-message-processor, "http://www.mulesoft.org/schema/mule/core":abstract-outbound-endpoint, "http://www.mulesoft.org/schema/mule/core":abstract-mixed-content-message-processor, "http://www.mulesoft.org/schema/mule/core":response}' is expected.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
...etc...
EDIT - This is to address the responses below.
This first private flow works perfectly when invoked from another flow via flow-ref. I see the "got here" message and the timing.
<flow name="test2Flow1" doc:name="test2Flow1">
<timer-interceptor/>
<logger level="INFO" message="got here" doc:name="Logger"/>
</flow>
However, this second private flow does not work when invoked from another flow...in fact, it won't even parse. The only difference is that the explicit use of the timer-interceptor is changed to be a reference to an interceptor-stack containing the timer-interceptor.
<interceptor-stack name="default">
<timer-interceptor/>
</interceptor-stack>
<flow name="test2Flow1" doc:name="test2Flow1">
<interceptor-stack ref="default"/>
<logger level="INFO" message="got here" doc:name="Logger"/>
</flow>
I think your flow is invalid because it doesnt have a message processor.
Take a look on the anatomy of a flow.
http://www.mulesoft.org/documentation/display/current/Using+Flows+for+Service+Orchestration#UsingFlowsforServiceOrchestration-TheAnatomyofaFlow
Your message processor must be the first item in the flow
Interceptors are meant to be used within components.
This configuration should work:
<interceptor-stack name="default">
<logging-interceptor/>
<timer-interceptor/>
</interceptor-stack>
<flow name="test2Flow1" doc:name="test2Flow1">
<pooled-component class="com.MyComponent">
<interceptor-stack ref="default"/> <!--this is line 15 -->
</pooled-component>
<logger level="INFO" message="Got here"/>
</flow>

How can I overwrite the payload in mule

I've a Soap request coming into mule flow. Am tasked with getting information out of payload and depending on outcome, push the original request to different jms queues.
To get the desired information out of payload, I'm using XSLT tranformer (not XPath, because I need to get IDREF attribute from an element, based on IDREF, get the element and then a child element out of the IDREF object).
Based on the outcome of the of XSLT tranformation, I use choice element to push original payload. Am storing original payload in a Session (can do it in Inbound as well). After XSLT tansformation, apply choice router to find out appropriate queue, and then want to push the original payload into queue(original payload in stored in a session variable). I am using <expression-component> element. Below is the snippet of mule-flow:
<flow name="ProcessXML121Order">
<jms:inbound-endpoint queue="mviq.121.order" exchange-pattern="one-way" />
<logger message="121 order payload is #[payload]" level="INFO" />
<message-properties-transformer scope="session">
<add-message-property key="mviPayload" value="#[payload]"/>
</message-properties-transformer>
<xm:xslt-transformer xsl-file="chooseVendor.xslt" />
<logger message="After xsl file payload is #[payload]" level="INFO" />
<choice>
<when expression="'EMSI'">
<logger message="Vendor is EMSI" level="INFO" />
<expression-component>payload=#[header:SESSION:mviPayload]</expression-component>
<jms:outbound-endpoint queue="mviq.121.order.emsi" />
</when>
<when expression="'PRMD'">
<logger message="Vendor is PRMD" level="INFO" />
<jms:outbound-endpoint queue="mviq.121.order.prmd" />
</when>
<when expression="'RSA'">
<logger message="Vendor is RSA" level="INFO" />
<logger message="RSA payload is #[payload]" level="INFO" />
<jms:outbound-endpoint queue="mviq.121.order.rsa" />
</when>
<otherwise>
<logger message="Vendor is Error" level="INFO" />
<logger message="Vendor error payload is #[payload]" level="INFO" />
<jms:outbound-endpoint queue="mviq.error" />
</otherwise>
</choice>
</flow>
Following exception is thrown when evaluating payload=#[header:SESSION:mviPayload]
[ProcessXML121Order.stage1.02] exception.AbstractExceptionListener (AbstractExceptionListener.java:296) -
********************************************************************************
Message : Execution of the expression "payload=#[header:SESSION:mviPayload]" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: byte[]
Code : MULE_ERROR-29999
--------------------------------------------------------------------------------
Exception stack is:
1. [Error: illegal use of operator: +]
[Near : {... Unknown ....}]
^
[Line: 1, Column: 0] (org.mvel2.CompileException)
org.mvel2.ast.OperatorNode:46 (null)
2. Execution of the expression "payload=#[header:SESSION:mviPayload]" failed. (org.mule.api.expression.ExpressionRuntimeException)
org.mule.el.mvel.MVELExpressionLanguage:211 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/expression/ExpressionRuntimeException.html)
3. Execution of the expression "payload=#[header:SESSION:mviPayload]" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: byte[] (org.mule.api.MessagingException)
org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor:35 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
[Error: illegal use of operator: +]
[Near : {... Unknown ....}]
^
[Line: 1, Column: 0]
at org.mvel2.ast.OperatorNode.getReducedValueAccelerated(OperatorNode.java:46)
at org.mvel2.MVELRuntime.execute(MVELRuntime.java:85)
at org.mvel2.compiler.CompiledExpression.getValue(CompiledExpression.java:105)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
I've 2 questions:
How can I overwrite the original payload? (Not saying this is the best way to go)
What is the better approach in this scenario? Is it advisable to keep original payload intact (in this case) and store XSLT output in other variable? How can I do that? What is the path (mule component) I can use to achieve that? I'm very new to Mule and seek community advice.
Thanks for your time looking into this.
Before answering your questions, let's rewrite this broken expression:
<expression-component>payload=#[header:SESSION:mviPayload]</expression-component>
as:
<set-payload value="#[sessionVars.mviPayload]" />
The following would work too but would be more complex for no good reason:
<expression-component>payload=sessionVars.mviPayload</expression-component>
Also this:
<message-properties-transformer scope="session">
<add-message-property key="mviPayload" value="#[payload]"/>
</message-properties-transformer>
would be better written:
<set-session-variable variableName="mviPayload" value="#[message.payload]" />
Now to your questions:
Use set-payload
What you are doing is the best: transformers, like XSL-T, applies naturally to the current message payload so saving the original in a property then transforming the main payload is OK. Just one thing: prefer a flow variable instead of a session variable. Indeed, in your case, I don't think you need the original payload outside this flow, so storing in session is overkill.
So I suggest you use:
<set-variable variableName="mviPayload" value="#[message.payload]" />
to store the original payload and the following to re-establish it:
<set-payload value="#[mviPayload]" />
Use Set-Payload and provide the data to be overwritten.
You could do this with lot of ways.
Use set-payload
Use expression, #[payload='']
Use an transformer/component
You can keep the payload intact and store the value of the xslt transformation in a variable using message enricher. Use the variable inside choice to determine which queue to go to. Below is a code snippet
<enricher doc:name="Message Enricher" target="#[flowVars.transformResultVar]">
<!--perform transformation logic here-->
</enricher>
Reference: https://dzone.com/articles/content-enrichment-using-mule-message-enricher-com