Zeus
Zeus

Reputation: 6566

JMS - Error adding listener to the MessageConsumer

I'm trying to create a POC for JMS Queue. I used spring mvc controllers as the client to the jms. I get the following error when trying to add asynchronous listeners onto the MessageConsumer object(code snippet). I've read somewhere that the listeners can only be added to the MDB (Message driven beans), is it true?

Setup: Using websphere server bus for JMS. Added jndi for conn factory, destinations etc., for synchronous operation everything is working. But, for asynchronous, this is not working.

Used this for setting up the JMS

[1/28/14 14:38:12:570 CST] 0000005d SystemErr     R javax.jms.IllegalStateException: CWSIA0084E: The method MessageConsu
mer.setMessageListener is not permitted in this container.
[1/28/14 14:38:12:572 CST] 0000005d SystemErr     R     at com.ibm.ws.sib.api.jms.impl.JmsMsgConsumerImpl._setMessageListen
er(JmsMsgConsumerImpl.java:660)
[1/28/14 14:38:12:573 CST] 0000005d SystemErr     R     at com.ibm.ws.sib.api.jms.impl.JmsMsgConsumerImpl.setMessageListene
r(JmsMsgConsumerImpl.java:609)

CODE:

public void connect(String hostName, String portNumber,

    String connectionFactoryString, String consumerJNDIName)

    throws Exception {

        Hashtable env = new Hashtable();

        env.put(Context.PROVIDER_URL, "iiop://" + hostName + ":" + portNumber
                + "");

        env.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.ibm.websphere.naming.WsnInitialContextFactory");

        InitialContext initialContext = new InitialContext(env);

        ConnectionFactory connectionFactory = (ConnectionFactory) initialContext
                .lookup(connectionFactoryString);

        connection = connectionFactory.createConnection();

        connection.start();

        // create destination - JMSQueue

        Destination destinationReceiver = (Destination) initialContext
                .lookup(consumerJNDIName);

        consumerSession = connection.createSession(false,
                Session.AUTO_ACKNOWLEDGE);

        consumer = consumerSession.createConsumer(destinationReceiver);

        consumer.setMessageListener(new MessageListener() { **// ERROR here**

            public void onMessage(Message msg) {
                try {
                    System.out.println("received: " + ((TextMessage) msg).getText());
                } catch (JMSException ex) {
                    ex.printStackTrace();
                }

            }
        });
    }

Upvotes: 0

Views: 1875

Answers (1)

Anton N
Anton N

Reputation: 2375

To consume messages from Queue you need only MessageListener registered in Spring context.

In web.xml you should register resource reference to JMS resources inside application server:

<resource-ref>
    <res-ref-name>jms.jndi.cf.name</res-ref-name>
    <res-type>javax.jms.ConnectionFactory</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

<resource-ref>
    <res-ref-name>jms.jndi.queue</res-ref-name>
    <res-type>javax.jms.Queue</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

Next step is Spring context:

    <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 
   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">

<tx:annotation-driven/>
<context:component-scan base-package="com.jms" />
    <!-- Connection Factory -->
<jee:jndi-lookup id="myConnectionFactory" jndi-name="jms.jndi.cf.name" />

<!-- Queue -->
<jee:jndi-lookup id="destination" jndi-name="jms.jndi.queue.name" />

<!-- JMS Destination Resolver -->
<bean id="jmsDestinationResolver" class="org.springframework.jms.support.destination.DynamicDestinationResolver">
</bean>

<!-- JMS Queue Template -->
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory">
        <ref bean="myConnectionFactory" />
    </property>
    <property name="destinationResolver">
        <ref bean="jmsDestinationResolver" />
    </property>
    <property name="pubSubDomain">
        <value>false</value>
    </property>
    <property name="receiveTimeout">
        <value>20000</value>
    </property>
</bean>

<bean id="messageListener" class="com.jms.JMSMessageListener" />

<!-- Message listener container -->
<bean id="jmsConsumerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="myConnectionFactory" />
    <property name="destination" ref="destination" />
    <property name="messageListener" ref="messageListener" />

</bean>
</beans>

And the final step is MessageListener:

package com.jms;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import javax.jms.BytesMessage;
import javax.jms.Message;
import javax.jms.MessageListener;
import java.io.ByteArrayInputStream;
import java.io.StringReader;

public class JMSMessageListener implements MessageListener {

private static final Logger LOGGER = LoggerFactory.getLogger(JMSMessageListener.class);

private static final String ENCODNG = "UTF-8";

@Transactional
public void onMessage(Message message) {
    if (message instanceof BytesMessage) {
        try {
            BytesMessage bytesMessage = (BytesMessage) message;
            LOGGER.debug("Receive message from Queue:\n" + bytesMessage);

            byte[] data = new byte[(int) bytesMessage.getBodyLength()];
            bytesMessage.readBytes(data);
            String stringMessagePayload = new String(data, ENCODNG);
            LOGGER.debug("Message payload: \n" + stringMessagePayload);
            }
        } catch (Exception ex) {
            LOGGER.error("Error has occured: " + ex);
            throw new RuntimeException(ex);
        }
    } else {
        throw new IllegalArgumentException("Message must be of type BytesMessage");
    }
}
}

I hope this quick example will help you.

Upvotes: 1

Related Questions