[[Messaging]]
= Messaging configuration

The Jakarta Messaging server configuration is done through the _messaging-activemq_
subsystem. In this chapter we are going outline the frequently used
configuration options. For a more detailed explanation please consult
the Artemis user guide (See "Component Reference").

[[required-extension-messaging]]
== Required Extension

The configuration options discussed in this section assume that the the
`org.wildfly.extension.messaging-activemq` extension is present in your
configuration. This extension is not included in the standard
`standalone.xml` and `standalone-ha.xml` configurations included in the
WildFly distribution. It is, however, included with the
`standalone-full.xml` and `standalone-full-ha.xml` configurations.

You can add the extension to a configuration without it either by adding
an `<extension module="org.wildfly.extension.messaging-activemq"/>`
element to the xml or by using the following CLI operation:

[source,options="nowrap"]
----
[standalone@localhost:9990 /]/extension=org.wildfly.extension.messaging-activemq:add
----

[[connectors]]
== Connectors

There are three kind of connectors that can be used to connect to
WildFly Jakarta Messaging Server

* `invm-connector` can be used by a local client (i.e. one running in
the same JVM as the server)
* `netty-connector` can be used by a remote client (and uses Netty over
TCP for the communication)
* `http-connector` can be used by a remote client (and uses Undertow Web
Server to upgrade from a HTTP connection)

[[Jakarta-Messaging-connection-factories]]
== Jakarta Messaging Connection Factories

There are three kinds of _basic_ Jakarta Messaging `connection-factory` that depends
on the type of connectors that is used.

There is also a `pooled-connection-factory` which is special in that it
is essentially a configuration facade for _both_ the inbound and
outbound connectors of the the Artemis Jakarta Connectors Resource Adapter. An MDB can
be configured to use a `pooled-connection-factory` (e.g. using
`@ResourceAdapter`). In this context, the MDB leverages the _inbound
connector_ of the Artemis Jakarta Connectors RA. Other kinds of clients can look up the
pooled-connection-factory in JNDI (or inject it) and use it to send
messages. In this context, such a client would leverage the _outbound
connector_ of the Artemis Jakarta Connectors RA. A `pooled-connection-factory` is also
special because:

* It is only available to local clients, although it can be configured
to point to a remote server.
* As the name suggests, it is pooled and therefore provides superior
performance to the clients which are able to use it. The pool size can
be configured via the `max-pool-size` and `min-pool-size` attributes.
* It should only be used to _send_ (i.e. produce) messages when looked
up in JNDI or injected.
* It can be configured to use specific security credentials via the
`user` and `password` attributes. This is useful if the remote server to
which it is pointing is secured.
* Resources acquired from it will be automatically enlisted any on-going
Jakarta Transactions. If you want to send a message from an Jakarta Enterprise Beans using CMT
then this is likely the connection factory you want to use so the send
operation will be atomically committed along with the rest of the Jakarta Enterprise Beans's
transaction operations.

To be clear, the _inbound connector_ of the Artemis Jakarta Connectors RA (which is for
consuming messages) is only used by MDBs and other Jakarta Connectors based components.
It is not available to traditional clients.

Both a `connection-factory` and a `pooled-connection-factory` reference
a `connector` declaration.

A `netty-connector` is associated with a `socket-binding` which tells
the client using the `connection-factory` where to connect.

* A `connection-factory` referencing a `netty-connector` is suitable to
be used by a _remote_ client to send messages to or receive messages
from the server (assuming the connection-factory has an appropriately
exported `entry`).
* A `pooled-connection-factory` looked up in JNDI or injected which is
referencing a `netty-connector` is suitable to be used by a _local_
client to send messages to a remote server granted the `socket-binding`
references an `outbound-socket-binding` pointing to the remote server in
question.
* A `pooled-connection-factory` used by an MDB which is referencing a
`remote-connector` is suitable to consume messages from a remote server
granted the `socket-binding` references an `outbound-socket-binding`
pointing to the remote server in question.

An `in-vm-connector` is associated with a `server-id` which tells the
client using the `connection-factory` where to connect (since multiple
Artemis servers can run in a single JVM).

* A `connection-factory` referencing an `in-vm-connector` is suitable to
be used by a _local_ client to either send messages to or receive
messages from a local server.
* A `pooled-connection-factory` looked up in JNDI or injected which is
referencing an `in-vm-connector` is suitable to be used by a _local_
client only to send messages to a local server.
* A `pooled-connection-factory` used by an MDB which is referencing an
`in-vm-connector` is suitable only to consume messages from a local
server.

A `http-connector` is associated with the `socket-binding` that
represents the HTTP socket (by default, named `http`).

* A `connection-factory` referencing a `http-connector` is suitable to
be used by a remote client to send messages to or receive messages from
the server by connecting to its HTTP port before upgrading to the
messaging protocol.
* A `pooled-connection-factory` referencing a `http-connector` is
suitable to be used by a local client to send messages to a remote
server granted the `socket-binding` references an
`outbound-socket-binding` pointing to the remote server in question.
* A `pooled-connection-factory` used by an MDB which is referencing a
`http-connector` is suitable only to consume messages from a remote
server granted the `socket-binding` references an
`outbound-socket-binding` pointing to the remote server in question.

The `entry` declaration of a `connection-factory` or a
`pooled-connection-factory` specifies the JNDI name under which the
factory will be exposed. Only JNDI names bound in the
`"java:jboss/exported"` namespace are available to remote clients. If a
`connection-factory` has an entry bound in the `"java:jboss/exported"`
namespace a remote client would look-up the `connection-factory` using
the text _after_ `"java:jboss/exported"`. For example, the "
`RemoteConnectionFactory`" is bound by default to
`"java:jboss/exported/jms/RemoteConnectionFactory"` which means a remote
client would look-up this `connection-factory` using "
`jms/RemoteConnectionFactory`". A `pooled-connection-factory` should
_not_ have any `entry` bound in the " `java:jboss/exported`" namespace
because a `pooled-connection-factory` is not suitable for remote
clients.

Since Jakarta Messaging 2.0, a default Jakarta Messaging connection factory is accessible to Jakarta EE
applications under the JNDI name `java:comp/DefaultJMSConnectionFactory.`
The WildFly messaging subsystem defines a `pooled-connection-factory` that
is used to provide this default connection factory. Any parameter change
on this `pooled-connection-factory` will be take into account by any EE
application looking the default Jakarta Messaging provider under the JNDI name
`java:comp/DefaultJMSConnectionFactory.`

[source,xml,options="nowrap"]
----
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
    <server name="default">
        [...]
        <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"/>
      [...]
      <connection-factory name="InVmConnectionFactory"
                            connectors="in-vm"
                            entries="java:/ConnectionFactory" />
      <pooled-connection-factory name="activemq-ra"
                            transaction="xa"
                            connectors="in-vm"
                            entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory"/>
      [...]
   </server>
</subsystem>
----

~(See standalone/configuration/standalone-full.xml)~

[[Jakarta-Messaging-queues-and-topics]]
== Jakarta Messaging Queues and Topics

Jakarta Messaging queues and topics are sub resources of the messaging-actively
subsystem. One can define either a `jms-queue` or `jms-topic`. Each
destination _must_ be given a `name` and contain at least one entry in
its `entries` element (separated by whitespace).

Each entry refers to a JNDI name of the queue or topic. Keep in mind
that any `jms-queue` or `jms-topic` which needs to be accessed by a
remote client needs to have an entry in the "java:jboss/exported"
namespace. As with connection factories, if a `jms-queue` or or
`jms-topic` has an entry bound in the "java:jboss/exported" namespace a
remote client would look it up using the text _after_
`"java:jboss/exported`". For example, the following `jms-queue`
"testQueue" is bound to "java:jboss/exported/jms/queue/test" which means
a remote client would look-up this \{\{kms-queue} using
"jms/queue/test". A local client could look it up using
"java:jboss/exported/jms/queue/test", "java:jms/queue/test", or more
simply "jms/queue/test":

[source,xml,options="nowrap"]
----
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
    <server name="default">
    [...]
    <jms-queue name="testQueue"
               entries="jms/queue/test java:jboss/exported/jms/queue/test" />
    <jms-topic name="testTopic"
               entries="jms/topic/test java:jboss/exported/jms/topic/test" />
</subsystem>
----

~(See standalone/configuration/standalone-full.xml)~

Jakarta Messaging endpoints can easily be created through the CLI:

[source,options="nowrap"]
----
[standalone@localhost:9990 /] jms-queue add --queue-address=myQueue --entries=queues/myQueue
----

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default/jms-queue=myQueue:read-resource
{
    "outcome" => "success",
    "result" => {
        "durable" => true,
        "entries" => ["queues/myQueue"],
        "selector" => undefined
    }
}
----


Pausing and resuming Queues and Topics

When a queue is paused, it will receive messages but will not deliver them. When it's resumed, it'll begin delivering the queued messages, if any.
When a topic is paused, it will receive messages but will not deliver them. Newly added subscribers will be paused too until the topic is resumed. When it is resumed, delivering will occur again. The `persist` parameter ensure that the topic stays paused on the restart of the server.

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default/jms-queue=myQueue:pause()
----

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default/jms-topic=myTopic:pause()
----

A number of additional commands to maintain the Jakarta Messaging subsystem are
available as well:

[source,options="nowrap"]
----
[standalone@localhost:9990 /] jms-queue --help --commands
add
...
remove
To read the description of a specific command execute 'jms-queue command_name --help'.
----

[[dead-letter-redelivery]]
== Dead Letter & Redelivery

Some of the settings are applied against an address wild card instead of
a specific messaging destination. The dead letter queue and redelivery
settings belong into this group:

[source,xml,options="nowrap"]
----
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
   <server name="default">
      [...]
      <address-setting name="#"
                       dead-letter-address="jms.queue.DLQ"
                       expiry-address="jms.queue.ExpiryQueue"
                       [...] />
----

~(See standalone/configuration/standalone-full.xml)~

[[security-settings-for-artemis-addresses-and-Jakarta-Messaging-destinations]]
== Security Settings for Artemis addresses and Jakarta Messaging destinations

Security constraints are matched against an address wildcard, similar to
the DLQ and redelivery settings.

[source,xml,options="nowrap"]
----
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
   <server name="default">
      [...]
      <security-setting name="#">
          <role name="guest"
                send="true"
                consume="true"
                create-non-durable-queue="true"
                delete-non-durable-queue="true"/>
----

~(See standalone/configuration/standalone-full.xml)~

[[security-domain-for-users]]
== Security Domain for Users

By default, Artemis will use the " `ApplicationDomain`" Elytron security 
domain. This domain is used to authenticate users making connections to Artemis
and then they are authorized to perform specific functions based on their
role(s) and the `security-settings` described above. This domain can be
changed by using the `security-domain`, e.g.:

[source,xml,options="nowrap"]
----
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
   <server name="default">
       <security elytron-domain="mySecurityDomain" />
      [...]
----

[[cluster-authentication]]
== Cluster Authentication

If the Artemis server is configured to be clustered, it will use the
`cluster` 's `user` and `password` attributes to connect to other
Artemis nodes in the cluster.

If you do not change the default value of <cluster-password>, Artemis
will fail to authenticate with the error:

[source,options="nowrap"]
----
HQ224018: Failed to create session: HornetQExceptionerrorType=CLUSTER_SECURITY_EXCEPTION message=HQ119099: Unable to authenticate cluster user: HORNETQ.CLUSTER.ADMIN.USER
----

To prevent this error, you must specify a value for
`<cluster-password>`. It is possible to encrypt this value by as an encrypted
expression by referring to the Elytron documentation.

Alternatively, you can use the system property
jboss.messaging.cluster.password to specify the cluster password from
the command line.

[[deployment-of--jms.xml-files]]
== Deployment of -jms.xml files

Starting with WildFly {wildflyVersion}, you have the ability to deploy a -jms.xml file
defining Jakarta Messaging destinations, e.g.:

[source,xml,options="nowrap"]
----
<?xml version="1.0" encoding="UTF-8"?>
<messaging-deployment xmlns="urn:jboss:messaging-activemq-deployment:1.0">
   <server name="default">
      <jms-destinations>
         <jms-queue name="sample">
            <entry name="jms/queue/sample"/>
            <entry name="java:jboss/exported/jms/queue/sample"/>
         </jms-queue>
      </jms-destinations>
   </server>
</messaging-deployment>
----

WARNING: This feature **is primarily intended for development** as destinations
deployed this way can not be managed with any of the provided management
tools (e.g. console, CLI, etc).

[[Jakarta-Messaging-bridge]]
== Jakarta Messaging Bridge

The function of a Jakarta Messaging bridge is to consume messages from a source Jakarta Messaging
destination, and send them to a target Jakarta Messaging destination. Typically either
the source or the target destinations are on different servers.
The bridge can also be used to bridge messages from other non Artemis
messaging servers, as long as they are JMS 1.1 compliant.

The Jakarta Messaging Bridge is provided by the Artemis project. For a detailed
description of the available configuration properties, please consult
the project documentation.

[[modules-for-other-messaging-brokers]]
=== Modules for other messaging brokers

Source and target Jakarta Messaging resources (destination and connection factories)
are looked up using JNDI.
If either the source or the target resources are managed by another
messaging server than WildFly, the required client classes must be
bundled in a module. The name of the module must then be declared when
the Jakarta Messaging Bridge is configured.

The use of a Jakarta Messaging bridges with any messaging provider will require to
create a module containing the jar of this provider.

Let's suppose we want to use an hypothetical messaging provider named
AcmeMQ. We want to bridge messages coming from a source AcmeMQ
destination to a target destination on the local WildFly messaging
server. To lookup AcmeMQ resources from JNDI, 2 jars are required,
acmemq-1.2.3.jar, mylogapi-0.0.1.jar (please note these jars do not
exist, this is just for the example purpose). We must _not_ include a
Jakarta Messaging jar since it will be provided by a WildFly module directly.

To use these resources in a Jakarta Messaging bridge, we must bundle them in a WildFly
module:

in JBOSS_HOME/modules, we create the layout:

[source,options="nowrap"]
----
modules/
`-- org
    `-- acmemq
        `-- main
            |-- acmemq-1.2.3.jar
            |-- mylogapi-0.0.1.jar
            `-- module.xml
----

We define the module in `module.xml`:

[source,xml,options="nowrap"]
----
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.9" name="org.acmemq">
    <properties>
        <property name="jboss.api" value="private"/>
    </properties>
 
 
    <resources>
        <!-- insert resources required to connect to the source or target   -->
        <!-- messaging brokers if it not another WildFly instance           -->
        <resource-root path="acmemq-1.2.3.jar" />
        <resource-root path="mylogapi-0.0.1.jar" />
    </resources>
 
 
    <dependencies>
       <!-- add the dependencies required by messaging Bridge code                -->
       <module name="javax.api" /> <!-- deprecated -->
       <module name="javax.jms.api" />
       <module name="javax.transaction.api"/>
       <module name="org.jboss.remote-naming"/>
       <!-- we depend on org.apache.activemq.artemis module since we will send messages to  -->
       <!-- the Artemis server embedded in the local WildFly instance       -->
       <module name="org.apache.activemq.artemis" />
    </dependencies>
</module>
----

[[configuration]]
=== Configuration

A Jakarta Messaging bridge is defined inside a `jms-bridge` section of the
`messaging-activemq` subsystem in the XML configuration files.

[source,xml,options="nowrap"]
----
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
   <jms-bridge name="myBridge" module="org.acmemq">
      <source connection-factory="ConnectionFactory"
              destination="sourceQ"
              user="user1"
              password="pwd1"
              quality-of-service="AT_MOST_ONCE"
              failure-retry-interval="500"
              max-retries="1"
              max-batch-size="500"
              max-batch-time="500"
              add-messageID-in-header="true">
         <source-context>
            <property name="java.naming.factory.initial"
                      value="org.acmemq.jndi.AcmeMQInitialContextFactory"/>
            <property name="java.naming.provider.url"
                      value="tcp://127.0.0.1:9292"/>
         </source-context>
      </source>
      <target connection-factory"/jms/invmTargetCF"
              destination="/jms/targetQ" />
      </target>
   </jms-bridge>
</subsystem>
----

The `source` and `target` sections contain the name of the Jakarta Messaging resource
( `connection-factory` and `destination`) that will be looked up in
JNDI.
It optionally defines the `user` and `password` credentials. If they are
set, they will be passed as arguments when creating the Jakarta Messaging connection
from the looked up ConnectionFactory.
It is also possible to define JNDI context properties in the
`source-context` and `target-context` sections. If these sections are
absent, the Jakarta Messaging resources will be looked up in the local WildFly
instance (as it is the case in the `target` section in the example
above).

[[management-commands]]
=== Management commands

A Jakarta Messaging Bridge can also be managed using the WildFly command line
interface:

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /subsystem=messaging/jms-bridge=myBridge/:add(module="org.acmemq",
      source-destination="sourceQ",
      source-connection-factory="ConnectionFactory",
      source-user="user1",
      source-password="pwd1",
      source-context={"java.naming.factory.initial" => "org.acmemq.jndi.AcmeMQInitialContextFactory",
                      "java.naming.provider.url" => "tcp://127.0.0.1:9292"},
      target-destination="/jms/targetQ",
      target-connection-factory="/jms/invmTargetCF",
      quality-of-service=AT_MOST_ONCE,
      failure-retry-interval=500,
      max-retries=1,
      max-batch-size=500,
      max-batch-time=500,
      add-messageID-in-header=true)
{"outcome" => "success"}
----

You can also see the complete Jakarta Messaging Bridge resource description from the
CLI:

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /subsystem=messaging/jms-bridge=*/:read-resource-description
{
    "outcome" => "success",
    "result" => [{
        "address" => [
            ("subsystem" => "messaging"),
            ("jms-bridge" => "*")
        ],
        "outcome" => "success",
        "result" => {
            "description" => "A Jakarta Messaging bridge instance.",
            "attributes" => {
                ...
        }
    }]
}
----

[[Jakarta-Messaging-bridge-statistics]]
=== Statistics of a Jakarta Messaging Bridge

Currently two statistics are available on a Jakarta Messaging bridge: the number of processed messages and the number of aborted/rolled back messages.
Those are available with the following command :

[source, ruby]
----
/subsystem=messaging/jms-bridge=myBridge:read-attribute(name=message-count)
{
    "outcome" => "success",
    "result" => 0L
}

/subsystem=messaging/jms-bridge=myBridge:read-attribute(name=aborted-message-count)
{
    "outcome" => "success",
    "result" => 0L
}
----

== Component Reference

The messaging-activemq subsystem is provided by the Artemis project. For
a detailed description of the available configuration properties, please
consult the project documentation.

****

* Artemis Homepage: http://activemq.apache.org/artemis/
* Artemis User Documentation:
http://activemq.apache.org/artemis/docs.html

****

=== Controlling internal broker usage of memory and disk space

You can configure the disk space usage of the journal by using the `global-max-disk-usage` attribute, thus blocking the paging and processing of new messages until some disk space is available.
This is done from the CLI:
[source,options="nowrap"]
----
[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default:write-attribute(name=global-max-disk-usage, value=70)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
----
You can define at which frequency the disk usage is checked using the `disk-scan-period` attribute.

In the same way configure the maximal memory affected to processing messages by using the `global-max-memory-size` attribute, thus blocking the processing of new messages until some memory space is available.
This is done from the CLI:
[source,options="nowrap"]
----
[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default:write-attribute(name=global-max-memory-size, value=960000000)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
----

=== Critical analysis of the broker

When things go wrong on the broker, the critical analyzer may act as a safeguard shutting down the broker or the JVM. +
If the response time goes beyond a configured timeout, the broker is considered unstable and an action can be taken to either shutdown the broker or halt the VM.
Currently in WildFly this will only be logged but you can change that behaviour by setting the `critical-analyzer-policy` attribute to *HALT* or *SHUTDOWN*.
For this, the critical analyzer measures the response time in:

 * Queue delivery (adding to the queue)
 * Journal storage
 * Paging operations

You can configure the critical analyzer on the broker using the CLI.
To disable the critical analyzer, you can execute the following CLI command:
----
[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default:write-attribute(name=critical-analyzer-enabled, value=false)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
----

You can configure the critical analyzer with the following attributes:

 * critical-analyzer-enabled
 * critical-analyzer-timeout
 * critical-analyzer-check-period
 * critical-analyzer-policy


=== Importing / Exporting the Journal 

WildFly provides an operation to `export` the journal to a file which *MUST* be run in `admin-mode`. 
This is done from the CLI:
[source,options="nowrap"]
----
[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default:export-journal()
{
    "outcome" => "success",
    "result" => "$JBOSS_HOME/standalone/data/activemq/journal-20210125-103331692+0100-dump.xml"
}
----
You can now import such a dump file, in `normal` mode, using the command:
[source,options="nowrap"]
----
[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default:import-journal(file=$FILE_PATH/journal-20210125-103331692+0100-dump.xml)
{
    "outcome" => "success"
}
----
If you need to troubleshoot the journal you can use the `print-data` operation. Like the `export` operation, it needs to be executed in `admin-mode`.
Also this will send back a file so it must be coupled with the `attachment` operation to display or save the result. Note that the `display` operation won't work properly if you are asking for a zipped version of the data.
[source,options="nowrap"]
----
[standalone@localhost:9990 /] attachment display --operation=/subsystem=messaging-activemq/server=default:print-data(secret)
ATTACHMENT a69b87f3-ffeb-4596-be51-d73ebdc48b66:
     _        _               _
    / \  ____| |_  ___ __  __(_) _____
   / _ \|  _ \ __|/ _ \  \/  | |/  __/
  / ___ \ | \/ |_/  __/ |\/| | |\___ \
 /_/   \_\|   \__\____|_|  |_|_|/___ /
 Apache ActiveMQ Artemis 2.16.0

 ....
----

:leveloffset: +1

include::Messaging_Connect_a_pooled-connection-factory_to_a_Remote_Artemis_Server.adoc[]

include::Messaging_Backward_and_Forward_Compatibility.adoc[]

include::Mesaging_AIO_-_NIO_for_messaging_journal.adoc[]

include::Messaging_JDBC_Store_for_Messaging_Journal.adoc[]

include::Messaging_Discovery_Configuration.adoc[]

:leveloffset: -1
