diff options
Diffstat (limited to 'staging/darwin-x86/sample/jmx/jmx-scandir/index.html')
-rw-r--r-- | staging/darwin-x86/sample/jmx/jmx-scandir/index.html | 2217 |
1 files changed, 2217 insertions, 0 deletions
diff --git a/staging/darwin-x86/sample/jmx/jmx-scandir/index.html b/staging/darwin-x86/sample/jmx/jmx-scandir/index.html new file mode 100644 index 0000000..4fd2ae6 --- /dev/null +++ b/staging/darwin-x86/sample/jmx/jmx-scandir/index.html @@ -0,0 +1,2217 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<html> + <head> +<!-- + Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of Oracle nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + + <title>JMX(TM) "scandir" Example</title> + </head> + <body> + + <h1><center>Java<font size="-1"><sup>TM</sup></font> Management Extensions (JMX<font size="-1"><sup>TM</sup></font>) <i>scandir</i> Example</center></h1> + + <h2><a name="h2-Introduction">Introduction</a></h2> + <ul> + <p>The JMX <i>scandir</i> 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. + </p> + <p>The JMX <i>scandir</i> 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.</p> + <p>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 <a + href="http://java.sun.com/javase/6/docs/technotes/guides/jmx/" + >JMX API Overview, Tutorial and Examples</a> before going any further. + </p> + <p></p> + <hr> + <blockquote> + <u>Note:</u> This example was developed using <a + href="http://www.netbeans.org">NetBeans 5.0 IDE</a>. The instructions + given in this document to build, run, and test the example assume that + you have at your disposal: + <ul><li>either <a href="http://www.netbeans.org">NetBeans 5.0 IDE</a>,</li> + <li>or <a href="http://ant.apache.org/">Apache Ant 1.6.5</a> and + <a href="http://sourceforge.net/projects/junit/">JUnit 3.8.1 or + 3.8.2</a><br> + (JUnit is only needed to run the example's unit tests). + </li> + </ul> + <p><a name="setup">In order to build the example</a>, + <u>you may need to copy the jmx-scandir</u> + directory to somewhere where you have write permissions. + <br>In that case, you will need to update the <i>nbjdk.home</i> variable + in the copied <i><a href="build.properties">build.properties</a></i> + file located at the root of the copied project directory. + Please make sure that this variable points to the JDK 6 home directory. + </p> + <p>If you wish to run the testsuite from within the <a + href="http://www.netbeans.org">NetBeans IDE</a> you will also have + to set the <i>libs.junit.classpath</i> variable in + <a href="build.properties">build.properties</a>. + The <i>libs.junit.classpath</i> variable should point to your + <a href="http://sourceforge.net/projects/junit/">junit.jar</a>, + version 3.8.1 or 3.8.2. + </p> + </blockquote> + <hr> + <p></p> + <p><u>Table Of Contents:</u></p> + <p><center>[<a href="#h2-Generating">Generating the Java Documentation</a>] + [<a href="#h2-Overview">Overview of the <i>scandir</i> Example</a>] + [<a href="#h2-API-Doc">API Documentation and Sources</a>] + [<a href="#h2-Patterns">Patterns, Best Practices, and Common Pitfalls</a>] + [<a href="#h2-Testing">Testing the <i>scandir</i> Example</a>] + [<a href="#h2-Running">Running the <i>scandir</i> Example</a>] + [<a href="#h2-Playing">Playing with JConsole</a>] + [<a href="#h2-Turning">Turning the example into a Secure JMX Application</a>] + [<a href="#h2-Connecting">Connecting to the Secure JMX Application</a>] + [<a href="#h2-Conclusion">Conclusion</a>] + [<a href="#h2-References">References</a>]</center></p> + + </ul> + <h2><a name="h2-Generating">Generating the Java Documentation</a></h2> + + <ul> + <p>Before reading further, you will need to generate the + Java Documentation for the example's sources.</p> + <p>In the example root directory (where the <code>build.xml</code> + file is located) run the following command: + <pre>ant javadoc</pre> + </p> + <p>Alternatively you can open the jmx-scandir project with the + NetBeans IDE and generate the Javadoc from its <code>Build</code> + menu. + </p> + <p>If building the documentation fails, please make sure to read the + <a href="#setup">note</a> at the beginning of this document.</p> + </ul> + + <h2><a name="h2-Overview">Overview of the <i>scandir</i> Example</a></h2> + + <ul> + <p>The JMX <i>scandir</i> example is built around the + following MBeans:</p> + <ul> + <li>The first MBean we will present here is the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a>. <br>A + <code>DirectoryScannerMXBean</code> 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 <code>DirectoryScannerMXBean</code> takes the + action for which it was configured: emit a notification, + <i>and/or</i> log a <code>record</code> for this file, + <i>and/or</i> 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.<br> <code>DirectoryScannerMXBeans</code> are + created by the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> - see next item on the list, from its + configuration. + </li> + <li> + The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> is the actual entry point of the + application. It reads the application's + configuration, and from that configuration, + will create a <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManager.html" +title="The ResultLogManager is in charge of managing result logs" + >ResultLogManager</a> and some <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBeans</a>. + <br>The <code>ScanManagerMXBean</code> lets you start, stop, and + schedule directory scans. The + <code>ScanManagerMXBean</code> is a singleton + MBean: there can be at most one instance of such + an MBean registered in a given MBeanServer. + </li> + <li>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> 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 <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> </code> to apply the + configuration again.<br> + The <code>ScanDirConfigMXBean</code> is created by the + <code>ScanManagerMXBean</code>, when the + <code>ScanManagerMXBean</code> is registered. + It is also possible to create an alternate + <code>ScanDirConfigMXBean</code>, and to switch the + <code>ScanDirConfigMXBean</code> to use one or the other + configuration. + <br>An example of XML configuration file is given + <a href="src/etc/testconfig.xml" + title="An Example Of Configuration" + >here</a>. Although you could edit such a file by + hand, it is easier to do it programmatically (or + with <a href="#JConsole">JConsole</a>) through + the <code>ScanDirConfigMXBean</code> interface. + </li> + <li>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a> is in charge of managing result logs. + <br>Directory Scanners can be configured to log a + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/config/ResultRecord.html" +title="A ResultRecord contains information about a file matching the criteria of a Directory Scanner" + >ResultRecord</a> whenever they take action upon a file that + matches their criteria. The <code>ResultLogManagerMXBean</code> is + responsible for logging these result records. + The <code>ResultLogManagerMXBean</code> 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. + <br>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. + <br>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. + <br>The <code>ResultLogManagerMXBean</code> + 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 <code>ResultLogManagerMXBean</code>, while + the file log doesn't have this facility.<br> + 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: + <br>The <i>scandir</i> 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).<br> + The <code>ResultLogManagerMXBean</code> is a singleton + MBean created by the <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> </code> + which reads and writes its configuration from the + <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a></code>. + </li> + </ul> + <p>An application <code>main()</code> method is + provided in the <a + href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html" + >ScanDirAgent</a> class. The <code>main()</code> simply registers + a <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> </code> in the platform MBeanServer, and + then waits for someone to call <code>close()</code> on the + <code>ScanManagerMXBean</code>. + </p> + <p>When the <code>ScanManagerMXBean</code> is registered, it + will create a default <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a></code> bound + to a default XML config file. + </p> + <p>The application's default XML config file is determined as + follows: + <ol> + <li>If the property <code>scandir.config.file</code> 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 + <code>ScanDirConfigMXBean.save()</code> is + invoked. + </li> + <li>Otherwise the application config file is + assumed to be a file called <code>jmx-scandir.xml</code>, + located in the user's directory (as defined by + the System property <code>user.home</code>). + If that file doesn't exists, it will be created when + <code>ScanDirConfigMXBean.save()</code> is + invoked. + </li> + </ol> + <p>It is worth noting that this project is defined to + run with the following properties: + <pre>-Djava.util.logging.config.file=logging.properties</pre> + <pre>-Dscandir.config.file=src/etc/testconfig.xml</pre> + With <code>ScanDirAgent</code> defined as the project's + main class. Hence when you invoke from the NetBeans IDE + <i>Run Project</i> on the <i>jmx-scandir</i> project, + or <i>Run file</i> on the <code>ScanDirAgent</code>, the + application starts with the test configuration provided in + <a href="src/etc/testconfig.xml" + title="An Example Of Configuration" + >src/etc/testconfig.xml</a> + </p> + </ul> + <h2><a name="h2-API-Doc">API Documentation and Sources</a></h2> + <ul> + <p>Once generated, the Javadoc of example classes can + be found starting from <a href="dist/javadoc/index.html" + title="The API Documentation" + ><code>dist/javadoc/index.html</code></a>.</p> + <p>You can view the sources in the <a + href="src" + title="The Example Source Tree" + ><code>src</code></a> subdirectory.</p> + </ul> + <h2><a name="h2-Patterns">Patterns, Best Practices, and Common Pitfalls</a></h2> + <ul> + <p>This section discusses some common patterns and + design choices that this example demonstrates, and some pitfalls that + it avoids. + </ul> + <h3>MBeans or MXBeans?</h3> + <ul> + <p>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. + </p> + <p>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 <code>WombatMBean</code> interface into <code>WombatMXBean</code>.</p> + <p>Using MXBeans rather than plain Standard MBean brings its + own advantages:</p> + <ul> + <li> + 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 <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> with JConsole and you will + understand the benefits. + </li> + <li> + 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. + </li> + <li> + 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 + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> which exposes a list + of <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a></code> and points + towards a <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a></code>. + </li> + </ul> + <p>In short, MXBeans are so much easier to use that + this example doesn't even have a single regular + Standard MBean. + </p> + <p>See also <a +href="http://weblogs.java.net/blog/emcmanus/archive/2006/02/what_is_an_mxbe.html" +title="What is an MXBean?" + >What is an MXBean?</a> + and <a +href="http://weblogs.java.net/blog/emcmanus/archive/2006/06/intermxbean_ref.html" +title="Inter-MXBean references" + >Inter-MXBean References</a>. + </p> + <blockquote><u>Hint:</u> 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 + <code>IOException</code>. Proxy objects will then be able + to rethrow directly any <code>IOException</code> received from + their underlying MBean Server connection, without wrapping + them into <code>UndeclaredThrowableExceptions</code>.<br> + 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 + <code>InstanceNotFoundException</code> or more generally + <code>JMException</code>. + </blockquote> + </ul> + <h3>MBean Names - aka ObjectNames</h3> + <ul> + <p>As you must know if you've been studying JMX, MBeans are + named objects. The names of MBeans are represented by + instances of <code>ObjectName</code>. An ObjectName is + composed of a <i>domain</i>, followed by a colon ':', + followed by a comma-separated list of <i>key=value</i> + pairs.<br> + The ordering of the <i>key=value</i> pairs is not + important, but <code>ObjectNames</code> are case sensitive + (both keys and values are case sensitive) and <b>white space + is not ignored</b>.<br> + 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.<br> + As an example, the ObjectName '<b><code>D:k1=v1, k2=v2, k3=v3</code></b>' has + three keys, which are '<b><code>k1</code></b>', '<b><code> k2</code></b>', + and '<b><code> k3</code></b>': beware + of the space in the name of the second and third + keys!<br> + It is therefore a different ObjectName from + '<b><code>D:k1=v1,k2=v2,k3=v3</code></b>' (the keys are now + '<b><code>k1</code></b>', '<b><code>k2</code></b>', and + '<b><code>k3</code></b>'), but the same ObjectName as + '<b><code>D: k2=v2, k3=v3,k1=v1</code></b>', and yet different + from '<b><code>D:k2=v2, k3=v3, k1=v1</code></b>'! + <p>In this example, we are following the rules + for ObjectName suggested in the <a +href="http://java.sun.com/products/JavaManagement/best-practices.html" + >JMX Best Practices</a>:</p> + <ul> + <li>ObjectNames should be <a + href="http://java.sun.com/products/JavaManagement/best-practices.html#mozTocId654884" + >predictable</a> + </li> + <li>The domain part of our ObjectNames starts with a Java + package name + </li> + <li>Our ObjectNames contain a <code>type=</code> + key property. This property is different for every + object type in our domain. + </li> + <li>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 <code>name=</code> key. + </li> + <li>When there can only be one instance of a given type + there aren't any other key properties than <code>type=</code>. + The ObjectNames of the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> and <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a>, which are both singleton MBeans, are + composed in this way. + </li> + <li>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 <code>type=</code>: the <code>name=</code> key. + In this example, a key property list of the form + <code>type=X,name=Y</code> is always enough to uniquely name + an MBean. Tools like jconsole are usually aware + of the semantics of the <code>type=</code> key and + <code>name=</code> key, and are therefore able to + display this form of name in a way that + is easier to read than other name forms. + </li> + </ul> + <p>The rules listed above are implemented by a couple + of static helper functions in the <a +href="src/com/sun/jmx/examples/scandir/ScanManager.java" +title="ScanManager.java" + >ScanManager</a> class. See the code of the + <b><code>makeSingletonName</code></b> and + <b><code>makeMBeanName</code></b> methods. + </p> + </ul> + <h3>Inter MBean Navigation</h3> + <ul> + <p>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.<br> + Prior to Java 6, there were basically three possible + choices:</p> + <ul> + <li><b>Make the relation appear in the ObjectName</b>. + 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. <br> + 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.<br> + 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. + <br>For instance, most MBean names defined by + <a href="http://jcp.org/en/jsr/detail?id=77" + >J2EE Management (JSR 77)</a> follow + this scheme. + </li> + <li><b>Design getters and setters (or operations) which + return <code>ObjectName</code> or + <code>ObjectName[]</code> values</b>. The ObjectNames + point to the MBeans which are related to that + object. For instance , <a + href="http://glassfish.dev.java.net/" + title="Open Source Java EE 5 Application Server" + >GlassFish</a> + defines MBeans which also use this pattern. + </li> + <li><b>Use the JMX RelationService</b>. The JMX RelationService + is quite powerful, but simple relationships often + do not justify that overhead. + </li> + </ul> + <p>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, <b>an MXBean can return a proxy</b> + to its related MXBeans. This is how we have chosen to + implement our inter MBean relationships in this + example: + <br>For instance the + <code>ScanManagerMXBean</code>/<code>DirectoryScannerMXBean</code> + relationship and the + <code>ScanManagerMXBean</code>/<code>ScanDirConfigMXBean</code> + relationships are implemented in this way. + <p> + 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: + <pre> + public Map<String,DirectoryScannerMXBean> getDirectoryScanners(); + </pre> + makes it immediately obvious that the MBeans to which we point are + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBeans</a>. It would have been much less obvious in prior + versions of Java SE, were the returned type would have had to be + <code>Map<String,ObjectName></code>, or + even worse just <code>Map</code>. + </p> + <p>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. + </p> + <p>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 + <code>getDirectoryScanners</code> will cause the + MBean to be invoked on the remote server side. + </p> + <p>If <code>getDirectoryScanners</code> were + defined as: + <pre> + public Map<String,DirectoryScannerConfig> getDirectoryScanners(); + </pre> + 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. + </p> + <p>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. + </p> + <p>For more information see also <a +href="http://weblogs.java.net/blog/emcmanus/archive/2006/06/intermxbean_ref.html" +title="Inter-MXBean references" + >Inter-MXBean References</a>. + </p> + </ul> + <h3>The MBeanRegistration interface, or how an MBean can + know or provide its own name</h3> + <ul> + <p> + 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. + </p> + <p> + 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. + </p> + <p> + Sometimes again, an MBean may need to perform some + checks, or some cleaning actions, just before, or + just after, it is unregistered. + </p> + <p> + When an MBean has such needs, the easiest solution + for it is to implement the <code>MBeanRegistration</code> + interface. + </p> + <p>The <code>MBeanRegistration</code> interface is a callback + interface which defines pre and post registration and + unregistration callbacks. + </p> + <p> + When an MBean implementing this interface is created + (with <code>createMBean</code>) or registered + (with <code>registerMBean</code>) in an MBeanServer, + the MBeanServer will call the <code>preRegister</code> + and <code>postRegister</code> method implemented by + the MBean. The <code>preRegister</code> method + has an <code>MBeanServer</code> and <code>ObjectName</code> + 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. + </p> + <p> + Most of the MXBeans we have defined in this example + implement the <code>MBeanRegistration</code> 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. + </p> + <p><br><center> + <table border="1" cellpadding="4" cellspacing="2" + bgcolor="#eeeeee" width="95%"> + <thead> + <tr bgcolor="#cecece"> + <th width="20%">MBean Requirement</th> + <th>callback</th> + <th>use case example</th> + </tr> + </thead> + <tbody> + <tr> + <td bgcolor="#dedede">get a reference to the MBeanServer</td> + <td><code>preRegister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> needs a reference + to the MBeanServer in order to create and + register other MBeans, such as the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a>, and the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBeans</a>. + </td> + </tr> + <tr> + <td bgcolor="#dedede">reject registration if conditions are + not met. + </td> + <td><code>preRegister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> will throw + an IllegalArgumentException in <code>preRegister</code> + if the ObjectName it is being passed is + illegal. Throwing an exception in + <code>preRegister</code> makes the registration fail. + </td> + </tr> + <tr> + <td bgcolor="#dedede">get my client-assigned MBean name</td> + <td><code>preRegister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> propagates the + value of the <code>name=</code> property of + the ObjectName it is given into its + ScanManagerConfig bean. + </td> + </tr> + <tr> + <td bgcolor="#dedede">provide my own default ObjectName if none + was given to the MBeanServer + </td> + <td><code>preRegister</code></td> + <td bgcolor="#fafafa">The name that is returned by <code>preRegister</code> + is the ObjectName with which the MBean will be + eventually registered. + The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> is able to suggest + a value for its own ObjectName if none was + provided. Similarly, the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> + always returns its singleton ObjectName + defined by <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html#SCAN_MANAGER_NAME" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean.SCAN_MANAGER_NAME</a>. + </td> + </tr> + <tr> + <td bgcolor="#dedede">perform initialization steps</td> + <td><code>preRegister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> uses <code>preRegister</code> + to initialize its internal ScanManagerConfig bean. + </td> + </tr> + <tr> + <td bgcolor="#dedede">perform initialization steps, once it is + known that the registration was successful. + </td> + <td><code>postRegister</code></td> + <td bgcolor="#fafafa">The <code>postRegister</code> 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 <code>preRegister</code> once it + is known that registration was not successful. + The <code>postRegister</code> method has a Boolean parameter + which tells the MBean whether it was or wasn't + successfully registered in the MBeanServer. + The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> uses <code>postRegister</code> to create + and register other MBeans, such as the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a> and the default + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a>. + Note that <code>postRegister</code> is not expected to throw any + exception. If an exception needs to be thrown, it should + be thrown in <code>preRegister</code>. + </td> + </tr> + <tr> + <td bgcolor="#dedede">check whether the MBean can be deregistered</td> + <td><code>preDeregister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> 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 <code>preDeregister</code> 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. + </td> + </tr> + <tr> + <td bgcolor="#dedede">clean up resources, refusing to be deregistered if + it fails + </td> + <td><code>preDeregister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> uses this method to unregister + all the other MBeans it has created and registered in the + MBeanServer. This includes the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a>, the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBeans</a> it has created, and the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBeans</a> it has created when + applying its configuration. + </td> + </tr> + <tr> + <td bgcolor="#dedede">clean up resources which need to be released in + a best-effort way, when it is known that the MBean is no + longer registered. + </td> + <td><code>postDeregister</code></td> + <td bgcolor="#fafafa"><code>postDeregister</code> is only called if the MBean was succesfully + unregistered. + The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> uses this method to cancel + its internal java.util.Timer. + </td> + </tr> + </tbody> + </table> + </center><br></p> + </ul> + <h3>The Singleton MBean Pattern</h3> + <ul> + <p> + A singleton MBean is an MBean which can only have one + instance registered in a given MBeanServer. <br> + 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 <code>new ObjectName(...)</code> + and catch the declared <code>MalformedObjectNameException</code>. + </p> + <p>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. + </p> + <p>In this example, we have two singleton MBeans: + The <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a></code> and the + <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a></code>. But in fact, + the only real singleton MBean is the + <code>ScanManagerMXBean</code>. The + <code>ResultLogManagerMXBean</code> just happens to + be a singleton MBean because it has a 1-1 relationship + with the <code>ScanManagerMXBean</code>. + </p> + <p>The <code>ScanManagerMXBean</code> implements the + singleton MBean pattern in this way: + </p> + <ul> + <li>The <code>ScanManagerMXBean</code> name has a single + key property: <code>type=ScanManagerMXBean</code>.</li> + <li>Its name is defined by an ObjectName constant called + <code>SCAN_MANAGER_NAME</code> in the <code>ScanManager</code> class</li> + <li>The <code>ScanManagerMXBean</code> enforces its status of + singleton MBean. It will refuse to be registered + with a name other than + the <code>SCAN_MANAGER_NAME</code>. You can therefore depend on + the fact that the <code>ScanManagerMXBean</code> will always + be registered with its singleton <code>SCAN_MANAGER_NAME</code> + (see <code>preRegister</code>) + </li> + <li>You are not obliged to provide a name when you + register the <code>ScanManagerMXBean</code>: if you pass null, + then the <code>ScanManager</code> will be registered with + its singleton <code>SCAN_MANAGER_NAME</code> + (see <code>preRegister</code>). + </li> + <li>The <code>ScanManager</code> class has a no-arg static + <code>register</code> method that will register + the singleton instance in the Platform MBeanServer. + This static <code>register</code> method returns + a proxy to the registered singleton. + </li> + <li>The <code>ScanManager</code> class has also a static + <code>register</code> method that will create + a singleton instance in a (possibly remote) + MBeanServerConnection - using + <code>createMBean</code>. + This static <code>register</code> method + also returns a proxy to the registered singleton. + </li> + <li>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. + </li> + </ul> + <p> + On the other hand, the <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a></code> + has a much more relaxed implementation of the pattern: + <br>It simply provides its own singleton name if it is + registered with a null ObjectName, but will not enforce + the use of that name. + </p> + <p>Note that all singleton MBean names in this example + are created using the <code>ScanManager.makeSingletonName</code> + method, which implements the pattern for ObjectNames suggested + in the JMX Best Practices. + </p> + </ul> + <h3>Managing the Life Cycle of dependent MBeans</h3> + <ul> + <p>A common task that many JMX applications have + is to manage the life cycle of MBeans registered + in the MBeanServer.</p> + <p>In this example, we have decided to follow a simple + pattern:</p> + <ul> + <li>The application is initialized simply + by registering the singleton + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> in + the MBeanServer. + </li> + <li>The <code>ScanManagerMXBean</code> will then + in turn register any other MBean that the + application might need: + <ul> + <li>It creates and registers the singleton + <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a></code> + </li> + <li>It creates and registers the default + <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a></code> + which loads the initial configuration + </li> + <li>It creates as many + <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBeans</a></code> as + needed when the configuration is applied + </li> + <li>It lets you create alternate + <code>ScanDirConfigMXBean</code>, to + which you can later switch in order + to apply a new alternate configuration. + </li> + </ul> + </li> + <li>When a new configuration is applied (or if the + current configuration is reapplied), the + <code>ScanManagerMXBean</code> will unregister + any <code>DirectoryScannerMXBeans</code> it has + previously registered, and will re-create + brand new <code>DirectoryScannerMXBeans</code> + from the applied configuration. + </li> + <li>When you unregister the <code>ScanManagerMXBean</code>, + it does all the cleanup for you, by unregistering + all the MBeans that it has created during the + course of the application. + </li> + </ul> + <p>The <code>ScanManagerMXBean</code> makes use of its + <code>MBeanRegistration</code> interface in order + to register the other MBeans it needs (see the + <code>ScanManager.postRegister</code> method) and to unregister + every MBean it has created (see the <code>ScanManager.preDeregister</code> + method). + </p> + <p>You will note that the <code>ScanManagerMXBean</code> + 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. + <br> + The deregistration of related MBeans will happen + in the <code>ScanManager.preDeregister</code> + method. + <br> + If one of these MBeans could not be deregistered, + then the <code>ScanManagerMXBean</code> will throw + an exception, refusing to be deregistered. + <br>This leaves you a chance to try to deregister it + again later. Since the <code>ScanManagerMXBean</code> + 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. + </p> + <p>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. + </p> + <p>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 <code>ScanManagerMXBean</code>) does + the trick. + </p> + </ul> + <h3>Emitting Notifications</h3> + <ul> + <p>In order to emit notifications, an MBean must be + an instance of <code>NotificationEmitter</code>. + The <code>NotificationEmitter</code> interface defines methods + that the MBeanServer will call on the MBean in order + to register <code>NotificationListeners</code> with the MBean. + </p> + <p>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 <i>only once</i> a single listener with each MBean + which is a <code>NotificationEmitter</code>. + 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. + </p> + <p>An MBean can therefore make no assumption about + which client or how many clients have registered for + notifications. + </p> + <p>It is also worth noting that the logic of the + methods defined in <code>NotificationEmitter</code> would not + be trivial to implement from scratch. Fortunately + the JMX API defines a helper class, called + <code>NotificationBroadcasterSupport</code>, which + provides an implementation for these methods. + </p> + <p>There are actually three ways for an MBean to + implement <code>NotificationEmitter</code>, of which only two + are recommended. + </p> + </ul> + + <h4>Extending NotificationBroadcasterSupport</h4> + <ul> + <p>This is the simplest way of coding an MBean which + is a <code>NotificationEmitter</code>: + </p> + <p>Simply extend <code>NotificationBroadcasterSupport</code>, + then override its <code>getNotificationInfo</code> method + which returns the <code>MBeanNotificationInfo[]</code> array + that should be included in your MBean's <code>MBeanInfo</code> + and that's it. + <br>You just need to call the <code>sendNotification</code> method + inherited from <code>NotificationBroadcasterSupport</code> whenever + your MBean needs to send a notification. + </p> + <p>In our example, both the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> and <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a> extend + <code>NotificationBroadcasterSupport</code> in order + to send notifications. + </p> + </ul> + <h4>The Delegation Pattern: delegating to a + NotificationBroadcasterSupport delegate</h4> + <ul> + <p>There may be cases however where delegating to a + wrapped <code>NotificationBroadcasterSupport</code> + object may be preferred to extending + <code>NotificationBroadcasterSupport</code>. + </p> + <p>For instance, if your MBeans already derive from + some base class, extending <code>NotificationBroadcasterSupport</code> + might not be an option. + </p> + <p>Similarly, if you do not want to have the inherited + <code>public void sendNotification(Notification notification)</code> + method appear in the Javadoc of the concrete class of your + MBean, you may want to consider using the delegation + pattern instead of extending + <code>NotificationBroadcasterSupport</code> + </p> + <p>In our example both the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> and the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a> use the delegation + pattern rather than extending + <code>NotificationBroadcasterSupport</code>. + 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. + </p> + <p>It may be also worth noting that some tools like + the JMX Module of <a +href="http://www.netbeans.org" + >NetBeans IDE</a>, will be able to + generate for you all the code that delegates to a + wrapped <code>NotificationBroadcasterSupport</code>. + </p> + </ul> + + <h4>Implementing NotificationEmitter from scratch</h4> + <ul> + <p>This is the last possibility for an MBean that + needs to send notifications: simply implement + <code>NotificationEmitter</code> from scratch. This is highly + discouraged since that logic is not trivial, and + already provided by + <code>NotificationBroadcasterSupport</code> anyway. + </p> + </ul> + + <h4>Beware of Synchronization Locks</h4> + <ul> + + <p>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.</p> + <p>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 <code>JMXConnector</code> (like the + <code>JMXRMIConnector</code>) + or through a direct reference to the MBeanServer + (by calling + <code>MBeanServer.addNotificationListener</code>). + </p> + <p>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 + <code>sendNotification</code>.</p> + <p>An easy way to do that is demonstrated in the + <code>ScanManager</code> 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. + <br>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. + </p> + <p>In our example the <code>ScanManager</code> class + ensures this by: + <ul> + <li>Only calling <code>sendNotification</code> + in its private <code>sendQueuedNotifications</code> + method. + </li> + <li>Only calling <code>sendQueuedNotifications</code> + when all locks have been released. + </li> + <li>Never calling a method that calls + <code>sendQueuedNotifications</code> from within + a synchronized block.</li> + </ul> + </p> + </ul> + + + + <h4>Don't subclass Notification</h4> + <ul> + <p>Another common best practice when you want + to improve interoperability is to use directly + the Notification base classes provided in the + JMX<sup>TM</sup> API. Do not create your own + subclasses of these standard classes. + </p> + <p>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. + </p> + <p> + 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. + </p> + <p>In this example, we are using directly the + standard notification classes: + <ul> + <li>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> and the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a> both use directly + <code>AttributeChangeNotification</code> to notify + changes in their <code>State</code> attribute. + </li> + <li>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a> + also uses the base <code>Notification</code> + class directly in order to notify whenever + it finds a matching file. + <br>In that case, we simply use the base + <code>Notification</code> + class with a new + <b><code>com.sun.jmx.examples.scandir.filematch</code></b> + type. + </li> + <li>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> and <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a> also both use the base + <code>Notification</code> class. + </li> + </ul> + <p>Careful readers will have noted that the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> and the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a> both use the + <code>AttributeChangeNotification</code> class + to notify about their state change, whereas the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> uses the base + <code>Notification</code> class. + </p> + <p>In fact, this is because the semantics of these + notifications is not exactly the same - although + both denote a state change: + <ul> + <p>In the case of <code>ScanManagerMXBean</code> + and <code>DirectoryScannerMXBean</code>, the + notification which is emitted is more about a + state transition, from one state to another. + For instance, going from <code>RUNNING</code> + to <code>STOPPED</code>, or from + <code>SCHEDULED</code> to <code>STOPPED</code>. + <br>In that case, the + <code>AttributeChangeNotification</code> 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. + </p> + <p>In the case of the <code>ScanDirConfigMXBean</code> + however, what is of interest is the state in + which the MBean has arrived. Using the base + <code>Notification</code> class with three different + notification type strings - + <b><code>com.sun.jmx.examples.scandir.config.loaded</code></b>, + <b><code>com.sun.jmx.examples.scandir.config.modified</code></b>, + and + <b><code>com.sun.jmx.examples.scandir.config.saved</code></b> - + was therefore closer to what we wanted to model. + </p> + </ul> + </p> + </ul> + + <h3>Configuration MBeans</h3> + <ul> + <p>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. + </p> + <p> + In our example, the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> is dedicated to the application configuration. + </p> + <p>The <code>ScanDirConfigMXBean</code> 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 + <code>applyConfiguration</code> on the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a>. + It is also possible to create many configurations, by creating as + many <code>ScanDirConfigMXBean</code>s, and then to choose and apply + one of these configurations by calling + <code>ScanManagerMXBean.setConfigurationMBean</code> and then + <code>ScanManagerMXBean.applyConfiguration</code>. + </p> + <p>In this way, all configurations aspects are gathered and concentrated + inside the <code>ScanDirConfigMXBean</code> instead of being scattered + throughout all the MBeans that compose the application. + </p> + <p>In order to save and store the application configuration data, the + <code>ScanDirConfigMXBean</code> uses a set of XML serializable Java beans + defined in the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/config/package-summary.html" +title="The com.sun.jmx.examples.scandir.config package defines XML serializable beans" + >com.sun.jmx.examples.scandir.config</a> package. These beans are very + simple Java beans which have been lightly annotated for XML binding. + </p> + <p>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 <b>are</b> serializable). + </p> + <p>The same <a +href="dist/javadoc/com/sun/jmx/examples/scandir/config/ScanManagerConfig.html" +title="The com.sun.jmx.examples.scandir.config package defines XML serializable beans" + >ScanManagerConfig</a> bean that we use to read from and write to the + XML configuration file is thus also used as attribute of the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a>. It is transformed into a <code>CompositeData</code> + by the MXBean framework, and can be easily introspected with + <a href="#JConsole">jconsole</a>. + </p> + </ul> + <h3>MBeans Must Be Thread-Safe</h3> + <ul> + <p>A question often asked by newcomers to JMX technology + is whether the MBeanServer is thread-safe. Well, the MBeanServer <b>is</b> + 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. + </p> + <p>In this example, we have been using two methods to ensure thread + safety for our MBeans: synchronized blocks, and semaphores. + </p> + <p>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: + <ul> + <li>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.</li> + <li>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.</li> + </ul> + </p> + <p>Another means of implementing thread-safe code is to use semaphores. + The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> uses a semaphore called + <code>sequencer</code> to ensure + that critical code sections are not executed concurrently. In this + MBean, we use <code>Semaphore.tryAcquire</code> to lock the sequencer + semaphore before entering the critical section. If the + <code>Semaphore.tryAcquire</code> 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: + <pre> + 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(); + } + </pre> + </p> + <p>Using <code>Semaphore.tryAcquire</code> 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 <code>IllegalStateException</code> + instead of being blocked on the deadlocked lock. + </p> + <p>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. + </p> + <p>Careful readers will also have noted that we used + <code>IllegalStateException</code> 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. + </p> + </ul> + + <h3>Waiting for Notifications</h3> + <ul> + <p>Implementing code that needs to wait for notifications is sometimes + difficult. Because notifications are asynchronous, doing something + like: + <pre> + // register a notification listener + ... + // start a management action + ... + // wait for a notification + ... + // do something based on whether the expected notification + // is received + ... + </pre> + is not always trivial. However, there's a very easy way to do that: use + a blocking queue of notifications. + <pre> + 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. + .... + </pre> + </p> + <p>You will note that this is a technique we've been using in the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html" +title="The ScanDirAgent class defines a main method for the scandir application" + >ScanDirAgent</a> class and in the example unit tests. + </p> + </ul> + + <h3>Holding hard references to other MBeans: proxy or direct reference?</h3> + <ul> + <p>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? + </p> + <p> + 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: + <ol> + <li>When MBean A needs to call a method of method B which + is not part of its MBean interface</li> + <li>When the overhead of going through the MBeanServer + plus the MXBean framework is too great (frequently-called + method, with creation of OpenType)</li> + </ol> + 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. + </p> + <p>In our example, the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> holds only proxy references to the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" + >ScanDirConfigMXBean</a> and the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" + >DirectoryScannerMXBeans</a>. <br> + However it holds a direct reference to the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManager.html" + >ResultLogManager</a>. This makes it possible to pass a direct + reference to the <code>DirectoryScannerMXBeans</code>, + which can then log their results + more efficiently, and would also make it possible to remove + the <code>log</code> method from the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" + >ResultLogManagerMXBean</a> interface - leaving it in the + <code>ResultLogManager</code> class (possibly as a package method) + should we wish to do so. + </p> + + </ul> + + <h3>Agent Class</h3> + <ul> + <p>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html" +title="The ScanDirAgent class defines a main method for the scandir application" + >ScanDirAgent</a> is the Agent class for the <i>scandir</i> application. + This class contains the <code>main</code> method to start a standalone + <i>scandir</i> application. + </p> + <p>The <code>main</code> method simply registers a <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> in the platform MBeanServer, and then waits + for someone to call <code>ScanManagerMXBean.close</code>. + </p> + <p> + When the <code>ScanManagerMXBean</code> state is switched to + <code>ScanManagerMXBean.ScanState.CLOSED</code>, the + <code>ScanManagerMXBean</code> is unregistered, and the application + terminates (i.e. the main thread completes). + </p> + <p>Standalone JMX applications usually have an Agent class that contain + their <code>main</code> 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 <code>main</code>. In our example the Agent + class could be easily turned into an MBean, exposing its three + <code>init</code>, <code>waitForClose</code> and <code>cleanup</code> + 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 <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a>. + </p> + </ul> + <h3>Secure Client Class</h3> + <ul> + <p>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirClient.html" +title="The ScanDirClient class is a very short example of secure programmatic client" + >ScanDirClient</a> is an example class that shows how a + programmatic client can connect to a secured <i>scandir</i> application. + This class contains a <code>main</code> method which creates and + configures a <code>JMXConnector</code> client to connect with + a secured <i>scandir</i> daemon. This class will not work with + the default unsecured agent since it requires mutual authentication. + </p> + <p>How to secure a JMX <i>scandir</i> application and run + the secure <code>ScanDirClient</code> is discussed <a href="#secure" + >later</a> in this document. + </p> + <p>The <code>ScanDirClient</code> is not really part of the + application - and is given here only for the sake of + the example. + </p> + </ul> + + <h2><a name="h2-Testing">Testing the <i>scandir</i> Example</a></h2> + <ul> + <p>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 + <code>CLASSPATH</code>.<br> + Then in the example root directory (where the <code>build.xml</code> + file is located) run the following command: + <pre>ant test -Dlibs.junit.classpath=<i><u>path to junit jar (either 3.8.1 or 3.8.2)</u></i></pre> + </p> + <p>Alternatively you can open the jmx-scandir project with the + NetBeans IDE and test the jmx-scandir project from the + <code>Run</code> menu. + </p> + + </ul> + + <h2><a name="h2-Running">Running the <i>scandir</i> Example</a></h2> + <ul> + <p>In the example root directory (where the <code>build.xml</code> + file is located) run the following commands: + <pre>ant jar +ant run-single -Drun.class=com.sun.jmx.examples.scandir.ScanDirAgent -Djavac.includes=src</pre> + or simply <pre>ant run</pre> + </p> + + <p>This will run the example using the configuration + file provided in the src/etc directory. + </p> + <p>Alternatively you can open the jmx-scandir project with the + NetBeans IDE. You can run the example by + selecting the <code>ScanDirAgent</code> file + and run it with <code>Run File</code> in the + <code>Run</code> menu or simply + set the <i>jmx-scandir</i> project as main project and + select <code>Run Main Project</code> from the + main menu. Both targets will use the configuration + file provided in the src/etc directory. + </p> + <p>When the application is started, you can connect to + it with <a href="#JConsole">jconsole</a>. + </p> + <blockquote> + <u>Note:</u> You can also run the <i>scandir</i> + application directly from the <code>java</code> + command line. Make sure to build the project jar + first. + <br>On Unix systems: + <pre>ant jar +java -Djava.util.logging.config.file=logging.properties \ + -Dscandir.config.file=src/etc/testconfig.xml \ + -jar dist/jmx-scandir.jar</pre> + <br>On Windows systems: + <p><code>ant jar<br> +java -Djava.util.logging.config.file=logging.properties + -Dscandir.config.file=src\etc\testconfig.xml + -jar dist\jmx-scandir.jar</code></p> + </blockquote> + </ul> + + <h2><a name="h2-Playing">Playing with JConsole</a></h2> + <ul> + <p>Run the example as explained in the previous section, so + that it uses the provided <code>src/etc/testconfig.xml</code> + configuration file. Then start + jconsole. In the connection window choose the process that runs + <code>com.sun.jmx.examples.scandir.ScanDirAgent</code> or + <code>jmx-scandir.jar</code>. + </p> + <p><center> + <table border="0" cellpadding="2" cellspacing="2"> + <tr><td> + <a href="docfiles/connect-local-ant-run.jpg" + title="jconsole connection window - connect to local process" + ><img height="440" + src="docfiles/connect-local-ant-run.jpg" + alt="jconsole connection window - connect to local process" + /></a> + </td> + <td> + <a href="docfiles/connect-local-java-jar.jpg" + title="jconsole connection window - connect to local process" + ><img height="440" + src="docfiles/connect-local-java-jar.jpg" + alt="jconsole connection window - connect to local process" + /></a> + </td></tr></table> + </center> + </p> + <p>Open the MBeans tab, and look for the + <code>ScanDirConfigMXBean</code>. + Click on its <code>Attributes</code> node and double click on its + <code>Configuration</code> attribute, to look at + the loaded configuration - values in bold can + be expanded by a double-click. + </p> + <p><center><a href="docfiles/scandir-config.jpg" + title="jconsole MBean tab: ScanDirConfigMXBean" + ><img + src="docfiles/scandir-config.jpg" + alt="jconsole MBean tab: ScanDirConfigMXBean" + /></a></center> + </p> + <p>Now go to the <code>ScanManagerMXBean</code>, click on + its <code>Notifications</code> node, and subscribe + for notifications. Then click on the + <code>Operations</code> node and invoke the + <code>start()</code> operation: + </p> + <p><center><a href="docfiles/scandir-start.jpg" + title="jconsole MBean tab: ScanDirConfigMXBean" + ><img + src="docfiles/scandir-start.jpg" + alt="jconsole MBean tab: ScanDirConfigMXBean" + /></a></center> + </p> + <p>You can see that the notifications counter was + incremented by three: you have just scheduled, + run, and completed a batch of directory scans. + </p> + <p>Now go to the <code>ResultLogManagerMXBean</code>, + click on its <code>Attributes</code> node, and + expand its <code>MemoryLog</code> attribute: + </p> + <p><center><a href="docfiles/scandir-result.jpg" + title="jconsole MBean tab: ScanDirConfigMXBean" + ><img + src="docfiles/scandir-result.jpg" + alt="jconsole MBean tab: ScanDirConfigMXBean" + /></a></center> + </p> + <p>You can see that the directory scan results have + been logged.</p> + <p>To make the application terminate go back to the + <code>ScanManagerMXBean</code> and invoke + <code>close()</code>. The <code>ScanDirAgent</code> + will receive the notification, step out of + the application main thread, and the application + will terminate. + </p> + <p>This is of course a very limited scenario. Feel free + to improvise with all the features of the example, creating + a new configuration - + <code>ScanManagerMXBean.createOtherConfigurationMBean</code> - + adding multiple directory scanners to that configuration - + <code>ScanDirConfigMXBean.addDirectoryScanner</code> - + then switching the <code>ScanManagerMXBean</code> current + configuration by changing the value of the <i>ConfigurationMBean</i> + attribute - <code>ScanManagerMXBean.setConfigurationMBean</code> + - then applying the new configuration - + <code>ScanManagerMXBean.applyConfiguration(true)</code> - + then scheduling repeated directory scans every 10 seconds - + <code>ScanManagerMXBean.schedule(0,10000)</code> - + subscribing for notifications, etc... + </p> + </ul> + + <a name="secure"></a> + <h2><a name="h2-Turning">Turning the example into a Secure JMX Application</a></h2> + <ul> + <p>In this section, we will see how to configure and + start the <i>scandir</i> 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 <code>ScanDirAgent</code> so + that a real secure RMIConnectorServer is started at bootstrap. + </p> + <p>To achieve this we will: <a href="#management.properties" + >provide our own management.properties</a>, <a + href="#password-access">create our own password and access files</a>, + <a href="#keystore-truststore">provide a keystore and truststore</a>, + <a href="#start-secure-agent">start the ScanDirAgent with the + appropriate system properties</a>. + </ul> + <h3>Configuring the JVM Agent for Secure Remote Connection</h3> + <ul> + <p>The easiest way to <a name="management.properties">configure the + JVM Agent</a> for Secure Remote + Connection is to use your own <a + href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#properties" + title="This page describes the properties you can put in your management.properties file" + >management.properties</a> file. + In this example, we have copied the default + <code>$JRE/lib/management/management.properties</code> + file to the example's <code>src/etc</code> directory and + modified it in <a href="src/etc/management.properties" + title="our modified management.properties" + >this way</a>: + <ul> + <li>We have set the RMI port to <u>4545</u> - this is just a + random port number we have picked up. Feel free to use your + own value suited to your environment. + <pre># For setting the JMX RMI agent port use the following line +com.sun.management.jmxremote.port=<b>4545</b></pre> + </li> + <li>We have <u>switched on</u> SSL <u>mutual authentication</u> + <pre># For RMI monitoring with SSL client authentication use the following line +com.sun.management.jmxremote.ssl.<b>need.client.auth</b>=<b>true</b></pre> + </li> + <li>We have also <u>secured the RMI Registry</u> with SSL + <pre># For using an SSL/TLS <b>protected</b> RMI Registry use the following line +com.sun.management.jmxremote.<b>registry.ssl</b>=<b>true</b></pre> + </li> + <li>We have provided <a + href="src/etc/password.properties">our own password file</a> + <pre># For a non-default password file location use the following line +com.sun.management.jmxremote.password.file=<i>src/etc/password.properties</i></pre> + </li> + <li>We have provided <a + href="src/etc/access.properties">our own access file</a> + <pre># For a non-default password file location use the following line +com.sun.management.jmxremote.access.file=<i>src/etc/access.properties</i></pre> + </li> + </ul> + <p>You will note that we haven't provided any value + for the other security properties, like + <code>com.sun.management.jmxremote.authenticate=true</code>, + 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. + </p> + <p>We do recommend that you <u>use the most secure configuration + when you deploy a JMX agent</u> - which means <u>switching on + SSL protection for the RMI registry</u> <b>and</b> <u>requiring + mutual authentication</u>, as we show in this example. + </p> + <p>We will use the <code>com.sun.management.config.file</code> + system property to pass our <a + href="src/etc/management.properties">management.properties</a> + file to the <code>ScanDirAgent</code>. + </p> + </ul> + + <h3>Creating a password and access file</h3> + <ul> + <p>As explained above, we have created our own + <a href="src/etc/password.properties">password file</a> + and <a href="src/etc/access.properties">access file</a> + for <a name="password-access">access control and authorization</a>. + </p> + <p>In the password file, we have defined two logins: + <i>guest</i> and <i>admin</i>. The password for + <i>guest</i> is <i>guestpasswd</i> and the password + for <i>admin</i> is <i>adminpasswd</i>. + </p> + <p>In the access file, we have mapped these two logins + to access rights: the <i>admin</i> login has <i>read-write</i> + access, while the <i>guest</i> login only has <i>read-only</i>. + </p> + <p>Before starting the <code>ScanDirAgent</code>, 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 + <a href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#PasswordAccessFiles" + title="Using Password and Access Files" + >here</a>. + </p> + <p>As we have seen above, the location + of our access and password files is configured in our own <a + href="src/etc/management.properties">management.properties</a> + file. + </p> + </ul> + <h3>Keystore and Truststore</h3> + <ul> + <p>Using SSL with mutual authentication means that both + client and server will need a <a name="keystore-truststore" + >keystore and a truststore</a> + to store their own certificates, and the certificates of + the parties they trust. Usually, client and server will + have their own keystore and truststore. + </p> + <p>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 <i>password</i>, and the + password for our truststore is <i>trustword</i>. + 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. + </p> + <p>A secure application will obviously need to use its own + keystore and truststore, <b><u>and should not rely on the keystore + and truststore we are providing here!</u></b> + </p> + <p>How to create your own keystore and truststore, is explained + in <a +href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#SSL_enabled" +title="Monitoring and Management Using JMX" + >here</a>. + As shown <a href="#start-secure-agent">later</a>, + we will need to use <a + href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#SSL_enabled" + >system properties</a> to pass our truststore + and keystore to the <code>ScanDirAgent</code>. + </p> + </ul> + <h3>Starting a Secure <i>scandir</i> agent</h3> + <ul> + <p>To start a <a name="start-secure-agent" + >secure <i>scandir</i> agent</a>, go to the + <i>scandir</i> example root directory and type the + following command:</p> + <p>On Unix Systems: +<pre>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</pre> + </p> + <p>On Windows Systems: +<p><code>ant jar<br> +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</code></p> + </p> + <p>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 + <a href="docfiles/remote-connection.jpg">localhost:4545</a>, + the connection will <a href="docfiles/remote-connection-failed.jpg" + >fail</a>, 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. + </p> + <p>The next section will discuss how to connect to the + secure agent. + </p> + </ul> + + <h2><a name="h2-Connecting">Connecting to the Secure JMX Application</a></h2> + <ul> + <p>We will now see how to connect to the secure agent, + using jconsole, and using a programmatic client. + </p> + </ul> + + <h3>Using jconsole to connect to the secure agent</h3> + <ul> + <p>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 <a + href="http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#HowSSLWorks" + title="How SSL Works" + >Java<sup>TM</sup> Secure Socket Extension (JSSE) Reference Guide</a>. + </p> + <p>To start jconsole with our provided keystore and + truststore, go to the scandir example root directory and + type in the following command: + <p><code>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</code></p> + </p> + <p>The <code>-J-Djava.util.logging.config.file=logging.properties</code> + flag is not mandatory, but passing a <code>logging.properties</code> + may help you debug connection problems if anything goes wrong. + </p> + <p>In jconsole connection window, choose to connect to a + remote process, using the address <i>localhost:4545</i> + and the guest login: + </p> + <p><center><a href="docfiles/remote-connection.jpg" + ><img src="docfiles/remote-connection.jpg" + alt="jconsole connection window"/></a></center> + </p> + <p>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. + </p> + <hr> + <p><u>Note:</u> if jconsole fails to connect and show + you <a href="docfiles/remote-connection-failed.jpg">this screen</a> + 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 <code>truststore</code> + and <code>keystore</code> files are located. This article - <a + href="http://blogs.sun.com/roller/page/jmxetc?entry=troubleshooting_connection_problems_in_jconsole" + title="Troubleshooting connection problems in JConsole" + >Troubleshooting connection problems in JConsole</a> - may help + you figure out what is going wrong. + </p> + <hr> + </ul> + + <h3>Writing a programmatic client to connect to the secure agent</h3> + <ul> + <p> + In this section we will show the steps involved in writing + a programmatic client that will connect to our secure agent. + </p> + <p>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirClient.html" +title="The ScanDirClient class is a very short example of secure programmatic client" + >ScanDirClient</a> is an example class that shows how a + programmatic client can connect to a secured <i>scandir</i> application. + This class contains a <code>main</code> method which creates and + configures a <code>JMXConnector</code> client to connect with + the secured <i>scandir</i> agent. + </p> + <p>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: + <ul> + <li>Creating an empty environment map: + <pre> + // 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>(); + </pre> + </li> + <li>Putting the client's credentials in that map: + <i>(here the client will log in as <b>guest</b>)</i> + <pre> + // 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); + </pre> + </li> + <li>Providing an <code>SslRMIClientSocketFactory</code> to interact + with the secure RMI Registry: + <pre> + // 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()); + </pre> + </li> + <li>Creating a JMXConnector and connecting with the + secure server: + <pre> + // 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); + </pre> + </li> + </ul> + <p>For this to work, we also need to start the <code>ScanDirClient</code> + with the appropriate system properties that will point to our + <code>keystore</code> and <code>truststore</code>. To start the secure + client, go to the <i>scandir</i> example root directory and type + the following command: + <p><code>ant jar<br> +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 + </code></p> + </p> + <p>You should be seeing this trace: +<center><table width="90%" border="0" bgcolor="#eeeeee"> +<tr><td> +<pre> +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! +</pre> +</td></tr></table></center> + <p>If the <code>ScanDirClient</code> fails to connect with + the secure agent, then this article - <a + href="http://blogs.sun.com/roller/page/jmxetc?entry=troubleshooting_connection_problems_in_jconsole" + title="Troubleshooting connection problems in JConsole" + >Troubleshooting connection problems in JConsole</a> - may help + you figure out what is going wrong. Indeed the connection steps + performed by the <code>ScanDirClient</code> are very similar to + those performed by <code>jconsole</code>, and the problems you + could encounter are identical. Just remember that + <code>jconsole</code> needs the extra <code>-J</code> flag to pass + system properties to the VM, which is not needed with regular + <code>java</code> launcher invocations. + </p> + </ul> + + <h2><a name="h2-Conclusion">Conclusion</a></h2> + <ul> + <p> + 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. + </p> + </ul> + <h2><a name="h2-References">References</a></h2> + <ol> + <li><a href="http://java.sun.com/products/JavaManagement/best-practices.html" + >JMX Best Practices</a>: This document describes best practices that + have been identified for modeling using the JMX API. </li> + <li><a href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html" + >Monitoring and Management Using JMX</a>: How to enable, configure, and + connect to the JVM JMX agent.</li> + <li><a name="JConsole"><a +href="http://java.sun.com/javase/6/docs/technotes/guides/management/jconsole.html" +>Using JConsole</a>: JConsole is a JMX-Compliant monitoring tool which allows + you to interact graphically with your own MBeans. + </li> + <li><a href="http://java.sun.com/javase/6/docs/technotes/guides/management/" + >Monitoring and Management for the Java Platform</a>: The Java Platform + Standard Edition (Java SE) 6 provides comprehensive monitoring and + management support for the Java platform. </li> + <li><a href="http://java.sun.com/products/JavaManagement/community/jmx_blogs.html" + >List of JMX-related Blogs</a>: This page provides links to the + different web logs written by members of the Sun team working on the + JMX API.</li> + <li><a + href="http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#HowSSLWorks" + title="The JSSE Reference Guide" + >Java<sup>TM</sup> Secure Socket Extension (JSSE) Reference Guide</a>: + comprehensive documentation about the Java<sup>TM</sup> Secure Socket + Extension (JSSE) + </li> + <li><a href="http://java.sun.com/javase/6/docs/" + >Java SE 6 Documentation Index</a>: This document covers the + Java<sup>TM</sup> Platform, Standard Edition 6 JDK.</li> + </ol> + <p> + <hr> + <p> + </body> +</html> |