= Management
:idprefix:
:idseparator: -
:docinfo: shared

{project-name-full} has an extensive _management API_ that allows a user to modify a server's configuration, create new resources (e.g. addresses and queues), inspect these resources (e.g. how many messages are currently held in a queue), and interact with them (e.g. to remove messages from a queue).
Management _notifications_ are also sent for various events.

There are numerous ways to access the management API:

* Using JMX -- _JMX_ is the standard way to manage Java applications
* Using Jolokia -- Jolokia exposes the JMX API of an application through an _HTTP interface_
* Using the Core Client -- management operations are sent to the broker using _Core Client messages_
* Using any JMS Client -- management operations are sent to Apache Artemis server using _JMS Client messages_
* Web Console -- a web application which provides a graphical interface to the management API.

Although there are four different ways to manage the broker, each API supports the same functionality.
If it is possible to manage a resource using JMX it is also possible to achieve the same result using Core messages.

Besides these four management interfaces, a xref:management-console.adoc#management-console[Web Console] and a Command Line _management utility_ are also available to administrators.

The choice depends on your requirements, your application settings, and your environment to decide which way suits you best.

== The Management API

Regardless of the way you _invoke_ management operations, the management API is the same.

For each _managed resource_, there exists a Java interface describing what operations can be invoked for this type of resource.

To learn about available _management operations_, see the Javadoc for these interfaces.
They are located in the `org.apache.activemq.artemis.api.core.management` package and they are named with the word `Control` at the end.

=== Server Management

The `ActiveMQServerControl` interface is the entry point for broker management.

* Listing, creating, deploying, and destroying queues
+
A list of deployed queues can be retrieved using the `getQueueNames()` method.
+
Queues can be created or destroyed using the management operations `createQueue()` or `deployQueue()` or `destroyQueue()`.
+
`createQueue` will fail if the queue already exists while `deployQueue` will do nothing.

* Listing and closing remote connections
+
Client's remote addresses can be retrieved using `listRemoteAddresses()`.
It is also possible to close the connections associated with a remote address using the `closeConnectionsForAddress()` method.
+
Alternatively, connection IDs can be listed using `listConnectionIDs()` and all the sessions for a given connection ID can be listed using `listSessions()`.

* Transaction heuristic operations
+
In case of a server crash, when the server restarts, it possible that some transaction requires manual intervention.
The `listPreparedTransactions()` method lists the transactions which are in the prepared states (the transactions are represented as opaque Base64 Strings.) To commit or rollback a given prepared transaction, the `commitPreparedTransaction()` or `rollbackPreparedTransaction()` method can be used to resolve heuristic transactions.
Heuristically completed transactions can be listed using the `listHeuristicCommittedTransactions()` and `listHeuristicRolledBackTransactions` methods.

* Enabling and resetting Message counters
+
Message counters can be enabled or disabled using the `enableMessageCounters()` or `disableMessageCounters()` method.
To reset message counters, it is possible to invoke `resetAllMessageCounters()` and `resetAllMessageCounterHistories()` methods.

* Retrieving the server configuration and attributes
+
The `ActiveMQServerControl` exposes broker configuration through all its attributes (e.g. `getVersion()` method to retrieve the server's version, etc.)

* Listing, creating and destroying Core bridges and diverts
+
A list of deployed core bridges (resp.
diverts) can be retrieved using the `getBridgeNames()` (resp.
`getDivertNames()`) method.
+
Core bridges (resp.
diverts) can be created or destroyed using the management operations `createBridge()` and `destroyBridge()` (resp.
`createDivert()` and `destroyDivert()`).
+
Diverts can be updated using the management operation `updateDivert()`.

[#force_failover]
* It is possible to stop the server and force failover to occur with any currently attached clients.
+
To do this use the `forceFailover()` operation.
+
[NOTE]
====


Since this method actually stops the server you will probably receive some sort of error depending on which management service you use to call it.
====
* The effective configuration of the broker core can be exported as properties using `exportConfigAsProperties()`. This operation will write a file to the broker's tmp dir called `broker_config_as_properties.txt`. The content can provide an entry point for using xref:configuration-index.adoc#broker-properties[brokerProperties].

[NOTE]
====
The broker's tmp dir is configured via the system property `java.io.tmpdir`. The default value, set via the launch scripts, is `$ARTEMIS_INSTANCE/tmp`.
====

* The status of the broker, a json string, can be obtained through the `getStatus()` operation. The status includes identity, uptime, activation state, and information about broker properties configuration and reload.

=== Address Management

Individual addresses can be managed using the `AddressControl` interface.

* Modifying roles and permissions for an address
+
You can add or remove roles associated to a queue using the `addRole()` or `removeRole()` methods.
You can list all the roles associated to the queue with the `getRoles()` method

* Pausing and resuming an Address
+
The `AddressControl` can pause and resume an address and all the queues that are bound to it.
Newly added queue will be paused too until the address is resumed.
Thus all messages sent to the address will be received but not delivered.
When it is resumed, delivering will occur again.

* Blocking and un blocking an Address
+
The `AddressControl` can block and unblock an address.
A blocked address will not issue any more credit to existing producers.
New producers will not be granted any credit.
When the address is unblocked, credit granting will resume.
In this way, it is possible to drain all the queues associated with an address to quiesce a broker in a managed way.

=== Queue Management

The bulk of the management API deals with queues.
The `QueueControl` interface defines the queue management operations.

Most of the management operations on queues take either a single message ID (e.g. to remove a single message) or a filter (e.g. to expire all messages with a given property.)

[NOTE]
====


Passing `null` or an empty string in the `filter` parameter means that the management operation will be performed on _all messages_ in a queue.
====

* Expiring, sending to a dead letter address and moving messages
+
Messages can be expired from a queue by using the `expireMessages()` method.
If an expiry address is defined, messages will be sent to it, otherwise they are discarded.
+
Messages can also be sent to a dead letter address with the `sendMessagesToDeadLetterAddress()` method.
It returns the number of messages which are sent to the dead letter address.
If a dead letter address is not defined, message are removed from the queue and discarded.
+
Messages can also be moved from a queue to another queue by using the `moveMessages()` method.

* Listing and removing messages
+
Messages can be listed from a queue by using the `listMessages()` method which returns an array of `Map`, one `Map` for each message.
+
Messages can also be removed from the queue by using the `removeMessages()` method which returns a `boolean` for the single message ID variant or the number of removed messages for the filter variant.
The `removeMessages()` method takes a `filter` argument to remove only filtered messages.
Setting the filter to an empty string will in effect remove all messages.

* Counting messages
+
The number of messages in a queue is returned by the `getMessageCount()` method.
Alternatively, the `countMessages()` will return the number of messages in the queue which _match a given filter_.

* Changing message priority
+
The message priority can be changed by using the `changeMessagesPriority()` method which returns a `boolean` for the single message ID variant or the number of updated messages for the filter variant.

* Message counters
+
Message counters can be listed for a queue with the `listMessageCounter()` and `listMessageCounterHistory()` methods (see Message Counters section).
The message counters can also be reset for a single queue using the `resetMessageCounter()` method.

* Retrieving the queue attributes
+
The `QueueControl` exposes queue settings through its attributes (e.g. `getFilter()` to retrieve the queue's filter if it was created with one, `isDurable()` to know whether the queue is durable or not, etc.)

* Pausing and resuming Queues
+
The `QueueControl` can pause and resume the underlying queue.
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.

* Disabling and Enabling Queues
+
The `QueueControl` can disable and enable the underlying queue.
When a queue is disabled, it will not longer have messages routed to it.
When it's enabled, it'll begin having messages routed to it again.
+
This is useful where you may need to disable message routing to a queue but wish to keep consumers active to investigate issues, without causing further message build up in the queue.

=== Other Resources Management

The management API allows an administrator to start and stop various broker resources (acceptors, diverts, bridges, etc.) so that a broker can be taken partially off-line for a given period of time without stopping it completely (e.g. if other management operations must be performed such as resolving heuristic transactions).
These resources are:

* Acceptors
+
They can be started or stopped using the `start()` or.
`stop()` method on the `AcceptorControl` interface.
The acceptors parameters can be retrieved using the `AcceptorControl` attributes (see xref:configuring-transports.adoc#configuring-the-transport[Understanding Acceptors])

* Diverts
+
They can be started or stopped using the `start()` or `stop()` method on the `DivertControl` interface.
Diverts parameters can be retrieved using the `DivertControl` attributes (see xref:diverts.adoc#diverting-and-splitting-message-flows[Diverting and Splitting Message Flows])

* Bridges
+
They can be started or stopped using the `start()` (resp.
`stop()`) method on the `BridgeControl` interface.
Bridges parameters can be retrieved using the `BridgeControl` attributes (see xref:core-bridges.adoc#core-bridges[Core bridges])

* Broadcast groups
+
They can be started or stopped using the `start()` or `stop()` method on the `BroadcastGroupControl` interface.
Broadcast groups parameters can be retrieved using the `BroadcastGroupControl` attributes (see xref:clusters.adoc#clusters[Clusters])

* Cluster connections
+
They can be started or stopped using the `start()` or `stop()` method on the `ClusterConnectionControl` interface.
Cluster connections parameters can be retrieved using the `ClusterConnectionControl` attributes (see xref:clusters.adoc#clusters[Clusters])

== Management Via JMX

The broker can be managed using http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html[JMX].

The management API is exposed using MBeans.
By  default, these MBeans are registered with the domain  `org.apache.activemq.artemis`.
For example, the `ObjectName` to manage the anycast queue `exampleQueue` on the address `exampleAddress` is:

----
org.apache.activemq.artemis:broker=<brokerName>,component=addresses,address="exampleAddress",subcomponent=queues,routing-type="anycast",queue="exampleQueue"
----

and the MBean is:

----
org.apache.activemq.artemis.api.core.management.QueueControl
----

The MBean's `ObjectName` is built using the helper class `org.apache.activemq.artemis.api.core.management.ObjectNameBuilder`.
Example usage of the `ObjectNameBuilder` to obtain ``ActiveMQServerControl``'s name:

[,java]
----
brokerName = "0.0.0.0";  // configured e.g. in broker.xml <broker-name> element
objectNameBuilder = ObjectNameBuilder.create(ArtemisResolver.DEFAULT_DOMAIN, brokerName, true);
serverObjectName = objectNameBuilder.getActiveMQServerObjectName()
----

Managing a broker using JMX is identical to the management of any Java Applications using JMX.
It can be done by reflection or by creating proxies of the MBeans.

=== Configuring JMX

By default, JMX is enabled for broker management.
It can be disabled by setting `jmx-management-enabled` to `false` in `broker.xml`:

[,xml]
----
<jmx-management-enabled>false</jmx-management-enabled>
----

==== Role Based Authorisation for JMX

Artemis uses the Java Virtual Machine's `Platform MBeanServer` by default. This is guarded using role based authorisation that leverages the broker's JAAS plugin support.

The RBAC used to restrict access to Mbeans and their operations can be configured in `one` of two ways. Via security-settings in broker.xml, described in xref:management.adoc#jmx-authorization-in-broker-xml[JMX authorization in broker.xml], or via the `authorization` element in the `management.xml` that is described below.

===== JMX authorisation in management.xml

There are 3 elements within the `authorisation` element, `allowlist`, `default-access` and `role-access`.
Let's discuss each in turn.

Allowlist contains a list of MBeans that will bypass the authorisation, this is typically used for any MBeans that are needed by the console to run etc.
The default configuration is:

[,xml]
----
<allowlist>
   <entry domain="hawtio"/>
</allowlist>
----

This means that any MBean with the domain `hawtio` will be allowed access without authorisation.
for instance `hawtio:plugin=artemis`.
You can also use wildcards for the MBean properties so the following would also match.

[,xml]
----
<allowlist>
   <entry domain="hawtio" key="type=*"/>
</allowlist>
----

[NOTE]
====
The `allowlist` element has replaced the `whitelist` element which is now deprecated
====

The `role-access` defines how roles are mapped to particular MBeans and its attributes and methods.
The default configuration looks like:

[,xml]
----
<role-access>
  <match domain="org.apache.activemq.artemis">
     <access method="list*" roles="view,update,amq"/>
     <access method="get*" roles="view,update,amq"/>
     <access method="is*" roles="view,update,amq"/>
     <access method="set*" roles="update,amq"/>
     <access method="*" roles="amq"/>
  </match>
</role-access>
----

This contains 1 match and will be applied to any MBean that has the domain `org.apache.activemq.artemis`.
Any access to any MBeans that have this domain are controlled by the `access` elements which contain a method and a set of roles.
The method being invoked will be used to pick the closest matching method and the roles for this will be applied for access.
For instance if you try to invoke a method called `listMessages` on an MBean with the `org.apache.activemq.artemis` domain then this would match the `access` with the method of `list*`.
You could also explicitly configure this by using the full method name, like so:

[,xml]
----
<access method="listMessages" roles="view,update,amq"/>
----

You can also match specific MBeans within a domain by adding a key attribute that is used to match one of the properties on the MBean, like:

[,xml]
----
<match domain="org.apache.activemq.artemis" key="subcomponent=queues">
   <access method="list*" roles="view,update,amq"/>
   <access method="get*" roles="view,update,amq"/>
   <access method="is*" roles="view,update,amq"/>
   <access method="set*" roles="update,amq"/>
   <access method="*" roles="amq"/>
</match>
----

You could also match a specific queue for instance:

----
org.apache.activemq.artemis:broker=<brokerName>,component=addresses,address="exampleAddress",subcomponent=queues,routing-type="anycast",queue="exampleQueue"
----

by configuring:

[,xml]
----
<match domain="org.apache.activemq.artemis" key="queue=exampleQueue">
   <access method="list*" roles="view,update,amq"/>
   <access method="get*" roles="view,update,amq"/>
   <access method="is*" roles="view,update,amq"/>
   <access method="set*" roles="update,amq"/>
   <access method="*" roles="amq"/>
</match>
----

You can also use wildcards for the MBean properties so the following would also match, allowing prefix match for the MBean properties.

[,xml]
----
<match domain="org.apache.activemq.artemis" key="queue=example*">
   <access method="list*" roles="view,update,amq"/>
   <access method="get*" roles="view,update,amq"/>
   <access method="is*" roles="view,update,amq"/>
   <access method="set*" roles="update,amq"/>
   <access method="*" roles="amq"/>
</match>
----

In case of multiple matches, the exact matches have higher priority than the wildcard matches and the longer wildcard matches have higher priority than the shorter wildcard matches.

Access to JMX MBean attributes are converted to method calls so these are controlled via the `set*`, `get*` and `is*`.
The `*` access is the catch-all for everything other method that isn't specifically matched.

The `default-access` element is basically the catch-all for every method call that isn't handled via the `role-access` configuration.
This has the same semantics as a `match` element.


==== JMX authorization in broker.xml
The existing xref:security.adoc#role-based-security-for-addresses[security-settings] in broker.xml can be used for JMX RBAC.

Using the `view` and `edit` permissions on matches in security-settings provides an alternative to the authorization section in management.xml.
Using a single security model based on addresses, with reloadable configuration, simplifies operation.

An xref:management.adoc#artemis_rbac_mbean_server_guard[MBeanServer interceptor] that delegates to the broker security manager must be configured with a JVM system property that allows it to be added to all MBeanServers in the JVM.

This is configured via a system property as follows:

[,sh]
----
 java -Djavax.management.builder.initial=org.apache.activemq.artemis.core.server.management.ArtemisRbacMBeanServerBuilder
----
IMPORTANT: When this property is provided, the authorization section of management.xml *_MUST_* be omitted/removed as that depends on an alternative MBeanServer interceptor and builder.

The security-settings match addresses used for JMX RBAC use the `mops.` (shorthand for management operations) xref:configuration-index.adoc#management-rbac-prefix[prefix].

The MBeanServer guard maps JMX MBean ObjectNames to a hierarchical address of the general form:

     mops<.jmx domain><.type><.component><.name>[.operation]

NOTE: for the broker domain, the domain is omitted.


For example, to give the `admin` role `view` and `edit` permissions on all MBeans, use the following security-setting:

[,xml]
----
<security-setting match="mops.#">
   <permission type="view" roles="admin"/>
   <permission type="edit" roles="admin"/>
</security-setting>
----

To grant the `managerRole` role `view` permission to just the `activemq.management` address, target the `address` component with name `activemq.management` and with `.*` to include all operations.

[,xml]
----
<security-setting match="mops.address.activemq.management.*">
   <permission type="view" roles="managerRole"/>
</security-setting>
----


To ensure no user has permission to xref:management.adoc#force_failover[force a failover] using the broker (server control) MBean, use the following that defines the empty roles set for a particular mutating operation on the `broker` component:
[,xml]
----
<security-setting match="mops.broker.forceFailover">
   <permission type="edit" roles=""/>
</security-setting>
----


==== Local JMX Access with JConsole

Due to the authorisation which is enabled by default, the broker can _not_ be managed locally using JConsole when connecting as a _local  process_.
This is because JConsole does not pass any authentication information when connecting this way, which means the user cannot, therefore, be authorised  for any management operations.
To use JConsole, the user will either have to disable authorisation by completely removing the `authorisation` element from `management.xml` or by enabling remote access and providing the proper username and password credentials (discussed next).

==== Remote JMX Access

By default, remote JMX access to Artemis is disabled for security reasons.

Artemis has a JMX agent which allows access to JMX MBeans remotely.
This is configured via the `connector` element in the `management.xml` configuration file.
To enable this, you add the following XML:

[,xml]
----
<connector connector-port="1099"/>
----

This exposes the agent remotely on the port `1099`.
If you were connecting via JConsole you would connect as a remote process using the service url:

----
service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
----

You'd be able to supply an appropriate user name and password in this case as well.

You can also configure the connector using the following:

connector-host::
The host to expose the agent on.

connector-port::
The port to expose the agent on.

rmi-registry-port::
The port that the RMI registry binds to.
If not set, the port is always random.
Set to avoid problems with remote JMX connections tunnelled through firewall.

jmx-realm::
The jmx realm to use for authentication, defaults to `activemq` to match the JAAS configuration.

object-name::
The object name to expose the remote connector on;
default is `connector:name=rmi`.

secured::
Whether the connector is secured using SSL.

key-store-path::
The location of the keystore.

key-store-password::
The keystore password.
This can be xref:masking-passwords.adoc#masking-passwords[masked].

key-store-provider::
The provider;
`JKS` by default.

trust-store-path::
The location of the truststore.

trust-store-password::
The trustore password.
This can be xref:masking-passwords.adoc#masking-passwords[masked].

trust-store-provider::
The provider;
`JKS` by default.

password-codec::
The fully qualified class name of the password codec to use.
See the xref:masking-passwords.adoc#masking-passwords[password masking] documentation for more details on how this works.

[NOTE]
====
It is important to note that the rmi registry will pick an ip address to bind to, If you have a multi IP addresses/NICs  present on the system then you can choose the ip address to use by adding the following to artemis.profile `-Djava.rmi.server.hostname=localhost`
====

[NOTE]
====
Remote connections using the default JVM Agent not enabled by default as Artemis exposes the MBean Server via its own configuration.
This is so Artemis can leverage the JAAS authentication layer via JMX.
If you want to expose this then you will need to disable both the connector and the authorisation by removing them from the `management.xml` configuration.
Please refer to https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html[Java Management guide] to configure the server for remote management (system properties must be set in `artemis.profile`).
====

By default, the broker uses the JMX domain ``"``org.apache.activemq.artemis``"``.
To manage several brokers from the _same_ MBeanServer, the JMX domain can be configured for each individual broker by setting `jmx-domain` in `broker.xml`:

[,xml]
----
<!-- use a specific JMX domain for Apache Artemis MBeans -->
<jmx-domain>my.org.apache.activemq</jmx-domain>
----

=== Example

See the xref:examples.adoc#jmx-management[JMX Management Example] which shows how to use a remote connection to JMX and MBean proxies to manage a broker.

=== Exposing JMX using Jolokia

The default broker configuration ships with the https://jolokia.org[Jolokia] HTTP agent deployed as a web application.
Jolokia is a remote JMX-over-HTTP bridge that exposes MBeans.
For a full guide as to how to use it refer to https://jolokia.org/reference/html/manual/jolokia_protocol.html[Jolokia documentation].

==== Reading an Attribute

A simple example to check whether a broker is active would be to use a `curl` command like this:

[,console]
----
$ curl -s -H "Origin: http://localhost" -u myUser:myPass http://localhost:8161/console/jolokia/read/org.apache.activemq.artemis:broker=\"0.0.0.0\"/Active
----

Or you could send a JSON formatted `POST` request instead of using the URL

[,console]
----
$ curl -s -H "Origin: http://localhost" -u myUser:myPass --header "Content-type: application/json" --request POST --data '{"attribute": "Active", "mbean": "org.apache.activemq.artemis:broker=\"0.0.0.0\"", "type": "read"}' http://localhost:8161/console/jolokia
----

By default it's necessary to pass the `Origin` header due to the https://en.wikipedia.org/wiki/Cross-origin_resource_sharing[CORS] checking which is configured in `etc/jolokia-access.xml`.

Either such `curl` command would give you back something like the following (after formatting):

[,json]
----
{
  "request": {
    "mbean": "org.apache.activemq.artemis:broker=\"0.0.0.0\"",
    "attribute": "Version",
    "type": "read"
  },
  "value": "true",
  "timestamp": 1663086398,
  "status": 200
}
----

The value of the attribute is contained in `value` (i.e. `true`).
You could easily parse this JSON data with a tool like https://jqlang.github.io/jq/[`jq`] which is available in most Linux distributions, e.g.:

[,console]
----
$ curl -s -H "Origin: http://localhost" -u myUser:myPass --header "Content-type: application/json" --request POST --data '{"attribute": "Active", "mbean": "org.apache.activemq.artemis:broker=\"0.0.0.0\"", "type": "read"}' http://localhost:8161/console/jolokia | jq -r '.value'
----

This command would simply return:

[,console]
----
true
----

See more details on Jolokia's `read` functionality in the https://jolokia.org/reference/html/manual/jolokia_protocol.html#read[Jolokia documentation].

==== Executing an Operation

Aside from reading an attribute the next most common task is executing an operation.
For example, you can list the connections to the broker with `curl` and parse the output with `jq` like this:

[,console]
----
$ curl -s -H "Origin: http://localhost" -u myUser:myPass "http://localhost:8161/console/jolokia/exec/org.apache.activemq.artemis:broker=\"0.0.0.0\"/listConnections/\"\"/-1/-1" | jq '.value | fromjson'
----

Or you could send a JSON formatted `POST` request instead of using the URL

[,console]
----
$ curl -s -H "Origin: http://localhost" -u myUser:myPass --header "Content-type: application/json" --request POST --data '{"operation": "listConnections", "mbean": "org.apache.activemq.artemis:broker=\"0.0.0.0\"", "type": "exec", "arguments": [ "", -1, -1 ] }' http://localhost:8161/console/jolokia | jq '.value | fromjson'
----

Either such command would give you back something like the following (after formatting):

[,json]
----
{
  "data": [
    {
      "connectionID": "bd8d4635",
      "remoteAddress": "127.0.0.1:55754",
      "users": "",
      "creationTime": "Wed Jan 1 12:00:00 CDT 2020",
      "implementation": "RemotingConnectionImpl",
      "protocol": "CORE",
      "clientID": "",
      "localAddress": "tcp:///127.0.0.1:61616",
      "sessionCount": 2
    },
    {
      "connectionID": "2a7ac661",
      "remoteAddress": "127.0.0.1:54394",
      "users": "",
      "creationTime": "Wed Jan 1 12:00:00 CDT 2020",
      "implementation": "OpenWireConnection",
      "protocol": "OPENWIRE",
      "clientID": "ID:myMachine-34439-1727292626395-0:1",
      "localAddress": "tcp:///127.0.0.1:61616",
      "sessionCount": 3
    }
  ],
  "count": 2
}
----

You could also leverage the <<management-method-option-syntax>> to get more specific results.

[,console]
----
$ curl -s -H "Origin: http://localhost" -u myUser:myPass "http://localhost:8161/console/jolokia/exec/org.apache.activemq.artemis:broker=\"0.0.0.0\"/listConnections/\{\"field\":\"protocol\",\"operation\":\"EQUALS\",\"value\":\"OPENWIRE\"\}/-1/-1" | jq '.value | fromjson'
----

Or you could send a JSON formatted `POST` request instead of using the URL

[,console]
----
$ curl -s -H "Origin: http://localhost" -u myUser:myPass --header "Content-type: application/json" --request POST --data '{"operation": "listConnections", "mbean": "org.apache.activemq.artemis:broker=\"0.0.0.0\"", "type": "exec", "arguments": [ "{\"field\":\"protocol\",\"operation\":\"EQUALS\",\"value\":\"OPENWIRE\"}", -1, -1 ] }' http://localhost:8161/console/jolokia | jq '.value | fromjson'
----

Either such command would give you back something like the following (after formatting):

[,json]
----
{
  "data": [
    {
      "connectionID": "2a7ac661",
      "remoteAddress": "127.0.0.1:54394",
      "users": "",
      "creationTime": "Wed Jan 1 12:00:00 CDT 2020",
      "implementation": "OpenWireConnection",
      "protocol": "OPENWIRE",
      "clientID": "ID:myMachine-34439-1727292626395-0:1",
      "localAddress": "tcp:///127.0.0.1:61616",
      "sessionCount": 3
    }
  ],
  "count": 1
}
----

See more details on Jolokia's `exec` functionality in the https://jolokia.org/reference/html/manual/jolokia_protocol.html#exec[Jolokia documentation].

=== Management Method Option Syntax

When there are lots of these resources to manage it can sometimes be difficult to find a particular resource.
For example, if there are 1,000 connections to the broker and you just want to manage one particular connection that is using a specific client ID.
A handful of management operations support a special JSON syntax to filter results based on the following inputs:

* `field` (see the list of fields for each management operation below)
* `operation`
** `CONTAINS`
** `NOT_CONTAINS`
** `EQUALS`
** `NOT_EQUALS`
** `GREATER_THAN`
** `LESS_THAN`
* `value`
* `sortField` (optional)
* `sortOrder` (optional)
** `asc`
** `desc`

Here are the methods which support this syntax along with the available fields:

listConnections::
* `connectionID`
* `clientID`
* `users`
* `protocol`
* `sessionCount`
* `remoteAddress`
* `localAddress`
* `sessionID`
* `creationTime`
* `implementation`
* Example:
+
[,json]
----
{
  "field": "protocol",
  "operation": "EQUALS",
  "value": "OPENWIRE"
}
----

listSessions::
* `id`
* `connectionID`
* `consumerCount`
* `producerCount`
* `user`
* `validatedUser`
* `protocol`
* `clientID`
* `localAddress`
* `remoteAddress`
* `creationTime`
* Example:
+
[,json]
----
{
  "field": "remoteAddress",
  "operation": "CONTAINS",
  "value": "127.0.0.1"
}
----

listAddresses::
* `id`
* `name`
* `routingTypes`
* `producerId`
* `queueCount`
* `internal`
* Example:
+
[,json]
----
{
  "field": "name",
  "operation": "CONTAINS",
  "value": "shipping"
}
----

listQueues::
* `id`
* `name`
* `consumerID`
* `address`
* `maxConsumers`
* `filter`
* `messageCount`
* `consumerCount`
* `deliveringCount`
* `messagesAdded`
* `messagesAcked`
* `messagesExpired`
* `routingType`
* `user`
* `autoCreated`
* `durable`
* `paused`
* `temporary`
* `purgeOnNoConsumers`
* `messagesKilled`
* `directDeliver`
* `lastValue`
* `exclusive`
* `scheduledCount`
* `lastValueKey`
* `groupRebalance`
* `groupRebalancePauseDispatch`
* `groupBuckets`
* `groupFirstKey`
* `enabled`
* `ringSize`
* `consumersBeforeDispatch`
* `delayBeforeDispatch`
* `autoDelete`
* `internalQueue`
* Example:
+
[,json]
----
{
  "field": "consumerCount",
  "operation": "GREATER_THAN",
  "value": "7"
}
----

listConsumers::
* `id` or `consumerID`
* `sequentialId` or `sequentialId`
* `session` or `sessionID`
* `connection` or `connectionID`
* `queue` or `queueName`
* `filter`
* `address`
* `user`
* `validatedUser`
* `protocol`
* `clientID`
* `localAddress`
* `remoteAddress`
* `queueType`
* `browseOnly`
* `creationTime`
* `messagesInTransit` or `deliveringCount`
* `messagesInTransitSize`
* `messagesDelivered`
* `messagesDeliveredSize`
* `messagesAcknowledged`
* `messagesAcknowledgedAwaitingCommit`
* `lastDeliveredTime`
* `lastAcknowledgedTime`
* `status`
* Example:
+
[,json]
----
{
  "field": "messagesAcknowledged",
  "operation": "LESS_THAN",
  "value": "10"
}
----

listProducers::
* `id`
* `name`
* `session` or `sessionID`
* `connectionID`
* `address` or `destination`
* `user`
* `validatedUser`
* `protocol`
* `clientID`
* `localAddress`
* `remoteAddress`
* `creationTime`
* `msgSent`
* `msgSizeSent`
* `lastProducedMessageID`
* Example:
+
[,json]
----
{
  "field": "validatedUser",
  "operation": "EQUALS",
  "value": "bob"
}
----

==== Sorting

Results can be sorted by any field in either ascending (`asc`) or descending (`desc`) order.
For example, use something like this in a call to `listConnections` to get all the AMQP connections with the newest connections first.

[,json]
----
{
  "field": "protocol",
  "operation": "EQUALS",
  "value": "AMQP",
  "sortField": "creationTime",
  "sortOrder": "desc"
}
----

==== Pagination

These methods also support _pagination_.
In other words, the results can be divided into groups and then iterated through.
The second parameter is the "page number" (i.e. which page to inspect) and the third parameter is the "page size" (i.e. how many results to return on each page).
This is how, for example, the web console displays paginated results.

To disable pagination pass `-1` for either page number of page size (or both).

=== JMX and the Web Console

The web console that ships with Artemis uses Jolokia under the covers which in turn uses JMX.
This will use the authentication configuration as described in the xref:management.adoc#role-based-authorisation-for-jmx[Role Based Authorisation for JMX section].
This means that when MBeans are accessed via the console the credentials used to log into the console and the roles associated with them.
By default, access to the console is only allow via users with the `amq` role.
This is configured in the `artemis.profile` via the system property `-Dhawtio.role=amq`.
You can configure multiple roles by changing this to `-Dhawtio.roles=amq,view,update`.

If a user doesn't have the correct role to invoke a specific operation then this will display an authorisation exception in the console.


[#artemis_rbac_mbean_server_guard]
==== ArtemisRbacMBeanServerBuilder and ArtemisRbacInvocationHandler
The ArtemisRbacMBeanServerBuilder class, when configured as value for the system property `javax.management.builder.initial` will cause the ArtemisRbacInvocationHandler to be installed on every JMX MBeanServer in the JVM.
The ArtemisRbacInvocationHandler intercepts all operations on the MBeanServer and chooses to guard a subsection of those operations.

For guarded operations the `view` or `edit` permissions are required to make an invocation. If the current authenticated subject does not have the required roles to grant those permissions, a security exception is thrown.

For query operations on the MBeanServer, the results of the query are limited to entries that have the required `view` permission.

== Using Management Message API

The management message API is accessed by sending Core Client messages to a special address, the _management address_.

_Management messages_ are regular Core Client messages with well-known properties that the server needs to understand to interact with the management API:

* The name of the managed resource
* The name of the management operation
* The parameters of the management operation

When such a management message is sent to the management address the broker will handle it, extract the information, invoke the operation on the managed resources, and send a _management reply_ to the management message's reply-to address (specified by `ClientMessageImpl.REPLYTO_HEADER_NAME`).

A `ClientConsumer` can be used to consume the management reply and retrieve the result of the operation (if any) stored in the reply's body.
For portability, results are returned as a https://json.org[JSON] String rather than Java Serialization (the `org.apache.activemq.artemis.api.core.management.ManagementHelper` can be used to convert the JSON string to Java objects).

These steps can be simplified to make it easier to invoke management operations using Core messages:

. Create a `ClientRequestor` to send messages to the management address and receive replies
. Create a `ClientMessage`
. Use the helper class `org.apache.activemq.artemis.api.core.management.ManagementHelper` to fill the message with the management properties
. Send the message using the `ClientRequestor`
. Use the helper class `org.apache.activemq.artemis.api.core.management.ManagementHelper` to retrieve the operation result from the management reply.

For example, to find out the number of messages in the queue `exampleQueue`:

[,java]
----
ClientSession session = ...
ClientRequestor requestor = new ClientRequestor(session, "activemq.management");
ClientMessage message = session.createMessage(false);
ManagementHelper.putAttribute(message, "queue.exampleQueue", "messageCount");
session.start();
ClientMessage reply = requestor.request(m);
int count = (Integer) ManagementHelper.getResult(reply);
System.out.println("There are " + count + " messages in exampleQueue");
----

Management operation name and parameters must conform to the Java interfaces defined in the `management` packages.

Names of the resources are built using the helper class `org.apache.activemq.artemis.api.core.management.ResourceNames` and are straightforward (e.g. `queue.exampleQueue` for `QueueControl` of the Queue `exampleQueue`, or `broker` for the `ActiveMQServerControl`).

[NOTE]
====


The `ManagementHelper` class can be used only with Core JMS messages.
When called with a message from a different JMS library, an exception will be thrown.
====

=== Configuring Management

The management address to send management messages is configured in `broker.xml`:

[,xml]
----
<management-address>activemq.management</management-address>
----

By default, the address is `activemq.management`.

The management address requires a _special_ user permission `manage` to be able to receive and handle management messages.
This is also configured in broker.xml:

[,xml]
----
<!-- users with the admin role will be allowed to manage the broker using management messages -->
<security-setting match="activemq.management">
   <permission type="manage" roles="admin" />
</security-setting>
----

=== Fine grained RBAC on management messages
There is optional RBAC on the content of management messages sent to the management address.
RBAC is enabled through configuration by setting the attribute xref:configuration-index.adoc#management-message-rbac[management-message-rbac] to `true`.

NOTE: The `manage` permission is required to execute management operations via messages. The `view` and `edit` permissions must be used in conjunction with the `manage` permission.

When enabled, more fine-grained permissions on the content of management messages sent to the management address can be configured through the security-settings.

The security-settings match addresses used for RBAC follow the general hierarchical form of: xref:configuration-index.adoc#management-rbac-prefix[management-rbac-prefix], component type, component name, operation. Where the values are extracted from the management message headers.

  <management-rbac-prefix>.<resource type>.<resource name>.<operation>

xref:configuration-index.adoc#view-permission-method-match-pattern[Immutable operations and attribute access] will require the `view` permission, all other operations will require the `edit` permission.


In the following example the `dataImport` role can only access the id attribute of queues, which is the only management operation that is required by the xref:using-cli.adoc#command-line-interface[data import] command line tool.

[,xml]
----
<security-setting match="mops.queue.*.getID">
   <permission type="view" roles="dataImport" />
   <permission type="manage" roles="dataImport" />
</security-setting>
----

If you want the `admin` role to have full access, use a wildcard after the management-rbac-prefix and grant both the `view` and `edit` permissions:

[,xml]
----
<security-setting match="mops.#">
   <permission type="view" roles="admin" />
   <permission type="update" roles="admin" />
   <permission type="manage" roles="admin" />
</security-setting>
----

=== Management Example

See the xref:examples.adoc#management[Management Example] which shows how to use JMS messages to manage the broker.

== Management Notifications

The broker emits _notifications_ to inform listeners of potentially interesting events (creation of new resources, security violation, etc.).

These notifications can be received in two different ways:

* JMX notifications
* Notification messages

=== JMX Notifications

If JMX is enabled (see Configuring JMX section), JMX notifications can be received by subscribing to `org.apache.activemq.artemis:type=Broker,brokerName=<broker name>,module=Core,serviceType=Server` for notifications on resources.

=== Notification Messages

A special address is defined for _management notification_.
Queues can be bound to this address so that clients will receive management notifications as messages.

A client which wants to receive management notifications must create a queue bound to the management notification address.
It can then receive the notifications from its queue.

Notification messages are regular messages with additional properties corresponding to the notification (its type, when it occurred, the resources which were concerned, etc.).

Since notifications are regular messages, it is possible to use message selectors to filter out notifications and receive only a subset of all the notifications emitted by the server.

==== Configuring The Management Notification Address

The management notification address to receive management notifications is configured in `broker.xml`:

[,xml]
----
<management-notification-address>activemq.notifications</management-notification-address>
----

By default, the address is `activemq.notifications`.

==== Suppressing Session Notifications

Some messaging patterns can generate a lot of `SESSION_CREATED` and  `SESSION_CLOSED` notifications.
In a clustered environment this will come with some computational overhead.
If these notifications are not otherwise used they can be disabled through:

[,xml]
----
<suppress-session-notifications>true</suppress-session-notifications>
----

The only time these notifications are _required_ is in a cluster with MQTT clients where unique client ID utilization needs to be enforced.
Default value is `false`

==== Receiving Notification Messages

A Core JMS Client can be used to receive notifications:

[,java]
----
Topic notificationsTopic = ActiveMQJMSClient.createTopic("activemq.notifications");

Session session = ...
MessageConsumer notificationConsumer = session.createConsumer(notificationsTopic);
notificationConsumer.setMessageListener(new MessageListener() {
   public void onMessage(Message notif) {
    System.out.println("------------------------");
    System.out.println("Received notification:");
    try {
     Enumeration propertyNames = notif.getPropertyNames();
     while (propertyNames.hasMoreElements()) {
      String propertyName = (String)propertyNames.nextElement();
      System.out.format("  %s: %s\n", propertyName, notif.getObjectProperty(propertyName));
     }
    } catch (JMSException e) {
    }
    System.out.println("------------------------");
   }
});
----

=== Example

See the xref:examples.adoc#management-notification[Management Notification Example] which shows how to use a JMS `MessageListener` to receive management notifications.

=== Notification Types and Headers

Below is a list of all the different kinds of notifications as well as which headers are on the messages.
Every notification has a `_AMQ_NotifType` (value noted in parentheses) and `_AMQ_NotifTimestamp` header.
The timestamp is the un-formatted result of a call to `java.lang.System.currentTimeMillis()`.

BINDING_ADDED (0)::
`_AMQ_Binding_Type`, `_AMQ_Address`, `_AMQ_ClusterName`, `_AMQ_RoutingName`, `_AMQ_Binding_ID`, `_AMQ_Distance`, `_AMQ_FilterString`

BINDING_REMOVED (1)::
`_AMQ_Address`, `_AMQ_ClusterName`, `_AMQ_RoutingName`, `_AMQ_Binding_ID`, `_AMQ_Distance`, `_AMQ_FilterString`

CONSUMER_CREATED (2)::
`_AMQ_Address`, `_AMQ_ClusterName`, `_AMQ_RoutingName`, `_AMQ_Distance`, `_AMQ_ConsumerCount`, `_AMQ_User`, `_AMQ_ValidatedUser`, `_AMQ_RemoteAddress`, `_AMQ_SessionName`, `_AMQ_FilterString`, `_AMQ_CertSubjectDN`

CONSUMER_CLOSED (3)::
`_AMQ_Address`, `_AMQ_ClusterName`, `_AMQ_RoutingName`, `_AMQ_Distance`, `_AMQ_ConsumerCount`, `_AMQ_User`, `_AMQ_RemoteAddress`, `_AMQ_SessionName`, `_AMQ_FilterString`

SECURITY_AUTHENTICATION_VIOLATION (6)::
`_AMQ_User`, `_AMQ_CertSubjectDN`, `_AMQ_RemoteAddress`

SECURITY_PERMISSION_VIOLATION (7)::
`_AMQ_Address`, `_AMQ_CheckType`, `_AMQ_User`

DISCOVERY_GROUP_STARTED (8)::
`name`

DISCOVERY_GROUP_STOPPED (9)::
`name`

BROADCAST_GROUP_STARTED (10)::
`name`

BROADCAST_GROUP_STOPPED (11)::
`name`

BRIDGE_STARTED (12)::
`name`

BRIDGE_STOPPED (13)::
`name`

CLUSTER_CONNECTION_STARTED (14)::
`name`

CLUSTER_CONNECTION_STOPPED (15)::
`name`

ACCEPTOR_STARTED (16)::
`factory`, `id`

ACCEPTOR_STOPPED (17)::
`factory`, `id`

PROPOSAL (18)::
`_JBM_ProposalGroupId`, `_JBM_ProposalValue`, `_AMQ_Binding_Type`, `_AMQ_Address`, `_AMQ_Distance`

PROPOSAL_RESPONSE (19)::
`_JBM_ProposalGroupId`, `_JBM_ProposalValue`, `_JBM_ProposalAltValue`, `_AMQ_Binding_Type`, `_AMQ_Address`, `_AMQ_Distance`

CONSUMER_SLOW (21)::
`_AMQ_Address`, `_AMQ_ConsumerCount`, `_AMQ_RemoteAddress`, `_AMQ_ConnectionName`, `_AMQ_ConsumerName`, `_AMQ_SessionName`

ADDRESS_ADDED (22)::
`_AMQ_Address`, `_AMQ_Routing_Type`

ADDRESS_REMOVED (23)::
`_AMQ_Address`, `_AMQ_Routing_Type`

CONNECTION_CREATED (24)::
`_AMQ_ConnectionName`, `_AMQ_RemoteAddress`

CONNECTION_DESTROYED (25)::
`_AMQ_ConnectionName`, `_AMQ_RemoteAddress`

SESSION_CREATED (26)::
`_AMQ_ConnectionName`, `_AMQ_User`, `_AMQ_SessionName`

SESSION_CLOSED (27)::
`_AMQ_ConnectionName`, `_AMQ_User`, `_AMQ_SessionName`

MESSAGE_DELIVERED (28)::
`_AMQ_Address`, `_AMQ_Routing_Type`, `_AMQ_RoutingName`, `_AMQ_ConsumerName`, `_AMQ_Message_ID`

MESSAGE_EXPIRED (29)::
`_AMQ_Address`, `_AMQ_Routing_Type`, `_AMQ_RoutingName`, `_AMQ_ConsumerName`, `_AMQ_Message_ID`

== Message Counters

Message counters can be used to obtain information on queues _over time_ as the broker keeps a history on queue metrics.

They can be used to show _trends_ on queues.
For example, using the management API, it would be possible to query the number of messages in a queue at regular interval.
However, this would not be enough to know if the queue is used: the number of messages can remain constant because nobody is sending or receiving messages from the queue or because there are as many messages sent to the queue than messages consumed from it.
The number of messages in the queue remains the same in both cases but its use is widely different.

Message counters give additional information about the queues:

count::
The _total_ number of messages added to the queue since the server was started

countDelta::
the number of messages added to the queue _since the last message counter update_

messageCount::
The _current_ number of messages in the queue

messageCountDelta::
The _overall_ number of messages added/removed from the queue _since the last message counter update_.
For example, if `messageCountDelta` is equal to `-10` this means that overall 10 messages have been removed from the queue (e.g. 2 messages were added and 12 were removed)

lastAddTimestamp::
The timestamp of the last time a message was added to the queue

lastAckTimestamp::
The timestamp of the last time a message from the queue was acknowledged

updateTimestamp::
The timestamp of the last message counter update
+
These attributes can be used to determine other meaningful data as well.
For example, to know specifically how many messages were _consumed_ from the queue since the last update simply subtract the `messageCountDelta` from `countDelta`.

=== Configuring Message Counters

By default, message counters are disabled as it might have a small negative effect on memory.

To enable message counters, you can set it to `true` in `broker.xml`:

[,xml]
----
<message-counter-enabled>true</message-counter-enabled>
----

Message counters keep a history of the queue metrics (10 days by default) and sample all the queues at regular interval (10 seconds by default).
If message counters are enabled, these values should be configured to suit your messaging use case in `broker.xml`:

[,xml]
----
<!-- keep history for a week -->
<message-counter-max-day-history>7</message-counter-max-day-history>
<!-- sample the queues every minute (60000ms) -->
<message-counter-sample-period>60000</message-counter-sample-period>
----

Message counters can be retrieved using the Management API.
For example, to retrieve message counters on a queue using JMX:

[,java]
----
// retrieve a connection to the broker's MBeanServer
MBeanServerConnection mbsc = ...
QueueControlMBean queueControl = (QueueControl)MBeanServerInvocationHandler.newProxyInstance(mbsc,
   on,
   QueueControl.class,
   false);
// message counters are retrieved as a JSON String
String counters = queueControl.listMessageCounter();
// use the MessageCounterInfo helper class to manipulate message counters more easily
MessageCounterInfo messageCounter = MessageCounterInfo.fromJSON(counters);
System.out.format("%s message(s) in the queue (since last sample: %s)\n",
messageCounter.getMessageCount(),
messageCounter.getMessageCountDelta());
----

=== Example

See the xref:examples.adoc#message-counter[Message Counter Example] which shows how to use message counters to retrieve information on a queue.
