Mule message.payload and payload - mule

I have a Mule Expression Language expression:
<set-payload value="#[message.payload.hasNext() ? message.payload.next(): null]" doc:name="Set Payload"/>
<choice doc:name="Choice">
<when expression="#[message.payload != null]">
I am trying to iterate over a ConsumerIterator and am getting the error
Execution of the expression "message.payload.hasNext() ? message.payload.next(): null" failed. (org.mule.api.expression.ExpressionRuntimeException)
org.mule.el.mvel.MVELExpressionLanguage:202 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/expression/ExpressionRuntimeException.html)
6. Execution of the expression "message.payload.hasNext() ? message.payload.next(): null" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: ConsumerIterator (org.mule.api.transformer.TransformerMessagingException)
org.mule.transformer.AbstractTransformer:135 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transformer/TransformerMessagingException.html)
My solution to this is to rewrite the code without the message. prefix:
<set-payload value="#[payload.hasNext() ? payload.next(): null]" doc:name="Set Payload"/>
<choice doc:name="Choice">
<when expression="#[payload is NullPayload]">
What is the difference between #[message.payload] and #[payload]?
If payload is an instance of NullPayload why doesn't payload.hasNext() throw an Exception?
From what I've read the best practice is to use #[message.payload] instead of #[payload].
I am using Mule 3.6.2.

There is no difference between message.payload and payload. Payload is a shortcut left there just for compatibility with Mule 2.
From time to time there is an issue here and there about a difference between one and the other, just small nuisances but in this case I believe you should try message.payload is NullPayload.

I solved the problem by assigning set-payload to false or an empty String instead of null:
<set-payload value="#[message.payload.hasNext() ? message.payload.next(): 'none']" doc:name="Set Payload"/>
Even assigning null is not valid in batch-steps process, it is better to assign some other String. Now I am able to use #[message.payload]:
<logger message="Query: #[message.payload]" level="INFO" doc:name="Logger"/>

Related

Mule 3 to Mule 4 error handling queries for error types and http status

I am migrating an error handling file from Mule 3 to Mule 4 using Anypoint Studio 7.
My queries are:
How would I do I now do this check as I cannot see the same information in the exception message? #[exception.causedBy(org.mule.module.http.internal.request.ResponseValidatorException)]"
Where do I find the http.status property now? I can see it as a variable when it is 200 but when the error is thrown it seems to disappear and cannot locate it in the message
Where can I find a list of error handling types?
The error handling types I'm particularly interested in are below but no idea if that is the correct value for the error type:
HTTP:BAD_REQUEST
HTTP:UNAUTHORIZED
HTTP:FORBIDDEN
HTTP:RESOURCE_NOT_FOUND
HTTP:METHOD_NOT_ALLOWED
HTTP:NOT_ACCEPTABLE
HTTP:CONFLICT
HTTP:UNSUPPORTED_MEDIA_TYPE
HTTP:INTERNAL_SERVER_ERROR
HTTP:BAD_GATEWAY
Snippet of the Mule 3 code I am migrating is below and I think it was based on a template:
<choice-exception-strategy name="global-exception-strategy">
<catch-exception-strategy when="#[exception.causedBy(org.mule.module.http.internal.request.ResponseValidatorException)]" doc:name="Caused By (org.mule.module.http.internal.request.ResponseValidatorException)">
<choice doc:name="Choice">
<when expression="#[message.inboundProperties['http.status'] == 401]">
<set-variable variableName="errorMessage" value="Upstream service did not authorize the request." doc:name="Set Error Message"/>
<flow-ref name="global-bad-gateway-response-sub-flow" doc:name="Bad Gateway Response"/>
</when>
<otherwise>
<set-variable variableName="errorMessage" value="Upstream service internal error." doc:name="Set Error Message"/>
<flow-ref name="global-bad-gateway-response-sub-flow" doc:name="Bad Gateway Response"/>
</otherwise>
</choice>
</catch-exception-strategy>
</choice-exception-strategy>
<sub-flow name="global-bad-gateway-response-sub-flow">
<set-property propertyName="http.status" value="401" doc:name="Set Status"/>
<set-payload value="UNAUTHORIZED" doc:name="Set Error Code" mimeType="application/java"/>
<flow-ref name="global-prepare-error-response-sub-flow" doc:name="Prepare Error Response"/>
</sub-flow>
Thanks
Use these kind of check
#[contains(error.description,'internal server error (500).')]
in Mule 4 http status code for error response located here
#[error.errorMessage.attributes['statusCode']]

Initializing a Map using Mule Expression Language

I'm trying to initialize a map with the following in a mule expression-component:
#[message.payload = [ 'changeSet' : #[payload], 'sourceAndConnectionMap' : #[flowVars['sourceAndConnectionMap']]]]
Based on the following page, this looks okay, but does not work.
https://developer.mulesoft.com/docs/display/current/Mule+Expression+Language+Reference
Only the first key is set ('changeSet'), and for some reason the payload, which is a map, becomes an ArrayList containing a map... I can also initialize this with just the second key and valy, so I know there isn't an issue resolving the flowVar.
Is there something basic about how I am initializing this map that is incorrect?
In MEL a map should be created like:
#[{'key':'value', 'key1':'value1'}]
If you do
#[[]]
That's just a list of elements.
The other comments, if you're already inside a:
#[]
You need not to add it again. In your example you have it several times.
Please run this through the Mule debugger (put brakepoints in the logs)and you'll see the difference.
<flow name="test>
<set-payload value="#[{'key':'value', 'key1':'value1'}]" doc:name="Set Payload"/>
<logger level="INFO" doc:name="Logger"/>
<set-payload value="#[{'key':'value', 'key1':payload}]" doc:name="Copy_of_Set Payload"/>
<logger level="INFO" doc:name="Copy_of_Logger"/>
<set-payload value="#[['key','value', 'key1','value1']]" doc:name="Copy_of_Set Payload"/> <logger level="INFO" doc:name="Logger"/>
</flow>
HTH

Mule choice route depending on payload type ie object type?

I have route choice depending on the payload. The payload can be either list, map or string. The payload has to be identified and routed depending on the payload type.
I think that you want something like that
<choice doc:name="Choice">
<when expression="#[payload is List]">
<logger level="INFO" message="i am list" doc:name="Logger"/>
</when>
<when expression="#[payload is Map]">
<logger level="INFO" message="i am map" doc:name="Logger"/>
</when>
<when expression="#[payload is String]">
<logger level="INFO" message="i am string" doc:name="Logger"/>
</when>
<otherwise>
<logger message="class doesnt match with [list, map, string]" level="INFO" doc:name="Logger"/>
</otherwise>
</choice>
I do agree with EddĂș response, except for that I would add an otherwise path. If you don't do that and get something different than a list map or string you would get the rather cryptic error:
org.mule.api.routing.RoutePathNotFoundException: Can't process message because no route has been found matching any filter and no default route is defined. Failed to route event via endpoint: ChoiceRouter [flow-construct=testNull, started=true]. Message payload is of type: NullPayload

Mule expression compare the value of variable with a string #['${forwardAddress}'.startsWith('http://')]

I need to dynamically set address on an outbound endpoint, and depending on what I receive in forward.url, this outbound URL can be either HTTP or HTTPS. So, I created 2 subflows, one for HTTP and other for HTTPS.
To route the request to appropriate subflow, I am wrote a CHOICE router as shown below
<set-variable value="#[message.inboundProperties['http.query.params']['forward.url']]" variableName="forwardAddress" doc:name="Variable"/>
<logger message="Forward address is #[forwardAddress] , and does it start with http:// ~ #[String.valueOf('${forwardAddress}').startsWith('http://');]" level="INFO" doc:name="Logger"/>
<choice doc:name="Choice">
<when expression="#['${forwardAddress}'.startsWith('http://')]">
<flow-ref name="HttpCall" doc:name="HTTP subflow"/>
</when>
<when expression="#['${forwardAddress}'.startsWith('https://')]">
<flow-ref name="Httpscall" doc:name="HTTPS subflow"/>
</when>
<otherwise>
<set-payload value="The query string forward.url must start with http:// or https://" doc:name="Set Payload"/>
<http:response-builder doc:name="Invalid Request - 400" status="400"/>
</otherwise>
</choice>
However, the expression is not working correctly. What am I doing wrong?
The syntax ${} is for spring property placeholders. Use #[flowVars.forwardAddress] or #[forwardAddress] for flow variables.

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