I have got simple setup of mule. Reading from JMS queue processing message and in case of exception sending to DLQ. With Mule 3.3.0 and HornetQ 2.3.0.BETA1. I am getting following exception:
Caused by: java.lang.ClassCastException: org.mule.transport.jms.ReusableTopicSessionWrapper cannot be cast to javax.jms.QueueSession
at org.mule.transport.jms.Jms102bSupport.createDestination(Jms102bSupport.java:231)
at org.mule.transport.jms.Jms11Support.createDestination(Jms11Support.java:142)
at org.mule.transport.jms.JmsMessageDispatcher.dispatchMessage(JmsMessageDispatcher.java:163)
at org.mule.transport.jms.JmsMessageDispatcher.doDispatch(JmsMessageDispatcher.java:81)
at org.mule.transport.AbstractMessageDispatcher.process(AbstractMessageDispatcher.java:99)
... 113 more
My setup:
<jms:connector name="connector.jms" maxRedelivery="10" doc:name="JMS"
jndiInitialFactory="org.jnp.interfaces.NamingContextFactory"
jndiProviderUrl="jnp://localhost:1099"
connectionFactoryJndiName="ConnectionFactory"
createMultipleTransactedReceivers="true"
numberOfConcurrentTransactedReceivers="100"
acknowledgementMode="AUTO_ACKNOWLEDGE">
<reconnect-forever frequency="5000"/>
</jms:connector>
<flow name="jmsListenerFlow1" doc:name="jmsListenerFlow1">
<jms:inbound-endpoint queue="adsLogQueue" connector-ref="connector.jms" doc:name="JMS">
<jms:transaction action="ALWAYS_BEGIN"/>
</jms:inbound-endpoint>
<component >
<spring-object bean="logSaver"/>
</component>
<catch-exception-strategy>
<jms:outbound-endpoint queue="DLQ"> <!-- [2] -->
<jms:transaction action="ALWAYS_JOIN" />
</jms:outbound-endpoint>
</catch-exception-strategy>
</flow>
Can it be bug in Mule itself ? Or am I doing something wrong?
Set specification="1.1" on the jms:connector.
Related
I have a Mule flow which updates Magento Invtory through SOAP API. Everything runs great until I try to update an item which is not in the Magento Database. I then get an exception.
ERROR 2016-06-17 12:31:06,523 [[bwgs-to-magento].bwgs-to-magentoFlow.stage1.02] org.mule.retry.notifiers.ConnectNotifier: Failed to connect/reconnect: Work Descriptor. Root Exception was: Product not exists.. Type: class org.apache.axis.AxisFault
My exception strategy is this:
<choice-exception-strategy doc:name="Choice Exception Strategy">
<catch-exception-strategy when="#[exception.causedExactlyBy(org.mule.api.MessagingException)]" doc:name="Catch Exception Strategy">
<logger message="error" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</choice-exception-strategy>
My desired result is when an exception occurs, log it, but keep processing the flow.
Edit:
I have also tried the following exception strategy:
<choice-exception-strategy doc:name="Choice Exception Strategy">
<catch-exception-strategy when="#[exception.causeMatches(org.mule.api.*)]" enableNotifications="true" doc:name="Catch Exception Strategy">
<logger message="#[exception.cause.message]" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</choice-exception-strategy>
Here is the error syntax:
ERROR 2016-06-20 10:47:03,080 [[bwgs-to-magento].bwgs-to-magentoFlow.stage1.02] org.mule.exception.DefaultMessagingExceptionStrategy:
Message : Failed to invoke updateInventoryStockItem. Message payload is of type: String[]
Type : org.mule.api.MessagingException
Code : MULE_ERROR--2
Payload : [Ljava.lang.String;#191acd5
JavaDoc : http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.html
Exception stack is:
1. Product not exists. (org.apache.axis.AxisFault)
org.apache.axis.message.SOAPFaultBuilder:222 (null)
2. Product not exists. (org.mule.module.magento.api.MagentoException)
org.mule.module.magento.api.MagentoClientAdaptor:83 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/module/magento/api/MagentoException.html)
3. Failed to invoke updateInventoryStockItem. Message payload is of type: String[] (org.mule.api.MessagingException)
org.mule.devkit.processor.DevkitBasedMessageProcessor:133 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.html)
The best way to handle this scenario is your flow design. Put the Magento operation and the exception strategy in their own private flow and reference it from another flow. This way the exception will be caught and handled in the private flow and processing will return to the main flow where you can continue doing anything you want. For example:
<flow name="main-flow">
<flow-ref name="magento-flow" />
<logger level="INFO" message="This will continue processing" />
</flow>
<flow name="magento-flow">
<magento ... />
<choice-exception-strategy doc:name="Choice Exception Strategy">
<catch-exception-strategy when="#[exception.causeMatches(org.mule.api.*)]" enableNotifications="true" doc:name="Catch Exception Strategy">
<logger message="#[exception.cause.message]" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</choice-exception-strategy>
</flow>
In the MagnetoFlow make the flow end at DB level with flowRef and rest of the logic will continue in the next flow.If suppose exception happens it will caught in exception strategy. Here you log the exception and keep continue with the flow Ref of pendingLogic_MagnetoFlow. Check in choice whether the payload is available to continue( because here flow if flow continue from exception payload mightn't present), if so use the sessionVars where you have stored in session variable to continue with other logics.
<flow name="magnetoFlow">
<set-session-variable variableName="originalPayload" value="#[payload]" doc:name="Session Variable"/>
---DB here----
<flow-ref name="pendingLogicFrom_MagnetoFlow" doc:name="Flow Reference"/>
<catch-exception-strategy doc:name="Catch Exception Strategy" when="#[exception.causeMatches(org.mule.api.*)]">
<logger message="#[exception.cause.message]" level="INFO" doc:name="Logger"/>
<flow-ref name="pendingLogicFrom_MagnetoFlow" doc:name="pendingLogicFrom_MagnetoFlow"/>
</catch-exception-strategy>
</flow>
<flow name="pendingLogicFrom_MagnetoFlow">
<choice doc:name="Choice">
<when expression="#[check the payload is empty or not here ]">
<set-payload value="#[seesionVars.originalPayload]" doc:name="Set Payload"/>
</when>
<otherwise>
<logger level="INFO" doc:name="Logger"/>
</otherwise>
</choice>
<logger level="INFO" doc:name="Logger"/>
---other normal logic here ---
</flow>
Check this out.
I am using Spring Integration to send notifications and as an error test case, I am sending in malformed JSON (a Map) and am getting MessagingException which seems to just go on and on.. not stopping.. I have to kill the Application.
So want to know how to capture this, may be via errorChannel. Code examples would be helpful.
My Spring Integration config:
<!-- channel to connect to disruption exchange -->
<int-amqp:publish-subscribe-channel id="inputChannel"
connection-factory="connectionFactory"
exchange="notification.exchange"/>
<int:json-to-object-transformer input-channel="inputChannel"
output-channel="notificationChannel"
type="java.util.Map"/>
<int:channel id="notificationChannel">
<int:interceptors>
<int:wire-tap channel="loggingChannel"/>
</int:interceptors>
</int:channel>
<int:logging-channel-adapter id="loggingChannel" log-full-message="true" logger-name="tapInbound" level="INFO"/>
<!-- depending on the deviceType route to either apnsChannel or gcmChannel -->
<int:router ref="notificationTypeRouter" input-channel="notificationChannel"/>
<!-- apple push notification channel-->
<int:channel id="apnsChannel"/>
<!-- service activator to process disruptionNotificationChannel -->
<int:service-activator input-channel="apnsChannel" ref="apnsPushNotificationService" method="pushNotification"/>
<!-- google cloud messaging notification channel-->
<int:channel id="gcmChannel"/>
<!-- service activator to process disruptionNotificationChannel -->
<int:service-activator input-channel="gcmChannel" ref="gcmPushNotificationService" method="pushNotification"/>
<!-- error channel to may be log to file or email or store to db in the future -->
<int:channel id="errorChannel"/>
<int:service-activator input-channel="errorChannel" ref="notificationErrorHandler" method="handleFailedNotification"/>
<!-- Infrastructure -->
<rabbit:connection-factory id="connectionFactory"
host="${spring.rabbitmq.host}"
port="${spring.rabbitmq.port}"
username="${spring.rabbitmq.username}"
password="${spring.rabbitmq.password}"/>
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
<rabbit:admin connection-factory="connectionFactory"/>
<rabbit:fanout-exchange name="notification.exchange"/>
I also have an error handler:
public class NotificationErrorHandler {
private final Logger LOG = LoggerFactory.getLogger(NotificationErrorHandler.class);
public void handleFailedNotification(Message<MessageHandlingException> message) {
Map<String, Object> map = (Map) message.getPayload();
Notification notification = Notification.fromMap(map);
saveToBD(notification);
}
private void saveToBD(Notification notification) {
LOG.error("[Notification-Error-Handler] Couldn't Send Push notification: device='{}', type='{}', pushId='{}', message='{}', uid='{}'",
new Object[]{notification.getDevice(),
notification.getDeviceType(),
notification.getDeviceToken(),
notification.getBody(),
notification.getUid()});
}
}
This is the exception:
Caused by: org.springframework.messaging.MessagingException: Failure occured in AMQP listener while attempting to convert and dispatch Message.; nested exception is org.springframework.integration.transformer.MessageTransformationException: failed to transform message; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('}' (code 125)): was expecting double-quote to start field name
at [Source: [B#7a707c2c; line: 7, column: 2]
at org.springframework.integration.amqp.channel.AbstractSubscribableAmqpChannel$DispatchingMessageListener.onMessage(AbstractSubscribableAmqpChannel.java:202)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:799)
... 10 common frames omitted
Caused by: org.springframework.integration.transformer.MessageTransformationException: failed to transform message; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('}' (code 125)): was expecting double-quote to start field name
at [Source: [B#7a707c2c; line: 7, column: 2]
at org.springframework.integration.transformer.AbstractTransformer.transform(AbstractTransformer.java:44)
at org.springframework.integration.transformer.MessageTransformingHandler.handleRequestMessage(MessageTransformingHandler.java:68)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:99)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:160)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:142)
at org.springframework.integration.amqp.channel.AbstractSubscribableAmqpChannel$DispatchingMessageListener.onMessage(AbstractSubscribableAmqpChannel.java:181)
... 11 common frames omitted
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('}' (code 125)): was expecting double-quote to start field name
at [Source: [B#7a707c2c; line: 7, column: 2]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1419)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:508)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:437)
Hope someone can help.
Thanks in advance
GM
Changes made as per #Gary's answer and its working now:
<!-- Infrastructure -->
<rabbit:connection-factory id="connectionFactory"
host="${spring.rabbitmq.host}"
port="${spring.rabbitmq.port}"
username="${spring.rabbitmq.username}"
password="${spring.rabbitmq.password}"/>
<rabbit:admin connection-factory="connectionFactory"/>
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
<rabbit:direct-exchange name="notification.direct">
<rabbit:bindings>
<rabbit:binding queue="notification.queue" key="notification.queue"/>
</rabbit:bindings>
</rabbit:direct-exchange>
<rabbit:queue id="notification.queue" name="notification.queue"/>
<int-amqp:inbound-channel-adapter channel="inputChannel"
queue-names="notification.queue"
connection-factory="connectionFactory"
error-channel="errorChannel"/>
<int:json-to-object-transformer input-channel="inputChannel"
output-channel="notificationChannel"
type="java.util.Map"/>
<int:channel id="notificationChannel">
<int:interceptors>
<int:wire-tap channel="loggingChannel"/>
</int:interceptors>
</int:channel>
<int:logging-channel-adapter id="loggingChannel" log-full-message="true" logger-name="tapInbound" level="INFO"/>
<!-- depending on the deviceType route to either apnsChannel or gcmChannel -->
<int:router ref="notificationTypeRouter" input-channel="notificationChannel"/>
<!-- apple push notification channel-->
<int:channel id="apnsChannel"/>
<!-- service activator to process disruptionNotificationChannel -->
<int:service-activator input-channel="apnsChannel" ref="apnsPushNotificationService" method="pushNotification"/>
<!-- google cloud messaging notification channel-->
<int:channel id="gcmChannel"/>
<!-- service activator to process disruptionNotificationChannel -->
<int:service-activator input-channel="gcmChannel" ref="gcmPushNotificationService" method="pushNotification"/>
<!-- no op channel where message is logged for unknown devices -->
<int:channel id="noOpChannel"/>
<!-- service activator to process disruptionNotificationChannel -->
<int:service-activator input-channel="noOpChannel" ref="noOpPushNotificationService" method="pushNotification"/>
<!-- error channel to may be log to file or email or store to db in the future -->
<int:channel id="errorChannel"/>
<int:service-activator input-channel="errorChannel" ref="notificationErrorHandler"/>
Why are you starting the flow with a pub-sub channel? It's not normal to use a pub/sub channel for message distribution.
If you can use a message-driven channel adapter instead, you can add an error-channel.
You can't add an error channel to a pub-sub channel. You can, however inject an error-handler (implements org.springframework.util.ErrorHandler) and throw an AmqpRejectAndDontRequeueException when you detect a fatal error.
You can also use a Json MessageConverter in the channel instead of using a Json transformer downstream in the flow; in that case, the default error handler will detect a message conversion exception and reject the message rather than requeueing it.
I have two separate messages being published to a staging.queue. I want the JMS consumer of the staging queue to wait 10 seconds before consumer all the messages from the staging.queue. I have the following strategy:
<jms:activemq-connector name="Active_MQ" username="admin" password="admin" brokerURL="tcp://localhost:61616" validateConnections="true" doc:name="Active MQ">
<service-overrides transactedMessageReceiver="com.mulesoft.mule.transport.jms.TransactedPollingJmsMessageReceiver" />
</jms:activemq-connector>
<flow name="integration-consumer-client2" doc:name="integration-consumer-client2">
<jms:inbound-endpoint queue="client2.publish" connector-ref="Active_MQ" doc:name="JMS">
</jms:inbound-endpoint>
<logger message="Consumes Client 2 = #[payload]" level="INFO" doc:name="Logger"/>
<logger message="Client 2 Correlation = #[message.correlationId] and Correlation sequence = #[message.correlationSequence]" level="INFO" doc:name="Logger"/>
<json:object-to-json-transformer doc:name="Object to JSON"/>
<jms:outbound-endpoint queue="waiting.queue" connector-ref="Active_MQ" doc:name="JMS"/>
</flow>
<flow name="integration-consumer-client" doc:name="integration-consumer-client">
<jms:inbound-endpoint doc:name="JMS" connector-ref="Active_MQ" queue="client1.publish">
</jms:inbound-endpoint>
<logger message="Consumes Client 1 = #[payload]" level="INFO" doc:name="Logger"/>
<logger message="Client Correlation = #[message.correlationId] and Correlation sequence = #[message.correlationSequence]" level="INFO" doc:name="Logger"/>
<json:object-to-json-transformer doc:name="Object to JSON"/>
<jms:outbound-endpoint queue="waiting.queue" connector-ref="Active_MQ" doc:name="JMS"/>
</flow>
<flow name="integration-Flow3" doc:name="integration-Flow3">
<jms:inbound-endpoint queue="staging.queue" connector-ref="Active_MQ" doc:name="JMS">
<properties>
<spring:entry key="pollingFrequency" value="10000" />
</properties>
</jms:inbound-endpoint>
<logger message="after poller = #[payload]" level="INFO" doc:name="Logger"/>
</flow>
but the consumer doesn't wait 10 seconds. it consumes the messages immediately
You can do it by following way :-
Make integration-Flow3 as a sub flow
Use flow-ref to call the subflow integration-Flow3 after jms:outbound-endpoint of both the flow :- integration-consumer-client2 and integration-consumer-client
Now in the beginning of subflow integration-Flow3 remove JMS inbound endpoint and use a Groovy Script where you can define sleep(Your time)
Then after Groovy Script use Mule Module Requester component to call the JMS inbound endpoint ..
Mule Module Requester is the component that can able to call any inbound endpoint in the middle of the flow ..
You can found details of Mule Module Requester here https://github.com/mulesoft/mule-module-requester and http://blogs.mulesoft.org/introducing-the-mule-requester-module/
Just use it to call JMS inbound endpoint with queue="staging.queue" ..
Since you will be using GroovyScript before Mule Module Requester .. Groovy script will take care of holding the timer .. (You need to set sleep() method inside your Groovy Script ) .. That's all
currently I am working with mule and need to write in WMQ Queue. But instead of using WMQ endpoint, I want to do it by using JMS Endpoint. Here is my configuration:
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:jms="http://www.mulesoft.org/schema/mule/jms" xmlns:jetty="http://www.mulesoft.org/schema/mule/jetty" xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting" xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns:wmq="http://www.mulesoft.org/schema/mule/ee/wmq" xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns:json="http://www.mulesoft.org/schema/mule/json" xmlns:data-mapper="http://www.mulesoft.org/schema/mule/ee/data-mapper" xmlns:ajax="http://www.mulesoft.org/schema/mule/ajax" xmlns:jersey="http://www.mulesoft.org/schema/mule/jersey" 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:spring="http://www.springframework.org/schema/beans" version="EE-3.4.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
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://www.mulesoft.org/schema/mule/jersey http://www.mulesoft.org/schema/mule/jersey/current/mule-jersey.xsd
http://www.mulesoft.org/schema/mule/ajax http://www.mulesoft.org/schema/mule/ajax/current/mule-ajax.xsd
http://www.mulesoft.org/schema/mule/ee/data-mapper http://www.mulesoft.org/schema/mule/ee/data-mapper/current/mule-data-mapper.xsd
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd
http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/current/mule-xml.xsd
http://www.mulesoft.org/schema/mule/ee/wmq http://www.mulesoft.org/schema/mule/ee/wmq/current/mule-wmq-ee.xsd
http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd
http://www.mulesoft.org/schema/mule/jetty http://www.mulesoft.org/schema/mule/jetty/current/mule-jetty.xsd
http://www.mulesoft.org/schema/mule/jms http://www.mulesoft.org/schema/mule/jms/current/mule-jms.xsd">
<wmq:connector name="WMQ" hostName="localhost" port="1414" queueManager="localmanager" validateConnections="true" doc:name="WMQ" ccsId="819"/>
<data-mapper:config name="map_to_xml" transformationGraphPath="map_to_xml.grf" doc:name="map_to_xml"/>
<data-mapper:config name="xml_to_json" transformationGraphPath="xml_to_json.grf" doc:name="xml_to_json"/>
<jms:connector name="jmsConnector"
connectionFactoryJndiName="jms/ConnectionFactory"
jndiInitialFactory="com.ibm.websphere.naming.WsnInitialContextFactory"
specification="1.1"
connectionFactory-ref="MQConnectionFactory">
<spring:property name="jmsSupport" ref="customJmsSupport"/>
</jms:connector>
<spring:beans>
<spring:bean id="customJmsSupport" class="CustomJms11Support">
<spring:constructor-arg ref="jmsConnector" />
</spring:bean>
<spring:bean name="MQConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<spring:property name="hostName" value="localhost"/>
<spring:property name="port" value="1414"/>
<spring:property name="queueManager" value="localmanager"/>
<spring:property name="transportType" value="1"/>
</spring:bean>
</spring:beans>
<flow name="RequestFlow" doc:name="RequestFlow">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8088" path="uebermittleAusweisdaten" doc:name="HTTP" contentType="text/html"/>
<expression-filter expression="#[message.payload !='/favicon.ico']" doc:name="Expression"/>
<jersey:resources doc:name="REST">
<component class="de.fraport.sources.RestClass"/>
</jersey:resources>
<set-variable variableName="id" value="#[message.id]" doc:name="Message ID"/>
<json:json-to-object-transformer returnClass="java.util.Map" doc:name="JSON to Object"/>
<data-mapper:transform config-ref="map_to_xml" doc:name="Map To XML">
<data-mapper:input-arguments>
<data-mapper:input-argument key="id">#[flowVars['id']]</data-mapper:input-argument>
</data-mapper:input-arguments>
</data-mapper:transform>
<flow-ref name="Subflow1" doc:name="Flow Reference"/>
<parse-template location="D:\Workspace\ajax_rest\src\main\app\www\index.html" doc:name="Parse Template"/>
</flow>
<sub-flow name="Subflow1" doc:name="Subflow1">
<mulexml:xslt-transformer encoding="ISO8859-1" maxIdleTransformers="2" maxActiveTransformers="5" xsl-file="D:\Workspace\ajax_rest\mobako.sender.xsl" doc:name="SOAP Envelope"/>
<mulexml:dom-to-xml-transformer outputEncoding="ISO8859-1" doc:name="DOM to XML"/>
<outbound-endpoint doc:name="JMS" address="jms://LSMH.ZKSEAP.SERVICEBUS" connector-ref="jmsConnector" encoding="ISO8859-1"/>
<!-- <wmq:outbound-endpoint queue="LSMH.ZKSEAP.SERVICEBUS" encoding="ISO8859-1" connector-ref="WMQ" doc:name="ZKSEAP IN"/> -->
<set-property propertyName="MULE_CORRELATION_ID" value="#[function:dateStamp:yyyy-MM-dd HH:mm:ss]" doc:name="Set Correlation ID"/>
<request-reply>
<vm:outbound-endpoint path="sender">
<message-properties-transformer scope="outbound">
<delete-message-property key="MULE_REPLYTO"/>
</message-properties-transformer>
</vm:outbound-endpoint>
<vm:inbound-endpoint path="response">
<logger level="INFO" message="#[string:XXXXXX 1: #[message.inboundProperties]"/>
</vm:inbound-endpoint>
</request-reply>
</sub-flow>
<flow name="ResponseFlow" doc:name="ResponseFlow">
<inbound-endpoint address="jms://ZKSEAP.LSMH.SERVICEBUS" connector-ref="jmsConnector" doc:name="ZKSEAP OUT"/>
<!-- <wmq:inbound-endpoint queue="ZKSEAP.LSMH.SERVICEBUS" connector-ref="WMQ" doc:name="ZKSEAP OUT" encoding="UTF-8"/> -->
<set-property propertyName="MULE_CORRELATION_ID" value="#[function:dateStamp:yyyy-MM-dd HH:mm:ss]" doc:name="Set Correlation ID"/>
<data-mapper:transform doc:name="XML To JSON" config-ref="xml_to_json"/>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<vm:outbound-endpoint path="response" doc:name="Response Outbound" exchange-pattern="one-way"/>
</flow>
</mule>
I have successfully read message from WMQ Queue by using JMS endpoint. However, when I tried to write some message in WMQ Queue by using JMS Endpoint, I got following error from my server:
2014-07-22 10:11:27,064 [Axis2 Task] ERROR WMQMsg - Expected MQ
message format ' MQSTR ', but received 'MQHRF2 ' 2014-07-22
10:11:27,064 [Axis2 Task] WARN QMgrConnection - Moving msg into dead
letter queue after 1 try/tries:
414D51206C6F63616C6D616E616765721A0CCE5320003C0 2 [Fatal Error] :1:1:
Content ist nicht zulõssig in Prolog. ERROR: 'Content ist nicht
zulõssig in Prolog.' 2014-07-22 10:11:27,064 [Axis2 Task] WARN ESBMsg
- Error prettifying ESBMsg for log printing
I know that this error occured because I tried to write into Non-JMS Queue. Also I know that I have to solve it by setting "?targetClient=1". However, when I tried to add the targetClient attribute into my Queue URL, I still got the error (it seems that the attribute was recognized as URL too by WMQ).
Then, from my research, I found out that I can not directly set the "?targetClient" in the url. Instead of that, I need to create a Java Class to set the "?targetClient". To create those class, I follow some instructions from following URL
Create Custom JMSSupport Class
But unfortunatelly, it also did not work for me. Anyone has an idea about how can I solve it? Thanks.
NB: In Apache Camel, I can simply solve it by adding:
<setHeader headerName="CamelJmsDestinationName">
<constant>queue:///LSMH.ZKSEAP.SERVICEBUS?targetClient=1</constant>
</setHeader>
Is there something similar in Mule ESB?
Just solved the problem:
It is right that we need to create a java class to set the targetClient. And to do so, we can follow the link that I gave above. However, we will need to change the code a bit.
Here is the right code:
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Session;
import org.mule.api.endpoint.ImmutableEndpoint;
import org.mule.transport.jms.Jms11Support;
import org.mule.transport.jms.JmsConnector;
import com.ibm.mq.jms.JMSC;
import com.ibm.mq.jms.MQQueue;
/**
* Implements WebSphere MQ specific JMS support for Mule. The class
* overrides the createDestination method to intercept JMS Queue object
* creation and sets the targetClient=1 property on created MQQueue
* objects. This is necessary to prevent non-JMS consumers from being
* choked by RFH2 headers.
*/
public class CustomJms11Support extends Jms11Support {
public CustomJms11Support(JmsConnector connector) {
super(connector);
}
#Override
public Destination createDestination(Session session, String name, boolean
topic, ImmutableEndpoint ie) throws JMSException {
Destination destination = super.createDestination(session, name, topic, ie);
if (destination instanceof MQQueue){
((MQQueue) destination).setTargetClient(JMSC.MQJMS_CLIENT_NONJMS_MQ);
}
return destination;
}
}
And then, we will need to set a property called "JMS_IBM_Character_Set" (If not we will get "Expected MQ message characterSet '819', but received '1208'" error) before send the request to JMS endpoint. Here is how I configure it:
<set-property propertyName="JMS_IBM_Character_Set" value="ISO8859_1" doc:name="Property"/>
And just for your information, by changing the WMQ endpoint to JMS endpoint, for sure it improve the performance.
Hopefully it would be useful :D
/*Below Spring-integration configuration*/
/*Listener*/
<!--Reading the Message from Queue as a Listener -->
<int-jms:inbound-gateway connection-factory="MQConnectionFactory"
request-destination="ReadWsRequestQueue"
request-channel="ReadWsInputChannel"
transaction-manager="hibernateTransactionManager"
error-channel="errorReadChannel"/>
/*Processing Message*/
<!--Processing the message-->
<int:chain input-channel="ReadWsInputChannel">
<int:transformer ref="ReadUnmarshaller"/>
<int:transformer ref="RequestBuilder" method="build"/>
<int:service-activator ref="ReadService" method="registerRead" />
<int:transformer ref="ResponseBuilder" method="buildResponse"/>
<int:transformer ref="ReadMarshaller"/>
<int:transformer ref="toStringTransformer"/>
/*Error Channel config*/
<!--Error channel configuration -->
<int:channel id="errorReadChannel"/>
<int:chain input-channel="errorReadChannel">
<int-jms:outbound-gateway id="jmsOutboundGateway"
connection-factory="MQConnectionFactory"
request-destination="DLQErrorQueue" />
</int:chain>
Question:
In service Activator method we are throwing a RuntimeException, which should get redirected to the error channel??
All the exceptions should go to the error-channel,
Question 2.)
Also is there any way in Spring-integration by which we can forward the exception causing actual MQ message to a separate channel?