//  ========================================================================
//  Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
//  ========================================================================
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================

[[using-jmx]]
=== Using JMX with Jetty

Jetty JMX integration uses the platform MBean server implementation that Java VM provides.
The integration is based on the `ObjectMBean` implementation of `DynamicMBean`.
This implementation allows you to wrap an arbitrary POJO in an MBean and annotate it appropriately to expose it via JMX.
See xref:jetty-jmx-annotations[].

The `MBeanContainer` implementation of the `Container.Listener` interface coordinates creation of MBeans.
The Jetty Server and it's components use a link:{JDURL}/org/eclipse/jetty/util/component/Container.html[Container] to maintain a containment tree of components and to support notification of changes to that tree.
The `MBeanContainer` class listens for Container events and creates and destroys MBeans as required to wrap all Jetty components.

You can access the MBeans that Jetty publishes both through built-in Java VM connector via JConsole or JMC, or by registering a remote JMX connector and using a remote JMX agent to monitor Jetty.

[[configuring-jmx]]
==== Configuring JMX

This guide describes how to initialize and configure the Jetty JMX integration.

To monitor an application using JMX, perform the following steps:

* Configure the application to instantiate an MBean container.
* Instrument objects to be MBeans.
* Provide access for JMX agents to MBeans.

[[accessing-jetty-mbeans]]
===== Using JConsole to Access Jetty MBeans

The simplest way to access the MBeans that Jetty publishes is to use the http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html[JConsole utility] the Java Virtual Machine supplies.
See xref:jetty-jconsole[] for instructions on how to configure JVM for use with JConsole or JMC.

To access Jetty MBeans via JConsole or JMC, you must:

* Enable the registration of Jetty MBeans into the platform MBeanServer.
* Enable a `JMXConnectorServer` so that JConsole/JMC can connect and visualize the MBeans.

[[registering-jetty-mbeans]]
===== Registering Jetty MBeans

Configuring Jetty JMX integration differs for standalone and embedded Jetty.

[[jmx-standalone-jetty]]
====== Standalone Jetty

JMX is not enabled by default in the Jetty distribution.
To enable JMX in the Jetty distribution, run the following, where `{$jetty.home}` is the directory where you have the Jetty distribution located (see link:#startup-base-and-home[the documentation for Jetty base vs. home examples]):

[source, screen, subs="{sub-order}"]
....
$ java -jar {$jetty.home}/start.jar --add-to-start=jmx
....

Running the above command will append the available configurable elements of the JMX module to the `{$jetty.base}/start.ini` file.
If you are managing separate ini files for your modules in the distribution, use `--add-to-start.d=jmx` instead.

If you wish to add remote access for JMX, you will also need to enable the JMX-Remote module:

[source, screen, subs="{sub-order}"]
....
$ java -jar {$jetty.home}/start.jar --add-to-start=jmx-remote
....

[[jmx-embedded-jetty]]
====== Embedded Jetty

When running Jetty embedded into an application, create and configure an MBeanContainer instance as follows:

[source, java]
----

Server server = new Server();

// Setup JMX
MBeanContainer mbContainer=new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
server.addEventListener(mbContainer);
server.addBean(mbContainer);

// Add loggers MBean to server (will be picked up by MBeanContainer above)
server.addBean(Log.getLog());

----

Notice that Jetty creates the `MBeanContainer` immediately after creating the Server, and immediately after registering it as an `EventListener` of the Server object (which is also a Container object).

Because logging is initialized prior to the `MBeanContainer` (even before the Server itself), it is necessary to register the logger manually via `server.addBean()` so that the loggers may show up in the JMX tree.

[[jmx-using-jetty-maven-plugin]]
===== Using the Jetty Maven Plugin with JMX

If you are using the link:#jetty-maven-plugin[Jetty Maven plugin] you should copy the `/etc/jetty-jmx.xml` file into your webapp project somewhere, such as `/src/etc,` then add a `<jettyconfig>` element to the plugin `<configuration>`:

[source, xml, subs="{sub-order}"]
----
<plugin>
  <groupid>org.eclipse.jetty</groupid>
  <artifactid>jetty-maven-plugin</artifactid>
  <version>{VERSION}</version>
  <configuration>
    <scanintervalseconds>10</scanintervalseconds>
    <jettyXml>src/etc/jetty-jmx.xml</jettyXml>
  </configuration>
</plugin>
----


[[enabling-jmxconnectorserver-for-remote-access]]
==== Enabling JMXConnectorServer for Remote Access

There are two ways of enabling remote connectivity so that JConsole or JMC can connect to visualize MBeans.

* Use the `com.sun.management.jmxremote` system property on the command line.
Unfortunately, this solution does not work well with firewalls and is not flexible.
* Use Jetty's `ConnectorServer` class.
To enable use of this class, uncomment the correspondent portion in `/etc/jetty-jmx.xml,` like this:

[source, xml, subs="{sub-order}"]
----
<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
  <Arg>
    <New class="javax.management.remote.JMXServiceURL">
      <Arg type="java.lang.String">rmi</Arg>
      <Arg type="java.lang.String" />
      <Arg type="java.lang.Integer"><SystemProperty name="jetty.jmxrmiport" default="1099"/></Arg>
      <Arg type="java.lang.String">/jndi/rmi://<SystemProperty name="jetty.jmxrmihost" default="localhost"/>:<SystemProperty name="jetty.jmxrmiport" default="1099"/>/jmxrmi</Arg>
    </New>
  </Arg>
  <Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
  <Call name="start" />
</New>

----

This configuration snippet starts an `RMIRegistry` and a `JMXConnectorServer` both on port 1099 (by default), so that firewalls should open just that one port to allow connections from JConsole or JMC.

[[securing-remote-access]]
==== Securing Remote Access

`JMXConnectorServer` several options to restrict access.
For a complete guide to controlling authentication and authorization in JMX, see https://blogs.oracle.com/lmalventosa/entry/jmx_authentication_authorization[Authentication and Authorization in JMX RMI connectors] in Luis-Miguel Alventosa's blog.

To restrict access to the `JMXConnectorServer`, you can use this configuration, where the `jmx.password` and `jmx.access` files have the format specified in the blog entry above:

[source, xml, subs="{sub-order}"]
----

<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
  <Arg>
    <New class="javax.management.remote.JMXServiceURL">
      <Arg type="java.lang.String">rmi</Arg>
      <Arg type="java.lang.String" />
      <Arg type="java.lang.Integer"><SystemProperty name="jetty.jmxrmiport" default="1099"/></Arg>
      <Arg type="java.lang.String">/jndi/rmi://<SystemProperty name="jetty.jmxrmihost" default="localhost"/>:<SystemProperty name="jetty.jmxrmiport" default="1099"/>/jmxrmi</Arg>
    </New>
  </Arg>
  <Arg>
    <Map>
      <Entry>
        <Item>jmx.remote.x.password.file</Item>
        <Item>
          <New class="java.lang.String"><Arg><Property name="jetty.home" default="." />/resources/jmx.password</Arg></New>
        </Item>
      </Entry>
      <Entry>
        <Item>jmx.remote.x.access.file</Item>
        <Item>
          <New class="java.lang.String"><Arg><Property name="jetty.home" default="." />/resources/jmx.access</Arg></New>
        </Item>
      </Entry>
    </Map>
  </Arg>
  <Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
  <Call name="start" />
</New>


----

[[custom-monitor-applcation]]
==== Custom Monitor Application

Using the JMX API, you can also write a custom application to monitor your Jetty server.
To allow this application to connect to your Jetty server, you need to uncomment the last section of the `/etc/jetty-jmx.xml` configuration file and optionally modify the endpoint name.
Doing so creates a JMX HTTP connector and registers a JMX URL that outputs to the `Stderr` log.

You should provide the URL that appears in the log to your monitor application in order to create an `MBeanServerConnection.`
You can use the same URL to connect to your Jetty instance from a remote machine using JConsole or JMC.
See the link:{GITBROWSEURL}/jetty-jmx/src/main/config/etc/jetty-jmx.xml[configuration file] for more details.
