Results 1 to 3 of 3

Thread: Newbie: Start a listener without the broker running?

  1. #1
    Join Date
    Jun 2009
    Posts
    1

    Default Newbie: Start a listener without the broker running?

    Hi.

    Newbie to SpringJMS. I'm looking to be able to start up a Spring JMS-based process when the broker it will be listening to is not yet running. The idea is that at some point when the broker does start, reconnection would kick in and the connection would become valid.

    I'm using Tibco's EMS, and so far I have this config:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
     
    <beans>
      	<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
               <property name="environment">
                      <props>
                             <prop key="java.naming.factory.initial">
                                com.tibco.tibjms.naming.TibjmsInitialContextFactory
                             </prop>
                             <prop key="java.naming.provider.url">
                                ${com.tibco.tibjms.TibjmsConnectionFactory.server-url}
                             </prop>
                      </props>
               </property>
        </bean>
    	
    	<bean id="jmsTopicConnectionFactory" class="com.tibco.tibjms.TibjmsConnectionFactory">
            <property name="serverUrl" value="${com.tibco.tibjms.TibjmsConnectionFactory.server-url}" />
            
        </bean>
        
        <bean id="heartBeatSendDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
        	<property name="jndiTemplate" ref="jndiTemplate" />
        	<property name="jndiName" value="${heartbeat-topic}" />
        </bean>
        
        <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        	<property name="connectionFactory" ref="jmsTopicConnectionFactory" />
        	<property name="defaultDestination" ref="heartBeatSendDestination"/>
        	<property name="receiveTimeout" value="${heartbeat-receive-timeout}" />
    	</bean>
    	
    	
    	<bean name="jmsHeartbeatSender" class="my.package.JMSHeartbeatSender" init-method="init">
    		<property name="jmsTemplate" ref="jmsTemplate" />
    	</bean>
    </beans>
    If my EMS broker isn't running, I get the following error:


    Code:
    Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jmsHeartbeatSender' defined in class path resource [beans-spring-jms.xml]: Cannot resolve reference to bean 'jmsTemplate' while setting bean property 'jmsTemplate'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jmsTemplate' defined in class path resource [beans-spring-jms.xml]: Cannot resolve reference to bean 'heartBeatSendDestination' while setting bean property 'defaultDestination'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'heartBeatSendDestination' defined in class path resource [beans-spring-jms.xml]: Invocation of init method failed; nested exception is javax.naming.ServiceUnavailableException: Failed to query JNDI: Failed to connect to any server at: tcp://localhost:7222, tcp://localhost:7222 [Root exception is javax.jms.JMSException: Failed to connect to any server at: tcp://localhost:7222, tcp://localhost:7222]
    	<snip>
    	... 18 more
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jmsTemplate' defined in class path resource [beans-spring-jms.xml]: Cannot resolve reference to bean 'heartBeatSendDestination' while setting bean property 'defaultDestination'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'heartBeatSendDestination' defined in class path resource [beans-spring-jms.xml]: Invocation of init method failed; nested exception is javax.naming.ServiceUnavailableException: Failed to query JNDI: Failed to connect to any server at: tcp://localhost:7222, tcp://localhost:7222 [Root exception is javax.jms.JMSException: Failed to connect to any server at: tcp://localhost:7222, tcp://localhost:7222]
    	<snip>
    	... 31 more
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'heartBeatSendDestination' defined in class path resource [beans-spring-jms.xml]: Invocation of init method failed; nested exception is javax.naming.ServiceUnavailableException: Failed to query JNDI: Failed to connect to any server at: tcp://localhost:7222, tcp://localhost:7222 [Root exception is javax.jms.JMSException: Failed to connect to any server at: tcp://localhost:7222, tcp://localhost:7222]
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1338)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
    	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
    	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
    	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:269)
    	... 44 more
    Caused by: javax.naming.ServiceUnavailableException: Failed to query JNDI: Failed to connect to any server at: tcp://localhost:7222, tcp://localhost:7222 [Root exception is javax.jms.JMSException: Failed to connect to any server at: tcp://localhost:7222, tcp://localhost:7222]
    	at com.tibco.tibjms.naming.TibjmsContext.lookup(TibjmsContext.java:692)
    	at com.tibco.tibjms.naming.TibjmsContext.lookup(TibjmsContext.java:516)
    	at javax.naming.InitialContext.lookup(InitialContext.java:392)
    	at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:155)
    	at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:88)
    	at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:153)
    	at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:178)
    	at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:95)
    	at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:105)
    	at org.springframework.jndi.JndiObjectFactoryBean.lookupWithFallback(JndiObjectFactoryBean.java:200)
    	at org.springframework.jndi.JndiObjectFactoryBean.afterPropertiesSet(JndiObjectFactoryBean.java:186)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
    	... 54 more
    Caused by: javax.jms.JMSException: Failed to connect to any server at: tcp://localhost:7222, tcp://localhost:7222
    	at com.tibco.tibjms.TibjmsConnection._create(TibjmsConnection.java:740)
    	at com.tibco.tibjms.TibjmsConnection.<init>(TibjmsConnection.java:1955)
    	at com.tibco.tibjms.TibjmsQueueConnection.<init>(TibjmsQueueConnection.java:37)
    	at com.tibco.tibjms.TibjmsxCFImpl._createImpl(TibjmsxCFImpl.java:187)
    	at com.tibco.tibjms.TibjmsxCFImpl._createConnection(TibjmsxCFImpl.java:240)
    	at com.tibco.tibjms.TibjmsQueueConnectionFactory.createQueueConnection(TibjmsQueueConnectionFactory.java:79)
    	at com.tibco.tibjms.naming.TibjmsContext$Messenger.request(TibjmsContext.java:352)
    	at com.tibco.tibjms.naming.TibjmsContext.lookup(TibjmsContext.java:678)
    	... 66 more
    (snipped to allow posting)


    As you can see, it hasn't given the heartbeat sender a chance to get created because it initially attempts to connect to a broker, which deliberately isn't there. If I start the broker first, all works as I'd expect it to.

    How can I go about creating my final heartbeat sender bean such that it would allow creation without the broker needing to actually be up, and such that it would try to reconnect periodically?

    All help gratefully received, and happy to provide any more information if necessary.



    Thanks,
    Ian

  2. #2

    Default Jndi Lookup fail

    As far as i know using Spring's DefaultMessageListenerContainer, SimpleMessageListenerContainer etc. will not be able to startup if Broker is not available.
    But you will be able to extend it and override the initialization methods.
    The handling should be pretty like what it dose in case it looses connection at runntime.

    One part of the problem here might be that the destination requested via jndiTemplate is not available because the broker is down.
    javax.naming.ServiceUnavailableException: Failed to query JNDI

    I think a better solution to retrieve Destinations is (if working) to use a DestinationResolver instead of defining Destinations in XML.
    If you do so you can also work with JmTemplate using JmsTemplate.convertAndSend(String destinationName ....) Methods instead of defining a JmsTemplate for each Destination.

    Using a Destination Resolver you will be able to retrieve the destination via a provides JMS Session.

    DestinationResolver will look something like this.
    Code:
    public class MyDestinationResolver implements DestinationResolver{
     /**
         * {@inheritDoc} 
         */
        public Destination resolveDestinationName(final Session session, final String destinationName,
                final boolean pubSubDomain) throws JMSException {
            if (pubSubDomain) {
                Topic topic = session.createTopic(destinationName);
                return topic;
            } else {
                Queue queue = session.createQueue(destinationName);
                return queue;
            }
        }
    
    }
    This will work in case the heartbeat-topic dose exist and is accessible.
    session.createTopic() and session.createQueue() sometimes (for example if using ActiveMQ) also creates a Topic or Queue on the broker if not available but usually
    (for example with Oralce AQ, JBoss Messaging) there is a Broker specific API that allows you to create Queues and Topics within your code if you don't want to configure the destinations in the borker's configuration.


    The configuration of your Template and other JMS Artifacts will look like this.

    Code:
    <bean id="jmsTopicConnectionFactory" class="com.tibco.tibjms.TibjmsConnectionFactory">
            <property name="serverUrl" value="${com.tibco.tibjms.TibjmsConnectionFactory.server-url}" />
            
        </bean>
    
     <bean id="destinationResolver" class="an.example.MyDestinationResolver"/>
    
    
     <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
          <property name="connectionFactory" ref="jmsTopicConnectionFactory"></property>
          <property name="defaultDestinationName" value="${heartbeat-topic-name}""></property>
          <property name="destinationResolver" ref="destinationResolver"/>
        </bean>
    Last edited by c.petz@efkon.com; Jul 1st, 2009 at 07:15 AM.

  3. #3

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •