Search code examples
activemq-artemis

How to browse an ActiveMQ Artemis queue under different address using JMS and CORE protocol?


I am trying to browse a queue on ActiveMQ Artemis using a JMS QueueBrowser, but the name of the queue is different from the name of the address it is created under (e.g. automatically created expiry or dead-letter queues under a single address). I have replicated the problem in the scenario and code described below:

Create an address with name address and create a queue with name queue. Send a couple simple text messages to the queue. This will result in a situation like this:

Screenshot of Artemis admin console showing a queue with a different address

Now use the following code to browse through the queue and print the messages:

import java.util.Collections;
import java.util.List;

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
import javax.jms.Session;

import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;

public class ArtemisQueueBrowser {
    
    public static void main(String[] args) throws JMSException {
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
        Connection connection = connectionFactory.createConnection("admin", "admin");
        connection.start();
        Session session = connection.createSession();
        Queue queue = session.createQueue("queue");
        QueueBrowser browser = session.createBrowser(queue);
        
        List<Message> messages = Collections.list(browser.getEnumeration());
        
        System.out.println(messages.size() + " messages:");
        for (Message message : messages) {
            System.out.println("- "  + message.getBody(String.class));
        }
        connection.close();
    }
}

This should print the message bodies as a list, but instead exits with the following error:

ActiveMQQueueExistsException[errorType=QUEUE_EXISTS message=AMQ229019: Queue queue already exists on address address]

It looks like either the CORE client or the server fails to find the queue and tries to create it under an address with the same name as the queue. This fails of course since the queue already exists.

But it gets stranger! Because if I try the same thing using an AMQP connection factory the behaviour is different! I use the following code:

import java.util.Collections;
import java.util.List;

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
import javax.jms.Session;

import org.apache.qpid.jms.JmsConnectionFactory;

public class AmqpQueueBrowser {
    
    public static void main(String[] args) throws JMSException {
        JmsConnectionFactory connectionFactory = new JmsConnectionFactory("amqp://localhost:61616");
        Connection connection = connectionFactory.createConnection("admin", "admin");
        connection.start();
        Session session = connection.createSession();
        Queue queue = session.createQueue("queue");
        QueueBrowser browser = session.createBrowser(queue);
        
        List<Message> messages = Collections.list(browser.getEnumeration());
        
        System.out.println(messages.size() + " messages:");
        for (Message message : messages) {
            System.out.println("- "  + message.getBody(String.class));
        }
        connection.close();
    }
}

The output is:

[AmqpProvider :(1):[amqp://localhost:61616]] INFO org.apache.qpid.jms.JmsConnection - Connection ID:9e10c2c8-00c0-4e59-9401-9b0a53f40f49:1 connected to server: amqp://localhost:61616
3 messages:
- 1st message
- second message
- and another message just for good measure

Now the output is correct, but Artemis incorrectly created a new address with the name queue with no queues associated, while the QueueBrowser reads the queue under address address:

Screenshot of Artemis admin console showing an address was created with name "queue"

If you now switch back to the CORE protocol version it is also able to read the queue because of the existence of the queue-less address.

How can I read the correct queue without triggering the described error using the CORE protocol.


Solution

  • The behavior you're seeing with the Core JMS client is expected due to the way the JMS-to-Core mapping works. In short, a JMS queue is represented by a core address and a core queue of the same name. Since you don't have that the Core JMS client throws an error.

    I'm not entirely sure what's going on in the situation with the Qpid JMS client.

    In any case, you should be able to do everything you want with the Core JMS client by using the fully-qualified-queue-name, e.g.:

    Queue queue = session.createQueue("address::queue");
    

    Lastly, in order to make your code portable between JMS implementations you can put a jndi.properties file on your classpath, use a JNDI look-up for the ConnectionFactory, and remove references to implementation-specific classes in your code (e.g. ActiveMQConnectionFactory & JmsConnectionFactory).