I would like to do a proxy for backend rest service, but before I forward the request to backend, I need to do some checks. I checked the docments, there is a http-proxy can be used to do the proxy, but when I put into the flow, there are exceptions. If I use the http:outbound-endpoint the method cannot be a dynamic MEL expression(rest method could be POST, GET, PUT, DELTE etc).
Could you give me a suggestion? An example will be better, Thanks a lot.
My Configuration:
<flow name="demo.routerFlow1" doc:name="demo.routerFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8080" doc:name="HTTP" />
<logger
message="Method: #[message.inboundProperties['http.method']], URI: #[message.inboundProperties['http.request.path']], Params: #[message.inboundProperties['http.query.params']]"
level="INFO" doc:name="Logger" />
<http:body-to-parameter-map-transformer doc:name="Body to Parameter Map" />
<choice doc:name="Choice">
<when expression="(payload['timestamp'] == null || payload['nonce'] == null)">
<expression-component doc:name="Check Required Params"><![CDATA[payload="{\"code\":\"PA001\", \"message\":\"missing required parameter timestamp and nonce\"}"]]>
</expression-component>
</when>
<otherwise>
<choice doc:name="Choice">
<when expression="!replayAttackCheck.validate(payload)" evaluator="groovy">
<expression-component doc:name="Check Required Params"><![CDATA[payload="{\"code\":\"PA002\", \"message\":\"timestamp or nonce is illegal\"}"]]>
</expression-component>
</when>
<otherwise>
<processor-chain doc:name="Processor Chain">
<pattern:http-proxy name="http-proxy-sample"> <!--line 38-->
<http:inbound-endpoint address="http://localhost:8080/"></http:inbound-endpoint>
<http:outbound-endpoint address="http://localhost:8081/"></http:outbound-endpoint>
</pattern:http-proxy>
</processor-chain>
</otherwise>
</choice>
</otherwise>
</choice>
</flow>
Error:
Caused by: org.xml.sax.SAXParseException; lineNumber: 38; columnNumber: 31; cvc-complex-type.2.4.b: The content of element 'processor-chain' is not complete. 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-processor, "http://www.mulesoft.org/schema/mule/core":abstract-outbound-endpoint, "http://www.mulesoft.org/schema/mule/core":abstract-mixed-content-message-processor}' is expected.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
Configuration patterns are standalone and separate from any flow and cannot be configured within one. They are predefined integration patterns for common scenarios. Flows are for rolling your own. See here: http://www.mulesoft.org/documentation/display/current/Choosing+Between+Flows+and+Patterns
As a side note: Your already listening on localhost:8080, so I think you just want a http:outbound-endpoint to the service your running on 8081
<http:outbound-endpoint address="http://localhost:8081/" />
You just need a http:outbound to the actual rest service in your otherwise block.
Try using the following.
<otherwise>
<http:outbound-endpoint address="http://localhost:8081/"></http:outbound-endpoint>
</otherwise>
Hope this helps.
Related
I checked several previous discussions but couldnt find the answer.
I am trying to achieve synchronous communicaiton using JMS back-channel (http://www.whishworks.com/blog/synchronous-communication-using-jms-back-channel). Apart from the things mentioned in that site, I need to filter out the message from the inbound queue based on a dynamic Id.
Following are my mule flows:
<flow name="serverFlow" >
<jms:inbound-endpoint doc:name="REQUEST" queue="REQUEST.QUEUE" connector-ref="jmsConnector">
<jms:selector expression="MULE_CORRELATION_ID='#[sessionVars.myCorrelationId]'"/>
</jms:inbound-endpoint>
<set-payload value="#[payload] + Hello World from Receiver" doc:name="Set Payload" />
<jms:outbound-endpoint doc:name="REPLY" queue="REPLY.QUEUE" connector-ref="jmsConnector" />
</flow>
<flow name="mainFlow" >
<http:listener config-ref="HTTP_Listener_Configuration" path="/jms" allowedMethods="GET" doc:name="HTTP"/>
<set-session-variable variableName="myCorrelationId" value="#[System.currentTimeMillis().toString()]" doc:name="Set Correlation ID"/>
<set-payload value="New message sent from Mule - mainFlow at #[new Date()]" doc:name="Set Message"/>
<set-property propertyName="MULE_CORRELATION_ID" value="#[sessionVars.myCorrelationId]" doc:name="Property"/>
<request-reply doc:name="Request-Reply">
<jms:outbound-endpoint doc:name="REQUEST" connector-ref="jmsConnector" queue="REQUEST.QUEUE"/>
<jms:inbound-endpoint doc:name="REPLY" connector-ref="jmsConnector" queue="REPLY.QUEUE"/>
</request-reply>
<logger message="Reply to sender: #[message]" level="WARN" doc:name="Logger" />
</flow>
If I try a static value like "<jms:selector expression="MULE_CORRELATION_ID='12345'"/>", it works. But if I try a dynamic ID using MEL, its not working. The MEL inside the jms selector expression is not working. The message stays at the queue as Unread. I used logs to see what the MULE_CORRELATION_ID is while being set at mainFlow and found the same value is set in the message that is UNREAD in the queue. So, I guess nothing is wrong in the way the MULE_CORRELATION_ID is set. The only problem is that MEL is not working within jms:selector.
Could you please help how to get MEL working within JMS selector?
Thank you very much.
MEL is working fine in the selector but its usage is very limited. When the JMS selector is created, there's no in-flight event available to Mule so none of the event-bound data (including session) is available.
To select a very particular message, you need to use a JMS message requester, constructed with the desired selector, like:
jms://REQUEST.QUEUE?selector=MULE_CORRELATION_ID%3D'#[sessionVars.myCorrelationId]'
Here is the working solution based on David's suggestion. I am using wmq here (not jms).
<mulerequester:config name="Mule_Requester" doc:name="Mule Requester"/>
<flow name="mainFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/test" allowedMethods="GET" doc:name="HTTP"/>
<set-payload value="My Message" doc:name="Set Message"/>
<set-property propertyName="JMSCorrelationID" value="12345" doc:name="Property"/>
<set-session-variable variableName="myCorrelationId" value="ID:313233343500000000000000000000000000000000000000" doc:name="Set Correlation ID"/>
<!--313233343500000000000000000000000000000000000000 is the MQMD CorrelationId for 12345. This is set by IBM MQ -->
<logger message="The Message to REQUEST QUEUE: #[message]" level="WARN" doc:name="Logger"/>
<wmq:outbound-endpoint queue="REQUEST.QUEUE" connector-ref="wmqConnector" doc:name="OUT"/>
<mulerequester:request config-ref="Mule_Requester" resource="wmq://REPLY.QUEUE?selector=JMSCorrelationID%3D'#[sessionVars.myCorrelationId]'" doc:name="Mule Requester" timeout="120000"/>
<logger message="Final Response: #[message]" level="WARN" doc:name="Logger"/>
</flow>
Please note, I manually moved the message from Request queue to Reply queue using MQVE for my testing. In real time, it will be done by another program.
I am trying implement deadLetterQueue on UntilSuccessful for JDBC Connector. I would like to send the payload to a queue(DeadLetterQueue) when UntilSuccessful fails after trying no of times as configured. I referred following links
http://blogs.mulesoft.org/meet-until-successful-store-and-forward-for-mule/
Where in the application would you define the vm:endpoint for a dlqEndpoint-ref defined in an until-successful scope?
Below is my code snippet
<vm:endpoint exchange-pattern="one-way" path="dlqChannel" name="VM" doc:name="VM"/>
Above line is my global element
<flow...> .... <until-successful objectStore-ref="objectStore" deadLetterQueue-ref="dlqChannel" maxRetries="5" secondsBetweenRetries="60" doc:name="Until Successful" failureExpression="exception-type:java.sql.SQLException">
<jdbc-ee:outbound-endpoint exchange-pattern="request-response" queryKey="Insert Query" queryTimeout="-1" connector-ref="Database" doc:name="Database"/>
</until-successful>....</flow>
<flow name="Flow2" doc:name="Flow2">
<endpoint ref="dlqChannel" />
<logger message="DEAD DEAD DEAD LETTER LETTER LETTER #[message]" level="INFO" doc:name="Logger"/>
</flow>
At this line <endpoint ref="dlqChannel" /> I am getting compile error says "Reference to unknown global element:dlqChannel"
Can any one suggest a best way to achieve this scenario.
Thanks,
Kalyan
Your endpoint is called 'VM' not 'dlqChannel'. Change either the name to dlqChannel or point it to VM.
This issue is resolved.
Below is my code snippet.
<vm:endpoint exchange-pattern="one-way" path="dlq" name="dlqChannel" doc:name="VM"/>
Above line is vm global element
<flow...> ... <until-successful objectStore-ref="objectStore" deadLetterQueue-ref="dlqChannel" maxRetries="2" secondsBetweenRetries="10" doc:name="Until Successful" failureExpression="exception-type:java.sql.SQLException">
<jdbc-ee:outbound-endpoint exchange-pattern="request-response" queryKey="Insert Query" queryTimeout="-1" connector-ref="Database" doc:name="Database"/>
</until-successful>
....
</flow>
<flow name="Flow2" doc:name="Flow2">
<vm:inbound-endpoint exchange-pattern="one-way" path="dlq" doc:name="VM"/>
<logger message="DEAD DEAD DEAD LETTER LETTER LETTER #[message.payload]" level="INFO" doc:name="Logger"/>
</flow>
Based on "deadLetterQueue-ref" in UntilSuccessful, payload goes to vm:inbound-endpoint(vm://dlq) as defined in the vm global endpoint.
As Seba correctly points out, your error is due to a wrong name/ref. As for how to implement the deadLetterQueue, you need an inbound endpoint. So in Flow2, change the endpoint to <inbound-endpoint ref="dlqChannel" />.
How do I use a filter other than a choice filter to call a subflow based on the http status?
<flow>
<http:outbound-endpoint exhange-pattern="request-response>
if http.status!=201
<flow-ref="subflow-to-invoke">
</flow>
Check this post Mule-esb: Process Jersey Response based on Status code using Choice Router?
Here is snippet from the above link, that answers your question.
<flow>
<http:outbound-endpoint address="${host}" exchange-pattern="request-response"/>
<choice>
<when expression="#[message.inboundProperties['http.status']]==201">
<flow-ref name=="flow2">
</when>
<when expression="#[message.inboundProperties['http.status']]==503">
<flow-ref name="flow3">
</when>
<when expression="#[payload instanceof java.lang.SocketException]">
<flow-ref name="flow4">
</when>
<otherwise>
<!-- decide what you want to do here -->
</otherwise>
</choice>
You don't have to use a filter for that but a choice message processor:
http://www.mulesoft.org/documentation/display/current/Choice+Flow+Control+Reference
Please help me on this logic. I have to call the service and get the response back.If the service is down or something have to retry 3 times and once exhausted need to log in DLQ.I'm using until successful processor.For success scenario i'm getting only null payload in logger.But i tried keeping the HTTP outbound end point without until successfull able to get the response from the service. Please find my xml config.
<flow name="Flow" doc:name="eFlow" tracking:enable-default-events="true">
<wmq:inbound-endpoint queue="InputQ" tracking:enable-default-events="true" connector ref="WMQ_Connector" doc:name="connector">
<wmq:transaction action="NONE"/>
</wmq:inbound-endpoint>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<set-session-variable variableName="originalPayload" value="#[payload]" doc:name="Store_Payload"/>
<choice tracking:enable-default-events="true" doc:name="Choice">
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Master']">
<data-mapper:transform config-ref="Master_grf" doc:name="Master"/>
</when>
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Request']">
<data-mapper:transform config-ref="Request_grf" doc:name="Bulk"/>
</when>
<otherwise>
<scripting:component doc:name="Throw_Exception">
<scripting:script engine="Groovy"><![CDATA[throw new IllegalArgumentException ('requests invalid') ]]>
</otherwise>
</choice>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<flow-ref name="Invoke_Service" doc:name="Flow Reference"/>
</flow>
<flow name="Invoke_Service" doc:name="Invoke_Service" tracking:enable-default-events="true">
<cxf:jaxws-client enableMuleSoapHeaders="true" doc:name="SOAP" operation="Request" serviceClass="com.valid.ICase"/>
<until-successful objectStore-ref="objectStore" maxRetries="3" secondsBetweenRetries="2" deadLetterQueue-ref="VM" doc:name="UntilSuccessful_SymboticService">
<http:outbound-endpoint exchange-pattern="request-response" method="POST" doc:name="HTTP" address="http://localhost:1112/symbotic"/>
</until-successful>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger message="**********success***Payload: #[payload]*****" level="INFO" doc:name="Logger"/>
But incase of failure scenario until success retry 3 times ( works fine). I have tried request reply processor inside until also transactional processor. It is not working. Using Mule version 3.4.kindly suggest me.
Retried the same with request -reply processor as per the suggestion
<flow name="Flow" doc:name="eFlow" tracking:enable-default-events="true">
<wmq:inbound-endpoint queue="InputQ" tracking:enable-default-events="true" connector- ref="WMQ_Connector" doc:name="connector">
<wmq:transaction action="NONE"/>
</wmq:inbound-endpoint>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<set-session-variable variableName="originalPayload" value="#[payload]" doc:name="Store_Payload"/>
<choice tracking:enable-default-events="true" doc:name="Choice">
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Master']">
<data-mapper:transform config-ref="Master_grf" doc:name="Master"/>
</when>
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Request']">
<data-mapper:transform config-ref="Request_grf" doc:name="Bulk"/>
</when>
<otherwise>
<scripting:component doc:name="Throw_Exception">
<scripting:script engine="Groovy"><![CDATA[throw new IllegalArgumentException('requests other then Master andRequest') ]]>
</otherwise>
</choice>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<request-reply timeout="10000">
<vm:outbound-endpoint path="request"/>
<vm:inbound-endpoint path="reply"/>
</request-reply>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger message="**********success***Payload: #[payload]*****" level="INFO" doc:name="Logger"/>
</flow>
<flow name="Invoke_Service" doc:name="Invoke_Service" tracking:enable-default-events="true">
<vm:inbound-endpoint path="request" doc:name="VM"/>
<cxf:jaxws-client enableMuleSoapHeaders="true" doc:name="SOAP" operation="Request" serviceClass="com.valid.ICase"/>
<until-successful objectStore-ref="objectStore" maxRetries="3" secondsBetweenRetries="2" deadLetterQueue-ref="VM" doc:name="UntilSuccessful_Service">
<http:outbound-endpoint exchange-pattern="request-response" method="POST" doc:name="HTTP" address="http://localhost:1112/symbotic"/>
</until-successful>
</flow>
Even then getting the null payload. Kindly suggest is this is the way your were directing me. Please correct me if im wrong.
until-successful is an asynchronous processor. It does not return response from service call.
Success or failure are defined as:
If the child message processor throws an exception, this is a failure.
If the child message processor does not return a message (e.g. is a one-way endpoint), this is a success.
If a 'failure expression' (see below) has been configured, the return message is evaluated against this expression to determine failure or not.
Otherwise:
If the child message processor returns a message that contains an exception payload, this is a failure.
If the child message processor returns a message that does not contain an exception payload, this is a success.
http://www.mulesoft.org/documentation/display/current/Routing+Message+Processors#RoutingMessageProcessors-UntilSuccessful
I'm trying to follow the example in this blog post (http://blogs.mulesoft.org/meet-until-successful-store-and-forward-for-mule/) for defining a dead letter queue for an until-successful scope element. This is the snippet from the blog post that doesn't quite make sense:
<vm:endpoint name="dlqChannel" path="dlq" />
<until-successful objectStore-ref="objectStore"
dlqEndpoint-ref="dlqChannel"
maxRetries="3"
secondsBetweenRetries="10">
...
</until-successful>
I don't quite understand where the vm endpoint lives in the app. I don't think it goes in the same flow as the until-successful element. I've tried putting it in its own flow but I get a NoSuchBeanDefinitionException.
Here is my relevant code:
<flow ....>
....
<until-successful objectStore-ref="objectStore" failureExpression="#[header:INBOUND:http.status != 201]" maxRetries="1" secondsBetweenRetries="5" doc:name="Until Successful" deadLetterQueue-ref="aggieFeedDestinedDeadLetterQueue">
....
</flow>
<flow name="edus-pubFlow1" doc:name="edus-pubFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="aggieFeedDestinedDeadLetterQueue" doc:name="aggieFeedDestinedDeadLetterQueue"/>
<logger message="DEAD DEAD DEAD LETTER LETTER LETTER #[message]" level="INFO" doc:name="Logger"/>
</flow>
The dlqChannel attribute refers to a global endpoint. In your case, use:
<vm:inbound-endpoint exchange-pattern="one-way" path="aggieFeedDestinedDeadLetterQueue" />
<flow ....>
....
<until-successful objectStore-ref="objectStore"
failureExpression="#[header:INBOUND:http.status != 201]"
maxRetries="1" secondsBetweenRetries="5"
deadLetterQueue-ref="aggieFeedDestinedDeadLetterQueue">
....
</flow>
<flow name="edus-pubFlow1">
<endpoint ref="aggieFeedDestinedDeadLetterQueue" />
<logger message="DEAD DEAD DEAD LETTER LETTER LETTER #[message]" level="INFO" doc:name="Logger"/>
</flow>
Also if you're using Mule 3.3.0 or above, you can use MEL:
failureExpression="#[message.inboundProperties['http.status'] != 201]"