Search code examples
jmsspring-jmsstompactivemq-artemis

How Do I Connect Stomp Client to An ActiveMQ Artemis Destination Created Using JMS(Spring Boot)?


CONTEXT

I am trying to learn about SpringJMS and MOMS and I am using ActiveMQ Artemis for this. I created a Queue Destination address using the jakarta.jms.* API, and managed to send some message to the queue like this:

public void createUserDestination(String userId) throws JMSException {
        queueDestination = setupConnection().createQueue("user" + userId);
        producer = session.createProducer(queueDestination);
        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
        producer.send(session.createTextMessage("Testing queue availability"));

        connection.close();
        log.info("successfully created group... going back to controller");
}

So for example, if I pass an ID of user12345abc, I get a Queue Address user12345abc, of the routing type ANYCAST with one queue underneath(with that same address) with my message placed there.

PROBLEM

Now, I wanted to write a simple web front-end with STOMP that can connect to this queue. But I have been having a ton of problems connecting to that queue address because each time I try to connect by providing the destination address, it creates a new address in the MOM and connects to that instead. My STOMP code looks like this(the first argument is the destination address, you can ignore the rest of the code):

stompClient.subscribe("jms.queue.user12345abc", (message) => {
               receivedMessages.value.push(message.body);
 });

In this case, completely brand new queue is created with the address jms.queue.user12345abc which is not what I want at all. I configured my Spring Backend to use an external MOM broker like this(I know this is important):

public void configureMessageBroker(MessageBrokerRegistry registry) {
        // these two end points are prefixes for where the messages are pushed to
        registry.enableStompBrokerRelay("jms.topic", "jms.queue")
            .setRelayHost("127.0.0.1")
            .setRelayPort(61613)
            .setSystemLogin(brokerUsername)
            .setSystemPasscode(brokerPassword)
            .setClientLogin(brokerUsername)
            .setClientPasscode(brokerPassword);

        // this prefixes the end points where clients send messages
        registry.setApplicationDestinationPrefixes("/app", "jms.topic", "jms.queue");

        // this prefixes the end points where the user's subscribe to
        registry.setUserDestinationPrefix("/user");
}

But it's still not working as I expect it to. Am I getting some concept wrong here? How do I use STOMP to connect to that queue I created earlier with JMS?


Solution

  • It's not clear why you are using the jms.queue and jms.topic prefixes. Those are similar but not quite the same as the jms.queue. and jms.topic. prefixes which were used way back in ActiveMQ Artemis 1.x (whose last release was in early 2018 almost 5 years ago now).

    In any case, I recommend you use the more widely adopted /queue/ and /topic/, e.g.:

    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // these two end points are prefixes for where the messages are pushed to
        registry.enableStompBrokerRelay("/topic/", "/queue/")
                .setRelayHost("127.0.0.1")
                .setRelayPort(61613)
                .setSystemLogin(brokerUsername)
                .setSystemPasscode(brokerPassword)
                .setClientLogin(brokerUsername)
                .setClientPasscode(brokerPassword);
    
        // this prefixes the end points where clients send messages
        registry.setApplicationDestinationPrefixes("/app", "/topic/", "/queue/");
    
        // this prefixes the end points where the user's subscribe to
        registry.setUserDestinationPrefix("/user");
    }
    

    The in broker.xml you'd need to add the corresponding anycastPrefix and multicastPrefix values on the STOMP acceptor, e.g.:

    <acceptor name="stomp">tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true;anycastPrefix=/queue/;multicastPrefix=/topic/</acceptor>
    

    To be clear, your JMS code will stay the same, but your STOMP consumer would be something like:

    stompClient.subscribe("/queue/user12345abc", (message) => {
                   receivedMessages.value.push(message.body);
    });