Search code examples
javawildflyjboss-arquillianactivemq-artemis

Send AMQ Message using ActiveMQ Artemis


I want to send a message to an ActiveMQ Artemis instance on a WildFly server. I am using this tutorial in trying to configure the standalone-full.xml. I am using the jboss/wildfly docker image and am exposing the below netty port: 5445.

Standalone configuration:

<subsystem xmlns="urn:jboss:domain:messaging-activemq:10.0">
    <server name="default">
        <security enabled="true"/>
        <security-setting name="#">
            <role name="SuperUser" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
        </security-setting>
        <address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10" redistribution-delay="1000"/>
        <http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
        <http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
            <param name="batch-delay" value="50"/>
        </http-connector>
        <in-vm-connector name="in-vm" server-id="0"/>
        <remote-connector name="netty" socket-binding="messaging"/>
        <remote-acceptor name="netty" socket-binding="messaging"/>

        <http-acceptor name="http-acceptor" http-listener="default"/>
        <http-acceptor name="http-acceptor-throughput" http-listener="default">
            <param name="batch-delay" value="50"/>
            <param name="direct-deliver" value="false"/>
        </http-acceptor>
        <in-vm-acceptor name="in-vm" server-id="0"/>

        <jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
        <jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
        <jms-queue name="JoeIsCool" entries="java:/jms/queue/JoeIsCool"/>

        <connection-factory name="InVmConnectionFactory" connectors="in-vm" entries="java:/ConnectionFactory"/>
        <connection-factory name="RemoteConnectionFactory" ha="true" block-on-acknowledge="true" reconnect-attempts="-1" connectors="netty" entries="java:jboss/exported/jms/RemoteConnectionFactory"/>
        <pooled-connection-factory name="activemq-ra" transaction="xa" connectors="in-vm" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory"/>
    </server>
</subsystem>


<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">

    ...
    <socket-binding name="messaging" port="5445"/>
    ...

</socket-binding-group>

I tried to create a simple test case that would send a message to the ActiveMQ Artemis instance:

public void sendAmqMessage() throws Exception {
    final ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("admin", "secretPassoword", "tcp://localhost:5445");
    final Connection connection = connectionFactory.createConnection();
    connection.start();
    final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    final Destination destination = session.createQueue("JoeIsCool");
    final MessageProducer producer = session.createProducer(destination);
    final TextMessage message =
    session.createTextMessage("Hello !!! Welcome to the world of ActiveMQ.");
    producer.send(message);
    connection.close();
}

Upon execution, I get this error on my client:

javax.jms.JMSException: Cannot send, channel has already failed: tcp://127.0.0.1:5445

I get this error on my server:

(Thread-1 (activemq-netty-threads)) AMQ214013: Failed to decode packet: java.lang.IllegalArgumentException: AMQ219032: Invalid type: 1

I tried to follow this post in answering my own question but was unable to find a useful solution.

What am I missing in configuring the ActiveMQ instance, and how can I test it with Java code?


Solution

  • In your sendAmqMessage method you're creating a javax.jms.ConnectionFactory instance like so:

    final ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("admin", "secretPassoword", "tcp://localhost:5445");
    

    This ActiveMQConnectionFactory is from the ActiveMQ 5.x client and uses the OpenWire protocol which the remote-acceptor in your standalone-full.xml doesn't understand, hence the error about failing to decode the incoming backup.

    As the documentation you're following suggests, instead of instantiating the ConnectionFactory directly you should simply look it up in JNDI like so:

    final Properties env = new Properties();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
    env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
    InitialContext remotingCtx = new InitialContext(env);
    final ConnectionFactory connectionFactory = (ConnectionFactory) remotingCtx.lookup("jms/RemoteConnectionFactory");
    

    Also, make sure you're using the correct dependency, i.e.:

    <dependencies>
      <dependency>
        <groupId>org.wildfly</groupId>
        <artifactId>wildfly-jms-client-bom</artifactId>
        <type>pom</type>
      </dependency>
    </dependencies>
    

    Using JNDI this way will also allow you to remove this from your standalone-full.xml:

    <remote-connector name="netty" socket-binding="messaging"/>
    <remote-acceptor name="netty" socket-binding="messaging"/>
    

    As well as this:

    <socket-binding name="messaging" port="5445"/>
    

    You really only need the resources defined in the default standalone-full.xml.