////
  Copyright 2009-2023 Roland Huss

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
////
[#jmx]
= JMX Support

The main focus of Jolokia is to allow easy access to JMX MBeans
from everywhere. MBeans can be provided by the JVM itself, by an
application server or an application. See xref:jmx_guide.adoc#_mbeans_and_metadata[MBeans and metadata]
for more details.

Each MBean is
registered at a specific `MBeanServer`. Multiple MBeanServers can
co-exist in a single JVM. The so called
_PlatformMBeanServer_ is always present and is
created by the JVM during startup. Especially application servers
often create additional MBeanServers for various purposes. The details are presented in
xref:jmx_guide.adoc#_how_to_create_more_mbeanservers[How to create more MBeanServers?]

When
accessing an MBean remotely via JSR-160 _Connector Server_, the MBeanServer holding
the requested MBean is the one _attached_ to the connector. Jolokia being a _JMX protocol adaptor_
(see xref:architecture.adoc[])
_merges_ all MBeanServers it can find in the JVM to give a
single view on all MBeans. The merging algorithm is described in
<<mbeanserver-merging>>.

For application specific MBeans, Jolokia provides an own, so
called _Jolokia MBeanServer_ which is treated
specially by the Jolokia agent. The Jolokia MBeanServer and its
features are explained in <<jolokia-mbeanserver>>.

Developing application specific MBeans is easy, especially if
http://docs.oracle.com/javase/tutorial/jmx/mbeans/standard.html[Standard
MBeans,role=externalLink,window=_blank] are used. However, for Spring users there is even a
easier, more
https://docs.spring.io/spring-framework/reference/integration/jmx/exporting.html[declarative
way,role=externalLink,window=_blank] for turning POJOs into MBeans. On top of this Jolokia
provides an easy, declarative way for firing up a Jolokia JVM
agent merely by including some Jolokia specific Spring
configuration. This is described in xref:spring.adoc[].

Here's the overview of how Jolokia fits into the picture of JMX architecture in a single JVM and what is the place for the <<jolokia-mbeanserver>> and <<json-mbean>>:

image:jolokia-mbeanserver.png[]

Platform MBeanServer:: This is the _main_ MBeanServer where MBeans like `java.lang:type=Runtime` are registered.

MBeanServer:: We can have more MBeanServers created using `javax.management.MBeanServerFactory.newMBeanServer()`

Connector Server:: JSR-160 connector _attached_ to an MBeanServer to allow remote access to the MBeans registered there. Each Connector Server is attached to exactly one MBeanServers and more connectors can be attached to a single MBeanServer (including Platform MBeanServer).

Jolokia MBeanServer:: Also created using `MBeanServerFactory.newMBeanServer()` but _never_ attached to a JSR-160 Connector. This means that MBeans registered in this MBeanServer will never be accessible remotely using JSR-160 Connector.

Jolokia JMX Protocol Adaptor:: An agent component that allows remote access, but operates on a _unified view_ of all discovered MBeanServers. So it's not a JMX Connector Server. See xref:architecture.adoc[].

Unified View:: When accessing MBeans using Jolokia Protocol Adapter (the Agent), we can access all MBeans registered in all discovered MBeanServers. There's an order defined in which the MBeanServers are checked.

@JsonMBean:: Special kind of MBean - when an MBean (standard, dynamic, open, model) is registered in the Jolokia MBeanServer (and not elsewhere), Jolokia registers _additional_ Dynamic MBean in the Platform MBeanServer. THe original and the dynamic one are _related_. See below for more details.

[#jolokia-mbeanserver]
== Jolokia MBeanServer

The Jolokia MBeanServer can be easily created and used with a locator:

[,java]
----
MBeanServer jolokiaServer = JolokiaMBeanServerUtil.getJolokiaMBeanServer();
----

Internally, `javax.management.MBeanServerFactory.newMBeanServer()` is called, so it's not returned when
calling `javax.management.MBeanServerFactory.findMBeanServer()`.

This MBeanServer is treated specially by a Jolokia Agent:

* Every MBean registered at the Jolokia MBeanServer will never
show up remotely via JSR-160. The Jolokia MBeanServer is never
exposed over JSR-160.
* Each Jolokia MBeanServer registered MBean will shadow any
MBean with the same ObjectName in any other MBeanServer
present. See below for more details.
* The Jolokia MBeanServer is also responsible for managing so
called _JSON MBeans_. These are MBeans
annotated with `@JsonMBean` on the class
level. JSON MBean are explained in
<<json-mbean>>.

[#mbeanserver-merging]
=== MBeanServer merging

Jolokia tries hard to detect as many MBeanServers as available
in a JVM. Beside the always present
_Platform MBeanServer_, many
application servers create own MBeanServer(s) which not always
can be found using standard mechanisms. Therefore Jolokia comes
with so called ``ServerDetector``s for many
known brands of applications server. These server detectors
know how to find MBeanServer by application server specific
means.

The set of available of MBeanServers is detected during
startup and kept, except for the Jolokia MBeanServer which can
kick in and out at any time. For Jolokia operations, all these
MBeanServers are tried according the order given below. Jolokia provides
a _unified view_ of all MBeanServers.

* *Jolokia `MBeanServer`* is queried first, if available.
* Next every `MBeanServer` as detected by the _server
detectors_ a queried in turn.
* All MBeanServers returned by
`MBeanServerFactory.findMBeanServer(null)` (which should return all the `MBeanServers` created with
`MBeanServerFactory.createMBeanServer()`, but not the ones created by `javax.management.MBeanServerFactory.newMBeanServer()`) are
called if not already tried previously.
* Finally, the
`ManagementFactory.getPlatformMBeanServer()` is
used (also, if not found in a former step).

All MBeans contained in all detected MBeanServers are merged
to give a single view on the set of available MBeans.
For MBeans registered with the same name at different
MBeanServers, MBeans registered in later MBeanServers are not
visible. These hidden MBeans will never be called on
`read`, `write` or
`exec` operations. Also, for
`list` operations only the meta data of the
visible MBeans is returned.

This hiding mechanism is used by
`@JsonMBean` to provide a different view of
an MBean for JSR-160 connectors (see below).

[#json-mbean]
== @JsonMBean

JMX 1.4 introduced
https://docs.oracle.com/en/java/javase/17/docs/api/java.management/javax/management/MXBean.html[MXBeans,role=externalLink,window=_blank]
which allow for nearly arbitrary data to be translated into so called __OpenData__
which are accessible via JMX. For example,
arbitrary Java Beans are translated into a
`https://docs.oracle.com/en/java/javase/17/docs/api/java.management/javax/management/openmbean/CompositeData.html[CompositeData,role=externalLink,window=_blank]`
structure with property names as keys and their values in
OpenData values.

Jolokia provides an annotation `@JsonMBean`
for marking an MBean as a JSON MBean. Such an MBean, if
registered at the _Jolokia MBeanServer_
creates a proxy on the _PlatformMBeanServer_
where every complex value gets translated into plain strings in
JSON format. This is true for attributes, operation return
values and arguments. That way, a JSR-160 based console (like
`jconsole`) can easily access complex data
type exposed by custom MBeans. Json MBeans work for Java 6 and
newer.

[#fig-jconsole-json-mbean]
.A @JsonMBean in jconsole
image::jconsole-json-mbean2.png[]

As presented in the `jconsole` attribute view, the type of the attribute is simply `java.lang.String` even if the original attribute is `ComplexTestData` bean defined as:
[source,java]
----
@JsonMBean
public class JsonChecking implements JsonCheckingMBean {

    ComplexTestData data;

    public JsonChecking() {
        data = new ComplexTestData();
    }

    public ComplexTestData getData() {
        return data;
    }
}

public class ComplexTestData {
    private int number;
    private String string;
    private Map<String,Boolean> map;
    private Set<Integer> set;
    private String[] stringArray;
    private List<Boolean> list;
    private Map<String,List<Map<String,String>>> complex;

    ...
}
----

The actual instance of `JsonChecking` is registered in the Jolokia MBeanServer and what is registered in the
Platform MBeanServer (accessible to `jconsole` using JSR-160 RMI Connector) is a Dynamic MBean (implementing `javax.management.DynamicMBean` interface). This dynamic MBean translates the string input (for writing attributes and passing operation arguments) and output (for reading attributes and operation return values) into actual data types
required by the original MBean annotated with `@JsonMBean`.

JsonMBean and MXBean are quite similar as both do a translation
from complex data types to a standard format (OpenType for
MXBeans, JSON strings for JsonMBean). However, there are also
differences:

* MXBeans are a standard mechanism which are available on every
JVM since 1.5footnote:jboss-mxbean[
For JBoss prior to version 7 there are some slight issues
since JBoss used to replace the standard MBeanServer with an
own variant. See this
https://community.jboss.org/thread/167796[discussion]
for details.].
* Serialization of complex Java Beans is more powerful with
JsonMBeans, e.g. Jolokia can detect self (or cyclic) object
references. MXBeans will cause an error in this case.
* JsonMBeans must be added to the Jolokia MBeanServer to
work. MXBeans work with the PlatformMBeanServer, too.
* JsonMBean work also with JMX support libraries which use
``ModelMBean``'s under the hood. E.g.
https://docs.spring.io/spring-framework/reference/integration/jmx.html[Spring
JMX,role=externalLink,window=_blank] uses a ModelMBean for
`@ManagedResource` annotated
MBeans. `@JsonMBean` can be easily added,
whereas `@MXBean` wouldn't work here.

The Jolokia MBeanServer and the
`@JsonMBean` annotation are contained in the
Maven module `jolokia-support-jmx`.
