How to start DefaultMessageListenerContainer? - java

I have written a Spring application for consuming messages using MDP which uses DefaultMessageListnerContainer. I wrote a messageListner and passed it to the property of messageListener to DMLC.
My Spring configuration is below
<!-- ConnectionFactory Definition -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="amqConnectionFactory" />
</bean>
<!-- Message Receiver Definition -->
<bean id="messageReceiver" class="com.practice.MessageReceiver.MyMessageConsumer">
</bean>
<bean id="actualQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="ActualQueue" />
</bean>
<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="actualQueue" />
<property name="messageListener" ref="messageReceiver" />
</bean>
I want to know how to start this DMLC? I deployed it in Jboss 6.1. But its not consuming messages. I am missing something which I am not able to get by searching for an answer.

Related

Camel creating too many tcp connections (over 15000) in TIME_WAIT status to connect ActiveMQ

I am using Apache Camel(with Spring) and ActiveMQ in project. Here are the settings related to JMS/ActiveMQ:
Camel version: activemq-camel-5.15.3.jar (all ActiveMQ related jars)
ActiveMQ version : 5.15.0
<!-- language: lang-xml -->
<bean id="defaultActiveMQRedeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
</bean>
<util:list id="redeliveryPolicyEntries">
<bean id="activeMQRedeliveryPolicy1" class="org.apache.activemq.RedeliveryPolicy">
<property name="queue" value="inbox"></property>
</bean>
</util:list>
<bean id="amqRedeliveryPolicyMap"
class="org.apache.activemq.broker.region.policy.RedeliveryPolicyMap">
<property name="defaultEntry" ref="defaultActiveMQRedeliveryPolicy"></property>
<property name="redeliveryPolicyEntries" ref="redeliveryPolicyEntries"></property>
</bean>
<bean id="amqPrefetchPolicy" class="org.apache.activemq.ActiveMQPrefetchPolicy">
</bean>
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" destroy-method="stop">
<property name="maxConnections" value="20" />
<property name="maximumActiveSessionPerConnection" value="40" />
<property name="connectionFactory" ref="jmsConnectionFactory">
</property>
</bean>
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${jmsConnectionFactory.brokerURL}" />
<property name="userName" value="admin" />
<property name="password" value="admin" />
<property name="prefetchPolicy" ref="amqPrefetchPolicy" />
<property name="redeliveryPolicyMap" ref="amqRedeliveryPolicyMap" />
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory" />
<property name="concurrentConsumers" value="15" />
<property name="maxConcurrentConsumers" value="30" />
<property name="asyncConsumer" value="false" />
<property name="cacheLevelName" value="CACHE_CONSUMER" />
</bean>
<!-- this bean actually represents a jms component to be used in our camel-integration
setup.make endpoints by using name(id) of this bean. -->
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig" />
<property name="transacted" value="false" />
<property name="transactionManager">
<bean class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
</property>
</bean>
As you see I am using PooledConnectionFactory so I am expecting a fixed no of connections to connect with ActiveMQ. But unexpectedly I see a large no of TCP connections being opened in TIME_WAIT even when my application is idle and no messages are being produced/consumed at time. I confirmed this situation with infra team that confirmed all the Operating System level configuration are fine.
Here I tried debugging the doReceiveAndExecute method in AbstractPollingMessageListenerContainer- sessionToUse is not null, consumerToUse is also not null and code flows through receiveMessage(line number 304).I could not find the problem in debug trace as attached in debug screenshots:
and
and my actual problem
Is it a problem with MessageListenerContainer or with ConnectionFactory?? Am I missing some configuration which would prevent this from happening or is this an existing issue? If so is there a workaround?
Just spotted in your configuration that you configured the jmsConnectionFactory (not the pooled factory) in your transaction manager. Not sure if this could raise the issue because the pooled factory is simply not used.
<property name="transactionManager">
<bean class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
</property>

Using messageSelector with AbstractMessageListenerContainer Spring Framework

I want to use messageSelector String which is inside the class AbstractMessageListenerContainer.class and here is the XML Configurations that i am giving.
<bean id="jmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="autoStartup" value="${listener.setup}" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="paymentResponseQueue" />
<property name="messageListener" ref="myAbstractListener" />
</bean>
<bean id="myAbstractListener"
class="org.springframework.jms.listener.AbstractMessageListenerContainer">
<property name="autoStartup" value="${listener.setup}" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="paymentResponseQueue" />
<property name="messageListener" ref="authorisationResponseHandler" />
<property name="messageSelector" value="JMSCorelationId = 'AMM--AS1-6e07c3092bc94f77a183889ababeabc2'" />
</bean>
After giving this configuration, when i start tomcat, my application is not getting started.
Where as when i give the config as below and start tomcat, i am able to start my application and working as expected. xyzResponseHandler is referencing to Class file where i am implementing
public class xyzResponseHandler implements MessageListener{
}
<bean id="jmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="autoStartup" value="${listener.setup}" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="paymentResponseQueue" />
<property name="messageListener" ref="xyzResponseHandler" />
</bean>
What wrong i am doing in the First Config. Can you please correct me if i am going in wrong direction. Basically i want to filter the message using messageSelector.
In DefaultMessageListenerContainer the property messageListener should be either a standard JMS MessageListener object or a Spring SessionAwareMessageListener object.
Refer the below spring doc
http://docs.spring.io/spring-framework/docs/3.0.5.RELEASE/api/org/springframework/jms/listener/AbstractMessageListenerContainer.html#setMessageListener(java.lang.Object)
But you are referring to a bean of another ListenerContainer.

Producer and Consumer in Spring Jms use same connection factory?

I have a component which reads messages from a queue and meanwhile sends the processed messages to another queue. Therefore, this component is both a message consumer and producer. For configuring them, I need a connection factory for consuming and another connection factory for the producing. Here is part of the spring configuration.
<!-- Configuration for listener -->
<bean id="mdc.TargetConnectionFactory4Listener" class="com.tibco.tibjms.TibjmsConnectionFactory">
<property name="serverUrl" value="tcp://localhost:7222"/>
</bean>
<bean id="mdc.ConnectionFactory4Listener" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="mdc.TargetConnectionFactory"/>
<property name="username" value="admin" />
<property name="password" value="test" />
</bean>
<bean id="mdc.InputQueue" class="com.tibco.tibjms.TibjmsQueue">
<constructor-arg>
<value>INPUT_QUEUE</value>
</constructor-arg>
</bean>
<bean id="mdc.JmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="mdc.ConnectionFactory4Listener" />
<property name="destination" ref="mdc.InputQueue" />
<property name="messageListener" ref="mdc.MessageReceiver" />
......
</bean>
<!-- Configuration for sender -->
<bean id="mdc.TargetConnectionFactory4Sender" class="com.tibco.tibjms.TibjmsQueue">
<property name="serverUrl" value="tcp://localhost:7222"/>
</bean>
<bean id="mdc.CachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="mdc.TargetConnectionFactory4Sender" />
<property name="sessionCacheSize" value="50" />
</bean>
<bean id="mdc.OutputQueue" class="com.tibco.tibjms.TibjmsQueue">
<constructor-arg>
<value>DISCOVERY_QUEUE</value>
</constructor-arg>
</bean>
<bean id="mdc.JmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="mdc.CachingConnectionFactory" />
</bean>
<bean id="mdc.MessageReceiver" class="net.siemens.discovery.queue.QueueMessageListener">
<property name="jmsTemplate" ref="mdc.JmsTemplate" />
<property name="destination" ref="mdc.OutputQueue" />
......
</bean>
The two queues are running on the same EMS server. Some has opinions about this configurations: they can be configured by using only one ConnectionFactory and two instances are not necessary. However, if I use one ConnectionFactory instance, then the instance is used both in the DefaultMessageListenerContainer and the CachingConnectionFactory (further used in JmsTemplate). I don't know whether they have impact on each other.
It is perfectly normal to use a single connection factory; it is very unusual to use 2 factories in this case.
In fact, if you want to perform JmsTemplate operations on the container thread and you want the interactions to run in a transaction (sessionTransacted = true in the container), then you must use the same connection factory. This allows everything to roll back if there's an exception.
When using a caching connection factory in the listener container you should set the connection factory cacheConsumers to false. (See this answer for more information.

Consume Messages in ActiveMQ with a service or a listener

I have written a small test where I send a message to an existing ActiveMQ FORWARD queue. Unfortunately the message is sent to the queue but not received. Below you will find my two attempts to receive this message: through a MyMessageListener and through a MessageService. Both methods fail.
Here is my test:
Map<Parameter, String> params = new HashMap<Parameter, String>();
params.put(key1, "601");
params.put(key2, "3000");
Map<String,String> headers = Collections.singletonMap("method-name","prepareHotDrink");
Message<?> msg = MessageBuilder.withPayload(params)
.copyHeaders(headers)
.build();
boolean i = inputChannel.send(msg);
This is my configuration file:
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${jms.primary.server}"/>
</bean>
<!-- spring integration beans -->
<int-jms:channel id="inputChannel" queue-name="FORWARD"
connection-factory="connectionFactory" auto-startup="true">
</int-jms:channel>
<!-- Consumers -->
<int-jms:message-driven-channel-adapter
id="jmsIn"
container="messageListenerContainer"
channel="inputChannel"
extract-payload="true" />
<int:service-activator input-channel="inputChannel"
ref="messageService"
method="processMessage"/>
<bean id="messageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="requestQueue"/>
<property name="exposeListenerSession" value="false"/>
<property name="messageListener" ref="messageListener" />
</bean>
<bean id="messageListener" class="com.ucware.ucpo.forward.mess.MyMessageListener"/>
<bean id="messageService" class="com.ucware.ucpo.forward.jms.MessageService"/>
<bean id="requestQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg name="name" value="FORWARD"/>
</bean>
It turned out ActiveMQ does not support channels. So I had to define a <jms:lintener-container> and <jms:listener> to be able to consume the messages. In addition I created a message producer that sends messages to the existing ActiveMQ queue.
<!-- RECEIVER -->
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory" p:brokerURL="${jms.primary.server}"/>
<bean id="messageListener" class="com.ucware.ucpo.forward.jms.ProductMessageListener"/>
<jms:listener-container connection-factory="connectionFactory" concurrency="2" acknowledge="auto">
<jms:listener destination="FORWARD" ref="messageListener" method="onMessage"/>
</jms:listener-container>
<!-- SENDER -->
<!-- A cached connection to wrap the ActiveMQ connection -->
<bean id="cachedConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory"
p:targetConnectionFactory-ref="connectionFactory"
p:sessionCacheSize="10" />
<!-- A destination in ActiveMQ -->
<bean id="destination"
class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="FORWARD" />
</bean>
<!-- A JmsTemplate instance that uses the cached connection and destination -->
<bean id="producerTemplate"
class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="cachedConnectionFactory"
p:defaultDestination-ref="destination" />
</beans>

Restart server without losing JMS connection

I have two app servers. One sends messages to the other using JMS. The sender runs on Tomcat, with ActiveMQ used inside a Spring Framework template method call. The receiver runs on Jetty.
The problem is that when I restart one of the servers-- the receiver of the messages-- after it restarts it doesn't get any more JMS messages until the other server is also restarted. I'm not sure why this is happening. Is there a way to only require a reboot of one server?
The sender XML configuration:
<bean id="producerJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<bean
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="jmsFactory"/>
</bean>
</property>
</bean>
<bean id="simulationMessageSender" class="com.forio.simulate.activemq.SimulationMessageSenderImpl">
<constructor-arg ref="producerJmsTemplate"/>
</bean>
<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue"
autowire="constructor">
<constructor-arg value="com.forio.simulate.activemq"/>
</bean>
The sender java code:
public void send(final SimulationMessage simulationMessage) throws JMSException
{
jmsTemplate.send(destination, new MessageCreator()
{
public Message createMessage(Session session) throws JMSException
{
Log.debug("Sending message: " + simulationMessage);
ObjectMessage message = session.createObjectMessage(simulationMessage);
message.setStringProperty("simulationMessage", "true");
return message;
}
});
}
The receiver XML configuration:
<bean id="brokerContainer" class="org.apache.activemq.xbean.BrokerFactoryBean">
<property name="config" value="classpath:activemq.xml" />
</bean>
<bean id="jmsFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${jms.url}" />
</bean>
<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue"
autowire="constructor">
<constructor-arg>
<value>com.forio.simulate.activemq</value>
</constructor-arg>
</bean>
<bean id="messageListener"
class="com.forio.simulate.activemq.SimulationMessageListener">
<property name="messageConverter">
<bean
class="com.forio.simulate.activemq.converter.SimulationMessageConverter" />
</property>
<property name="simulationMessageService" ref="simulationMessageService"/>
</bean>
<bean
class="org.springframework.jms.listener.SimpleMessageListenerContainer" init-method="start">
<property name="connectionFactory" ref="jmsFactory" />
<property name="destination" ref="destination" />
<property name="concurrentConsumers" value="3" />
<property name="messageListener" ref="messageListener" />
</bean>
<bean id="consumerJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsFactory" />
</bean>
It is because you are using SingleConnectionFactory. each time SingleConnectionFactory.createConnection() is called, it returns the same connection, even after it is closed by restarting your receiving server.
Maybe CachingConnectionFactory will suite your needs as it has some recover on exception mechanism.

Categories

Resources