summaryrefslogtreecommitdiff
path: root/staging/darwin-x86/sample/jmx/jmx-scandir/index.html
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2018-02-28 16:19:41 -0800
committerColin Cross <ccross@android.com>2018-02-28 16:21:03 -0800
commitbb7dab15c8f2839694a4ced717ea2102e9a5b2a1 (patch)
tree01bd432e31d7cf56674aa9b4f2b00ed315386305 /staging/darwin-x86/sample/jmx/jmx-scandir/index.html
parent9396a3bdcaea77fc7e633b79fad487f76954e90d (diff)
downloadjdk8-bb7dab15c8f2839694a4ced717ea2102e9a5b2a1.tar.gz
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.html2217
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&nbsp;the&nbsp;Java&nbsp;Documentation</a>]
- [<a href="#h2-Overview">Overview&nbsp;of&nbsp;the&nbsp;<i>scandir</i>&nbsp;Example</a>]
- [<a href="#h2-API-Doc">API&nbsp;Documentation&nbsp;and&nbsp;Sources</a>]
- [<a href="#h2-Patterns">Patterns,&nbsp;Best&nbsp;Practices,&nbsp;and&nbsp;Common&nbsp;Pitfalls</a>]
- [<a href="#h2-Testing">Testing&nbsp;the&nbsp;<i>scandir</i>&nbsp;Example</a>]
- [<a href="#h2-Running">Running&nbsp;the&nbsp;<i>scandir</i>&nbsp;Example</a>]
- [<a href="#h2-Playing">Playing&nbsp;with&nbsp;JConsole</a>]
- [<a href="#h2-Turning">Turning&nbsp;the&nbsp;example&nbsp;into&nbsp;a&nbsp;Secure&nbsp;JMX&nbsp;Application</a>]
- [<a href="#h2-Connecting">Connecting&nbsp;to&nbsp;the&nbsp;Secure&nbsp;JMX&nbsp;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&lt;String,DirectoryScannerMXBean&gt; 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&lt;String,ObjectName&gt;</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&lt;String,DirectoryScannerConfig&gt; 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&lt;Notification&gt; notifQueue =
- new LinkedBlockingQueue&lt;Notification&gt;();
-
- 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 &nbsp;-Djava.util.logging.config.file=logging.properties
- &nbsp;-Dscandir.config.file=src\etc\testconfig.xml
- &nbsp;-jar&nbsp;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
- &nbsp;-Djava.util.logging.config.file=logging.properties
- &nbsp;-Djavax.net.ssl.keyStore=keystore
- &nbsp;-Djavax.net.ssl.keyStorePassword=password
- &nbsp;-Djavax.net.ssl.trustStore=truststore
- &nbsp;-Djavax.net.ssl.trustStorePassword=trustword
- &nbsp;-Dcom.sun.management.config.file=src\etc\management.properties
- &nbsp;-Dscandir.config.file=src\etc\testconfig.xml
- &nbsp;-jar&nbsp;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
- &nbsp;-J-Djava.util.logging.config.file=logging.properties
- &nbsp;-J-Djavax.net.ssl.keyStore=keystore
- &nbsp;-J-Djavax.net.ssl.keyStorePassword=password
- &nbsp;-J-Djavax.net.ssl.trustStore=truststore
- &nbsp;-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&lt;String,Object> env = new HashMap&lt;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
- &nbsp;-Djava.util.logging.config.file=logging.properties
- &nbsp;-Djavax.net.ssl.keyStore=keystore
- &nbsp;-Djavax.net.ssl.keyStorePassword=password
- &nbsp;-Djavax.net.ssl.trustStore=truststore
- &nbsp;-Djavax.net.ssl.trustStorePassword=trustword
- &nbsp;-classpath&nbsp;dist/jmx-scandir.jar
- &nbsp;com.sun.jmx.examples.scandir.ScanDirClient&nbsp;localhost&nbsp;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:
-
-&lt;ScanManager xmlns="jmx:com.sun.jmx.examples.scandir.config" name="testconfig">
- &lt;InitialResultLogConfig>
- &lt;LogFileMaxRecords>2048&lt;/LogFileMaxRecords>
- &lt;LogFileName>build/scandir.log&lt;/LogFileName>
- &lt;MemoryMaxRecords>128&lt;/MemoryMaxRecords>
- &lt;/InitialResultLogConfig>
- &lt;DirectoryScannerList>
- &lt;DirectoryScanner name="scan-build">
- &lt;Actions>NOTIFY LOGRESULT&lt;/Actions>
- &lt;ExcludeFiles/>
- &lt;IncludeFiles>
- &lt;FileFilter>
- &lt;FilePattern>.*\.class&lt;/FilePattern>
- &lt;SizeExceedsMaxBytes>4096&lt;/SizeExceedsMaxBytes>
- &lt;/FileFilter>
- &lt;/IncludeFiles>
- &lt;RootDirectory>build&lt;/RootDirectory>
- &lt;/DirectoryScanner>
- &lt;/DirectoryScannerList>
-&lt;/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>