Search code examples
javaactivemq-artemis

No error is displayed when sending a message to a queue without ActiveMQ Artemis rights


I'm trying to send 2 different messages to a queue where there is no SEND permission. In the case of setting producer.setDeliveryMode(DeliveryMode.PERSISTENT) everything is fine (the error is displayed in the console), but if I set the value producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT) then there will be no error and the message will not be sent to the queue. I would like the error to be reproduced in two cases or is this a feature of the broker?

My broker.xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<configuration xmlns="urn:activemq"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
    <core xmlns="urn:activemq:core">
      <name>localhost</name>
      
      <bindings-directory>./data/messaging/bindings</bindings-directory>

      <journal-directory>./data/messaging/journal</journal-directory>

      <large-messages-directory>./data/messaging/largemessages</large-messages-directory>

      <paging-directory>./data/messaging/paging</paging-directory>


      <!-- true to expose ActiveMQ Artemis resources through JMX -->
      <jmx-management-enabled>true</jmx-management-enabled>

      <!-- Acceptors -->
      <acceptors>
         <acceptor name="netty">tcp://localhost:61616</acceptor>
      </acceptors>

      <!-- Other config -->

      <security-settings>
         <!--security for example queue-->
         <security-setting match="exampleQueue">
            <permission roles="amq" type="createDurableQueue"/>
            <permission roles="amq" type="deleteDurableQueue"/>
            <permission roles="amq" type="createNonDurableQueue"/>
            <permission roles="amq" type="deleteNonDurableQueue"/>
            <permission roles="amq" type="consume"/>
            <permission roles="no" type="send"/>
            <permission roles="amq" type="browse"/>
         </security-setting>
         <security-setting match="TestQueue">
            <permission roles="amq" type="createDurableQueue"/>
            <permission roles="amq" type="deleteDurableQueue"/>
            <permission roles="amq" type="createNonDurableQueue"/>
            <permission roles="amq" type="deleteNonDurableQueue"/>
            <permission roles="amq" type="consume"/>
            <permission roles="no" type="send"/>
            <permission roles="amq" type="browse"/>
         </security-setting>
         <security-setting match="TestQueueSecond">
            <permission roles="amq" type="createDurableQueue"/>
            <permission roles="amq" type="deleteDurableQueue"/>
            <permission roles="amq" type="createNonDurableQueue"/>
            <permission roles="amq" type="deleteNonDurableQueue"/>
            <permission roles="no" type="consume"/>
            <permission roles="no" type="send"/>
         </security-setting>
      </security-settings>

      <addresses>
         <address name="exampleQueue">
            <anycast>
               <queue name="exampleQueue"/>
            </anycast>
         </address>
         <address name="TestQueue">
            <anycast>
               <queue name="TestQueue"/>
            </anycast>
         </address>
         <address name="TestQueueSecond">
            <anycast>
               <queue name="TestQueueSecond"/>
            </anycast>
         </address>
      </addresses>
   </core>
</configuration>

My class java:

@RestController
public class Producer implements Serializable {

    String url = "tcp://localhost:61616";

    @GetMapping("/send")
    public String sendMessage() throws JMSException {

        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
        connectionFactory.setUser("test");
        connectionFactory.setPassword("qwe123");

        Connection connection = connectionFactory.createConnection();
        connection.start();

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

        Destination destination = session.createQueue("exampleQueue");

        MessageProducer producer = session.createProducer(destination);
        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);

        Message message = session.createTextMessage("BodyTextMessage");
        message.setStringProperty("TEST", "TEST");

        producer.send(message);

        String body = message.getBody(String.class);

        connection.close();

        return body;
    }

This is exactly the example when I send a message to the queue, but there is no error that the message cannot be sent because there is no permission to send.


Solution

  • When sending a non-persistent message the core JMS client from ActiveMQ Artemis uses "fire-and-forget" semantics which means it doesn't wait to determine if the send was successful or not; it simply returns control to the sending application. This is a performance optimization based on the fact that non-persistent messages are by nature volatile. In other words, since non-persistent messages do not survive a broker restart that means their loss is acceptable.

    You can change these semantics by setting blockOnNonDurableSend=true on your connection URL, e.g.:

    String url = "tcp://localhost:61616?blockOnNonDurableSend=true";
    

    This, of course, will make sending non-persistent messages much slower. See more in the documentation.