JMX(TM) "scandir" Example

#
JavaTM Management Extensions (JMXTM) scandir Example

## Introduction

The JMX scandir example is an application that scans parts of a filesystem - e.g. a set of directories used by a number of lab machines when running tests - in order to clean up and optimize disk space by removing obsolete files - e.g. files that are leaked by the test suites running on those machines, like coredump files, or temporary files that might remain after a test crash. It could also serve as a basis for an application that would monitor disk usage and suggest removal of old big long-unaccessed files.

The JMX scandir example does not however implement the full fledged logic that such an application might have. It implements a subset of this logic which is sufficient to demonstrate common patterns and solutions used when implementing a monitoring and management interface for an application with JMX Technology.

This example is an advanced JMX example, which presents advanced JMX concepts. It is assumed that the reader is already familiar with the JMX API. Newcomers to JMX Technology are invited to have a look at the JMX API Overview, Tutorial and Examples before going any further.

> Note: This example was developed using NetBeans 5.0 IDE. The instructions given in this document to build, run, and test the example assume that you have at your disposal:
> - either NetBeans 5.0 IDE,
> - or Apache Ant 1.6.5 and JUnit 3.8.1 or 3.8.2
>   (JUnit is only needed to run the example's unit tests).

> In order to build the example, you may need to copy the jmx-scandir directory to somewhere where you have write permissions.
> In that case, you will need to update the nbjdk.home variable in the copied build.properties file located at the root of the copied project directory. Please make sure that this variable points to the JDK 6 home directory.

> If you wish to run the testsuite from within the NetBeans IDE you will also have to set the libs.junit.classpath variable in build.properties. The libs.junit.classpath variable should point to your junit.jar, version 3.8.1 or 3.8.2.

Table Of Contents:

[Generating the Java Documentation] [Overview of the scandir Example] [API Documentation and Sources] [Patterns, Best Practices, and Common Pitfalls] [Testing the scandir Example] [Running the scandir Example] [Playing with JConsole] [Turning the example into a Secure JMX Application] [Connecting to the Secure JMX Application] [Conclusion] [References]

## Generating the Java Documentation

Before reading further, you will need to generate the Java Documentation for the example's sources.

In the example root directory (where the `build.xml` file is located) run the following command:

    ant javadoc

Alternatively you can open the jmx-scandir project with the NetBeans IDE and generate the Javadoc from its `Build` menu.

If building the documentation fails, please make sure to read the note at the beginning of this document.

## Overview of the scandir Example

The JMX scandir example is built around the following MBeans:

- The first MBean we will present here is the DirectoryScannerMXBean.
  A `DirectoryScannerMXBean` is an MBean that scans a file system starting at a given root directory, and then looks for files that match the given criteria. When such a file is found, the `DirectoryScannerMXBean` takes the action for which it was configured: emit a notification, and/or log a `record` for this file, and/or delete that file. The code that would actually delete the file is commented out - so that nothing valuable is lost if the example is run by mistake on the wrong set of directories.
  `DirectoryScannerMXBeans` are created by the ScanManagerMXBean - see next item on the list, from its configuration.
- The ScanManagerMXBean is the actual entry point of the application. It reads the application's configuration, and from that configuration, will create a ResultLogManager and some DirectoryScannerMXBeans.
  The `ScanManagerMXBean` lets you start, stop, and schedule directory scans. The `ScanManagerMXBean` is a singleton MBean: there can be at most one instance of such an MBean registered in a given MBeanServer.
- The ScanDirConfigMXBean is an MBean which is able to load/save the configuration to/from an XML file. It will also let you modify that configuration - by e.g. creating new directory scanners in there. The corresponding MBeans will be created later, only when you later ask the `ScanManagerMXBean` to apply the configuration again.
  The `ScanDirConfigMXBean` is created by the `ScanManagerMXBean`, when the `ScanManagerMXBean` is registered. It is also possible to create an alternate `ScanDirConfigMXBean`, and to switch the `ScanDirConfigMXBean` to use one or the other configuration.
  An example of XML configuration file is given here. Although you could edit such a file by hand, it is easier to do it programmatically (or with JConsole) through the `ScanDirConfigMXBean` interface.
- The ResultLogManagerMXBean is in charge of managing result logs.
  Directory Scanners can be configured to log a ResultRecord whenever they take action upon a file that matches their criteria. The `ResultLogManagerMXBean` is responsible for logging these result records. The `ResultLogManagerMXBean` can be configured to log such records to a flat file, or into a log held in memory, or both. Both logs (file and memory) can be configured with a maximum capacity.
  When the maximum capacity of the memory log is reached, its first entry (i.e. its oldest entry) is removed to make place for the latest one.
  When the maximum capacity of the file log is reached, the file is renamed by appending a tilde '~' to its name and a new result log is created.
  The `ResultLogManagerMXBean` will let you interactively clear these result logs, change their capacity, and decide where (memory or file) to log. The memory log is useful in that its content can be interactively returned by the `ResultLogManagerMXBean`, while the file log doesn't have this facility.
  The result logs are intended to be used by e.g. an offline program that would take some actions on the files that matched the scan criteria:
  The scandir application could be configured to only produce logs (i.e. takes no action but logging the matching files), and the real action could be performed by another program or module (e.g. mail the result log to the engineer who maintains the lab, or parse that log and delete all the files listed there, or parse the log and prepare and send a single mail to each owner of matching files, containing the list of files they should consider deleting).
  The `ResultLogManagerMXBean` is a singleton MBean created by the `ScanManagerMXBean` which reads and writes its configuration from the `ScanDirConfigMXBean`.

An application `main()` method is provided in the ScanDirAgent class. The `main()` simply registers a `ScanManagerMXBean` in the platform MBeanServer, and then waits for someone to call `close()` on the `ScanManagerMXBean`.

When the `ScanManagerMXBean` is registered, it will create a default `ScanDirConfigMXBean` bound to a default XML config file.

The application's default XML config file is determined as follows:

1. If the property `scandir.config.file` is defined, the default application file will be the file pointed to by this property. If that file doesn't exist, it will be created when `ScanDirConfigMXBean.save()` is invoked.
2. Otherwise the application config file is assumed to be a file called `jmx-scandir.xml`, located in the user's directory (as defined by the System property `user.home`). If that file doesn't exists, it will be created when `ScanDirConfigMXBean.save()` is invoked.

It is worth noting that this project is defined to run with the following properties:

    -Djava.util.logging.config.file=logging.properties

    -Dscandir.config.file=src/etc/testconfig.xml

With `ScanDirAgent` defined as the project's main class. Hence when you invoke from the NetBeans IDE Run Project on the jmx-scandir project, or Run file on the `ScanDirAgent`, the application starts with the test configuration provided in src/etc/testconfig.xml

## API Documentation and Sources

Once generated, the Javadoc of example classes can be found starting from `dist/javadoc/index.html`.

You can view the sources in the `src` subdirectory.

## Patterns, Best Practices, and Common Pitfalls

This section discusses some common patterns and design choices that this example demonstrates, and some pitfalls that it avoids.

### MBeans or MXBeans?

What is an MXBean? MXBeans made their appearance in J2SE 5.0 (Tiger), with the Management and Monitoring API of the JVM. However, Java SE 6 is the first Java SE release that contains a standard framework which makes it possible to create and register your own MXBeans.

MXBeans are a special kind of MBean, which once registered in the MBeanServer, get automatically transformed into OpenMBeans. From a developer point of view, nothing changes: A Wombat MBean can become an MXBean simply by renaming its `WombatMBean` interface into `WombatMXBean`.

Using MXBeans rather than plain Standard MBean brings its own advantages:

- Generic tools, like JConsole, will be able to display and interact with your MXBeans nicely, even if your MXBean interfaces reference custom types - e.g. custom Java enums. This is because all the types exposed by your MXBeans are converted to Open Types. Just look at the ScanDirConfigMXBean with JConsole and you will understand the benefits.
- When writing a programmatic client, you can obtain a proxy that implements the original MXBean interface, and forget about the Open Type conversion. The JUnit unit tests that come with this example use this feature very widely. Have a look at them.
- The MXBean framework also lets you nicely navigate from one MXBean to another: your MXBeans can have attributes and parameters which are proxies to other MXBeans! We demonstrate this in the ScanManagerMXBean which exposes a list of `DirectoryScannerMXBean` and points towards a `ScanDirConfigMXBean`.

In short, MXBeans are so much easier to use that this example doesn't even have a single regular Standard MBean.

See also What is an MXBean? and Inter-MXBean References.

> Hint: In order to simplify the task of coding a JMX programmatic client, we recommend that getters, setters, and operations defined in MBean and MXBean interfaces throw `IOException`. Proxy objects will then be able to rethrow directly any `IOException` received from their underlying MBean Server connection, without wrapping them into `UndeclaredThrowableExceptions`.
> Since the life cycle of the proxy object is not directly tied to the life cycle of the MBean it proxies, you may also want to have all methods in the MBean or MXBean interface throw `InstanceNotFoundException` or more generally `JMException`.

### MBean Names - aka ObjectNames

As you must know if you've been studying JMX, MBeans are named objects. The names of MBeans are represented by instances of `ObjectName`. An ObjectName is composed of a domain, followed by a colon ':', followed by a comma-separated list of key=value pairs.
The ordering of the key=value pairs is not important, but `ObjectNames` are case sensitive (both keys and values are case sensitive) and white space is not ignored.
A common pitfall for JMX beginners is to inadvertently insert white space after commas into an ObjectName, and expect that two ObjectNames which differ only by such white space will be considered identical. This is not the case.
As an example, the ObjectName '`D:k1=v1, k2=v2, k3=v3`' has three keys, which are '`k1`', '`k2`', and '`k3`': beware of the space in the name of the second and third keys!
It is therefore a different ObjectName from '`D:k1=v1,k2=v2,k3=v3`' (the keys are now '`k1`', '`k2`', and '`k3`'), but the same ObjectName as '`D: k2=v2, k3=v3,k1=v1`', and yet different from '`D:k2=v2, k3=v3, k1=v1`'!

In this example, we are following the rules for ObjectName suggested in the JMX Best Practices:

- ObjectNames should be predictable
- The domain part of our ObjectNames starts with a Java package name
- Our ObjectNames contain a `type=` key property. This property is different for every object type in our domain.
- For every ObjectName with a given type, we have the same set of key properties with the same syntax and semantics for their values - in fact we only use an additional `name=` key.
- When there can only be one instance of a given type there aren't any other key properties than `type=`. The ObjectNames of the ScanManagerMXBean and ResultLogManagerMXBean, which are both singleton MBeans, are composed in this way.
- When there can be several instances of a given type, we differentiate them by further key properties. To achieve this, we are using the most usual key property in addition to `type=`: the `name=` key. In this example, a key property list of the form `type=X,name=Y` is always enough to uniquely name an MBean. Tools like jconsole are usually aware of the semantics of the `type=` key and `name=` key, and are therefore able to display this form of name in a way that is easier to read than other name forms.

The rules listed above are implemented by a couple of static helper functions in the ScanManager class. See the code of the `makeSingletonName` and `makeMBeanName` methods.

### Inter MBean Navigation

One of the most common problems that needs to be solved when designing a management interface with JMX is to choose a representation for inter-MBean relationships.
Prior to Java 6, there were basically three possible choices:

- Make the relation appear in the ObjectName. For instance, if MBean B was contained in MBean A, you could choose to name MBean B so that its parent relationship with MBean A appeared in its name.
  The obvious limitation of this solution is that it only allows to model one such relation (an MBean has only one name) and the relation must be fixed - it cannot change during the life of the MBean since the name of an MBean cannot change.
  This scheme is therefore mostly used when the application MBeans are modeling objects which are conceptually contained within each other in a tree-like structure.
  For instance, most MBean names defined by J2EE Management (JSR 77) follow this scheme.
- Design getters and setters (or operations) which return `ObjectName` or `ObjectName[]` values. The ObjectNames point to the MBeans which are related to that object. For instance , GlassFish defines MBeans which also use this pattern.
- Use the JMX RelationService. The JMX RelationService is quite powerful, but simple relationships often do not justify that overhead.

In Java 6, these three possibilities still remain, but the new MXBean framework brings up an interesting alternative. Instead of returning an ObjectName or an ObjectName array, an MXBean can return a proxy to its related MXBeans. This is how we have chosen to implement our inter MBean relationships in this example:
For instance the `ScanManagerMXBean`/`DirectoryScannerMXBean` relationship and the `ScanManagerMXBean`/`ScanDirConfigMXBean` relationships are implemented in this way.

The additional benefit, as compared to returning ObjectNames or using the RelationService is that interface type of the MBeans which are pointed to by the relationship becomes directly apparent. The method:

                public Map<String,DirectoryScannerMXBean> getDirectoryScanners();

makes it immediately obvious that the MBeans to which we point are DirectoryScannerMXBeans. It would have been much less obvious in prior versions of Java SE, were the returned type would have had to be `Map<String,ObjectName>`, or even worse just `Map`.

However, it must be clear that the behaviour will be quite different when an MXBean is returned as compared to when a simple bean is returned.

When an MXBean is returned, the remote client sees either an ObjectName, if it is a generic client like jconsole, or a proxy to a remote MXBean, if the client is working with the MXBean interface. Invoking an operation on one of the proxy returned by a method such as `getDirectoryScanners` will cause the MBean to be invoked on the remote server side.

If `getDirectoryScanners` were defined as:

                public Map<String,DirectoryScannerConfig> getDirectoryScanners();

then invoking a method on one of the returned objects would have absolutely no effect on the remote server side - because the returned objects in this case would simply be a bunch of serialized data objects.

It is worth noting that although an MXBean interface can have getters and operations which return an MXBean interface, a regular standard MBean shouldn't have any getters or methods which return MBean interfaces or MXBean interfaces.

For more information see also Inter-MXBean References.

### The MBeanRegistration interface, or how an MBean can know or provide its own name

Sometimes, an MBean needs to have a reference to the MBeanServer in which it is registered, or needs to know with which ObjectName it has been registered.

Sometimes also, an MBean may need to perform some checks before being registered, or will need to carry out some actions right after it has been successfully registered in the MBeanServer.

Sometimes again, an MBean may need to perform some checks, or some cleaning actions, just before, or just after, it is unregistered.

When an MBean has such needs, the easiest solution for it is to implement the `MBeanRegistration` interface.

The `MBeanRegistration` interface is a callback interface which defines pre and post registration and unregistration callbacks.

When an MBean implementing this interface is created (with `createMBean`) or registered (with `registerMBean`) in an MBeanServer, the MBeanServer will call the `preRegister` and `postRegister` method implemented by the MBean. The `preRegister` method has an `MBeanServer` and `ObjectName` parameter, which are passed by the MBeanServer to the MBean. The MBean can store the reference it is being passed in a private instance variable for later use.

Most of the MXBeans we have defined in this example implement the `MBeanRegistration` interface. The table below show how our MBeans use this interface to control their own names, make sanity checks, perform initialization steps or cleanup actions.

MBean Requirement | callback | use case example
--- | --- | ---
get a reference to the MBeanServer | `preRegister` | The ScanManagerMXBean needs a reference to the MBeanServer in order to create and register other MBeans, such as the ResultLogManagerMXBean, and the DirectoryScannerMXBeans.
reject registration if conditions are not met. | `preRegister` | The ScanManagerMXBean will throw an IllegalArgumentException in `preRegister` if the ObjectName it is being passed is illegal. Throwing an exception in `preRegister` makes the registration fail.
get my client-assigned MBean name | `preRegister` | The ScanDirConfigMXBean propagates the value of the `name=` property of the ObjectName it is given into its ScanManagerConfig bean.
provide my own default ObjectName if none was given to the MBeanServer | `preRegister` | The name that is returned by `preRegister` is the ObjectName with which the MBean will be eventually registered. The ScanDirConfigMXBean is able to suggest a value for its own ObjectName if none was provided. Similarly, the ScanManagerMXBean always returns its singleton ObjectName defined by ScanManagerMXBean.SCAN_MANAGER_NAME.
perform initialization steps | `preRegister` | The ScanDirConfigMXBean uses `preRegister` to initialize its internal ScanManagerConfig bean.
perform initialization steps, once it is known that the registration was successful. | `postRegister` | The `postRegister` method can be used to implement initialization steps that need to be done once it is known that the registration was successful, or to undo any action performed by `preRegister` once it is known that registration was not successful. The `postRegister` method has a Boolean parameter which tells the MBean whether it was or wasn't successfully registered in the MBeanServer. The ScanManagerMXBean uses `postRegister` to create and register other MBeans, such as the ResultLogManagerMXBean and the default ScanDirConfigMXBean. Note that `postRegister` is not expected to throw any exception. If an exception needs to be thrown, it should be thrown in `preRegister`.
check whether the MBean can be deregistered | `preDeregister` | The ScanManagerMXBean uses this method to verify that its state allows it to be deregistered. In particular, it will refuse to be deregistered if it is in the RUNNING or SCHEDULED state. If `preDeregister` throws an exception, the unregisterMBean call will fail and the MBean will remain registered in the MBeanServer. Take particular care when implementing business logic in this method: if the logic you implement has an unfortunate bug which makes it always throw an exception, you will never be able to unregister that MBean.
clean up resources, refusing to be deregistered if it fails | `preDeregister` | The ScanManagerMXBean uses this method to unregister all the other MBeans it has created and registered in the MBeanServer. This includes the ResultLogManagerMXBean, the ScanDirConfigMXBeans it has created, and the DirectoryScannerMXBeans it has created when applying its configuration.
clean up resources which need to be released in a best-effort way, when it is known that the MBean is no longer registered. | `postDeregister` | `postDeregister` is only called if the MBean was succesfully unregistered. The ScanManagerMXBean uses this method to cancel its internal java.util.Timer.

### The Singleton MBean Pattern

A singleton MBean is an MBean which can only have one instance registered in a given MBeanServer.
A singleton MBean usually has a well-known name, which can be defined as a constant. In that case, clients no longer need to call `new ObjectName(...)` and catch the declared `MalformedObjectNameException`.

There are already quite a few examples of singleton MBeans in the java.lang.management API. The ThreadingMXBean, ClassLoadingMXBean, RuntimeMXBean, etc. are all singleton MBeans.

In this example, we have two singleton MBeans: The `ScanManagerMXBean` and the `ResultLogManagerMXBean`. But in fact, the only real singleton MBean is the `ScanManagerMXBean`. The `ResultLogManagerMXBean` just happens to be a singleton MBean because it has a 1-1 relationship with the `ScanManagerMXBean`.

The `ScanManagerMXBean` implements the singleton MBean pattern in this way:

- The `ScanManagerMXBean` name has a single key property: `type=ScanManagerMXBean`.
- Its name is defined by an ObjectName constant called `SCAN_MANAGER_NAME` in the `ScanManager` class
- The `ScanManagerMXBean` enforces its status of singleton MBean. It will refuse to be registered with a name other than the `SCAN_MANAGER_NAME`. You can therefore depend on the fact that the `ScanManagerMXBean` will always be registered with its singleton `SCAN_MANAGER_NAME` (see `preRegister`)
- You are not obliged to provide a name when you register the `ScanManagerMXBean`: if you pass null, then the `ScanManager` will be registered with its singleton `SCAN_MANAGER_NAME` (see `preRegister`).
- The `ScanManager` class has a no-arg static `register` method that will register the singleton instance in the Platform MBeanServer. This static `register` method returns a proxy to the registered singleton.
- The `ScanManager` class has also a static `register` method that will create a singleton instance in a (possibly remote) MBeanServerConnection - using `createMBean`. This static `register` method also returns a proxy to the registered singleton.
- Only the MBeanServer has a reference to the singleton instance. The singleton instance is not returned to the caller, and not kept in any other static data structure.

On the other hand, the `ResultLogManagerMXBean` has a much more relaxed implementation of the pattern:
It simply provides its own singleton name if it is registered with a null ObjectName, but will not enforce the use of that name.

Note that all singleton MBean names in this example are created using the `ScanManager.makeSingletonName` method, which implements the pattern for ObjectNames suggested in the JMX Best Practices.

### Managing the Life Cycle of dependent MBeans

A common task that many JMX applications have is to manage the life cycle of MBeans registered in the MBeanServer.

In this example, we have decided to follow a simple pattern:

- The application is initialized simply by registering the singleton ScanManagerMXBean in the MBeanServer.
- The `ScanManagerMXBean` will then in turn register any other MBean that the application might need:
  - It creates and registers the singleton `ResultLogManagerMXBean`
  - It creates and registers the default `ScanDirConfigMXBean` which loads the initial configuration
  - It creates as many `DirectoryScannerMXBeans` as needed when the configuration is applied
  - It lets you create alternate `ScanDirConfigMXBean`, to which you can later switch in order to apply a new alternate configuration.
- When a new configuration is applied (or if the current configuration is reapplied), the `ScanManagerMXBean` will unregister any `DirectoryScannerMXBeans` it has previously registered, and will re-create brand new `DirectoryScannerMXBeans` from the applied configuration.
- When you unregister the `ScanManagerMXBean`, it does all the cleanup for you, by unregistering all the MBeans that it has created during the course of the application.

The `ScanManagerMXBean` makes use of its `MBeanRegistration` interface in order to register the other MBeans it needs (see the `ScanManager.postRegister` method) and to unregister every MBean it has created (see the `ScanManager.preDeregister` method).

You will note that the `ScanManagerMXBean` will only allow itself to be deregistered if it can be closed - that is if there's no other action in progress. This is to make sure that the deregistration of dependent MBeans will work smoothly.
The deregistration of related MBeans will happen in the `ScanManager.preDeregister` method.
If one of these MBeans could not be deregistered, then the `ScanManagerMXBean` will throw an exception, refusing to be deregistered.
This leaves you a chance to try to deregister it again later. Since the `ScanManagerMXBean` has switched its state to CLOSED before starting to unregister its dependent MBeans, it will refuse any further actions, ensuring that e.g. nobody can try to start it or schedule it while it is in that partially-deregistered state.

Handling the LifeCycle of all the application's MBeans in a single MBean is usually a good design pattern, especially if the application is a module which is intended to share a JVM - or an MBeanServer - with other modules.

This is specially useful if the application needs to be loaded and unloaded on demand: in that case, simply registering or unregistering the top level MBean (in our example the `ScanManagerMXBean`) does the trick.

### Emitting Notifications

In order to emit notifications, an MBean must be an instance of `NotificationEmitter`. The `NotificationEmitter` interface defines methods that the MBeanServer will call on the MBean in order to register `NotificationListeners` with the MBean.

It is worth noting that the MBean may not be invoked each time a JMX client wants to register a listener. For instance, the RMIConnectorServer registers only once a single listener with each MBean which is a `NotificationEmitter`. In that specific case, the listener may even be registered with the MBean before any client has actually subscribed for notifications from that particular MBean.

An MBean can therefore make no assumption about which client or how many clients have registered for notifications.

It is also worth noting that the logic of the methods defined in `NotificationEmitter` would not be trivial to implement from scratch. Fortunately the JMX API defines a helper class, called `NotificationBroadcasterSupport`, which provides an implementation for these methods.

There are actually three ways for an MBean to implement `NotificationEmitter`, of which only two are recommended.

#### Extending NotificationBroadcasterSupport

This is the simplest way of coding an MBean which is a `NotificationEmitter`:

Simply extend `NotificationBroadcasterSupport`, then override its `getNotificationInfo` method which returns the `MBeanNotificationInfo[]` array that should be included in your MBean's `MBeanInfo` and that's it.
You just need to call the `sendNotification` method inherited from `NotificationBroadcasterSupport` whenever your MBean needs to send a notification.

In our example, both the ScanDirConfigMXBean and ResultLogManagerMXBean extend `NotificationBroadcasterSupport` in order to send notifications.

#### The Delegation Pattern: delegating to a NotificationBroadcasterSupport delegate

There may be cases however where delegating to a wrapped `NotificationBroadcasterSupport` object may be preferred to extending `NotificationBroadcasterSupport`.

For instance, if your MBeans already derive from some base class, extending `NotificationBroadcasterSupport` might not be an option.

Similarly, if you do not want to have the inherited `public void sendNotification(Notification notification)` method appear in the Javadoc of the concrete class of your MBean, you may want to consider using the delegation pattern instead of extending `NotificationBroadcasterSupport`

In our example both the ScanManagerMXBean and the DirectoryScannerMXBean use the delegation pattern rather than extending `NotificationBroadcasterSupport`. In the end, choosing between one or the other method is more a question of taste, although the delegation pattern could be considered more flexible since it doesn't require extending any given superclass.

It may be also worth noting that some tools like the JMX Module of NetBeans IDE, will be able to generate for you all the code that delegates to a wrapped `NotificationBroadcasterSupport`.

#### Implementing NotificationEmitter from scratch

This is the last possibility for an MBean that needs to send notifications: simply implement `NotificationEmitter` from scratch. This is highly discouraged since that logic is not trivial, and already provided by `NotificationBroadcasterSupport` anyway.

#### Beware of Synchronization Locks

One thing you must keep in mind when sending notifications is not to send them from within a synchronized block, or while holding a lock on some resource.

Indeed, what happens when you send a notification may vary greatly depending on whether the client which has registered for notifications has done so through a `JMXConnector` (like the `JMXRMIConnector`) or through a direct reference to the MBeanServer (by calling `MBeanServer.addNotificationListener`).

In this latter case, the listener will be invoked synchronously in the same thread that your MBean is using to send its notification. If by misfortune, the code of that listener now re-enters your MBean through a call that flows through a JMXConnector, a deadlock could occur. It is therefore very important to release any lock you may have before calling `sendNotification`.

An easy way to do that is demonstrated in the `ScanManager` class. The ScanManager has an internal private queue of pending notifications. When a notification needs to be sent (e.g. because the ScanManager state is being switched), the notification is simply prepared and put into the pending notification queue. The notification queue is then processed later on, at the end of the method, when the processing is finally completed and all the locks have been released.
At this point the notification queue might already have been emptied by another thread - in which case the pending notifications will have already been removed from the queue. Which thread actually gets to send the notifications is of no importance. The important point is that all the locks detained by your MBean code in that thread were released before the notification was sent.

In our example the `ScanManager` class ensures this by:

- Only calling `sendNotification` in its private `sendQueuedNotifications` method.
- Only calling `sendQueuedNotifications` when all locks have been released.
- Never calling a method that calls `sendQueuedNotifications` from within a synchronized block.

#### Don't subclass Notification

Another common best practice when you want to improve interoperability is to use directly the Notification base classes provided in the JMXTM API. Do not create your own subclasses of these standard classes.

Indeed, if you code your own subclass, a generic client, like jconsole, will not be able to receive that notification unless it has that custom subclass in its classpath.

If you want your application to be interoperable, it is therefore preferable not to subclass any of the standard Notification classes. You can define your own Notification type string, and if you need to send additional data, you can put a CompositeData, or a HashMap of serializable standard types in the Notification's user data fields.

In this example, we are using directly the standard notification classes:

- The ScanManagerMXBean and the DirectoryScannerMXBean both use directly `AttributeChangeNotification` to notify changes in their `State` attribute.
- The DirectoryScannerMXBean also uses the base `Notification` class directly in order to notify whenever it finds a matching file.
  In that case, we simply use the base `Notification` class with a new `com.sun.jmx.examples.scandir.filematch` type.
- The ScanDirConfigMXBean and ResultLogManagerMXBean also both use the base `Notification` class.

Careful readers will have noted that the ScanManagerMXBean and the DirectoryScannerMXBean both use the `AttributeChangeNotification` class to notify about their state change, whereas the ScanDirConfigMXBean uses the base `Notification` class.

In fact, this is because the semantics of these notifications is not exactly the same - although both denote a state change:

In the case of `ScanManagerMXBean` and `DirectoryScannerMXBean`, the notification which is emitted is more about a state transition, from one state to another. For instance, going from `RUNNING` to `STOPPED`, or from `SCHEDULED` to `STOPPED`.
In that case, the `AttributeChangeNotification` was more appropriate because it made it possible to send the previous and the new value of the state attribute, thus reflecting the whole state transition.

In the case of the `ScanDirConfigMXBean` however, what is of interest is the state in which the MBean has arrived. Using the base `Notification` class with three different notification type strings - `com.sun.jmx.examples.scandir.config.loaded`, `com.sun.jmx.examples.scandir.config.modified`, and `com.sun.jmx.examples.scandir.config.saved` - was therefore closer to what we wanted to model.

### Configuration MBeans

A common practice when designing a management application is to have an MBean, or a set of MBeans, dedicated to configuration. Separating configuration from control and monitoring allows more appropriate logic, and often simplifies the design and implementation of the management interface.

In our example, the ScanDirConfigMXBean is dedicated to the application configuration.

The `ScanDirConfigMXBean` will let you interactively modify, save, or load the application configuration. The modifications will not be taken into account until it is applied, by invoking `applyConfiguration` on the ScanManagerMXBean. It is also possible to create many configurations, by creating as many `ScanDirConfigMXBean`s, and then to choose and apply one of these configurations by calling `ScanManagerMXBean.setConfigurationMBean` and then `ScanManagerMXBean.applyConfiguration`.

In this way, all configurations aspects are gathered and concentrated inside the `ScanDirConfigMXBean` instead of being scattered throughout all the MBeans that compose the application.

In order to save and store the application configuration data, the `ScanDirConfigMXBean` uses a set of XML serializable Java beans defined in the com.sun.jmx.examples.scandir.config package. These beans are very simple Java beans which have been lightly annotated for XML binding.

It is worth noting that these same beans can also be handled by the MXBean framework (our beans don't contain recursive data structures) and can therefore be used directly as attributes and parameters of MXBeans, without needing to be Java-serializable (the MXBean framework transform them in CompositeData objects - which are serializable).

The same ScanManagerConfig bean that we use to read from and write to the XML configuration file is thus also used as attribute of the ScanDirConfigMXBean. It is transformed into a `CompositeData` by the MXBean framework, and can be easily introspected with jconsole.

### MBeans Must Be Thread-Safe

A question often asked by newcomers to JMX technology is whether the MBeanServer is thread-safe. Well, the MBeanServer is thread safe, but it doesn't put any locks on the MBeans it contains. The MBeans can be concurrently accessed by multiple threads, and must therefore take care of their own thread safety.

In this example, we have been using two methods to ensure thread safety for our MBeans: synchronized blocks, and semaphores.

Using synchronized blocks is probably the most common and easiest way to implement thread safety in Java. When dealing with MBeans though, here are a couple of rules to keep in mind:

- Don't send notifications from within a synchronized block: there's no way to tell whether the listener's code will be executed in the same thread or a different thread, and holding a lock in these conditions is therefore dangerous, as it could lead to deadlocks.
- Also avoid invoking another MBean from a synchronized block unless you are completely in control of both MBeans, and you can ascertain that it won't lead to any deadlock. Indeed, if you invoke an MBean exposed by another application, it can be sometime hard to know with certainty whether holding a lock while invoking that MBean will have any side effect. Maybe that MBean will make further calls to other MBeans which will in turn try to call your MBean, or maybe it will emit a notification, and we'll be back to the considerations just above.

Another means of implementing thread-safe code is to use semaphores. The ScanManagerMXBean uses a semaphore called `sequencer` to ensure that critical code sections are not executed concurrently. In this MBean, we use `Semaphore.tryAcquire` to lock the sequencer semaphore before entering the critical section. If the `Semaphore.tryAcquire` returns true then we enter the critical section. If it returns false, we throw an IllegalStateException, stating that we couldn't acquire the lock. The code looks like this:

            if (!sequencer.tryAcquire())
                throw new IllegalStateException("resource locked");
            try {
                // critical code here ...
            } finally {
                // Always use try/finally to ensure that the semaphore
                // will be released, even if exceptions or errors are raised!
                sequencer.release();
            }

Using `Semaphore.tryAcquire` and throwing an exception if the semaphore is already locked makes it safer to call other MBeans from within the critical section: in potential deadlock situations the calling code will get the `IllegalStateException` instead of being blocked on the deadlocked lock.

It is worth noting that each of these techniques has its own advantages and disadvantages - which can make one of them more or less appropriate depending on the inner logic of the MBean you're implementing.

Careful readers will also have noted that we used `IllegalStateException` directly, instead of defining our own subclass of RuntimeException, which could have had a more precise semantics. If you define a new exception for your JMX application, you must keep in mind that your client will need to have the class of your exception in its classpath to get that exception. Otherwise your client will get a completely different exception, indicating a deserialization issue.

### Waiting for Notifications

Implementing code that needs to wait for notifications is sometimes difficult. Because notifications are asynchronous, doing something like:

              // register a notification listener
              ...
              // start a management action
              ...
              // wait for a notification
              ...
              // do something based on whether the expected notification
              // is received
              ...

is not always trivial. However, there's a very easy way to do that: use a blocking queue of notifications.

           final BlockingQueue<Notification> notifQueue =
                    new LinkedBlockingQueue<Notification>();

           final NotificationListener listener = new NotificationListener() {
                public void handleNotification(Notification notification,
                                               Object handback) {
                    try {
                        // Just put the received notification in the queue.
                        // It will be consumed later on.
                        //
                        notifQueue.put(notification);
                    } catch (InterruptedException ex) {
                        // OK
                    }
                }
              };

           // register the listener - possibly also as a JMXConnectionNotification
           // listener to get Notification Lost notification
           ...
           // start management action
           ...
           // wait for notification
           while (expected notif not received and delay not expired) {
                Notification n = notifQueue.poll(3,TimeUnit.SECONDS);
                // if expected notif, do something
                ...
           }
           // if expected notification not received do something else.
           ....

You will note that this is a technique we've been using in the ScanDirAgent class and in the example unit tests.

### Holding hard references to other MBeans: proxy or direct reference?

We have seen that MXBeans will let you return proxy references to other MXBeans. But should that MXBean hold a direct reference to the MXBeans it relates to, or would it be better for it to hold only a proxy?

As a general rule it is better when an MBean reference is only held by the MBeanServer. It is a better design to hold a reference to a proxy, rather than to hold a hard reference to an MBean. However there are two cases when holding a hard reference might be preferred:

1. When MBean A needs to call a method of method B which is not part of its MBean interface
2. When the overhead of going through the MBeanServer plus the MXBean framework is too great (frequently-called method, with creation of OpenType)

However - holding a hard reference is only advisable when both MBeans are created by the same piece of code, and the application can ensure that the life cycle of each MBean is consistent with regard to the other.

In our example, the ScanManagerMXBean holds only proxy references to the ScanDirConfigMXBean and the DirectoryScannerMXBeans.
However it holds a direct reference to the ResultLogManager. This makes it possible to pass a direct reference to the `DirectoryScannerMXBeans`, which can then log their results more efficiently, and would also make it possible to remove the `log` method from the ResultLogManagerMXBean interface - leaving it in the `ResultLogManager` class (possibly as a package method) should we wish to do so.

### Agent Class

The ScanDirAgent is the Agent class for the scandir application. This class contains the `main` method to start a standalone scandir application.

The `main` method simply registers a ScanManagerMXBean in the platform MBeanServer, and then waits for someone to call `ScanManagerMXBean.close`.

When the `ScanManagerMXBean` state is switched to `ScanManagerMXBean.ScanState.CLOSED`, the `ScanManagerMXBean` is unregistered, and the application terminates (i.e. the main thread completes).

Standalone JMX applications usually have an Agent class that contain their `main` method, which performs all the MBean registration steps. However, it is usually not a bad idea if that class can be easily turned into an MBean. Indeed, this will make your application easier to integrate in an environment where it would no longer be standalone and would no longer control the implementation of `main`. In our example the Agent class could be easily turned into an MBean, exposing its three `init`, `waitForClose` and `cleanup` method. However we didn't go as far as turning it into an MBean since the application can be already easily started by registering an instance of ScanManagerMXBean.

### Secure Client Class

The ScanDirClient is an example class that shows how a programmatic client can connect to a secured scandir application. This class contains a `main` method which creates and configures a `JMXConnector` client to connect with a secured scandir daemon. This class will not work with the default unsecured agent since it requires mutual authentication.

How to secure a JMX scandir application and run the secure `ScanDirClient` is discussed later in this document.

The `ScanDirClient` is not really part of the application - and is given here only for the sake of the example.

## Testing the scandir Example

Make sure that you have access to junit.jar (either 3.8.1 or 3.8.2). Make sure also that you have junit.jar in your `CLASSPATH`.
Then in the example root directory (where the `build.xml` file is located) run the following command:

    ant test -Dlibs.junit.classpath=path to junit jar (either 3.8.1 or 3.8.2)

Alternatively you can open the jmx-scandir project with the NetBeans IDE and test the jmx-scandir project from the `Run` menu.

## Running the scandir Example

In the example root directory (where the `build.xml` file is located) run the following commands:

    ant jar
    ant run-single -Drun.class=com.sun.jmx.examples.scandir.ScanDirAgent -Djavac.includes=src

or simply

    ant run

This will run the example using the configuration file provided in the src/etc directory.

Alternatively you can open the jmx-scandir project with the NetBeans IDE. You can run the example by selecting the `ScanDirAgent` file and run it with `Run File` in the `Run` menu or simply set the jmx-scandir project as main project and select `Run Main Project` from the main menu. Both targets will use the configuration file provided in the src/etc directory.

When the application is started, you can connect to it with jconsole.

> Note: You can also run the scandir application directly from the `java` command line. Make sure to build the project jar first.
> On Unix systems:

>     ant jar
>     java -Djava.util.logging.config.file=logging.properties \
>          -Dscandir.config.file=src/etc/testconfig.xml \
>          -jar dist/jmx-scandir.jar

> On Windows systems:

> `ant jar
> java -Djava.util.logging.config.file=logging.properties -Dscandir.config.file=src\etc\testconfig.xml -jar dist\jmx-scandir.jar`

## Playing with JConsole

Run the example as explained in the previous section, so that it uses the provided `src/etc/testconfig.xml` configuration file. Then start jconsole. In the connection window choose the process that runs `com.sun.jmx.examples.scandir.ScanDirAgent` or `jmx-scandir.jar`.

Open the MBeans tab, and look for the `ScanDirConfigMXBean`. Click on its `Attributes` node and double click on its `Configuration` attribute, to look at the loaded configuration - values in bold can be expanded by a double-click.

Now go to the `ScanManagerMXBean`, click on its `Notifications` node, and subscribe for notifications. Then click on the `Operations` node and invoke the `start()` operation:

You can see that the notifications counter was incremented by three: you have just scheduled, run, and completed a batch of directory scans.

Now go to the `ResultLogManagerMXBean`, click on its `Attributes` node, and expand its `MemoryLog` attribute:

You can see that the directory scan results have been logged.

To make the application terminate go back to the `ScanManagerMXBean` and invoke `close()`. The `ScanDirAgent` will receive the notification, step out of the application main thread, and the application will terminate.

This is of course a very limited scenario. Feel free to improvise with all the features of the example, creating a new configuration - `ScanManagerMXBean.createOtherConfigurationMBean` - adding multiple directory scanners to that configuration - `ScanDirConfigMXBean.addDirectoryScanner` - then switching the `ScanManagerMXBean` current configuration by changing the value of the ConfigurationMBean attribute - `ScanManagerMXBean.setConfigurationMBean` - then applying the new configuration - `ScanManagerMXBean.applyConfiguration(true)` - then scheduling repeated directory scans every 10 seconds - `ScanManagerMXBean.schedule(0,10000)` - subscribing for notifications, etc...

## Turning the example into a Secure JMX Application

In this section, we will see how to configure and start the scandir example so that the JVM agent is bootstrapped with a secure JMXConnectorServer. Indeed, until now we have only used the insecure local connection, which can only be used as long as both the client and the server run on the same machine. This section will explain how to start the `ScanDirAgent` so that a real secure RMIConnectorServer is started at bootstrap.

To achieve this we will: provide our own management.properties, create our own password and access files, provide a keystore and truststore, start the ScanDirAgent with the appropriate system properties.

### Configuring the JVM Agent for Secure Remote Connection

The easiest way to configure the JVM Agent for Secure Remote Connection is to use your own management.properties file. In this example, we have copied the default `$JRE/lib/management/management.properties` file to the example's `src/etc` directory and modified it in this way:

- We have set the RMI port to 4545 - this is just a random port number we have picked up. Feel free to use your own value suited to your environment.

      # For setting the JMX RMI agent port use the following line
      com.sun.management.jmxremote.port=4545

- We have switched on SSL mutual authentication

      # For RMI monitoring with SSL client authentication use the following line
      com.sun.management.jmxremote.ssl.need.client.auth=true

- We have also secured the RMI Registry with SSL

      # For using an SSL/TLS protected RMI Registry use the following line
      com.sun.management.jmxremote.registry.ssl=true

- We have provided our own password file

      # For a non-default password file location use the following line
      com.sun.management.jmxremote.password.file=src/etc/password.properties

- We have provided our own access file

      # For a non-default password file location use the following line
      com.sun.management.jmxremote.access.file=src/etc/access.properties

You will note that we haven't provided any value for the other security properties, like `com.sun.management.jmxremote.authenticate=true`, because these properties already default to a value which enables security by default. Note however that protecting the RMI Registry with SSL improves the application security, but only as long as mutual authentication is also switched on. Otherwise, just anybody would be able to connect to the registry and get the RMIServer stub.

We do recommend that you use the most secure configuration when you deploy a JMX agent - which means switching on SSL protection for the RMI registry and requiring mutual authentication, as we show in this example.

We will use the `com.sun.management.config.file` system property to pass our management.properties file to the `ScanDirAgent`.

### Creating a password and access file

As explained above, we have created our own password file and access file for access control and authorization.

In the password file, we have defined two logins: guest and admin. The password for guest is guestpasswd and the password for admin is adminpasswd.

In the access file, we have mapped these two logins to access rights: the admin login has read-write access, while the guest login only has read-only.

Before starting the `ScanDirAgent`, you will need to restrict access permission to the password file, in such a way that nobody but you can read it. Otherwise, the JVM Agent will refuse to start the JMXConnectorServer, as it will fear that security can be compromised if other parties can have read access to the password file. How to restrict read access to the password file is explained in detail here.

As we have seen above, the location of our access and password files is configured in our own management.properties file.

### Keystore and Truststore

Using SSL with mutual authentication means that both client and server will need a keystore and a truststore to store their own certificates, and the certificates of the parties they trust. Usually, client and server will have their own keystore and truststore.

For the sake of simplicity - and to get you started without the tedious necessity of creating your own keystore and truststore, we are providing a dummy keystore and truststore, containing a certificate self-signed by duke. The password for our keystore is password, and the password for our truststore is trustword. We suggest that you first get the example running with the keystore and truststore we are providing before attempting to use your own keystore and truststore.

A secure application will obviously need to use its own keystore and truststore, and should not rely on the keystore and truststore we are providing here!

How to create your own keystore and truststore, is explained in here. As shown later, we will need to use system properties to pass our truststore and keystore to the `ScanDirAgent`.

### Starting a Secure scandir agent

To start a secure scandir agent, go to the scandir example root directory and type the following command:

On Unix Systems:

    ant jar
    java \
        -Djava.util.logging.config.file=logging.properties \
        -Djavax.net.ssl.keyStore=keystore \
        -Djavax.net.ssl.keyStorePassword=password \
        -Djavax.net.ssl.trustStore=truststore \
        -Djavax.net.ssl.trustStorePassword=trustword \
        -Dcom.sun.management.config.file=src/etc/management.properties \
        -Dscandir.config.file=src/etc/testconfig.xml \
        -jar dist/jmx-scandir.jar

On Windows Systems:

`ant jar
java -Djava.util.logging.config.file=logging.properties -Djavax.net.ssl.keyStore=keystore -Djavax.net.ssl.keyStorePassword=password -Djavax.net.ssl.trustStore=truststore -Djavax.net.ssl.trustStorePassword=trustword -Dcom.sun.management.config.file=src\etc\management.properties -Dscandir.config.file=src\etc\testconfig.xml -jar dist\jmx-scandir.jar`

If you start jconsole now, you will see that you are still able to connect to the agent using the local connection. However, if you try to connect through the remote connector, using localhost:4545, the connection will fail, even if you provide a correct login/password pair. Indeed, since the JMXConnectorServer is now protected with SSL, jconsole must also be configured with the appropriate SSL parameters so that it can authenticate the server and get authenticated by the server too as the SSL configuration of the server requires mutual authentication.

The next section will discuss how to connect to the secure agent.

## Connecting to the Secure JMX Application

We will now see how to connect to the secure agent, using jconsole, and using a programmatic client.

### Using jconsole to connect to the secure agent

The only special thing you need to do in order to be able to connect to your secure agent with jconsole, is to give it a keystore (containing its client certificate) and a truststore (containing the certificates of the servers it can trust). In our example, we use the same keystore/truststore pair on the client and server side - but this is not what a real application would do. Indeed a real application would have different certificates for the client and the server, and thus use different keystores (and probably truststores). More information on SSL authentication can be obtained from the JavaTM Secure Socket Extension (JSSE) Reference Guide.

To start jconsole with our provided keystore and truststore, go to the scandir example root directory and type in the following command:

`jconsole -J-Djava.util.logging.config.file=logging.properties -J-Djavax.net.ssl.keyStore=keystore -J-Djavax.net.ssl.keyStorePassword=password -J-Djavax.net.ssl.trustStore=truststore -J-Djavax.net.ssl.trustStorePassword=trustword`

The `-J-Djava.util.logging.config.file=logging.properties` flag is not mandatory, but passing a `logging.properties` may help you debug connection problems if anything goes wrong.

In jconsole connection window, choose to connect to a remote process, using the address localhost:4545 and the guest login:

You will see that the agent will let view all the MBeans and their attributes, but will reject any attribute modification or remote method invocation.

Note: if jconsole fails to connect and show you this screen you have probably misspelled some of the properties on jconsole command line, or you didn't start jconsole from the scandir example root directory where our `truststore` and `keystore` files are located. This article - Troubleshooting connection problems in JConsole - may help you figure out what is going wrong.

### Writing a programmatic client to connect to the secure agent

In this section we will show the steps involved in writing a programmatic client that will connect to our secure agent.

The ScanDirClient is an example class that shows how a programmatic client can connect to a secured scandir application. This class contains a `main` method which creates and configures a `JMXConnector` client to connect with the secured scandir agent.

The secure client differs only from a non secure client in so far as it needs to use SSL RMI Factories and credentials to connect to the secure agent. The steps required mainly involve:

- Creating an empty environment map:

                  // Create an environment map to hold connection properties
                  // like credentials etc... We will later pass this map
                  // to the JMX Connector.
                  //
                  System.out.println("\nInitialize the environment map");
                  final Map<String,Object> env = new HashMap<String,Object>();

- Putting the client's credentials in that map: (here the client will log in as guest)

                  // Provide the credentials required by the server
                  // to successfully perform user authentication
                  //
                  final String[] credentials = new String[] { "guest" , "guestpasswd" };
                  env.put("jmx.remote.credentials", credentials);

- Providing an `SslRMIClientSocketFactory` to interact with the secure RMI Registry:

                  // Provide the SSL/TLS-based RMI Client Socket Factory required
                  // by the JNDI/RMI Registry Service Provider to communicate with
                  // the SSL/TLS-protected RMI Registry
                  //
                  env.put("com.sun.jndi.rmi.factory.socket",
                          new SslRMIClientSocketFactory());

- Creating a JMXConnector and connecting with the secure server:

                  // Create the RMI connector client and
                  // connect it to the secure RMI connector server.
                  // args[0] is the server's host - localhost
                  // args[1] is the secure server port - 4545
                  //
                  System.out.println("\nCreate the RMI connector client and " +
                          "connect it to the RMI connector server");
                  final JMXServiceURL url = new JMXServiceURL(
                          "service:jmx:rmi:///jndi/rmi://"+args[0]+":"+args[1]+
                          "/jmxrmi");
                  final JMXConnector jmxc = JMXConnectorFactory.connect(url, env);

For this to work, we also need to start the `ScanDirClient` with the appropriate system properties that will point to our `keystore` and `truststore`. To start the secure client, go to the scandir example root directory and type the following command:

`ant jar
java -Djava.util.logging.config.file=logging.properties -Djavax.net.ssl.keyStore=keystore -Djavax.net.ssl.keyStorePassword=password -Djavax.net.ssl.trustStore=truststore -Djavax.net.ssl.trustStorePassword=trustword -classpath dist/jmx-scandir.jar com.sun.jmx.examples.scandir.ScanDirClient localhost 4545`

You should be seeing this trace:

    Initialize the environment map

    Create the RMI connector client and connect it to the RMI connector server
    Connecting to: service:jmx:rmi:///jndi/rmi://localhost:4545/jmxrmi

    Get the MBeanServerConnection

    Get ScanDirConfigMXBean from ScanManagerMXBean

    Get 'Configuration' attribute on ScanDirConfigMXBean

    Configuration:

    <ScanManager xmlns="jmx:com.sun.jmx.examples.scandir.config" name="testconfig">
        <InitialResultLogConfig>
            <LogFileMaxRecords>2048</LogFileMaxRecords>
            <LogFileName>build/scandir.log</LogFileName>
            <MemoryMaxRecords>128</MemoryMaxRecords>
        </InitialResultLogConfig>
        <DirectoryScannerList>
            <DirectoryScanner name="scan-build">
                <Actions>NOTIFY LOGRESULT</Actions>
                <ExcludeFiles/>
                <IncludeFiles>
                    <FileFilter>
                        <FilePattern>.*\.class</FilePattern>
                        <SizeExceedsMaxBytes>4096</SizeExceedsMaxBytes>
                    </FileFilter>
                </IncludeFiles>
                <RootDirectory>build</RootDirectory>
            </DirectoryScanner>
        </DirectoryScannerList>
    </ScanManager>

    Invoke 'close' on ScanManagerMXBean

    Got expected security exception: java.lang.SecurityException: Access denied!
    Invalid access level for requested MBeanServer operation.

    Close the connection to the server

    Bye! Bye!

If the `ScanDirClient` fails to connect with the secure agent, then this article - Troubleshooting connection problems in JConsole - may help you figure out what is going wrong. Indeed the connection steps performed by the `ScanDirClient` are very similar to those performed by `jconsole`, and the problems you could encounter are identical. Just remember that `jconsole` needs the extra `-J` flag to pass system properties to the VM, which is not needed with regular `java` launcher invocations.

## Conclusion

In this document, we have presented an advanced JMX example, and shown how to run a secure JMX agent in a production environment. We have also shown how to connect to such a secure agent with both jconsole and a programmatic client. We have also discuss various JMX design-patterns and best practices. Readers who would wish to learn more about JMX, and Monitoring and Management of the JVM, are invited to follow the links given in reference below.

## References

1. JMX Best Practices: This document describes best practices that have been identified for modeling using the JMX API.
2. Monitoring and Management Using JMX: How to enable, configure, and connect to the JVM JMX agent.
3. Using JConsole: JConsole is a JMX-Compliant monitoring tool which allows you to interact graphically with your own MBeans.
4. Monitoring and Management for the Java Platform: The Java Platform Standard Edition (Java SE) 6 provides comprehensive monitoring and management support for the Java platform.
5. List of JMX-related Blogs: This page provides links to the different web logs written by members of the Sun team working on the JMX API.
6. JavaTM Secure Socket Extension (JSSE) Reference Guide: comprehensive documentation about the JavaTM Secure Socket Extension (JSSE)
7. Java SE 6 Documentation Index: This document covers the JavaTM Platform, Standard Edition 6 JDK.