mule expression transformer exception - mule

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" />

Related

Mule Munit with Choice followed by Dataweave transform

I have a flow that has a Choice followed by a Dataweave transform.
Input to the flow is json.
The choice has this when statement:
<when expression="#[payload.resultSet1.size() >= 1]">
The flow works well:
<flow name="test1">
<db:stored-procedure doc:name="MyStoredProc"></db:stored-procedure>
<choice doc:name="data found?">
<when expression="#[payload.resultSet1.size() >= 1]">
<dw:transform-message doc:name="CreateResponse">
<dw:set-payload resource="classpath:/dataweave/someDataweave.dwl" />
</dw:transform-message>
</when>
<otherwise>
<logger message="False: payload:#[payload]" level="INFO" doc:name="Log-False"/>
</otherwise>
</choice>
</flow>
Now I’m trying to create an Munit test for it. In order to get the choice to work, I had to do some playing with the data.
The choice now works but now the dataweave transform throws an exception because it says the json data is missing quotes.
The munit:
<munit:test name="test1-tryit" description="Test">
<mock:when messageProcessor=".*:.*" doc:name="Mock MyStoredProcResults">
<mock:with-attributes>
<mock:with-attribute name="doc:name" whereValue="#['MyStoredProc']"/>
</mock:with-attributes>
<mock:then-return payload="#[flowVars.jsonStoredProcResponse]" mimeType="text/json"/>
</mock:when>
<set-payload value="#[getResource('myTestData.json').asStream()]" doc:name="GetStoredProcResponse" mimeType="application/json"/>
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/>
<set-variable variableName="jsonStoredProcResponse" value="#[payload]" doc:name="jsonStoredProcResponse" />
<flow-ref name="test1" doc:name="Flow-ref to test1 flow" />
The data in myTestData.json file looks like this:
{"resultSet1": [{ "field1":"123" } ]}
Not sure how to resolve this issue and get both the choice and the transform to work.
Thanks.
Try using below groovy script:
<scripting: script name="mockDataBaseResponse" engine="groovy" doc:name="Script"><![CDATA[
Hashmap<String,String> cursor = new Hashmap<String,String>();
cursor.put("field1","123");
LinkedList List = new LinkedList();
List.add(cursor);
Hashmap<String,Object> cursorMap = new Hashmap<String,Object>();
cursorMap.put("resultSet1",List);
return cursorMap;]]>
</scripting:script>
Mock payload using script:
<mock:then-return payload="#[resultOfScript('mockDataBaseresponse')]" mimeType="text/java"/>
Also include this script file in you Munit xml file.

MEL Expression Issues

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

How to capture an exception using the regex-filter filter in Mule ESB

Currently I have a flow that exposes a REST service with a string as input parameter . I am using a regex -filter to ensure the format parameter as follows :
<http:inbound-endpoint doc:name="HTTP"
connector-ref="ciuServiceHTTPConnector" ref="ciuServiceHTTPEndpoint"
exchange-pattern="request-response" />
<logger level="INFO" doc:name="Logger" message="epale1 #[payload]"/>
<regex-filter pattern="^/api/person/(V|E)[0-9]{8}$"
doc:name="Regex" />
<logger message="epale2 #[payload]" level="INFO" doc:name="Logger"/>
<jersey:resources doc:name="REST" >
<component class="...resource.CiudadanoResource"/>
</jersey:resources>
I need to send the customer a message "Invalid or missing parameter" . For this I use a choice-exception-strategy and catch-exception-strategy and then call a Subflow and perform http:response-builder.
How can I throw an exception(type) when the regex-filter do not match?. It is possible to incorporate this behavior or should I change my flow?
Thanks for your help;
Wrap it in a message-filter, like this:
<message-filter throwOnUnaccepted="true">
<regex-filter pattern="^/api/person/(V|E)[0-9]{8}$"
doc:name="Regex" />
</message-filter>
See the official documentation for further details:
Check the Throw On Unaccepted box to throw an exception if a message
or event is not handled. The default when not checked is to not throw
an exception.

Mule ESB: Filter based on HTTP method

I'm wondering if there is a way to filter / route messages based on HTTP method. What I'm looking to do is NOT process incoming requests that have been posted with the OPTIONS method. (this is for cross-origin resource share handling)
You can use MEL(Mule Exression Language - http://www.mulesoft.org/documentation/display/current/Mule+Expression+Language+MEL) to query the http.method param and a choice router if you want to do something with OPTIONS request such as send back the allowed methods like so:
<choice doc:name="Choice">
<when expression="#[message.inboundProperties['http.method'] == 'OPTIONS']">
<http:response-builder status="200"
doc:name="HTTP Response Builder(200 - OPTIONS)">
<http:header name="Allow" value="GET" />
<http:header name="Content-Type" value="#[null]" />
<set-payload value="#[null]" />
</http:response-builder>
</when>
<otherwise>
<!-- Do something else -->
</oherwise>
</choice>
Or you can use an expression filter if you just want to drop the message if not OPTIONS:
<expression-filter
expression="#[message.inboundProperties['http.method'] != 'OPTIONS']" />
More info on routing and filtering here:
http://www.mulesoft.org/documentation/display/current/Routing+Message+Processors
http://www.mulesoft.org/documentation/display/current/Using+Filters
Another solution is, you can use message-filter with not-filter and message-property-filter and return 405 method not allowed on an HTTP OPTIONS request is unaccepted by the filter.
Below is a sample flow
<flow name="filterOptionsMethod">
<http:listener config-ref="httpListener" path="/test" doc:name="receiveReq" />
<message-filter onUnaccepted="set405" doc:name="filterOptionsMethod">
<not-filter>
<message-property-filter pattern="http.method=options" caseSensitive="false" scope="inbound" />
</not-filter>
</message-filter>
</flow>
and onUnaccepted
<sub-flow name="set405">
<set-property propertyName="http.status" value="405" doc:name="405" />
<set-payload value="HTTP method OPTIONS not allowed" doc:name="setRes" />
</sub-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