3

First I have a question on how to configure JMS MQ to reconnect to an application when the broker connection is shutdown and restarted.

Below is what I tried,

This is the configuration that I initially had in my spring-mq-jms-connections.xml

<!-- Spring JMS Queue Connection Factory -->
        <!--
        <bean id="jmsQueueConnectionFactory.7"
            class="org.springframework.jms.connection.SingleConnectionFactory"  >
            <property name="targetConnectionFactory">
                <ref bean="internalJmsQueueConnectionFactory.7"/>
            </property>
        </bean> -->

I replaced this with the below configuration introduced "DefaultMessageListenerContainer" which would wrap "SingleConnectionFactory".

<bean id="jmsQueueConnectionFactory.7" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory">
            <ref bean="single.connection.factory.7"/>
        </property>

        <property name="recoveryInterval" value="5000"/>

    </bean>

    <bean id="single.connection.factory.7" class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory">
        <ref bean="internalJmsQueueConnectionFactory.7"/>
    </property>
    </bean>

But I started getting the below exception after this configuration change.

Failed to configure emapi:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'senderAgent.7' defined in URL 
[file://localhost/home/qos/qosdata/config/general/emapi/spring-mq-jms-connections.xml]: 
Cannot resolve reference to bean 'jmsQueueTemplate.7' while setting bean property 'jmsTemplate';
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean 
with name 'jmsQueueTemplate.7' defined in URL 
[file://localhost/home/qos/qosdata/config/general/emapi/spring-mq-jms-connections.xml]: 
Cannot resolve reference to bean 'jmsQueueConnectionFactory.7' while setting bean property 'connectionFactory'; 
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 
'jmsQueueConnectionFactory.7' defined in URL [file://localhost/home/qos/qosdata/config/general/emapi/spring-mq-jms-connections.xml]: 
Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 
Property 'destination' or 'destinationName' is required
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:275)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:104)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1244)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1008)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:470)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
        at java.security.AccessController.doPrivileged(Native Method)

It says 'destination' or 'destinationName' is required, I am dealing with legacy code, not sure where to look for this or I am doing the right thing when I changed the configuration.

Please suggest if there is any better way to reconnect OpenMQ with an application when the broker connection goes down due to exception or when it is restarted. I also looked at spring jms connection factory with exception listener, but couldnt figure out.

likeToCode
  • 852
  • 2
  • 10
  • 20

1 Answers1

1

A DefaultMessageListenerContainer is a listener container (used to receive messages from the broker), not a connection factory.

If you are just using it as a vehicle to reconnect, it needs a dummy queue to "listen" to.

EDIT: Updated in response to your comment below.

Consider using Spring Integration; it can be configured to automatically fail over; something like

<int:gateway service interface="foo.Bar" default-request-channel="foo" />

<int:channel id="foo">
    <int:dispatcher load-balancer="false"/>
<int:channel/>

<int-jms:outbound-channel-adapter channel="foo" order="1" ... />

<int-file:outbound-channel-adapter channel="foo" order="2" mode="APPEND" ... />

By default, the dispatcher will load balance (round robin) to the two adapters by turning off load balancing it will always send it to JMS and fail over to the file.

Spring Integration also has lots of features for error handling, adding a retry advice to the adapter etc, etc.

If you don't want to use Spring Integration, you can simply do something like...

try {
    this.jmsTemplate.send(...);
}
catch (Exception e) {
    writeToFile(...);
}
Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Thank you for taking the time to answer, Yes the motive is to reconnect, but when do you mean by dummy queue ? Is it a queue which is not created at all ? How do I set it ? Could you please provide an example of the configuration for this? – likeToCode Jul 18 '13 at 20:04
  • The listener container is designed to receive messages from a queue - it will automatically re-establish the connection if it fails, but it need a queue to "listen" to, even if no data will ever be received. However, it's a bit of overkill to use the container for this purpose. Perhaps you should explain your exact use case - other components (such as the JmsTemplate) will reconnect if the connection is down. You just need to catch the exception and retry the send. You should update your question to explain the problem you have rather than the solution you tried. – Gary Russell Jul 18 '13 at 22:16
  • The exact thing I am trying to do is, I have an application which sends messages to a Queue. The application setup is when the broker connection to the Queue is down, the messages should be written to a local file so we dont lose any messages and when the broker connection is UP, the messages should be sent to the Queue instead of writing to the local file. Right now, even though the broker connection is UP, the file is still written to the local file, I am looking at a solution where when the broker connection is UP, the messages will be sent to the Queue. – likeToCode Jul 19 '13 at 07:08
  • Edited with some suggestions. – Gary Russell Jul 19 '13 at 12:48
  • 1
    Gary Russell, Thank you once again, I was able to fix the reconnect issue with just adding an additional property reconnectOnException for SingleConnectionFactory and it miraculously works when I bring down and up the broker connection. Like the below. – likeToCode Jul 23 '13 at 12:03