How to send JMS messages from WildFly 10 to remote ActiveMQ
Asked Answered
N

2

7

After so much fumbling around the internet, it's a surprise that I can't find a sample configuration for pushing to a remote message queue using JMS in WildFly 10 with ActiveMQ (Artemis). To worsen the situation standalone-full.xml is not bound to a schema (why???) and when I finally found the XSD for it here on GitHub, it contains no documentation stating what each node/attribute means and what values can be put in what.

Below is the original configuration from standalone-full.xml.

    <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
      <server name="default">
        <security-setting name="#">
          <role name="guest" delete-non-durable-queue="true" create-non-durable-queue="true" consume="true" send="true"/>
        </security-setting>
        <address-setting name="#" message-counter-history-day-limit="10" page-size-bytes="2097152" max-size-bytes="10485760" expiry-address="jms.queue.ExpiryQueue" dead-letter-address="jms.queue.DLQ"/>
        <http-connector name="http-connector" endpoint="http-acceptor" socket-binding="http"/>
        <http-connector name="http-connector-throughput" endpoint="http-acceptor-throughput" socket-binding="http">
          <param name="batch-delay" value="50"/>
        </http-connector>
        <in-vm-connector name="in-vm" server-id="0"/>
        <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"/>
        <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
        <connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
        <pooled-connection-factory name="activemq-ra" transaction="xa" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm"/>
      </server>
    </subsystem>

Below is my CDI queue client which is able to post messages to the local Artemis instance in the WildFly.

@ApplicationScoped
public class QueueClient {

  private static final Gson GSON = new Gson();

  @Resource(mappedName = "java:jboss/DefaultJMSConnectionFactory")
  private ConnectionFactory connectionFactory;

  public void sendMessage(String destinationName, Object message) throws JMSException {
    try (Connection conn = connectionFactory.createConnection();
        Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE)) {

      Queue queue = session.createQueue(destinationName);
      final Message consignment = session.createMessage();
      consignment.setStringProperty("MEDIA_TYPE", "application/json");
      consignment.setStringProperty("BODY", GSON.toJson(message));
      session.createProducer(queue).send(consignment);
    }
  }
}

My goal: to post messages to a remote ActiveMQ instance.

What I have: server url, topic name, username and password.

My question: how do I modify the configuration to achieve this goal?

Alternative question: if the above can't be answered, how else do I achieve this goal?

Thanks!

Novella answered 2/9, 2016 at 3:47 Comment(0)
S
7

Have you checked the following documentation.

https://docs.jboss.org/author/display/WFLY10/Connect+a+pooled-connection-factory+to+a+Remote+Artemis+Server

It probably addresses your current concern.

Thanks.

EDIT: Upon negative flagging of this post.

As the documentation that was listed above clearly describes. You need to create a pooled connection factory, that uses a remote connector and the remote connector references the IP x Socket of the remote Active MQ server. Please see the documentation on how to this, these the first three steps.

The configuration of such a pooled-connection-factory is done in 3 steps, and I quote:

  1. create an outbound-socket-binding pointing to the remote messaging server: /socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=remote-artemis:add(host=, port=61616)

  2. create a remote-connector referencing the outbound-socket-binding created at step (1). /subsystem=messaging-activemq/server=default/remote-connector=remote-artemis:add(socket-binding=remote-artemis)

  3. create a pooled-connection-factory referencing the remote-connector created at step (2). /subsystem=messaging-activemq/server=default/pooled-connection-factory=remote-artemis:add(connectors=[remote-artemis], entries=[java:/jms/remoteCF])

Finally, once you have your pooled connection factory properly configured, you can use it as just any JNDI resource available to a JEE container. Simply inject the pooled connction factory into your bean and use it to create a session.

Here, you have an example on how to send a JMS message to a server. In your case, it is only a matter of fixing the connection factory JNDI reference to your pooled connection factory associated to remote active MQ.

http://www.mastertheboss.com/jboss-server/jboss-jms/sending-jms-messages-over-xa-with-wildfly-jboss-as

And I quote:

@Stateless
public class JMSService {


    @Resource(mappedName = "java:jboss/jms/queue/exampleQueue")
    private Queue queueExample;

    @Resource(mappedName = "java:/JmsXA")
    private ConnectionFactory cf;

    private Connection connection;
    private MessageProducer publisher;
    private Session session;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void sendMessage(String txt) {

        try {         

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

            publisher = session.createProducer(queueExample);

            connection.start();

            TextMessage message = session.createTextMessage(txt);
            publisher.send(message);


        }
        catch (Exception exc) {
            exc.printStackTrace();
        }
        finally {         

          if (publisher != null) try { publisher.close(); } catch (Exception ignore) { }
          if (session != null) try { session.close(); } catch (Exception ignore) { }
          if (connection != null) try { connection.close(); } catch (Exception ignore) { }


         }
    } 
}

In this case you connection factory should:

@Inject

    @JMSConnectionFactory("java:/jms/remoteCF")

    private JMSContext context;

One more thing you need to be aware is that the queue you would like to inject into your bean is a remote queue. The way you get access to a remote queue is by doing a JNDI lookup on the the remote active MQ server. This is explained here. http://activemq.apache.org/artemis/docs/1.1.0/using-jms.html#jndi-configuration

And I quote the interesting part of the documentation starts. If you follow through, you can see how the JNDI initial context can be used to lookup the artemis queues.

And if the client wanted to bind this queue to "queues/OrderQueue" then the JNDI properties would be configured like so:

java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory java.naming.provider.url=tcp://myhost:5445 queue.queues/OrderQueue=OrderQueue

It is also possible to look-up JMS destinations which haven't been configured explicitly in the JNDI context environment. This is possible using dynamicQueues/ or dynamicTopics/ in the look-up string. For example, if the client wanted to look-up the aforementioned "OrderQueue" it could do so simply by using the string "dynamicQueues/OrderQueue". Note, the text that follows dynamicQueues/ or dynamicTopics/ must correspond exactly to the name of the destination on the server.

Please read through the artemis configuration on this.

Finally, there is another approach that you can try to explore. And these are JMS Queue Bridges. You have too google this up. But essentially, a JMS bridge can allow the contents of a queue to tunneled to a remote queue. So this mechanism of bridging should give you the possibility of programming your code as if against a local artemis JMS server, but with all the queues being bridged the data Being READ or being published is actually coming from or going to a remote server.

But you have to inform yourself to see what works best for you.

I sincerly hope this helps.

Selfdenial answered 22/11, 2016 at 19:17 Comment(4)
A link to a potential solution is always welcome, but please add context around the link so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline. Take into account that being barely more than a link to an external site is a possible reason as to Why and how are some answers deleted?.Tannenwald
Uau! Seriously? The URL is called: Connct a poolled JMS conneciton factory to a Remote Artemis Server. His problem is how to connect to a remote Active MQ server. Do you want me to paraphrase the full documentation?Selfdenial
"Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline."Tannenwald
thumbs up for pointing out the bridging approach as that seems to me as a more proper way. instead of changing my MDB (which according to STANDARD JMS shall not really happen) it is just the setup that changes.Puzzler
S
0

I've been struggling with a very similar issue this week. Due to my architecture I've selected an alternative approach that you might find useful:

Continue sending messages to the local Artemis Broker, but configure a JMS-bridge between the Artemis broker and the remote ActiveMQ broker.

This approach still caused me some headaches, but in the end I got it working nicely. Details at:

JMS Bridge Between WildFly 10 Artemis and ActiveMQ 5.14 (ONCE_AND_ONLY_ONCE Quality of Service)

Streaky answered 15/9, 2016 at 12:3 Comment(2)
I later opted for a different solution. I used the ActiveMQ Resource Adapter which I just deployed like a regular war file to the server. Not the solution I would have loved but well, it worked.Novella
@SayoOladeji , could you please detail your solution? I asked a question almost same with yours #43179783Kourtneykovac

© 2022 - 2024 — McMap. All rights reserved.