Compound MEL statement has problems - mule

I need to read values from a configuration file and I keep running into issues with an embedded MEL statement; chased multiple dead ends and am out of ideas. I distilled it down to a fairly simple example using a session variable.
Thank you,
- Don
The below code fails with:
Message : [Error: Missing left node]
[Near : {... message.payload.contains(#[sessionVars['valueToMatch']]) ....}]
<set-session-variable variableName="valueToMatch" value="Now we are engaged in a great civil war" />
<choice doc:name="Choice">
<when expression="#[message.payload.contains(#[sessionVars['valueToMatch']])]">
<set-session-variable variableName="success" value="true" />
</when>
<otherwise>
<set-session-variable variableName="success" value="false" />
</otherwise>
</choice>
Whereas the following code works:
<choice doc:name="Choice">
<when expression="#[message.payload.contains('Now we are engaged in a great civil war')]">
<set-session-variable variableName="success" value="true" />
</when>
<otherwise>
<set-session-variable variableName="success" value="false" />
</otherwise>
</choice>

My guess is that the problem is that you are putting an expression delimited inside of an expression, try this:
"#[message.payload.contains(sessionVars['valueToMatch'])]"
instead of this
"#[message.payload.contains(#[sessionVars['valueToMatch']])]"

Try this #[message.payload contains valueToMatch] ... It will work perfectly and simple:-
<set-session-variable variableName="valueToMatch" value="Now we are engaged in a great civil war" />
<choice doc:name="Choice">
<when expression="#[message.payload contains valueToMatch]">
<set-session-variable variableName="success" value="true" />
</when>
<otherwise>
<set-session-variable variableName="success" value="false" />
</otherwise>
</choice>

Related

Mule ConsumerIterator error is LinkedHashMap

I have a flow which queries SalesForce. The query is wrapped in an enricher. Here is the flow.
<flow name="ProcessEmployee">
<enricher doc:name="Message Enricher" target="#
[variable:IDRec]">
<sfdc:query config-ref="Salesforce_Config"
doc:name="Check if Employee Id exists"
query="select id from employee where
deptId='#[payload["deptId"]]' &&
empId='#[payload["empId"]]'" />
</enricher>
<choice>
<when expression="#[flowVars.IDRec.hasNext()]">
<logger level="INFO"
message="Employee exists, #[payload]" />
</when>
<otherwise>
<logger level="INFO" message="Employee does not exist"/>
</otherwise>
</choice>
</flow>
However, I get the following error
: Execution of the expression "flowVars.IDRec.hasNext()" failed.
(org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: LinkedHashMap
Type: org.mule.api.MessagingException
Code : MULE_ERROR--2
The returned value is a map. You can try this approach,
<choice>
<when expression="#[flowVars.IDRec.size() > 0]">
<logger level="INFO" message="Employee exists, #[payload]" />
</when>
<otherwise>
<logger level="INFO" message="Employee does not exist"/>
</otherwise>
</choice>

mule move file to another location dynamically from the db query

I want to move files to location D:\target dynamically from the query select filepath from emp where status='y':
This is my table:
emp_Name File Path File Name Status
ABC D:\emp abc.txt y
xyz D:\emp xyz.txt y
bcs D:\emp bcs.txt n
Following is my source code :
<flow name="testdbFlow1">
<http:listener config-ref="HTTP_Listener_Configuration"
path="/" doc:name="HTTP" />
<jdbc-ee:outbound-endpoint queryKey="allEmps"
queryTimeout="-1" connector-ref="JDBCConnector" exchange-pattern="request-response"
doc:name="Database" />
<foreach doc:name="Foreach">
<choice doc:name="Choice">
<when expression="#[payload.status == 'Y']">
<processor-chain doc:name="Processor Chain">
<set-variable variableName="filePath" value="#[payload.filepath]"
doc:name="Variable" />
<set-variable variableName="filename" value="#[payload.filename]"
doc:name="Variable" />
<logger message="#[filePath]" level="INFO"
doc:name="Logger" />
<logger message="#[filename]"
level="INFO" doc:name="Logger" />
<file:inbound-endpoint path="#[filePath]" name="input" doc:name="File"
pollingFrequency="12000" responseTimeout="10000"> <file:filename-wildcard-filter
pattern="#[filename]" /> </file:inbound-endpoint>
<file:outbound-endpoint name="output" path="D:\target" doc:name="File"/>
</processor-chain>
</when>
<otherwise>
<processor-chain doc:name="Processor Chain">
<set-variable variableName="filePath" value="#[payload.filepath]"
doc:name="Variable" />
<set-variable variableName="filename" value="#[payload.filename]"
doc:name="Variable" />
<logger message="#[filePath]" level="INFO"
doc:name="Logger" />
<logger message="#[filename]"
level="INFO" doc:name="Logger" />
</processor-chain>
</otherwise>
</choice>
</foreach>
</flow>
But it's not working.
Inbound doesn't work out of the box in the middle of the flow. I would suggest a simpler solution using Groovy because you know exactly the file you need to consume.
Instead of using file:inbound create a input stream manually:
<set-payload value="#[groovy: new java.io.FileInputStream(new java.io.File(filename))]"/>
You will have to delete the file with another groovy script after consumed.

NullPayload vs null check

According to the following ticket: https://www.mulesoft.org/jira/browse/MULE-6427 For NullPayload I should be able to use :
<when expression="#[payload == null]">
but that doesn't work. It fails. I am using Mule 3.5.1
Here is an example flow:
<flow name="testNull">
<poll frequency="10000">
<logger />
</poll>
<set-payload value="#[org.mule.transport.NullPayload.getInstance()]" />
<choice>
<when expression="#[payload == null]">
<logger level="ERROR" message="NullPayload is same as null" />
</when>
<otherwise>
<logger level="ERROR" message="Doesnt work" />
</otherwise>
</choice>
</flow>
This will always print 'Doesn't work'. However message.payload == null works. Whats the difference between "payload" and "message.payload"?
There seems to be an issue with the #[payload] alias. Use the real thing and it will work: #[message.payload].

Parallel Processing in Mule : Issue with getting right response

Requirement is to develop mule flow which calls 3 different sync services in parallel and then aggregate the response of each of these and send it back to caller.
I have followed fork join approach as mentioned in docs and How to make parallel outbound calls.
My config file looks like below :
<flow name="fork">
<http:inbound-endpoint host="localhost" port="8090" path="mainPath" exchange-pattern="request-response">
<set-property propertyName="MULE_CORRELATION_GROUP_SIZE"
value="2" />
<all enableCorrelation="IF_NOT_SET">
<async>
<set-property propertyName="MULE_CORRELATION_SEQUENCE"
value="1" />
<flow-ref name="parallel1" />
</async>
<async>
<set-property propertyName="MULE_CORRELATION_SEQUENCE"
value="2" />
<flow-ref name="parallel2" />
</async>
</all>
</flow>
<sub-flow name="parallel1">
<logger level="INFO" message="parallel1: processing started" />
<!- Transformation payload -->
<http:outbound-endpoint address="..."
exchange-pattern="request-response" />
<logger level="INFO" message="parallel1: processing finished" />
<flow-ref name="join" />
</sub-flow>
<sub-flow name="parallel2">
<logger level="INFO" message="parallel2: processing started" />
<!- Transformation payload -->
<http:outbound-endpoint address="..."
exchange-pattern="request-response" />
<logger level="INFO" message="parallel2: processing finished" />
<flow-ref name="join" />
</sub-flow>
<sub-flow name="join">
<collection-aggregator timeout="6000"
failOnTimeout="true" />
<combine-collections-transformer />
<logger level="INFO" message="Continuing processing of: #[message.payloadAs(java.lang.String)]" />
<set-payload value="Soap XML Response"/>
</sub-flow>
I am able to verify that till "join" subflow is working fine but the response is not coming back as "Soap XML Response".
The response is the same initial SOAP Request.
How can I make this thread wait till sub-flow processing is complete and it sends back response whatever "join" sub-flow returns ??
The fork join in the above post looks good. The issue here is there is no way to capture the payload after the join and bring it back to the main flow.
As the calls to parallel made async the main flow continues without waiting for the join output.
I have modified the flow to address this issue. Now the flow will have a processor to wait for the reply and read the joined output to be written onto the http transformer.
<flow name="fork">
<http:inbound-endpoint host="localhost" port="8090" path="mainPath" exchange-pattern="request-response">
<!-- To get back the response after the fork-join -->
<request-reply timeout="60000">
<jms:outbound-endpoint queue="parallel.processor.queue">
<message-properties-transformer scope="outbound">
<delete-message-property key="MULE_REPLYTO" />
</message-properties-transformer>
</jms:outbound-endpoint>
<jms:inbound-endpoint queue="join.queue" >
</jms:inbound-endpoint>
</request-reply>
</flow>
<flow name="fork_join_flow" >
<jms:inbound-endpoint queue="parallel.processor.queue" exchange-pattern="one-way" />
<set-property propertyName="MULE_CORRELATION_GROUP_SIZE"
value="2" />
<all enableCorrelation="IF_NOT_SET">
<async>
<set-property propertyName="MULE_CORRELATION_SEQUENCE"
value="1" />
<flow-ref name="parallel1" />
</async>
<async>
<set-property propertyName="MULE_CORRELATION_SEQUENCE"
value="2" />
<flow-ref name="parallel2" />
</async>
</all>
</flow>
<sub-flow name="parallel1">
<logger level="INFO" message="parallel1: processing started" />
<!- Transformation payload -->
<http:outbound-endpoint address="..."
exchange-pattern="request-response" />
<logger level="INFO" message="parallel1: processing finished" />
<flow-ref name="join" />
</sub-flow>
<sub-flow name="parallel2">
<logger level="INFO" message="parallel2: processing started" />
<!- Transformation payload -->
<http:outbound-endpoint address="..."
exchange-pattern="request-response" />
<logger level="INFO" message="parallel2: processing finished" />
<flow-ref name="join" />
</sub-flow>
<sub-flow name="join">
<collection-aggregator timeout="6000"
failOnTimeout="true" />
<combine-collections-transformer />
<logger level="INFO" message="Continuing processing of: #[message.payloadAs(java.lang.String)]" />
<set-payload value="Soap XML Response"/>
<jms:outbound-endpoint queue="join.queue">
</jms:outbound-endpoint>
</sub-flow>
Hope this helps.

Mule - Unable to find an StreamCloser for the stream type: class java.lang.String

After the JMS message is delivered to the queue I see a log statement related to Stream Closer. It doesn't look right to me .. why do I see this message?
2013-04-22 19:08:29,385 [DEBUG] org.mule.transport.jms.activemq.ActiveMQJmsConnector - Returning dispatcher for endpoint: jms://retry.queue = EeJmsMessageDispatcher{this=5c5801d7, endpoint=jms://retry.queue, disposed=false}
2013-04-22 19:08:29,433 [DEBUG] org.mule.util.DefaultStreamCloserService - Unable to find an StreamCloser for the stream type: class java.lang.String, the stream: <?xml version="1.0" encoding="UTF-8"?> < ....... rest of the XML ....... /> will not be closed.
What does it mean by - "the stream: will not be closed."?
What should I do to fix this?
====EDIT =====
There is an error happening. The JMS message has XML as payload. Mule version: 3.3.2
Here's my flow
<flow name="sendToHost">
<jms:inbound-endpoint queue="host.queue" exchange-pattern="one-way" />
<copy-properties propertyName="*" />
<file:outbound-endpoint path="/hostmessages" outputPattern="outgoing-xml-[function:dateStamp].log" />
<set-variable variableName="hostXML" value="#[payload]" />
<flow-ref name="webServiceCall" />
<flow-ref name="inspectWSResponse" />
<exception-strategy ref="retryExceptionStrategy" />
</flow>
<flow name="resendFailedMessages">
<description>
"*/15 07-18 * * ?" run every 15 minutes from 7 am to 6 pm every day -->
</description>
<quartz:inbound-endpoint jobName="hostRedeliveryJob" cronExpression="0 0/1 * * * ?">
<quartz:endpoint-polling-job>
<quartz:job-endpoint ref="redeliverToHost" />
</quartz:endpoint-polling-job>
</quartz:inbound-endpoint>
<set-variable variableName="hostXML" value="#[payload]" />
<logger message="QUARTZ found message for host" level="INFO" />
<flow-ref name="webServiceCall" />
<flow-ref name="inspectWSResponse" />
<exception-strategy ref="retryExceptionStrategy" />
</flow>
<choice-exception-strategy name="retryExceptionStrategy">
<catch-exception-strategy when="#[exception.causedBy(java.io.IOException)]">
<logger message="In retryExceptionStrategy IO exception strategy. " level="ERROR" />
<logger message="retryExceptionStrategy exception is #[exception.causeException]" level="ERROR" />
<set-property propertyName="exception" value="#[exception.summaryMessage]" />
<set-payload value="#[hostXML]" />
<logger message="retryExceptionStrategy payload is #[payload]" level="ERROR" />
<jms:outbound-endpoint queue="retry.queue" />
</catch-exception-strategy>
<catch-exception-strategy>
<logger message="Other error in sending result to host in retryExceptionStrategy flow." level="INFO" />
<set-property propertyName="exception" value="#[exception.summaryMessage]" />
<set-payload value="#[hostXML]" />
<jms:outbound-endpoint queue="declined.queue" />
</catch-exception-strategy>
</choice-exception-strategy>
<sub-flow name="webServiceCall">
<cxf:proxy-client payload="body" enableMuleSoapHeaders="false">
<cxf:inInterceptors>
<spring:bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</cxf:inInterceptors>
<cxf:outInterceptors>
<spring:bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
</cxf:outInterceptors>
</cxf:proxy-client>
<outbound-endpoint address="${host.ws.url}" mimeType="text/xml" connector-ref="http.connector" />
<byte-array-to-string-transformer />
</sub-flow>
<sub-flow name="inspectWSResponse">
<choice>
<when expression="#[xpath('//acord:TestResult/acord:TestCode/acord:Name/#tc').value == '1']">
<logger message="Message Delivered Successfully to host" level="INFO" />
</when>
<otherwise>
<set-payload value="#[hostXML]" />
<jms:outbound-endpoint queue="declined.queue" />
</otherwise>
</choice>
</sub-flow>
Log entries at DEBUG level can typically be safely ignored.
In this particular case, it seems Mule is using the StreamCloserService on a message's payload that is not a stream but a string.
Looking at the source code this can seem to possibly happen only when an exception is processed and Mule attempts to forcefully close a streaming payload without first checking if it is actually streaming. This is benign and can't trigger any side-effect so you can safely ignore this DEBUG statement.