PreviousPrevious Contents NextNext
Chapter 2

Monitoring and Management Using JMX Technology

The Java virtual machine (Java VM) has built-in instrumentation that enables you to monitor and manage it using the Java Management Extensions (JMX) technology. These built-in management utilities are often referred to as out-of-the-box management tools for the Java VM. You can also monitor any appropriately instrumented applications using the JMX API. 

Setting System Properties

To enable and configure the out-of-the-box JMX agent so that it can monitor and manage the Java VM, you must set certain system properties when you start the Java VM. You set a system property on the command-line as follows.

java -Dproperty=value ...

You can set any number of system properties in this way. If you do not specify a value for a management property, then the property is set with its default value. The full set of out-of-the-box management properties is described in Table 2-1 at the end of this chapter. You can also set system properties in a configuration file, as described in Out-of-the-Box Monitoring and Management Properties.


Note - To run the Java VM from the command line, you must add JRE_HOME/bin to your path, where JRE_HOME is the directory containing the Java Runtime Environment (JRE) implementation. Alternatively, you can enter the full path when you type the command.


The following documents describe the syntax and the full set of command-line options supported by the Java HotSpot VMs.

Enabling the Out-of-the-Box Management

To monitor a Java platform using the JMX API, you must do the following.

  1. Enable the JMX agent (another name for the platform MBean server) when you start the Java VM. You can enable the JMX agent for:

    • Local monitoring, for a client management application running on the local system.

    • Remote monitoring, for a client management application running on a remote system.

  2. Monitor the Java VM with a tool that complies to the JMX specification, such as JConsole. See Chapter 3, Using JConsole for more information about Console.

These steps are described in the next sections.

Local Monitoring and Management

Under previous releases of the Java SE platform, to allow the JMX client access to a local Java VM, you had to set the following system property when you started the Java VM or Java application.

com.sun.management.jmxremote

Setting this property registered the Java VM platform's MBeans and published the Remote Method Invocation (RMI) connector via a private interface to allow JMX client applications to monitor a local Java platform, that is, a Java VM running on the same machine as the JMX client.

In the Java SE 6 platform, it is no longer necessary to set this system property. Any application that is started on the Java SE 6 platform will support the Attach API, and so will automatically be made available for local monitoring and management when needed.

For example, previously, to enable the JMX agent for the Java SE sample application Notepad, you would have to run the following commands.

% cd JDK_HOME/demo/jfc/Notepad
% java -Dcom.sun.management.jmxremote -jar Notepad.jar

In the above command, JDK_HOME is the directory in which the Java Development Kit (JDK) is installed. In the Java SE 6 platform, you would simply have to run the following command to start Notepad.

% java -jar Notepad.jar

Once Notepad has been started, a JMX client using the Attach API can then enable the out-of-the-box management agent to monitor and manage the Notepad application.


Note - On Windows platforms, for security reasons, local monitoring and management is only supported if your default temporary directory is on a file system that allows the setting of permissions on files and directories (for example, on a New Technology File System (NTFS) file system). It is not supported on a File Allocation Table (FAT) file system, which provides insufficient access controls.


Local Monitoring and Management Using JConsole

Local monitoring with JConsole is useful for development and creating prototypes. Using JConsole locally is not recommended for production environments, because JConsole itself consumes significant system resources. Rather, you should use JConsole on a remote system to isolate it from the platform being monitored.

However, if you do wish to perform local monitoring using JConsole, you start the tool by typing jconsole in a command shell. When you start jconsole without any arguments, it will automatically detect all local Java applications, and display a dialog box that enables you to select the application you want to monitor. Both JConsole and the application must by executed by the same user, since the monitoring and management system uses the operating system's file permissions.


Note - To run JConsole from the command line, you must add JDK_HOME/bin to your path. Alternatively, you can enter the full path when you type the command.


For more information, see Chapter 3, Using JConsole.

Remote Monitoring and Management

To enable monitoring and management from remote systems, you must set the following system property when you start the Java VM.

com.sun.management.jmxremote.port=portNum

In the property above, portNum is the port number through which you want to enable JMX RMI connections. Be sure to specify an unused port number. In addition to publishing an RMI connector for local access, setting this property publishes an additional RMI connector in a private read-only registry at the specified port using a well known name, "jmxrmi".


Note - You must set the above system property in addition to any properties you might set for security.


Remote monitoring and management requires security to ensure that unauthorized persons cannot control or monitor your application. Password authentication over the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) is enabled by default. You can disable password authentication and SSL separately, as described in the next sections.


Note - For production systems, use both SSL client certificates to authenticate the client host and password authentication for user management. See the topics Using SSL and Using LDAP Authentication for more information.


The Java platform supports pluggable login modules for authentication. You can plug in any login module depending on the authentication infrastructure in your organization. The section titled Using LDAP Authentication describes how to plug in the com.sun.security.auth.module.LdapLoginModule for Lightweight Directory Access Protocol (LDAP) based authentication.

After you have enabled the JMX agent for remote use, you can monitor your application using JConsole, as described in Remote Monitoring with JConsole. How to connect to the management agent programmatically is described in Connecting to the JMX Agent Programmatically.

Using Password Authentication

Using LDAP Authentication

The JMXAuthenticator implementation in the JMX agent is based on Java Authentication and Authorization Service (JAAS) technology. Authentication is performed by passing the user credentials to a JAAS javax.security.auth.spi.LoginModule object. The com.sun.security.auth.module.LdapLoginModule class enables authentication using LDAP. You can replace the default LoginModule class with the LdapLoginModule as described next.

Create a JAAS configuration file that would work in the required business organization. An example of a configuration file (ldap.config) is shown next:

ExampleCompanyConfig {
    com.sun.security.auth.module.LdapLoginModule REQUIRED
        userProvider="ldap://example-ds/ou=people,dc=examplecompany,dc=com"
        userFilter="(&(uid={USERNAME})(objectClass=inetOrgPerson))"
        authzIdentity=monitorRole;
    };

The options in the configuration file are briefly explained next. See documentation for the com.sun.security.auth.module.LdapLoginModule class for information about the configuration options shown in the code snippet.

  • The com.sun.security.auth.module.LdapLoginModule REQUIRED option means that authentication using LdapLoginModule is required in order for overall authentication to be successful
  • The userProvider option identifies the LDAP server and the position in the directory tree where user entries are located
  • The userFilter option specifies the search filter to use to locate a user entry in the LDAP directory. The token {USERNAME} is replaced with the user name before the filter is used to search the directory.
  • The authzIdentity option specifies the access role for authenticated users. In the example, authenticated users will have the monitorRole. See the Access Files section for more information.

Start your application with the following properties set on the command line:

  • com.sun.management.jmxremote.login.config - This property configures the JMX agent to use the specified JAAS configuration entry.
  • java.security.auth.login.config - specifies the path to the JAAS configuration file.

A sample command line is shown next.

java -Dcom.sun.management.jmxremote.port=5000
     -Dcom.sun.management.jmxremote.login.config=ExampleCompanyConfig
     -Djava.security.auth.login.config=ldap.config
     -jar MyApplication.jar
Using File-Based Password Authentication

The file-based password authentication mechanism supported by the JMX agent stores the password in clear-text and is intended only for development use. For production use, it is strongly recommended that you use SSL client certificates for authentication or plug in a secure login configuration.


Caution - A potential security issue has been identified with password authentication for remote connectors when the client obtains the remote connector from an insecure RMI registry (the default). If an attacker starts a bogus RMI registry on the target server before the legitimate registry is started, then the attacker can steal clients' passwords. This scenario includes the case where you launch a Java VM with remote management enabled, using the system property com.sun.management.jmxremote.port=portNum, even when SSL is enabled. Although such attacks are likely to be noticed, it is nevertheless a vulnerability.


By default, when you enable the JMX agent for remote monitoring, it uses password authentication. However, the way you set it up depends on whether you are in a single-user environment or a multiple-user environment.

Since passwords are stored in clear-text in the password file, it is not advisable to use your regular user name and password for monitoring. Instead, use the user names specified in the password file such as monitorRole and controlRole. For more information, see Using Password and Access Files.

Single-User Environment To Set up a Single-User Environment

You set up the password file in the JRE_HOME/lib/management directory as follows.

  1. Copy the password template file, jmxremote.password.template, to jmxremote.password.
  2. Set file permissions so that only the owner can read and write the password file.
  3. Add passwords for roles such as monitorRole and controlRole.
Multiple-User Environment To Set up a Multiple-User Environment

You set up the password file in the JRE_HOME/lib/management directory as follows.

  1. Copy the password template file, jmxremote.password.template, to your home directory and rename it to jmxremote.password.
  2. Set file permissions so that only you can read and write the password file.
  3. Add passwords for the roles such as monitorRole and controlRole.
  4. Set the following system property when you start the Java VM.
    com.sun.management.jmxremote.password.file=pwFilePath
    

    In the above property, pwFilePath is the path to the password file.

Disabling Password Authentication

Password authentication for remote monitoring is enabled by default. To disable it, set the following system property when you start the Java VM.

com.sun.management.jmxremote.authenticate=false

Caution - This configuration is insecure. Any remote user who knows (or guesses) your JMX port number and host name will be able to monitor and control your Java application and platform. While it may be acceptable for development, it is not recommended for production systems.


When you disable password authentication, you can also disable SSL, as described in Disabling Security. You may also want to disable passwords, but use SSL client authentication, as described in Enabling SSL Client Authentication.

Using SSL

SSL is enabled by default when you enable remote monitoring and management. To use SSL, you need to set up a digital certificate on the system where the JMX agent (the MBean server) is running and then configure SSL properly. You use the command-line utility keytool to work with certificates. The general procedure is as follows.

Set up SSL To Set up SSL
  1. If you do not already have a key pair and certificate set up on the server:
  2. Configure SSL on the server system.

    A full explanation of configuring and customizing SSL is beyond the scope of this document, but you generally need to set the system properties described in the list below.

    System Property

    Description

    javax.net.ssl.keyStore

    Keystore location.

    javax.net.ssl.keyStoreType

    Default keystore type.

    javax.net.ssl.keyStorePassword

    Default keystore password.

    javax.net.ssl.trustStore

    Truststore location.

    javax.net.ssl.trustStoreType

    Default truststore type.

    javax.net.ssl.trustStorePassword

    Default truststore password.

    For more information about setting system properties, see Setting System Properties above, or consult the following documents.

Enabling RMI Registry Authentication

When setting up connections for monitoring remote applications, you can optionally bind the RMI connector stub to an RMI registry that is protected by SSL. This allows clients with the appropriate SSL certificates to get the connector stub that is registered in the RMI registry. To protect the RMI registry using SSL, you must set the following system property.

com.sun.management.jmxremote.registry.ssl=true

When this property is set to true, an RMI registry protected by SSL will be created and configured by the out-of-the-box management agent when the Java VM is started. The default value of this property is false. However, it is recommended that you set this property to true. If this property is set to true, then to have full security, you must also enable SSL client authentication, as described in the next section.

Enabling SSL Client Authentication

To enable SSL client authentication, set the following system property when you start the Java VM.

com.sun.management.jmxremote.ssl.need.client.auth=true

SSL must be enabled (default is set to false), to use client SSL authentication. It is recommended that you set this property to true. This configuration requires that the client system have a valid digital certificate. You must install a certificate and configure SSL on the client system, as described in Using SSL. As stated in the previous section, if RMI registry SSL protection is enabled, then client SSL authentication must be set to true.

Disabling SSL

To disable SSL when monitoring remotely, you must set the following system property when you start the Java VM.

com.sun.management.jmxremote.ssl=false

Password authentication will still be required unless you disable it, as specified in Disabling Password Authentication.

Disabling Security

To disable both password authentication and SSL (namely to disable all security), you should set the following system properties when you start the Java VM.

com.sun.management.jmxremote.authenticate=false
com.sun.management.jmxremote.ssl=false

Caution - This configuration is insecure: any remote user who knows (or guesses) your port number and host name will be able to monitor and control your Java applications and platform. Furthermore, possible harm is not limited to the operations you define in your MBeans. A remote client could create a javax.management.loading.MLet MBean and use it to create new MBeans from arbitrary URLs, at least if there is no security manager. In other words, a rogue remote client could make your Java application execute arbitrary code.

Consequently, while disabling security might be acceptable for development, it is strongly recommended that you do not disable security for production systems.


Remote Monitoring with JConsole

You can remotely monitor an application using JConsole, with or without security enabled.

Remote Monitoring with JConsole with SSL Disabled

To monitor a remote application with SSL disabled, you would start JConsole with the following command.

% jconsole hostName:portNum

You can also omit the host name and port number, and enter them in the dialog box that JConsole provides.

Remote Monitoring with JConsole with SSL Enabled

To monitor a remote application with SSL enabled, you need to set up the truststore on the system where JConsole is running and configure SSL properly. For example, you can create a keystore as described in the JSSE Guide and start your application (called Server in this example) with the following commands.

% java -Djavax.net.ssl.keyStore=keystore \
  -Djavax.net.ssl.keyStorePassword=password Server

If you created the keystore and started Server as shown above, then you would have to start JConsole as follows.

% jconsole -J-Djavax.net.ssl.trustStore=truststore \
  -J-Djavax.net.ssl.trustStorePassword=trustword

The above configuration authenticates the server only. If SSL client authentication is set up, you will need to provide a similar keystore for JConsole's keys, and an appropriate truststore for the application.

See Customizing the Default Key and Trust Stores, Store Types, and Store Passwords in the JSSE Guide for information.

For more information on using JConsole, see Chapter 3, Using JConsole.

Using Password and Access Files

The password and access files control security for remote monitoring and management. These files are located by default in JRE_HOME/lib/management and are in the standard Java properties file format. For more information on the format, see the API reference for the java.util.Properties package.

Password Files

The password file defines the different roles and their passwords. The access control file (jmxremote.access by default) defines the permitted access for each role. To be functional, a role must have an entry in both the password and the access files.

The JRE implementation contains a password file template named jmxremote.password.template. Copy this file to JRE_HOME/lib/management/jmxremote.password or to your home directory, and add the passwords for the roles defined in the access file.

You must ensure that only the owner has read and write permissions on this file, since it contains the passwords in clear text. For security reasons, the system checks that the file is only readable by the owner and exits with an error if it is not. Thus in a multiple-user environment, you should store the password file in private location such as your home directory.

Property names are roles, and the associated value is the role's password. For example, the following are sample entries in the password file.

Example 2-1 An Example Password File
# specify actual password instead of the text password
monitorRole password
controlRole password

On Solaris, Linux, or Mac OS X operating systems, you can set the file permissions for the password file by running the following command.

chmod 600 jmxremote.password

For instructions on how to set file permissions on Windows platforms, see Appendix A, Additional Security Information For Microsoft Windows.

Access Files

By default, the access file is named jmxremote.access. Property names are identities from the same space as the password file. The associated value must be either readonly or readwrite.

The access file defines roles and their access levels. By default, the access file defines the two following primary roles.

  • monitorRole, which grants read-only access for monitoring.

  • controlRole, which grants read-write access for monitoring and management.

An access control entry consists of a role name and an associated access level. The role name cannot contain spaces or tabs and must correspond to an entry in the password file. The access level can be either one of the following.

  • readonly, which grants access to read an MBean's attributes. For monitoring, this means that a remote client in this role can read measurements but cannot perform any action that changes the environment of the running program. The remote client can also listen to MBean notifications.

  • readwrite, which grants access to read and write an MBean's attributes, to invoke operations on them, and to create or remove them. This access should be granted to only trusted clients, since they can potentially interfere with the operation of an application.

A role should have only one entry in the access file. If a role has no entry, it has no access. If a role has multiple entries, then the last entry takes precedence. Typical predefined roles in the access file resemble the following.

Example 2-2 An Example Access File
# The "monitorRole" role has readonly access.
# The "controlRole" role has readwrite access.
monitorRole readonly
controlRole readwrite

Out-of-the-Box Monitoring and Management Properties

You can set out-of-the-box monitoring and management properties in a configuration file or on the command line. Properties specified on the command line override properties in a configuration file. The default location for the configuration file is JRE_HOME/lib/management/management.properties. The Java VM reads this file if either of the command-line properties com.sun.management.jmxremote or com.sun.management.jmxremote.port are set. Management via the Simple Network Management Protocol (SNMP) uses the same configuration file. For more information about SNMP monitoring, see Chapter 5, SNMP Monitoring and Management.

You can specify a different location for the configuration file with the following command-line option.

com.sun.management.config.file=ConfigFilePath

In the property above, ConfigFilePath is the path to the configuration file.

Table 2-1 describes all the out-of-the-box monitoring and management properties.

Table 2-1 Out-of-the-Box Monitoring and Management Properties
Property Description Values

com.sun.management.jmxremote

Enables the JMX remote agent and local monitoring via a JMX connector published on a private interface used by JConsole and any other local JMX clients that use the Attach API. JConsole can use this connector if it is started by the same user as the user that started the agent. No password or access files are checked for requests coming via this connector.

true / false. Default is true.

com.sun.management.jmxremote. port

Enables the JMX remote agent and creates a remote JMX connector to listen through the specified port. By default, the SSL, password, and access file properties are used for this connector. It also enables local monitoring as described for the com.sun.management.jmxremote property.

Port number. No default.

com.sun.management.jmxremote. registry.ssl

Binds the RMI connector stub to an RMI registry protected by SSL.

true / false. Default is false.

com.sun.management.jmxremote. ssl

Enables secure monitoring via SSL. If false, then SSL is not used.

true / false. Default is true.

com.sun.management.jmxremote. ssl.enabled.protocols

A comma-delimited list of SSL/TLS protocol versions to enable. Used in conjunction with com.sun.management.jmxremote.ssl.

Default SSL/TLS protocol version.

com.sun.management.jmxremote. ssl.enabled.cipher.suites

A comma-delimited list of SSL/TLS cipher suites to enable. Used in conjunction with com.sun.management.jmxremote.ssl.

Default SSL/TLS cipher suites.

com.sun.management.jmxremote. ssl.need.client.auth

If this property is true and the property com.sun.management.jmxremote.ssl is also true, then client authentication will be performed.

It is recommended that you set this property to true.

true / false. Default is false.

com.sun.management.jmxremote. authenticate

If this property is false then JMX does not use passwords or access files: all users are allowed all access.

true / false. Default is true.

com.sun.management.jmxremote. password.file

Specifies location for password file. If com.sun.management.jmxremote.authenticate is false, then this property and the password and access files are ignored. Otherwise, the password file must exist and be in the valid format. If the password file is empty or nonexistent, then no access is allowed.

JRE_HOME/lib/management/ jmxremote.password

com.sun.management.jmxremote. access.file

Specifies location for the access file. If com.sun.management.jmxremote.authenticate is false, then this property and the password and access files are ignored. Otherwise, the access file must exist and be in the valid format. If the access file is empty or nonexistent, then no access is allowed.

JRE_HOME/lib/management/ jmxremote.access

com.sun.management.jmxremote.login.config

Specifies the name of a Java Authentication and Authorization Service (JAAS) login configuration entry to use when the JMX agent authenticates users. When using this property to override the default login configuration, the named configuration entry must be in a file that is loaded by JAAS. In addition, the login modules specified in the configuration should use the name and password callbacks to acquire the user's credentials. For more information, see the API documentation for javax.security.auth.callback.NameCallback and javax.security.auth.callback.PasswordCallback.

Default login configuration is a file-based password authentication.

Configuration Errors

If any errors occur during start up of the MBean server, the RMI registry, or the connector, the Java VM will throw an exception and exit. Configuration errors include the following.

  • Failure to bind to the port number.

  • Invalid password file.

  • Invalid access file.

  • Password file is readable by users other than the owner.

If your application runs a security manager, then additional permissions are required in the security permissions file.

Connecting to the JMX Agent Programmatically

Once you have enabled the JMX agent, a client can use the following URL to access the monitoring service.

service:jmx:rmi:///jndi/rmi://hostName:portNum/jmxrmi

A client can create a connector for the agent by instantiating a javax.management.remote.JMXServiceURL object using the URL, and then creating a connection using the JMXConnectorFactory.connect method, shown in Example 2-3.

Example 2-3 Creating a Connection Using JMXConnectorFactory.connect
JMXServiceURL u = new JMXServiceURL(
  "service:jmx:rmi:///jndi/rmi://" + hostName + ":" + portNum +  "/jmxrmi");
  JMXConnector c = JMXConnectorFactory.connect(u); 

Setting up Monitoring and Management Programmatically

As stated previously, in the Java SE platform version 6, you can create a JMX client that uses the Attach API to enable out-of-the-box monitoring and management of any applications that are started on the Java SE 6 platform, without having to configure the applications for monitoring when you launch them. The Attach API provides a way for tools to attach to and start agents in the target application. Once an agent is running, JMX clients (and other tools) are able to obtain the JMX connector address for that agent via a property list that is maintained by the Java VM on behalf of the agents. The properties in the list are accessible from tools that use the Attach API. So, if an agent is started in an application, and if the agent creates a property to represent a piece of configuration information, then that configuration information is available to tools that attach to the application.

The JMX agent creates a property with the address of the local JMX connector server. This allows JMX tools to attach to and get the connector address of an agent, if it is running.

Example 2-4 shows code that could be used in a JMX tool to attach to a target VM, get the connector address of the JMX agent and connect to it.

Example 2-4 Attaching a JMX tool to a connector and getting the agent's address
static final String CONNECTOR_ADDRESS =
 "com.sun.management.jmxremote.localConnectorAddress";
 
// attach to the target application
VirtualMachine vm = VirtualMachine.attach(id);
 
// get the connector address
String connectorAddress =
    vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
 
// no connector address, so we start the JMX agent
if (connectorAddress == null) {
   String agent = vm.getSystemProperties().getProperty("java.home") +
       File.separator + "lib" + File.separator + "management-agent.jar";
   vm.loadAgent(agent);
 
   // agent is started, get the connector address
   connectorAddress =
       vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
}
 
// establish connection to connector server
JMXServiceURL url = new JMXServiceURL(connectorAddress);
JMXConnector = JMXConnectorFactory.connect(url);

Example 2-4 uses the com.sun.tools.attach.VirtualMachine class's attach() method to attach to a given Java VM so that it can read the properties that the target Java VM maintains on behalf of any agents running in it. If an agent is already running, then the VirtualMachine class's getAgentProperties() method is called to obtain the agent's address. The getAgentProperties() method returns a string property for the local connector address com.sun.management.jmxremote.localConnectorAddress, that you can use to connect to the local JMX agent.

If no agent is running already, then one is loaded by the VirtualMachine from JRE_HOME/lib/management-agent.jar, and its connector address is obtained by getAgentProperties().

A connection to the agent is then established by calling JMXConnectorFactory.connect on a JMX service URL that has been constructed from this connector address.

Mimicking Out-of-the-Box Management Using the JMX Remote API

As explained above, remote access to the out-of-the-box management agent is protected by authentication and authorization, and by SSL encryption, and all configuration is performed by setting system properties or by defining a management.properties file. In most cases, using the out-of-the-box management agent and configuring it through the management.properties file is more than sufficient to provide secure management of remote Java VMs. However, in some cases greater levels of security are required and in other cases certain system configurations do not allow the use of a management.properties file. Such cases might involve exporting the RMI server's remote objects over a certain port to allow passage through a firewall, or exporting the RMI server's remote objects using a specific network interface in multi-homed systems. For such cases, the behavior of the out-of-the-box management agent can be mimicked by using the JMX Remote API directly to create, configure and deploy the management agent programmatically.

Example of Mimicking Out-of-the-Box Management

This section provides an example of how to implement a JMX agent that identically mimics an out-of-the-box management agent. In exactly the same way as the out-of-the-box management agent, the agent created in Example 2-5 will run on port 3000, will have a password file named password.properties, an access file named access.properties and it will implement the default configuration for SSL/TLS-based RMI Socket Factories, requiring server authentication only. This example assumes a keystore has already been created, as described in Using SSL. Information about how to set up the SSL configuration can be found in the JSSE Reference Guide.

To enable monitoring and management on an application named com.example.MyApp using the out-of-the-box JMX agent with the configuration described above, you would run com.example.MyApp with the following command.

% java -Dcom.sun.management.jmxremote.port=3000 \
     -Dcom.sun.management.jmxremote.password.file=password.properties \
     -Dcom.sun.management.jmxremote.access.file=access.properties \
     -Djavax.net.ssl.keyStore=keystore \
     -Djavax.net.ssl.keyStorePassword=password \
     com.example.MyApp

Note - The com.sun.management.jmxremote.* properties could have been specified in a management.properties file instead of passing them at the command line. In that case, the system property -Dcom.sun.management.config.file=management.properties would be required to specify the location of the management.properties file.


Example 2-5 shows the code you would need to write to create programmatically a JMX agent that will allow exactly the same monitoring and management on com.example.MyApp as would be possible using the command above.

Example 2-5 Mimicking an Out-of-the-Box JMX Agent Programmatically
package com.example;

import java.lang.management.*;
import java.rmi.registry.*;
import java.util.*;
import javax.management.*;
import javax.management.remote.*;
import javax.management.remote.rmi.*;
import javax.rmi.ssl.*;

public class MyApp {

    public static void main(String[] args) throws Exception {

        // Ensure cryptographically strong random number generator used
        // to choose the object number - see java.rmi.server.ObjID
        //
        System.setProperty("java.rmi.server.randomIDs", "true");

        // Start an RMI registry on port 3000.
        //
        System.out.println("Create RMI registry on port 3000");
        LocateRegistry.createRegistry(3000);

        // Retrieve the PlatformMBeanServer.
        //
        System.out.println("Get the platform's MBean server");
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

        // Environment map.
        //
        System.out.println("Initialize the environment map");
        HashMap<String,Object> env = new HashMap<String,Object>();

        // Provide SSL-based RMI socket factories.
        //
        // The protocol and cipher suites to be enabled will be the ones
        // defined by the default JSSE implementation and only server
        // authentication will be required.
        //
        SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
        SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory();
        env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);
        env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf);

        // Provide the password file used by the connector server to
        // perform user authentication. The password file is a properties
        // based text file specifying username/password pairs.
        //
        env.put("jmx.remote.x.password.file", "password.properties");

        // Provide the access level file used by the connector server to
        // perform user authorization. The access level file is a properties
        // based text file specifying username/access level pairs where
        // access level is either "readonly" or "readwrite" access to the
        // MBeanServer operations.
        //
        env.put("jmx.remote.x.access.file", "access.properties");

        // Create an RMI connector server.
        //
        // As specified in the JMXServiceURL the RMIServer stub will be
        // registered in the RMI registry running in the local host on
        // port 3000 with the name "jmxrmi". This is the same name the
        // out-of-the-box management agent uses to register the RMIServer
        // stub too.
        //
        System.out.println("Create an RMI connector server");
        JMXServiceURL url =
            new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:3000/jmxrmi");
        JMXConnectorServer cs =
            JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);

        // Start the RMI connector server.
        //
        System.out.println("Start the RMI connector server");
        cs.start();
    }
}

Start this application with the following command.

java -Djavax.net.ssl.keyStore=keystore \
     -Djavax.net.ssl.keyStorePassword=password \
     com.example.MyApp

The com.example.MyApp application will enable the JMX agent and will be able to be monitored and managed in exactly the same way as if the Java platform's out-of-the-box management agent had been used. However, there is one slight but important difference between the RMI registry used by the out-of-the-box management agent and the one used by a management agent that mimics it. The RMI registry used by the out-of-the-box management agent is read-only, namely a single entry can be bound to it and once bound this entry cannot be unbound. This is not true of the RMI registry created in Example 2-5.

Furthermore, both RMI registries are insecure as they do not use SSL/TLS. The RMI registries should be created using SSL/TLS-based RMI socket factories which require client authentication. This will prevent a client from sending its credentials to a rogue RMI server and will also prevent the RMI registry from giving access to the RMI server stub to a non-trusted client.

RMI registries which implement SSL/TLS RMI socket factories can be created by adding the following properties to your management.properties file.

com.sun.management.jmxremote.registry.ssl=true
com.sun.management.jmxremote.ssl.need.client.auth=true

Example 2-5 mimics the main behavior of the out-of-the-box JMX agent, but does not replicate all the existing properties in the management.properties file. However, you could add other properties by modifying com.example.MyApp appropriately.

Monitoring Applications through a Firewall

As stated above, the code in Example 2-5 can be used to monitor applications through a firewall, which might not be possible if you use the out-of-the-box monitoring solution. The com.sun.management.jmxremote.port management property specifies the port where the RMI Registry can be reached but the ports where the RMIServer and RMIConnection remote objects are exported is chosen by the RMI stack. To export the remote objects (RMIServer and RMIConnection) to a given port you need to create your own RMI connector server programmatically, as described in Example 2-5. However, you must specify the JMXServiceURL as follows:

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://localhost:" + 
      port1  + "/jndi/rmi://localhost:" + port2 + "/jmxrmi");

In the URL above, port1 is the port number on which the RMIServer and RMIConnection remote objects are exported and port2 is the port number of the RMI Registry.

Using an Agent Class to Instrument an Application

The Java SE platform provides services that allow Java programming language agents to instrument programs running on the Java VM. Creating an instrumentation agent means you do not have to add any new code to your application in order to allow it to be monitored. Instead of implementing monitoring and management in your application's static main method you implement it in a separate agent class, and start your application with the -javaagent option specified. See the API reference documentation for the java.lang.instrument package for full details about how to create an agent class to instrument your applications.

The following procedure shows how you can adapt the code of com.example.MyApp to make an agent to instrument any other application for monitoring and management.

Creating an Agent Class Creating an Agent Class to Instrument an Application

  1. Create a com.example.MyAgent class.

    Create a class called com.example.MyAgent, declaring a premain method rather than a main method.

    package com.example;
    
    [...]
    
    public class MyAgent {
        
        public static void premain(String args) throws Exception {
        
        [...]
    

    The rest of the code for the com.example.MyAgent class can be exactly the same as the com.example.MyApp class shown in Example 2-5.

  2. Compile the com.example.MyAgent class.
  3. Create a manifest file, MANIFEST.MF, with a Premain-Class entry.

    An agent is deployed as a Java archive (JAR) file. An attribute in the JAR file manifest specifies the agent class which will be loaded to start the agent. Create a file called MANIFEST.MF, containing the following line.

    Premain-Class: com.example.MyAgent
    
  4. Create a JAR file, MyAgent.jar.

    The JAR file should contain the following files.

    • META-INF/MANIFEST.MF

    • com/example/MyAgent.class

  5. Start an application, specifying the agent to provide monitoring and management services.

    You can use com.example.MyAgent to instrument any application for monitoring and management. This example uses the Notepad application.

    % java -javaagent:MyAgent.jar -Djavax.net.ssl.keyStore=keystore \
          -Djavax.net.ssl.keyStorePassword=password -jar Notepad.jar
    

    The com.example.MyAgent agent is specified using the -javaagent option when you start Notepad. Also, if your com.example.MyAgent application replicates the same code as the com.example.MyApp application shown in Example 2-5, then you will need to provide the keystore and password because the RMI connector server is protected by SSL.

PreviousPrevious Contents NextNext

Copyright © 1993, 2024, Oracle and/or its affiliates. All rights reserved.