diff options
author | Colin Cross <ccross@android.com> | 2018-02-28 16:19:41 -0800 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2018-02-28 16:21:03 -0800 |
commit | bb7dab15c8f2839694a4ced717ea2102e9a5b2a1 (patch) | |
tree | 01bd432e31d7cf56674aa9b4f2b00ed315386305 /staging/darwin-x86/sample/jmx/jmx-scandir/index.html | |
parent | 9396a3bdcaea77fc7e633b79fad487f76954e90d (diff) | |
download | jdk8-bb7dab15c8f2839694a4ced717ea2102e9a5b2a1.tar.gz |
Switch to JDK build 1.8.0_152-android-4343112-1android-wear-p-preview-2android-p-preview-5android-p-preview-4android-p-preview-3android-p-preview-2android-p-preview-1android-o-mr1-iot-release-1.0.2android-o-mr1-iot-release-1.0.1android-o-mr1-iot-release-1.0.0android-o-mr1-iot-preview-8android-o-mr1-iot-preview-7o-mr1-iot-preview-8o-mr1-iot-preview-7
Test: m EXPERIMENTAL_USE_OPENJDK9=false checkbuild
Test: prebuilts/devtools/tools/ddms on mac
Change-Id: Ib6f865809430e56b788d6e0f4437fb8d603343d0
Diffstat (limited to 'staging/darwin-x86/sample/jmx/jmx-scandir/index.html')
-rw-r--r-- | staging/darwin-x86/sample/jmx/jmx-scandir/index.html | 2217 |
1 files changed, 0 insertions, 2217 deletions
diff --git a/staging/darwin-x86/sample/jmx/jmx-scandir/index.html b/staging/darwin-x86/sample/jmx/jmx-scandir/index.html deleted file mode 100644 index 4fd2ae6..0000000 --- a/staging/darwin-x86/sample/jmx/jmx-scandir/index.html +++ /dev/null @@ -1,2217 +0,0 @@ -<!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> |