Mule4: How to define oneway and twoway pattern in IBM MQ connector - mule-studio

How to select oneway or two way in Mule IBM connector Config?
Is there a way we can mention in the config it is oneway or 'twoway (requestReply)' pattern externally. In this new version looks like it is always a 2 way (requestReply). I couldn't see any option to choose as in old connector. I wanted oneway here as i'm not expecting reply for the message.
<flow name="NotificationFlow" doc:id="a275ef91-8608-49a5-adcc-624c2dc6aacd" >
<ibm-mq:listener doc:name="On New Message" doc:id="5de4cf1b-bd66-4519-b170-69f2159bd8b4" config-ref="IBM_MQ_Config" destination="testQ" ackMode="AUTO"/>
<logger level="INFO" doc:name="Logger" doc:id="9c4c241b-d564-44ff-a2a3-6433e48ddf0a" />
<ee:transform doc:name="Transform Message" doc:id="46c10c0c-3f0a-4184-a722-7caab39ca97d" >
<ee:message >
<ee:set-payload ><![CDATA[%dw 2.0
import * from dw::Runtime
var result = []
output application/java
---
if(sizeOf(result) <= 0) fail('Data was empty') else result]]></ee:set-payload>
</ee:message>
</ee:transform>
</flow>
Using Mule version: 4.2.2

With the Mule IBM MQ connector listener operation, responses are automatic only when the message includes a REPLY_TO header. Since the IBM MQ version 1.6.0 it is possible to dissable the automatic REPLY_TO with the ignoreReplyTo attribute.
Example:
So I would not expect any reply by default unless the sender is requesting it using the REPLY_TO header.

Related

Kafka connector error on connecting WSO2 Micro Integrator with Kafka

I'm trying to connect Kafka with wso2 Micro Integrator by following this instructions. I used WSO2's Integration Studio to develop this. Here is the code,
<?xml version="1.0" encoding="UTF-8"?>
<api context="/create-customer" name="create-customer" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<kafkaTransport.init>
<bootstrapServers>localhost:9092</bootstrapServers>
<keySerializerClass>org.apache.kafka.common.serialization.StringSerializer</keySerializerClass>
<valueSerializerClass>org.apache.kafka.common.serialization.StringSerializer</valueSerializerClass>
</kafkaTransport.init>
<kafkaTransport.publishMessages>
<topic>customer</topic>
</kafkaTransport.publishMessages>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
But when I send the request, I got following Error.
[2023-01-14 21:27:36,570] INFO {KafkaProduceConnector} - {api:create-customer} SEND : send message to Broker lists
[2023-01-14 21:27:36,583] ERROR {KafkaProduceConnector} - {api:create-customer} Kafka producer connector : Error sending the message to broker org.wso2.carbon.connector.exception.InvalidConfigurationException: Connection name is not set.
at org.wso2.carbon.connector.KafkaProduceConnector.getConnectionName(KafkaProduceConnector.java:262)
at org.wso2.carbon.connector.KafkaProduceConnector.publishMessage(KafkaProduceConnector.java:237)
at org.wso2.carbon.connector.KafkaProduceConnector.connect(KafkaProduceConnector.java:138)
at org.wso2.carbon.connector.core.AbstractConnector.mediate(AbstractConnector.java:32)
at org.apache.synapse.mediators.ext.ClassMediator.updateInstancePropertiesAndMediate(ClassMediator.java:178)
at org.apache.synapse.mediators.ext.ClassMediator.mediate(ClassMediator.java:97)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:110)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:72)
at org.apache.synapse.mediators.template.TemplateMediator.mediate(TemplateMediator.java:136)
at org.apache.synapse.mediators.template.InvokeMediator.mediate(InvokeMediator.java:170)
at org.apache.synapse.mediators.template.InvokeMediator.mediate(InvokeMediator.java:93)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:110)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:72)
at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:158)
at org.apache.synapse.api.Resource.process(Resource.java:342)
at org.apache.synapse.api.API.process(API.java:477)
at org.apache.synapse.api.AbstractApiHandler.apiProcess(AbstractApiHandler.java:93)
at org.apache.synapse.api.AbstractApiHandler.dispatchToAPI(AbstractApiHandler.java:71)
at org.apache.synapse.api.rest.RestRequestHandler.dispatchToAPI(RestRequestHandler.java:90)
at org.apache.synapse.api.rest.RestRequestHandler.process(RestRequestHandler.java:76)
at org.apache.synapse.rest.RESTRequestHandler.process(RESTRequestHandler.java:54)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:344)
at org.apache.synapse.core.axis2.SynapseMessageReceiver.receive(SynapseMessageReceiver.java:101)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
at org.apache.synapse.transport.passthru.ServerWorker.processNonEntityEnclosingRESTHandler(ServerWorker.java:376)
at org.apache.synapse.transport.passthru.ServerWorker.processEntityEnclosingRequest(ServerWorker.java:435)
at org.apache.synapse.transport.passthru.ServerWorker.run(ServerWorker.java:183)
at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
I'm using MI 4.1.0 version and kafka 2.12 as required in the documentation. The Kafka connector used inside Integration studio is 3.12. As I noticed, according to this reference, inside <kafkaTransport.init> we can send a connection name. But Integration Studio doesn't allows me to add it inside it. When I checked the properties of <kafkaTransport.init>, it doesn't have a connection name field. Can anyone help me to get over this?
Indeed in <kafkaTransport.init> there should be name field usable. That may be a bug. In sourceCode it looks like can be retrieve from message context. Try declare this as property name, like below:
<property name="name" value="Kafka_Sample" scope="default"/>
Set this before <kafkaTransport.publishMessages>

JMS 2.0 durable subscriptions topic best practice in Kubernetes

We are creating a Mule application which will be running in a container on Kubernetes and will be in a replica set that will be connecting to JMS 2.0 Red Hat AMQ 7 (based on ActiveMQ Artemis).
The pom.xml has been configured to get the jms client:
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-jms-client-all</artifactId>
<version>2.10.1</version>
</dependency>
And the JMS config is configured as:
<jms:config name="JMS_Config" doc:name="JMS Config" doc:id="8621b07d-b203-463e-bbbe-76eb03741a61" >
<jms:generic-connection specification="JMS_2_0" username="${mq.user}" password="${mq.password}" clientId="${mq.client.id}">
<reconnection >
<reconnect-forever frequency="${mq.reconnection.frequency}" />
</reconnection>
<jms:connection-factory >
<jms:jndi-connection-factory connectionFactoryJndiName="ConnectionFactory" >
<jms:name-resolver-builder jndiInitialContextFactory="org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory" jndiProviderUrl="${mq.brokerurl}"/>
</jms:jndi-connection-factory>
</jms:connection-factory>
</jms:generic-connection>
<jms:consumer-config>
<jms:consumer-type >
<jms:topic-consumer shared="true" durable="true"/>
</jms:consumer-type>
</jms:consumer-config>
<jms:producer-config persistentDelivery="true"/>
</jms:config>
Then in the JMS listener component:
<jms:listener doc:name="EMS JMS Listener" doc:id="318b4f08-daf6-41f4-944b-3ec1420d5c12" config-ref="JMS_Config" destination="${mq.incoming.queue}" ackMode="AUTO" >
<jms:consumer-type >
<jms:topic-consumer shared="true" subscriptionName="${mq.sub.name}" durable="true"/>
</jms:consumer-type>
<jms:response sendCorrelationId="ALWAYS" />
</jms:listener>
The variables are set as:
mq.client.id=client-id-135a9514-d4d5-4f52-b01c-f6ca34a76b40
mq.sub.name=my-sub
mq.incoming.queue=my-queue
Is this the best way to configure the client? As we have seen errors in the logs when deployed to K8s regarding connections to the AMQ server:
javax.jms.InvalidClientIDException: client-id-135a9514-d4d5-4f52-b01c-f6ca34a76b40 was already set into another connection
In JMS 2.0 you don't have to set the client identifier when creating a shared durable subscription. However, if you do set the client identifier then it must be unique per connection. For whatever reason (e.g. due to Mule or perhaps K8s) multiple connections are being created and since each connection is using the same client identifier you're receiving the javax.jms.InvalidClientIDException.
Remove clientId="${mq.client.id}" from your configuration and the javax.jms.InvalidClientIDException should go away.

How to implement Callback interface using REST API with GET operation in Mule?

How to implement Callback interface using REST API with GET operation in Mule? Any reference example with Mule is welcome
Here are the steps with sample code (with a few assumptions stated at the end):
create RAML mapping in your project's src/main/api:
#%RAML 0.8
---
title: sample
/YourServiceEndpoint
get:
responses:
200:
body:
application/json:
Use APIKit Router in Mule to create a mapping in src/main/app. This uses GET as per the question (you can substitute with POST or any other REST action when writing integration tests for your use-case):
<!-- /api/v1 is defined in the APIKit configuration -->
<flow name="get:/api/v1/YourServiceEndPoint">
<http:inbound-endpoint exchange-pattern="request-response" connector-ref="HTTP_HTTPS" ref="HTTP" doc:name="HTTP"/>
<apikit:router config-ref="APIKitRouter" doc:name="APIkit Router"/>
<exception-strategy ref="Standard_Error_Responses" doc:name="Reference Exception Strategy"/>
<!-- do all other stuff here; for example -->
<when expression="#[payload.containsKey("resultSet1") && payload.get("resultSet1").size() > 0]">
<set-payload value="#[payload.get("resultSet1").get(0)]" doc:name="Set Payload"/>
<json:object-to-json-transformer doc:name="Object to JSON"/>
</when>
</flow>
The above connector-ref requires your global configuration (most probably defined as global-configuration.xml in your project) to have a configuration snippet similar to one as follows:
<https:connector name="HTTPS" enableCookies="true" cookieSpec="netscape" validateConnections="true" sendBufferSize="0" receiveBufferSize="0" receiveBacklog="0" clientSoTimeout="10000" serverSoTimeout="10000" socketSoLinger="0" doc:name="HTTP\HTTPS">
<https:tls-server path="${truststoreLocation}" storePassword="${truststorePassword}"/>
</https:connector>
Assumptions:
APIKit Router requires Enterprise license from Mulesoft/Salesforce, otherwise this does not work.
The snippet paths assume use of Maven. Choose Project > Mavenize if your project does not support maven already.
This is just a suggestion and not relevant to the question. The use-case states "huge data load", which implies this should be handled differently by architecture -- you should probably use SFTP instead of HTTP/HTTPS API.
Helpful note(s):
There are additional samples within the application's Help menu which demonstrate the use of SOAP, Callable interface, etc. That will allow you to move forward.

Mule Persistent storage

I am trying to use persistent queue storage to recover from unexpected failure. My mule version is 3.3.1
I pick up messages from a queue and enter "until successful" loop. If mule stops for some reason, I would like the message to be persistent.
Here is my relevant code
<spring:bean id="outboundStore" class="org.mule.util.store.QueuePersistenceObjectStore" />
<until-successful objectStore-ref="outboundStore"
I do not see the messages in .mule directory. What am I doing wrong?
Sorry if the question is not clear.
Adding Flows as requested:
<flow name="InitialFlow" processingStrategy="synchronous">
<inbound-endpoint ref="firstQueue"/>
<until-successful objectStore-ref="outboundStore" maxRetries="6" secondsBetweenRetries="5" deadLetterQueue-ref="secondQueue" failureExpression="groovy:message.getInvocationProperty('soapResponse') == 'BAD'">
<flow-ref name="somSubFlow" />
</until-successful>
</flow>
<sub-flow name="someSubFlow">
<http:outbound-endpoint ref="someEndpoint" exchange-pattern="request-response" method="GET" />
</sub-flow>
Please do let me know if you need more information.
Using a configuration very similar to yours, I can totally see messages pending delivery written in the .mule/queuestore/queuestore directory.
The only thing I can think of is an issue with this expression groovy:message.getInvocationProperty('soapResponse') == 'BAD' that would somehow mess with the processing.
Is this expression correct? Why not using MEL?

Messages pending in subscriber queue

I am using jboss-5.1 to deploy message driven bean which is used to subscribe messages from a third party queue.
Around 16 messages were posted to that queue but they remained pending in our subscriber queue. I restarted the server and the messages were readily picked.
As much as I have analysed, I think maxsize and maxsession could have affected it, as both are 15. But I do not understand if there was some real issue, how it got solved by just restarting.
The logs were in error mode. I did not get the full stack trace.
This is the snippet of that error log.
[2012-10-30 17:01:00,228] [MQQueueAgent (GQH1_PLANNING_MDM_001)]
[ERROR] STDERR: 2012.10.30 17:01:00 MQJMS1023E rollback failed
[2012-10-30 17:01:00,228] [exceptionDelivery0] [WARN ]
org.jboss.resource.adapter.jms.inflow.JmsActivation: Failure in jms activation
org.jboss.resource.adapter.jms.inflow.JmsActivationSpec#85d0d(ra=org.jboss.resource.adapter.jms.JmsResourceAdapter#b21aae
destination=remotewsmq/NOTIFICATION_PLANNING_MDM_001.SUBQ
destinationType=javax.jms.Queue tx=true durable=false reconnect=10 provider=RemoteWSMQJMSProvider
user=null maxMessages=1 minSession=1 maxSession=5 keepAlive=60000 useDLQ=false)
GQH1_PLANNING_MDM_001: The name of the queue used for subscribing.
The files that I use to configure the properties of the MDBs are as follows.
1.ejb3-interceptors-aop.xml
<domain name="Message Driven Bean" extends="Intercepted Bean" inheritBindings="true">
<bind pointcut="execution(public * *->*(..))">
<interceptor-ref name="org.jboss.ejb3.security.AuthenticationInterceptorFactory"/>
<interceptor-ref name="org.jboss.ejb3.security.RunAsSecurityInterceptorFactory"/>
</bind>
<!-- TODO: Authorization? -->
<bind pointcut="execution(public * *->*(..))">
<interceptor-ref name="org.jboss.ejb3.tx.CMTTxInterceptorFactory"/>
<interceptor-ref name="org.jboss.ejb3.stateless.StatelessInstanceInterceptor"/>
<interceptor-ref name="org.jboss.ejb3.tx.BMTTxInterceptorFactory"/>
<interceptor-ref name="org.jboss.ejb3.AllowedOperationsInterceptor"/>
<interceptor-ref name="org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor"/>
<!-- interceptor-ref name="org.jboss.ejb3.interceptor.EJB3InterceptorsFactory"/ -->
<stack-ref name="EJBInterceptors"/>
</bind>
<annotation expr="class(*) AND !class(#org.jboss.ejb3.annotation.Pool)">
#org.jboss.ejb3.annotation.Pool (value="StrictMaxPool", maxSize=15, timeout=10000)
</annotation>
</domain>
2.standardjboss.xml
<invoker-proxy-binding>
<name>message-driven-bean</name>
<invoker-mbean>default</invoker-mbean>
<proxy-factory>org.jboss.ejb.plugins.jms.JMSContainerInvoker</proxy-factory>
<proxy-factory-config>
<JMSProviderAdapterJNDI>DefaultJMSProvider</JMSProviderAdapterJNDI>
<ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>
<CreateJBossMQDestination>false</CreateJBossMQDestination>
<!-- WARN: Don't set this to zero until a bug in the pooled executor is fixed -->
<MinimumSize>1</MinimumSize>
<MaximumSize>15</MaximumSize>
<KeepAliveMillis>30000</KeepAliveMillis>
<MaxMessages>1</MaxMessages>
<MDBConfig>
<ReconnectIntervalSec>10</ReconnectIntervalSec>
<DLQConfig>
<DestinationQueue>queue/DLQ</DestinationQueue>
<MaxTimesRedelivered>10</MaxTimesRedelivered>
<TimeToLive>0</TimeToLive>
</DLQConfig>
</MDBConfig>
</proxy-factory-config>
</invoker-proxy-binding>
<activation-config-property>
<activation-config-property-name>maxSession</activation-config-property-name>
<activation-config-property-value>15</activation-config-property-value>
</activation-config-property>
3.jms-ds.xml
<?xml version="1.0" encoding="UTF-8"?>
<connection-factories>
<!-- ==================================================================== -->
<!-- JMS Stuff -->
<!-- ==================================================================== -->
<!--
The JMS provider loader. Currently pointing to a non-clustered ConnectionFactory. Need to
be replaced with a clustered non-load-balanced ConnectionFactory when it becomes available.
See http://jira.jboss.org/jira/browse/JBMESSAGING-843.
-->
<mbean code="org.jboss.jms.jndi.JMSProviderLoader"
name="jboss.messaging:service=JMSProviderLoader,name=JMSProvider">
<attribute name="ProviderName">DefaultJMSProvider</attribute>
<attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
<attribute name="FactoryRef">java:/XAConnectionFactory</attribute>
<attribute name="QueueFactoryRef">java:/XAConnectionFactory</attribute>
<attribute name="TopicFactoryRef">java:/XAConnectionFactory</attribute>
</mbean>
<!-- JMS XA Resource adapter, use this to get transacted JMS in beans -->
<tx-connection-factory>
<jndi-name>JmsXA</jndi-name>
<xa-transaction/>
<rar-name>jms-ra.rar</rar-name>
<connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>
<config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>
<config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:/DefaultJMSProvider</config-property>
<max-pool-size>20</max-pool-size>
<security-domain-and-application>JmsXARealm</security-domain-and-application>
<depends>jboss.messaging:service=ServerPeer</depends>
</tx-connection-factory>
</connection-factories>
Please help.
If the listener did not try to reconnect, then it might be the messages pending which caused it to fail.
According to the error, a transaction ROLLBACK call failed. After the failure, the queue manager probably held those messages in an outstanding unit of work. Restarting the server would have closed the connection at which point the queue manager will have rolled back the transaction on behalf of the application. On restart, the application will create a new UOW and retrieve the messages.
Look in WebSphere MQ's queue manager error logs and global error logs to determine whether the error was caused by a resource shortage. It may be necessary to increase the size of the queue manager transaction logs or to tune transaction parameters such as MAXUOW.
You may also need to update the MQ client version or Queue Manager version. According to this Technote, WebSphere MQ JMS classes were updated as of 6.0.2.3 to fix a bug that resulted in MQJMS1023E errors. If you need to update the client version, it is available as a free download as SupportPac MQC75. A new client is able to run with any back level queue manager. After upgrading, the app benefits from the bug fixes and performance enhancements of the new client code and provides API functionality appropriate for the version of Queue Manager to which it connects. What version of WebSphere MQ JMS client is currently installed? What version of WebSphere MQ queue manager is currently installed?