Announcement Announcement Module
Collapse
No announcement yet.
How to wire up jms:listener-container for message-driven-channel-adapter Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to wire up jms:listener-container for message-driven-channel-adapter

    Currently I have a working example of a SI process using the DefaultMessageListenerContainer. I would like to convert this to a jms:listener-container. I have questions about how this should done.

    Current setup.

    Code:
    <bean id="messageListenerContainer"
    		class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    		<property name="connectionFactory" ref="jmsConnectionFactory" />
    		<property name="destination" ref="orderEvent" />
    		<property name="sessionTransacted" value="true" />
    		<property name="maxConcurrentConsumers" value="1" />
    		<property name="concurrentConsumers" value="1" />
    		<property name="receiveTimeout" value="5000" />
    		<property name="recoveryInterval" value="60000" />
    		<property name="autoStartup" value="true" />
    	</bean>
    Code:
    <int-jms:message-driven-channel-adapter
    		id="jmsIn" channel="inbound" container="messageListenerContainer"
    		acknowledge="transacted" />
    This what I'm trying to configure. Not sure how the listener should be configured.
    How would I configure multiple listeners and point to different message-driven-channel-adapter?


    Code:
    	<jms:listener-container connection-factory="connectionFactory" 	concurrency="1" receive-timeout="5000" client-id="messageListenerContainer">
    		<jms:listener destination="orderEvent" ref="?"  />
    	</jms:listener-container>

  • #2
    The <jms:listener-container/> element is just a convenience. Each <jms:listener /> element gets its own DMLC (with shared attributes defined on the <jms:listener-container/> element). You "can" give each listener element an ID, and use that to inject into the channel adapter, however, the <jms:/> namespace requires a real listener. Since, for Spring Integration, the adapter itself needs to configure the listener, the configured listener will be overwritten. If you go this route, you will see a warning for each adapter...

    Code:
    if (logger.isWarnEnabled() && listenerContainer.getMessageListener() != null) {
    	logger.warn("The provided listener container already has a MessageListener implementation, " +
    			"but it will be overridden by the provided ChannelPublishingJmsMessageListener.");
    }
    So, generally, you should use the <bean/> configuration you already have. If you want to configure multiple containers (with similar attributes), you can define an abstract <bean/> and set the 'parent' attribute on each DMLC.

    Comment


    • #3
      Thanks for the reply I will stick with bean configuration.

      Comment


      • #4
        I think that JMS Message-Driven Channel Adapter needs a better explanation for container in the documentation (and a sample, if it's possible)

        Maybe I can create a JIRA ticket for this.

        If you don't mind, let me tell you a long story:

        I'd like to configure a Message-Driven Channel Adapter for consuming JMS messages into a Spring Integration flow, but I find the explanations not too clear.

        The application will be deployed in WebSphere Application Server, so I'd like to follow the instructions called "Using Spring JMS" that you can find at Using Spring and Hibernate with WebSphere Application Server

        That is, a DefaultMessageListenerContainer class for managing messages from the JMS queue using a POJO.

        Why? Because I need to provide some content managed resources, as the transactionManager (an instance of WebSphereUowTransactionManager), a taskExecutor (a configured Work Manager via a commonj WorkManagerTaskExecutor bean) , and of course, the JMS resources, obtained via jndi-lookup.

        Thanks to Spring, I can provide a different configuration in my local environment (ActiveMQ, for instance, and some local transaction manager and task executor)

        To configure a DefaultMessageListenerContainer, Josh Long gave a clear explanation in "Listening Makes It More Simple", in his blog entry for using Spring for enterprise messaging at GREEN BEANS: GETTING STARTED WITH ENTERPRISE MESSAGING AND SPRING

        It's clear that using the <jms:listener-container> element from the JMS namespace is the best option.

        BUT...

        Things get complicated, because according the "JMS Namespace Support" , a <listener> element requires a destination (OK), and a ref (a bean name of the handler object)

        At that moment I can't understand how to configure a handler, just a POJO with a method, to process an incoming JMS in order to provide a Spring Integration Message to the Spring Integration flow.

        Furthermore, in the MessageListenerAdapter documentation you can read that it's possible to configure a DefaultMessageListenerContainer with a "Message Driven POJO" using the MessageListenerAdapter with a POJO, but, all the examples that you can find have POJOs with "handle" methods that returns void.

        Apologize for all this context, but it took my a while, and I had to deep dive into the source code, to find out that JmsMessageDrivenEndpointParser will provide a JmsMessageDrivenEndpoint using a parsed AbstractMessageListenerContainer (a DefaultMessageListenerContainer by defaut) and a ChannelPublishingJmsMessageListener.

        OK, this very listener will override the one that DefaultMessageListenerContainer has, if any.

        According to this POST, where you can find the same explanation but summarized, since the JMS namespace requires a real listener, maybe a bean configuration is a better option.

        In my case, I've created listener with actual references to empty classes.

        Code:
            <jms:listener-container connection-factory="jmsConnectionFactory" task-executor="websphereTaskExecutor" transaction-manager="websphereTransactionManager">
            	<jms:listener id="myListenerContainer" destination="${jms.queue.myQueue}" ref="emptyListenerContainerConsumer" />
            	...
           </jms:listener-container>
        IMH, all this stuff is very complicated, and it should be clarified in the documentation, and the best option for doing so, is with an example (what about an aditional sample in the spring-integration-samples project?)

        Besides, I find the container attribute within the int-jms:message-driven-channel-adapter element, has a name that not explain its function, and it's not well documented: the parser will fail if there is a container attribute and any other attribute that belongs to the containerAttributes set (connectionFactory, destination, destination-name, transaction-manager...)

        Thank you very much for listening (reading) this.

        Greetings.

        Comment


        • #5
          As I said in post #2, the <jms:listener-container/> namespace is just a convenience; it is functionally equivalent to the bean definition in post #1, except it requires a listener child element (which is where a number of important properties are specified).

          I would not recommend using the namespace with a "dummy" listener that will get replaced by the adapter.

          It's not clear to me exactly what you are asking for.

          If you are simply asking for us to clarify (in http://static.springsource.org/sprin...hannel-adapter) that the container should be defined in a <bean/> instead of using the namespace, we can do that. Please open a 'Documentation' JIRA; but please be very clear as to what you think is lacking. You could also open an INTSAMPLES JIRA for a sample using an external container - but it would be even better to contribute such a sample (or extension to the existing sample) https://github.com/SpringSource/spri...ONTRIBUTING.md.

          Comment

          Working...
          X