| <!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> |