how to set Fixed backoff for MQQueueConnectionFactory - jms

I have implemented for DefaultJmsListenerContainerFactory its works fine, now I am looking to implement for IBM MQ( MQQueueConnectionFactory looking for the solution) below is example snippet from DefaultJmsListenerContainerFactory.
Expecting :
FixedBackOff{interval=200, currentAttempts=1, maxAttempts=7}`
DefaultJmsListenerContainerFactory ---->
FixedBackOff{interval=5000, currentAttempts=1, maxAttempts=unlimited}
I want to override interval and maxAttempts.
FixedBackOff backOff=new FixedBackOff();
backOff.setInterval(200);
backOff.setMaxAttempts(7);
factory.setBackOff(backOff);
factory.setErrorHandler(
new ErrorHandler() {
#Override
public void handleError(Throwable t) {
logger.error("An error has occurred in the transaction of JMSconnectionFactory");
}
});

In general do not use QueueConnectionFactory or TopicConnectionFactory, as ConnectionFactory (JMS 1.1) is replacement for both.
Spring xml configuration example:
<bean id="mqConnectionFactory" class="com.ibm.mq.jms.MQConnectionFactory"
p:queueManager="${QM_NAME}"
p:hostName="${QM_HOST_NAME}"
p:port="${QM_HOST_PORT}"
p:channel="${QM_CHANNEL}"
p:clientID="${QM_CLIENT_ID}">
<property name="transportType">
<util:constant static-field="com.ibm.msg.client.wmq.WMQConstants.WMQ_CM_CLIENT" />
</property>
</bean>
<bean id="messageListener" class="com.stackowerflow.example.MyMessageListenerStub" />
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"
p:corePoolSize="5"
p:maxPoolSize="10"
p:queueCapacity="25" />
<bean id="backOff" class="org.springframework.util.backoff.FixedBackOff"
p:interval="5000"
p:maxAttempts="10" />
<bean id="msgListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"
p:connectionFactory-ref="mqConnectionFactory"
p:destinationName="${QM_DESTINATION}"
p:messageListener-ref="messageListener"
p:taskExecutor-ref="taskExecutor"
p:backOff-ref="backOff" />

Related

Spring configuration split between xml resource and Java configuration

I am trying to mix both xml and Java Configuration.
I have a spring-security.xml resource that I import in my application boot.
Say this was a part of the initial xml:
<bean id="ldapContextSource" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="${ldap.url}" />
<property name="base" value="${ldap.base}" />
<property name="userDn" value="${ldap.user}" />
<property name="password" value="${ldap.password}" />
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="ldapContextSource" />
</bean>
Can I move just this part to be a Java config ? Or would the references be an issue.
Thank You
You can move it to Java Config
Declare configuration class
#Configuration
public class AppConfig {
#Bean
public LdapContextSource ldapContextSource(){
LdapContextSource lcontext = new LdapContextSource();
lcontext.setUrl("${ldap.url}");
lcontext.setBase("${ldap.base}");
lcontext.setUserDn("${ldap.user}");
lcontext.setPassword("${ldap.password}");
return lcontext;
}
#Bean
public LdapTemplate LdapTemplate(){
LdapTemplate lTemplate = new LdapTemplate(ldapContextSource());
return lTemplate;
}
}
In your XML add
<context:annotation-config/>
<bean class="com.mypackage.AppConfig"/>

Using topics but not all the consumers take the message

I want to create a sender to generate message and the send it to all consumers.
I am using topic, but something is wrong, if for example I have 3 consumers, only one takes the message in a random way.
I donĀ“t know what is wrog. Here is my server configuration
<amq:broker brokerName="granicaBroker" id="broker"
persistent="false" deleteAllMessagesOnStartup="true" enableStatistics="false"
useLoggingForShutdownErrors="true">
<amq:networkConnectors>
<amq:networkConnector name="linkToBrokerB"
uri="static:(tcp://xxx.xx.xxx.xx:61617)" networkTTL="3" duplex="true" />
</amq:networkConnectors>
<amq:transportConnectors>
<amq:transportConnector
uri="nio://xxx.xx.xxx.xx:61616?jms.useAsyncSend=true?jms.useCompression=true"
disableAsyncDispatch="false" />
</amq:transportConnectors>
</amq:broker>
<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="JMS.TOPIC.NOTIFICATION" />
</bean>
<bean id="producerTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="connectionFactory"
p:defaultDestination-ref="destination" />
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="nio://xxx.xx.xxx.xx:61616" />
And my producer class(just the part to send the message)
#Autowired
protected JmsTemplate jmsTemplate;
final String text = applicationEvent.getMsg();
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage message = session.createTextMessage(text);
return message;
}
});
My client context configuration:
p:brokerURL="nio://xxx.xx.xxx.xx:61616" />
<bean id="simpleMessageListener" class="notifications.NotifierControllerImpl"/>
<jms:listener-container container-type="default"
connection-factory="connectionFactory" acknowledge="auto">
<jms:listener destination="JMS.TOPIC.NOTIFICATION" ref="simpleMessageListener"
method="onMessage" />
</jms:listener-container>
And the java client class
public class NotifierControllerImpl implements MessageListener{
#Override
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage tm = (TextMessage)message;
System.out.println(tm.getText());
}
} catch (JMSException e) {
System.out.println(e.toString());
}
}
}
The destination needs to be a topic not a queue; use ActiveMQTopic not ActiveMQQueue.
I change jms:listener-container part
Here is the code:
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="messageListener" ref="simpleMessageListener" />
</bean>
And it works!

MessageListenerContainer with MessageHandler?

If I use Spring Integration with XML-Configuration, a Message Listener can be done like the following:
<int:channel id="handlerChannel"/>
<bean class="org.springframework.integration.endpoint.EventDrivenConsumer">
<constructor-arg name="inputChannel" ref="handlerChannel"/>
<constructor-arg name="handler" ref="alertHandler" />
</bean>
<int-jms:message-driven-channel-adapter channel="handlerChannel" container="listenerContainer" />
<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" scope="prototype">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="defaultDestination"/>
</bean>
The problem is: I want to create own ListenerContainers at the runtime... how I can get the same result or rather how can I combine a MessageHandler with a MessageListenerContainer?
thx and greeting
MessageChannel channel = new DirectChannel();
DefaultMessageListenerContainer container = ...
JmsMessageDrivenEndpoint inbound = new JmsMessageDrivenEndpoint(container);
inbound.setOutputChannel(channel);
handler.subscribe(channel);
inbound.afterPropertiesSet();
inbound.start();
However, why use Spring Integration at all here; you can wire a MessageListener into the message listener container directly.

Spring Jms #JmsListener annotation doesnt work

I have such method
#JmsListener(containerFactory = "jmsListenerContainerFactory", destination = "myQName")
public void rceive(MySerializableObject message) {
log.info("received: {}", message);
}
and such config on xml
<jms:annotation-driven />
<bean id="jmsListenerContainerFactory" class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="connectionFactory" ref="pooledConnectionFactory" />
<property name="concurrency" value="3-10" />
</bean>
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${brokerURL}" />
</bean>
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="maxConnections" value="5" />
<property name="maximumActiveSessionPerConnection" value="500" />
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
<bean id="jmsContainerFactory" class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="connectionFactory" ref="pooledConnectionFactory" />
<property name="concurrency" value="3-10" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate" p:connectionFactory-ref="pooledConnectionFactory" />
Seems consumer was not created. I can send messages but cannot receive them.
Any idea whats wrong here?
Just tested your config and it works well. Only difference that I make a class with #JmsListener as a <bean> in that context:
<bean class="org.springframework.integration.jms.JmsListenerAnnotationTests$TestService"/>
#ContextConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#DirtiesContext
public class JmsListenerAnnotationTests {
#Autowired
private JmsTemplate jmsTemplate;
#Autowired
private TestService testService;
#Test
public void test() throws InterruptedException {
this.jmsTemplate.convertAndSend("myQName", "foo");
assertTrue(this.testService.receiveLatch.await(10, TimeUnit.SECONDS));
assertNotNull(this.testService.received);
assertEquals("foo", this.testService.received);
}
public static class TestService {
private CountDownLatch receiveLatch = new CountDownLatch(1);
private Object received;
#JmsListener(containerFactory = "jmsListenerContainerFactory", destination = "myQName")
public void receive(String message) {
this.received = message;
this.receiveLatch.countDown();
}
}
}
<jms:annotation-driven /> makes the #JmsListener infrastructure available, but to force Spring to see those methods your classes should be beans anyway.
For example <component-scan> for the package with #Service classes.
Cheers!

Restrict execution of concurrent queue in Spring JMS

Ideally after one queue completes its execution, another queue should start.
I am using Spring JMS. But at a time more than one queue able to execute by which data mismatch occurs.
So can anyone please tell how to restrict concurrent queue or unless first queue ends the 2nd queue cannot be started or all other queues are in waiting.
public class MyQueueListener implements MessageListener {
public void onMessage(Message message) {
try {
if (message instanceof ObjectMessage) {
ObjectMessage objectMessage = (ObjectMessage) message;
MyQueueObject obj= (MyQueueObject)objectMessage.getObject();
String productId = obj.getProductId();
IMyService myService;
myService.updateAllCustomerDetails(productId);
}
} catch (JMSException j) {
j.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
}
<bean id="mySenderService" class="MySenderService">
<property name="jmsTemplate" ref="myjmsTemplate" />
<property name="queue" ref="myQueueDestination" />
</bean>
<bean id="myQueueDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>queue/myQueue</value>
</property>
<property name="resourceRef">
<value>true</value>
</property>
</bean>
<bean id="myQueueListener" class="MyQueueListener" ></bean>
<bean id="jmsImportContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="myQueueDestination" />
<property name="messageListener" ref="myQueueListener" />
</bean>
mySenderService.sendMessages();

Resources