0N/A<!
DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
0N/A Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. 0N/A Redistribution and use in source and binary forms, with or without 0N/A modification, are permitted provided that the following conditions 0N/A - Redistributions of source code must retain the above copyright 0N/A notice, this list of conditions and the following disclaimer. 0N/A - Redistributions in binary form must reproduce the above copyright 0N/A notice, this list of conditions and the following disclaimer in the 0N/A documentation and/or other materials provided with the distribution. 0N/A - Neither the name of Sun Microsystems nor the names of its 0N/A contributors may be used to endorse or promote products derived 0N/A from this software without specific prior written permission. 0N/A THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 0N/A IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 0N/A THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 0N/A PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 0N/A CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 0N/A EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 0N/A PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 0N/A PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 0N/A LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 0N/A NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 0N/A SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0N/A <
title>JMX(TM) "scandir" Example</
title>
0N/A <
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>
0N/A <
h2><
a name="h2-Introduction">Introduction</
a></
h2>
0N/A <
p>The JMX <
i>scandir</
i> example is an application that
0N/A scans parts of a filesystem -
e.g. a set of directories
0N/A used by a number of lab machines when running tests - in
0N/A order to clean up and optimize disk space by removing
0N/A obsolete files -
e.g. files that are leaked by the test
0N/A suites running on those machines, like coredump files, or
0N/A temporary files that might remain after a test crash.
0N/A It could also serve as a basis for an application that
0N/A would monitor disk usage and suggest removal of old big
0N/A long-unaccessed files.
0N/A <
p>The JMX <
i>scandir</
i> example does not however implement
0N/A the full fledged logic that such an application might
0N/A have. It implements a subset of this logic which is
0N/A sufficient to demonstrate common patterns and
0N/A solutions used when implementing a monitoring and
0N/A management interface for an application with JMX
0N/A <
p>This example is an advanced JMX example, which presents
0N/A advanced JMX concepts. It is assumed that the reader is already
0N/A familiar with the JMX API. Newcomers to JMX Technology are
0N/A invited to have a look at the <
a 0N/A >JMX API Overview, Tutorial and Examples</
a> before going any further.
0N/A <
u>Note:</
u> This example was developed using <
a 0N/A given in this document to build, run, and test the example assume that
0N/A you have at your disposal:
0N/A (JUnit is only needed to run the example's unit tests).
0N/A <
p><
a name="setup">In order to build the example</
a>,
0N/A <
u>you may need to copy the jmx-scandir</
u>
0N/A directory to somewhere where you have write permissions.
0N/A <
br>In that case, you will need to update the <
i>
nbjdk.home</
i> variable
0N/A file located at the root of the copied project directory.
0N/A Please make sure that this variable points to the JDK 6 home directory.
0N/A <
p>If you wish to run the testsuite from within the <
a 0N/A version 3.8.1 or 3.8.2.
0N/A <
p><
u>Table Of Contents:</
u></
p>
0N/A <
p><
center>[<
a href="#h2-Generating">Generating the Java Documentation</
a>]
0N/A [<
a href="#h2-Overview">Overview of the <
i>scandir</
i> Example</
a>]
0N/A [<
a href="#h2-API-Doc">API Documentation and Sources</
a>]
0N/A [<
a href="#h2-Patterns">Patterns, Best Practices, and Common Pitfalls</
a>]
0N/A [<
a href="#h2-Testing">Testing the <
i>scandir</
i> Example</
a>]
0N/A [<
a href="#h2-Running">Running the <
i>scandir</
i> Example</
a>]
0N/A [<
a href="#h2-Playing">Playing with JConsole</
a>]
0N/A [<
a href="#h2-Turning">Turning the example into a Secure JMX Application</
a>]
0N/A [<
a href="#h2-Connecting">Connecting to the Secure JMX Application</
a>]
0N/A [<
a href="#h2-Conclusion">Conclusion</
a>]
0N/A [<
a href="#h2-References">References</
a>]</
center></
p>
0N/A <
h2><
a name="h2-Generating">Generating the Java Documentation</
a></
h2>
0N/A <
p>Before reading further, you will need to generate the
0N/A Java Documentation for the example's sources.</
p>
0N/A <
p>In the example root directory (where the <
code>
build.xml</
code>
0N/A file is located) run the following command:
0N/A <
pre>ant javadoc</
pre>
0N/A <
p>Alternatively you can open the jmx-scandir project with the
0N/A NetBeans IDE and generate the Javadoc from its <
code>Build</
code>
0N/A <
p>If building the documentation fails, please make sure to read the
0N/A <
a href="#setup">note</
a> at the beginning of this document.</
p>
0N/A <
h2><
a name="h2-Overview">Overview of the <
i>scandir</
i> Example</
a></
h2>
0N/A <
p>The JMX <
i>scandir</
i> example is built around the
0N/A following MBeans:</
p>
0N/A <
li>The first MBean we will present here is the
0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBean</
a>. <
br>A
0N/A <
code>DirectoryScannerMXBean</
code> is an MBean that scans a
0N/A file system starting at a given root directory, and then looks
0N/A for files that match the given criteria. When such a file is
0N/A found, the <
code>DirectoryScannerMXBean</
code> takes the
0N/A action for which it was configured: emit a notification,
0N/A <
i>
and/
or</
i> log a <
code>record</
code> for this file,
0N/A <
i>
and/
or</
i> delete that file. The code that would actually
0N/A delete the file is commented out - so that nothing valuable is
0N/A lost if the example is run by mistake on the wrong set of
0N/A directories.<
br> <
code>DirectoryScannerMXBeans</
code> are
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> - see next item on the list, from its
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> is the actual entry point of the
0N/A application. It reads the application's
0N/A configuration, and from that configuration,
0N/Atitle="The ResultLogManager is in charge of managing result logs" 0N/A >ResultLogManager</
a> and some <
a 0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBeans</
a>.
0N/A <
br>The <
code>ScanManagerMXBean</
code> lets you start, stop, and
0N/A schedule directory scans. The
0N/A <
code>ScanManagerMXBean</
code> is a singleton
0N/A MBean: there can be at most one instance of such
0N/A an MBean registered in a given MBeanServer.
0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a> is an MBean which is able to
0N/A will also let you modify that configuration - by
e.g. 0N/A creating new directory scanners in there.
0N/A The corresponding MBeans will be created later, only
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> </
code> to apply the
0N/A configuration again.<
br>
0N/A The <
code>ScanDirConfigMXBean</
code> is created by the
0N/A <
code>ScanManagerMXBean</
code>, when the
0N/A <
code>ScanManagerMXBean</
code> is registered.
0N/A It is also possible to create an alternate
0N/A <
code>ScanDirConfigMXBean</
code>, and to switch the
0N/A <
code>ScanDirConfigMXBean</
code> to use one or the other
0N/A <
br>An example of XML configuration file is given
0N/A title="An Example Of Configuration" 0N/A >here</
a>. Although you could edit such a file by
0N/A hand, it is easier to do it programmatically (or
0N/A with <
a href="#JConsole">JConsole</
a>) through
0N/A the <
code>ScanDirConfigMXBean</
code> interface.
0N/Atitle="The ResultLogManagerMXBean is in charge of managing result logs" 0N/A >ResultLogManagerMXBean</
a> is in charge of managing result logs.
0N/A <
br>Directory Scanners can be configured to log a
0N/Atitle="A ResultRecord contains information about a file matching the criteria of a Directory Scanner" 0N/A >ResultRecord</
a> whenever they take action upon a file that
0N/A matches their criteria. The <
code>ResultLogManagerMXBean</
code> is
0N/A responsible for logging these result records.
0N/A The <
code>ResultLogManagerMXBean</
code> can be configured to log
0N/A such records to a flat file, or into a log held in memory, or
0N/A both. Both logs (file and memory) can be configured with a
0N/A <
br>When the maximum capacity of the memory
0N/A log is reached, its first entry (
i.e. its oldest entry) is
0N/A removed to make place for the latest one.
0N/A <
br>When the maximum
0N/A capacity of the file log is reached, the file is
0N/A renamed by appending a tilde '~' to its name and a
0N/A new result log is created.
0N/A <
br>The <
code>ResultLogManagerMXBean</
code>
0N/A will let you interactively clear these result logs, change their
0N/A capacity, and decide where (memory or file) to log.
0N/A The memory log is useful in that its content can be interactively
0N/A returned by the <
code>ResultLogManagerMXBean</
code>, while
0N/A the file log doesn't have this facility.<
br>
0N/A The result logs are intended to be used by
e.g. an offline
0N/A program that would take some actions on the files that
0N/A matched the scan criteria:
0N/A <
br>The <
i>scandir</
i> application
0N/A could be configured to only produce logs (
i.e. takes no
0N/A action but logging the matching files), and the real
0N/A action could be performed by another program or module (
e.g. mail the result log to the engineer who
0N/A maintains the lab, or parse that log and delete all the
0N/A files listed there, or parse the log and prepare and send
0N/A a single mail to each owner of matching files, containing
0N/A the list of files they should consider deleting).<
br>
0N/A The <
code>ResultLogManagerMXBean</
code> is a singleton
0N/A MBean created by the <
code><
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> </
code>
0N/A which reads and writes its configuration from the
0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a></
code>.
0N/A <
p>An application <
code>main()</
code> method is
0N/A >ScanDirAgent</
a> class. The <
code>main()</
code> simply registers
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> </
code> in the platform MBeanServer, and
0N/A then waits for someone to call <
code>close()</
code> on the
0N/A <
code>ScanManagerMXBean</
code>.
0N/A <
p>When the <
code>ScanManagerMXBean</
code> is registered, it
0N/A will create a default <
code><
a 0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a></
code> bound
0N/A to a default XML config file.
0N/A <
p>The application's default XML config file is determined as
0N/A defined, the default application file will be the
0N/A file pointed to by this property. If that file
0N/A doesn't exist, it will be created when
0N/A <
li>Otherwise the application config file is
0N/A located in the user's directory (as defined by
0N/A If that file doesn't exists, it will be created when
0N/A <
p>It is worth noting that this project is defined to
0N/A run with the following properties:
0N/A With <
code>ScanDirAgent</
code> defined as the project's
0N/A main class. Hence when you invoke from the NetBeans IDE
0N/A <
i>Run Project</
i> on the <
i>jmx-scandir</
i> project,
0N/A or <
i>Run file</
i> on the <
code>ScanDirAgent</
code>, the
0N/A application starts with the test configuration provided in
0N/A title="An Example Of Configuration" 0N/A <
h2><
a name="h2-API-Doc">API Documentation and Sources</
a></
h2>
0N/A <
p>Once generated, the Javadoc of example classes can
0N/A title="The API Documentation" 0N/A <
p>You can view the sources in the <
a 0N/A title="The Example Source Tree" 0N/A ><
code>src</
code></
a> subdirectory.</
p>
0N/A <
h2><
a name="h2-Patterns">Patterns, Best Practices, and Common Pitfalls</
a></
h2>
0N/A <
p>This section discusses some common patterns and
0N/A design choices that this example demonstrates, and some pitfalls that
0N/A <
h3>MBeans or MXBeans?</
h3>
0N/A <
p>What is an MXBean? MXBeans made their appearance in
0N/A J2SE 5.0 (Tiger), with the Management and Monitoring
0N/A API of the JVM. However, Java SE 6 is the first
0N/A Java SE release that contains a standard framework which
0N/A makes it possible to create and register your own MXBeans.
0N/A <
p>MXBeans are a special kind of MBean, which once registered
0N/A in the MBeanServer, get automatically transformed into
0N/A OpenMBeans. From a developer point of view, nothing changes:
0N/A A Wombat MBean can become an MXBean simply by renaming
0N/A its <
code>WombatMBean</
code> interface into <
code>WombatMXBean</
code>.</
p>
0N/A <
p>Using MXBeans rather than plain Standard MBean brings its
0N/A Generic tools, like JConsole, will be able to
0N/A display and interact with your MXBeans nicely, even
0N/A if your MXBean interfaces reference custom types
0N/A -
e.g. custom Java enums. This is because all the types
0N/A exposed by your MXBeans are converted to Open Types.
0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a> with JConsole and you will
0N/A understand the benefits.
0N/A When writing a programmatic client, you can obtain
0N/A a proxy that implements the original MXBean interface,
0N/A and forget about the Open Type conversion.
0N/A The JUnit unit tests that come with this example
0N/A use this feature very widely. Have a look at them.
0N/A The MXBean framework also lets you nicely navigate
0N/A from one MXBean to another: your MXBeans can
0N/A have attributes and parameters which are proxies
0N/A to other MXBeans! We demonstrate this in the
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> which exposes a list
0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBean</
a></
code> and points
0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a></
code>.
0N/A <
p>In short, MXBeans are so much easier to use that
0N/A this example doesn't even have a single regular
0N/Atitle="What is an MXBean?" 0N/A >What is an MXBean?</
a>
0N/Atitle="Inter-MXBean references" 0N/A >Inter-MXBean References</
a>.
0N/A <
blockquote><
u>Hint:</
u> In order to simplify the task of coding a
0N/A JMX programmatic client, we recommend that getters, setters, and
0N/A operations defined in MBean and MXBean interfaces throw
0N/A <
code>IOException</
code>. Proxy objects will then be able
0N/A to rethrow directly any <
code>IOException</
code> received from
0N/A their underlying MBean Server connection, without wrapping
0N/A them into <
code>UndeclaredThrowableExceptions</
code>.<
br>
0N/A Since the life cycle of the proxy object is not directly tied to
0N/A the life cycle of the MBean it proxies, you may also want to
0N/A have all methods in the MBean or MXBean interface throw
0N/A <
code>InstanceNotFoundException</
code> or more generally
0N/A <
code>JMException</
code>.
0N/A <
h3>MBean Names - aka ObjectNames</
h3>
0N/A <
p>As you must know if you've been studying JMX, MBeans are
0N/A named objects. The names of MBeans are represented by
0N/A instances of <
code>ObjectName</
code>. An ObjectName is
0N/A composed of a <
i>domain</
i>, followed by a colon ':',
0N/A followed by a comma-separated list of <
i>key=value</
i>
0N/A The ordering of the <
i>key=value</
i> pairs is not
0N/A important, but <
code>ObjectNames</
code> are case sensitive
0N/A (both keys and values are case sensitive) and <
b>white space
0N/A is not ignored</
b>.<
br>
0N/A A common pitfall for JMX beginners is to inadvertently
0N/A insert white space after commas into an ObjectName,
0N/A and expect that two ObjectNames which differ only by such white
0N/A space will be considered identical. This is not the
0N/A As an example, the ObjectName '<
b><
code>D:k1=v1, k2=v2, k3=v3</
code></
b>' has
0N/A three keys, which are '<
b><
code>k1</
code></
b>', '<
b><
code> k2</
code></
b>',
0N/A and '<
b><
code> k3</
code></
b>': beware
0N/A of the space in the name of the second and third
0N/A It is therefore a different ObjectName from
0N/A '<
b><
code>D:k1=v1,k2=v2,k3=v3</
code></
b>' (the keys are now
0N/A '<
b><
code>k1</
code></
b>', '<
b><
code>k2</
code></
b>', and
0N/A '<
b><
code>k3</
code></
b>'), but the same ObjectName as
0N/A '<
b><
code>D: k2=v2, k3=v3,k1=v1</
code></
b>', and yet different
0N/A from '<
b><
code>D:k2=v2, k3=v3, k1=v1</
code></
b>'!
0N/A <
p>In this example, we are following the rules
0N/A for ObjectName suggested in the <
a 0N/A >JMX Best Practices</
a>:</
p>
0N/A <
li>ObjectNames should be <
a 0N/A <
li>The domain part of our ObjectNames starts with a Java
0N/A <
li>Our ObjectNames contain a <
code>type=</
code>
0N/A key property. This property is different for every
0N/A object type in our domain.
0N/A <
li>For every ObjectName with a given type, we have the same set of key
0N/A properties with the same syntax and semantics for their values - in
0N/A fact we only use an additional <
code>name=</
code> key.
0N/A <
li>When there can only be one instance of a given type
0N/A there aren't any other key properties than <
code>type=</
code>.
0N/A The ObjectNames of the <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> and <
a 0N/Atitle="The ResultLogManagerMXBean is in charge of managing result logs" 0N/A >ResultLogManagerMXBean</
a>, which are both singleton MBeans, are
0N/A composed in this way.
0N/A <
li>When there can be several instances of a given type,
0N/A we differentiate them by further key properties.
0N/A To achieve this, we are using the most usual key property
0N/A in addition to <
code>type=</
code>: the <
code>name=</
code> key.
0N/A In this example, a key property list of the form
0N/A <
code>type=X,name=Y</
code> is always enough to uniquely name
0N/A an MBean. Tools like jconsole are usually aware
0N/A of the semantics of the <
code>type=</
code> key and
0N/A <
code>name=</
code> key, and are therefore able to
0N/A display this form of name in a way that
0N/A is easier to read than other name forms.
0N/A <
p>The rules listed above are implemented by a couple
0N/A of static helper functions in the <
a 0N/A >ScanManager</
a> class. See the code of the
0N/A <
b><
code>makeSingletonName</
code></
b> and
0N/A <
b><
code>makeMBeanName</
code></
b> methods.
0N/A <
h3>Inter MBean Navigation</
h3>
0N/A <
p>One of the most common problems that needs to be solved
0N/A when designing a management interface with JMX is to
0N/A choose a representation for inter-MBean relationships.<
br>
0N/A Prior to Java 6, there were basically three possible
0N/A <
li><
b>Make the relation appear in the ObjectName</
b>.
0N/A For instance, if MBean B was contained in
0N/A MBean A, you could choose to name MBean B so
0N/A that its parent relationship with MBean A
0N/A appeared in its name. <
br>
0N/A The obvious limitation of this solution is that
0N/A it only allows to model one such relation (an
0N/A MBean has only one name) and the relation must
0N/A be fixed - it cannot change during the life of
0N/A the MBean since the name of an MBean cannot
0N/A This scheme is therefore mostly used when
0N/A the application MBeans are modeling objects
0N/A which are conceptually contained within
0N/A each other in a tree-like structure.
0N/A <
br>For instance, most MBean names defined by
0N/A >J2EE Management (JSR 77)</
a> follow
0N/A <
li><
b>Design getters and setters (or operations) which
0N/A return <
code>ObjectName</
code> or
0N/A <
code>ObjectName[]</
code> values</
b>. The ObjectNames
0N/A point to the MBeans which are related to that
0N/A object. For instance , <
a 0N/A title="Open Source Java EE 5 Application Server" 0N/A defines MBeans which also use this pattern.
0N/A <
li><
b>Use the JMX RelationService</
b>. The JMX RelationService
0N/A is quite powerful, but simple relationships often
0N/A do not justify that overhead.
0N/A <
p>In Java 6, these three possibilities still remain, but
0N/A the new MXBean framework brings up an interesting
0N/A alternative. Instead of returning an ObjectName or
0N/A an ObjectName array, <
b>an MXBean can return a proxy</
b>
0N/A to its related MXBeans. This is how we have chosen to
0N/A implement our inter MBean relationships in this
0N/A <
br>For instance the
0N/A <
code>ScanManagerMXBean</
code>/<
code>DirectoryScannerMXBean</
code>
0N/A relationship and the
0N/A <
code>ScanManagerMXBean</
code>/<
code>ScanDirConfigMXBean</
code>
0N/A relationships are implemented in this way.
0N/A The additional benefit, as compared to returning ObjectNames or
0N/A using the RelationService is that interface type of the MBeans
0N/A which are pointed to by the relationship becomes directly
0N/A apparent. The method:
0N/A public Map<String,DirectoryScannerMXBean> getDirectoryScanners();
0N/A makes it immediately obvious that the MBeans to which we point are
0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBeans</
a>. It would have been much less obvious in prior
0N/A versions of Java SE, were the returned type would have had to be
0N/A <
code>Map<String,ObjectName></
code>, or
0N/A even worse just <
code>Map</
code>.
0N/A <
p>However, it must be clear that the behaviour will be
0N/A quite different when an MXBean is returned as compared
0N/A to when a simple bean is returned.
0N/A <
p>When an MXBean is returned, the remote client sees either
0N/A an ObjectName, if it is a generic client like jconsole, or
0N/A a proxy to a remote MXBean, if the client is working with the
0N/A MXBean interface. Invoking an operation on one of the
0N/A proxy returned by a method such as
0N/A <
code>getDirectoryScanners</
code> will cause the
0N/A MBean to be invoked on the remote server side.
0N/A <
p>If <
code>getDirectoryScanners</
code> were
0N/A public Map<String,DirectoryScannerConfig> getDirectoryScanners();
0N/A then invoking a method on one of the returned objects
0N/A would have absolutely no effect on the remote
0N/A server side - because the returned objects in this
0N/A case would simply be a bunch of serialized data objects.
0N/A <
p>It is worth noting that although an MXBean interface
0N/A can have getters and operations which return an MXBean
0N/A interface, a regular standard MBean shouldn't have
0N/A any getters or methods which return MBean interfaces or
0N/A <
p>For more information see also <
a 0N/Atitle="Inter-MXBean references" 0N/A >Inter-MXBean References</
a>.
0N/A <
h3>The MBeanRegistration interface, or how an MBean can
0N/A know or provide its own name</
h3>
0N/A Sometimes, an MBean needs to have a reference to the
0N/A MBeanServer in which it is registered, or needs to know
0N/A with which ObjectName it has been registered.
0N/A Sometimes also, an MBean may need to perform some
0N/A checks before being registered, or will need
0N/A to carry out some actions right after it has been
0N/A successfully registered in the MBeanServer.
0N/A Sometimes again, an MBean may need to perform some
0N/A checks, or some cleaning actions, just before, or
0N/A just after, it is unregistered.
0N/A When an MBean has such needs, the easiest solution
0N/A for it is to implement the <
code>MBeanRegistration</
code>
0N/A <
p>The <
code>MBeanRegistration</
code> interface is a callback
0N/A interface which defines pre and post registration and
0N/A unregistration callbacks.
0N/A When an MBean implementing this interface is created
0N/A (with <
code>createMBean</
code>) or registered
0N/A (with <
code>registerMBean</
code>) in an MBeanServer,
0N/A the MBeanServer will call the <
code>preRegister</
code>
0N/A and <
code>postRegister</
code> method implemented by
0N/A the MBean. The <
code>preRegister</
code> method
0N/A has an <
code>MBeanServer</
code> and <
code>ObjectName</
code>
0N/A parameter, which are passed by the MBeanServer to the
0N/A MBean. The MBean can store the reference it is being passed
0N/A in a private instance variable for later use.
0N/A Most of the MXBeans we have defined in this example
0N/A implement the <
code>MBeanRegistration</
code> interface. The table
0N/A below show how our MBeans use this interface to control
0N/A their own names, make sanity checks, perform
0N/A initialization steps or cleanup actions.
0N/A <
table border="1" cellpadding="4" cellspacing="2" 0N/A bgcolor="#eeeeee" width="95%">
0N/A <
tr bgcolor="#cecece">
0N/A <
th width="20%">MBean Requirement</
th>
0N/A <
th>use case example</
th>
0N/A <
td bgcolor="#dedede">get a reference to the MBeanServer</
td>
0N/A <
td><
code>preRegister</
code></
td>
0N/A <
td bgcolor="#fafafa">The <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> needs a reference
0N/A to the MBeanServer in order to create and
0N/A register other MBeans, such as the
0N/Atitle="The ResultLogManagerMXBean is in charge of managing result logs" 0N/A >ResultLogManagerMXBean</
a>, and the
0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBeans</
a>.
0N/A <
td bgcolor="#dedede">reject registration if conditions are
0N/A <
td><
code>preRegister</
code></
td>
0N/A <
td bgcolor="#fafafa">The <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> will throw
0N/A an IllegalArgumentException in <
code>preRegister</
code>
0N/A if the ObjectName it is being passed is
0N/A illegal. Throwing an exception in
0N/A <
code>preRegister</
code> makes the registration fail.
0N/A <
td bgcolor="#dedede">get my client-assigned MBean name</
td>
0N/A <
td><
code>preRegister</
code></
td>
0N/A <
td bgcolor="#fafafa">The <
a 0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a> propagates the
0N/A value of the <
code>name=</
code> property of
0N/A the ObjectName it is given into its
0N/A ScanManagerConfig bean.
0N/A <
td bgcolor="#dedede">provide my own default ObjectName if none
0N/A was given to the MBeanServer
0N/A <
td><
code>preRegister</
code></
td>
0N/A <
td bgcolor="#fafafa">The name that is returned by <
code>preRegister</
code>
0N/A is the ObjectName with which the MBean will be
0N/A eventually registered.
0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a> is able to suggest
0N/A a value for its own ObjectName if none was
0N/A provided. Similarly, the <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a>
0N/A always returns its singleton ObjectName
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A <
td bgcolor="#dedede">perform initialization steps</
td>
0N/A <
td><
code>preRegister</
code></
td>
0N/A <
td bgcolor="#fafafa">The <
a 0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a> uses <
code>preRegister</
code>
0N/A to initialize its internal ScanManagerConfig bean.
0N/A <
td bgcolor="#dedede">perform initialization steps, once it is
0N/A known that the registration was successful.
0N/A <
td><
code>postRegister</
code></
td>
0N/A <
td bgcolor="#fafafa">The <
code>postRegister</
code> method
0N/A can be used to implement
0N/A initialization steps that need to be done once it
0N/A is known that the registration was successful, or to
0N/A undo any action performed by <
code>preRegister</
code> once it
0N/A is known that registration was not successful.
0N/A The <
code>postRegister</
code> method has a Boolean parameter
0N/A which tells the MBean whether it was or wasn't
0N/A successfully registered in the MBeanServer.
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> uses <
code>postRegister</
code> to create
0N/A and register other MBeans, such as the
0N/Atitle="The ResultLogManagerMXBean is in charge of managing result logs" 0N/A >ResultLogManagerMXBean</
a> and the default
0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a>.
0N/A Note that <
code>postRegister</
code> is not expected to throw any
0N/A exception. If an exception needs to be thrown, it should
0N/A be thrown in <
code>preRegister</
code>.
0N/A <
td bgcolor="#dedede">check whether the MBean can be deregistered</
td>
0N/A <
td><
code>preDeregister</
code></
td>
0N/A <
td bgcolor="#fafafa">The <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> uses this method to verify
0N/A that its state allows it to be deregistered.
0N/A In particular, it will refuse to be deregistered
0N/A if it is in the RUNNING or SCHEDULED state.
0N/A If <
code>preDeregister</
code> throws an exception, the unregisterMBean
0N/A call will fail and the MBean will remain registered in
0N/A Take particular care when implementing business logic
0N/A in this method: if the logic you implement has an
0N/A unfortunate bug which makes it always throw an
0N/A exception, you will never be able to unregister
0N/A <
td bgcolor="#dedede">clean up resources, refusing to be deregistered if
0N/A <
td><
code>preDeregister</
code></
td>
0N/A <
td bgcolor="#fafafa">The <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> uses this method to unregister
0N/A all the other MBeans it has created and registered in the
0N/A MBeanServer. This includes the <
a 0N/Atitle="The ResultLogManagerMXBean is in charge of managing result logs" 0N/A >ResultLogManagerMXBean</
a>, the
0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBeans</
a> it has created, and the
0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBeans</
a> it has created when
0N/A applying its configuration.
0N/A <
td bgcolor="#dedede">clean up resources which need to be released in
0N/A a best-effort way, when it is known that the MBean is no
0N/A <
td><
code>postDeregister</
code></
td>
0N/A <
td bgcolor="#fafafa"><
code>postDeregister</
code> is only called if the MBean was succesfully
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> uses this method to cancel
0N/A <
h3>The Singleton MBean Pattern</
h3>
0N/A A singleton MBean is an MBean which can only have one
0N/A instance registered in a given MBeanServer. <
br>
0N/A A singleton MBean usually has a well-known name,
0N/A which can be defined as a constant. In that case,
0N/A clients no longer need to call <
code>new ObjectName(...)</
code>
0N/A and catch the declared <
code>MalformedObjectNameException</
code>.
0N/A <
p>There are already quite a few examples of singleton
0N/A ThreadingMXBean, ClassLoadingMXBean, RuntimeMXBean, etc.
0N/A are all singleton MBeans.
0N/A <
p>In this example, we have two singleton MBeans:
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a></
code> and the
0N/Atitle="The ResultLogManagerMXBean is in charge of managing result logs" 0N/A >ResultLogManagerMXBean</
a></
code>. But in fact,
0N/A the only real singleton MBean is the
0N/A <
code>ScanManagerMXBean</
code>. The
0N/A <
code>ResultLogManagerMXBean</
code> just happens to
0N/A be a singleton MBean because it has a 1-1 relationship
0N/A with the <
code>ScanManagerMXBean</
code>.
0N/A <
p>The <
code>ScanManagerMXBean</
code> implements the
0N/A singleton MBean pattern in this way:
0N/A <
li>The <
code>ScanManagerMXBean</
code> name has a single
0N/A key property: <
code>type=ScanManagerMXBean</
code>.</
li>
0N/A <
li>Its name is defined by an ObjectName constant called
0N/A <
code>SCAN_MANAGER_NAME</
code> in the <
code>ScanManager</
code> class</
li>
0N/A <
li>The <
code>ScanManagerMXBean</
code> enforces its status of
0N/A singleton MBean. It will refuse to be registered
0N/A with a name other than
0N/A the <
code>SCAN_MANAGER_NAME</
code>. You can therefore depend on
0N/A the fact that the <
code>ScanManagerMXBean</
code> will always
0N/A be registered with its singleton <
code>SCAN_MANAGER_NAME</
code>
0N/A (see <
code>preRegister</
code>)
0N/A <
li>You are not obliged to provide a name when you
0N/A register the <
code>ScanManagerMXBean</
code>: if you pass null,
0N/A then the <
code>ScanManager</
code> will be registered with
0N/A its singleton <
code>SCAN_MANAGER_NAME</
code>
0N/A (see <
code>preRegister</
code>).
0N/A <
li>The <
code>ScanManager</
code> class has a no-arg static
0N/A <
code>register</
code> method that will register
0N/A the singleton instance in the Platform MBeanServer.
0N/A This static <
code>register</
code> method returns
0N/A a proxy to the registered singleton.
0N/A <
li>The <
code>ScanManager</
code> class has also a static
0N/A <
code>register</
code> method that will create
0N/A a singleton instance in a (possibly remote)
0N/A MBeanServerConnection - using
0N/A <
code>createMBean</
code>.
0N/A This static <
code>register</
code> method
0N/A also returns a proxy to the registered singleton.
0N/A <
li>Only the MBeanServer has a reference to the
0N/A singleton instance. The singleton instance is
0N/A not returned to the caller, and not kept
0N/A in any other static data structure.
0N/A On the other hand, the <
code><
a 0N/Atitle="The ResultLogManagerMXBean is in charge of managing result logs" 0N/A >ResultLogManagerMXBean</
a></
code>
0N/A has a much more relaxed implementation of the pattern:
0N/A <
br>It simply provides its own singleton name if it is
0N/A registered with a null ObjectName, but will not enforce
0N/A the use of that name.
0N/A <
p>Note that all singleton MBean names in this example
0N/A method, which implements the pattern for ObjectNames suggested
0N/A in the JMX Best Practices.
0N/A <
h3>Managing the Life Cycle of dependent MBeans</
h3>
0N/A <
p>A common task that many JMX applications have
0N/A is to manage the life cycle of MBeans registered
0N/A in the MBeanServer.</
p>
0N/A <
p>In this example, we have decided to follow a simple
0N/A <
li>The application is initialized simply
0N/A by registering the singleton
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> in
0N/A <
li>The <
code>ScanManagerMXBean</
code> will then
0N/A in turn register any other MBean that the
0N/A application might need:
0N/A <
li>It creates and registers the singleton
0N/Atitle="The ResultLogManagerMXBean is in charge of managing result logs" 0N/A >ResultLogManagerMXBean</
a></
code>
0N/A <
li>It creates and registers the default
0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a></
code>
0N/A which loads the initial configuration
0N/A <
li>It creates as many
0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBeans</
a></
code> as
0N/A needed when the configuration is applied
0N/A <
li>It lets you create alternate
0N/A <
code>ScanDirConfigMXBean</
code>, to
0N/A which you can later switch in order
0N/A to apply a new alternate configuration.
0N/A <
li>When a new configuration is applied (or if the
0N/A current configuration is reapplied), the
0N/A <
code>ScanManagerMXBean</
code> will unregister
0N/A any <
code>DirectoryScannerMXBeans</
code> it has
0N/A previously registered, and will re-create
0N/A brand new <
code>DirectoryScannerMXBeans</
code>
0N/A from the applied configuration.
0N/A <
li>When you unregister the <
code>ScanManagerMXBean</
code>,
0N/A it does all the cleanup for you, by unregistering
0N/A all the MBeans that it has created during the
0N/A course of the application.
0N/A <
p>The <
code>ScanManagerMXBean</
code> makes use of its
0N/A <
code>MBeanRegistration</
code> interface in order
0N/A to register the other MBeans it needs (see the
0N/A <
p>You will note that the <
code>ScanManagerMXBean</
code>
0N/A will only allow itself to be deregistered if it can be
0N/A closed - that is if there's no other action in
0N/A This is to make sure that the deregistration of
0N/A dependent MBeans will work smoothly.
0N/A The deregistration of related MBeans will happen
0N/A If one of these MBeans could not be deregistered,
0N/A then the <
code>ScanManagerMXBean</
code> will throw
0N/A an exception, refusing to be deregistered.
0N/A <
br>This leaves you a chance to try to deregister it
0N/A again later. Since the <
code>ScanManagerMXBean</
code>
0N/A has switched its state to CLOSED before starting
0N/A to unregister its dependent MBeans, it will refuse
0N/A any further actions, ensuring that
e.g. nobody
0N/A can try to start it or schedule it while it
0N/A is in that partially-deregistered state.
0N/A <
p>Handling the LifeCycle of all the application's
0N/A MBeans in a single MBean is usually a good design
0N/A pattern, especially if the application is a
0N/A module which is intended to share a JVM - or
0N/A an MBeanServer - with other modules.
0N/A <
p>This is specially useful if the application needs to
0N/A be loaded and unloaded on demand: in that
0N/A case, simply registering or unregistering the top level
0N/A MBean (in our example the <
code>ScanManagerMXBean</
code>) does
0N/A <
h3>Emitting Notifications</
h3>
0N/A <
p>In order to emit notifications, an MBean must be
0N/A an instance of <
code>NotificationEmitter</
code>.
0N/A The <
code>NotificationEmitter</
code> interface defines methods
0N/A that the MBeanServer will call on the MBean in order
0N/A to register <
code>NotificationListeners</
code> with the MBean.
0N/A <
p>It is worth noting that the MBean may not be
0N/A invoked each time a JMX client wants to register
0N/A a listener. For instance, the RMIConnectorServer
0N/A registers <
i>only once</
i> a single listener with each MBean
0N/A which is a <
code>NotificationEmitter</
code>.
0N/A In that specific case, the listener may even be registered
0N/A with the MBean before any client has actually subscribed
0N/A for notifications from that particular MBean.
0N/A <
p>An MBean can therefore make no assumption about
0N/A which client or how many clients have registered for
0N/A <
p>It is also worth noting that the logic of the
0N/A methods defined in <
code>NotificationEmitter</
code> would not
0N/A be trivial to implement from scratch. Fortunately
0N/A the JMX API defines a helper class, called
0N/A <
code>NotificationBroadcasterSupport</
code>, which
0N/A provides an implementation for these methods.
0N/A <
p>There are actually three ways for an MBean to
0N/A implement <
code>NotificationEmitter</
code>, of which only two
0N/A <
h4>Extending NotificationBroadcasterSupport</
h4>
0N/A <
p>This is the simplest way of coding an MBean which
0N/A is a <
code>NotificationEmitter</
code>:
0N/A <
p>Simply extend <
code>NotificationBroadcasterSupport</
code>,
0N/A then override its <
code>getNotificationInfo</
code> method
0N/A which returns the <
code>MBeanNotificationInfo[]</
code> array
0N/A that should be included in your MBean's <
code>MBeanInfo</
code>
0N/A <
br>You just need to call the <
code>sendNotification</
code> method
0N/A inherited from <
code>NotificationBroadcasterSupport</
code> whenever
0N/A your MBean needs to send a notification.
0N/A <
p>In our example, both the <
a 0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a> and <
a 0N/Atitle="The ResultLogManagerMXBean is in charge of managing result logs" 0N/A >ResultLogManagerMXBean</
a> extend
0N/A <
code>NotificationBroadcasterSupport</
code> in order
0N/A to send notifications.
0N/A <
h4>The Delegation Pattern: delegating to a
0N/A NotificationBroadcasterSupport delegate</
h4>
0N/A <
p>There may be cases however where delegating to a
0N/A wrapped <
code>NotificationBroadcasterSupport</
code>
0N/A object may be preferred to extending
0N/A <
code>NotificationBroadcasterSupport</
code>.
0N/A <
p>For instance, if your MBeans already derive from
0N/A some base class, extending <
code>NotificationBroadcasterSupport</
code>
0N/A might not be an option.
0N/A <
p>Similarly, if you do not want to have the inherited
0N/A <
code>public void sendNotification(Notification notification)</
code>
0N/A method appear in the Javadoc of the concrete class of your
0N/A MBean, you may want to consider using the delegation
0N/A pattern instead of extending
0N/A <
code>NotificationBroadcasterSupport</
code>
0N/A <
p>In our example both the <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> and the <
a 0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBean</
a> use the delegation
0N/A pattern rather than extending
0N/A <
code>NotificationBroadcasterSupport</
code>.
0N/A In the end, choosing between one or the other method
0N/A is more a question of taste, although the delegation
0N/A pattern could be considered more flexible since it
0N/A doesn't require extending any given superclass.
0N/A <
p>It may be also worth noting that some tools like
0N/A the JMX Module of <
a 0N/A >NetBeans IDE</
a>, will be able to
0N/A generate for you all the code that delegates to a
0N/A wrapped <
code>NotificationBroadcasterSupport</
code>.
0N/A <
h4>Implementing NotificationEmitter from scratch</
h4>
0N/A <
p>This is the last possibility for an MBean that
0N/A needs to send notifications: simply implement
0N/A <
code>NotificationEmitter</
code> from scratch. This is highly
0N/A discouraged since that logic is not trivial, and
0N/A <
code>NotificationBroadcasterSupport</
code> anyway.
0N/A <
h4>Beware of Synchronization Locks</
h4>
0N/A <
p>One thing you must keep in mind when sending
0N/A notifications is not to send them from within
0N/A a synchronized block, or while holding a lock on
0N/A <
p>Indeed, what happens when you send a notification
0N/A may vary greatly depending on whether the client
0N/A which has registered for notifications has done
0N/A so through a <
code>JMXConnector</
code> (like the
0N/A <
code>JMXRMIConnector</
code>)
0N/A or through a direct reference to the MBeanServer
0N/A <
p>In this latter case, the listener will be invoked
0N/A synchronously in the same thread that your MBean is
0N/A using to send its notification. If by misfortune, the
0N/A code of that listener now re-enters your MBean through a
0N/A call that flows through a JMXConnector, a deadlock
0N/A could occur. It is therefore very important to release
0N/A any lock you may have before calling
0N/A <
code>sendNotification</
code>.</
p>
0N/A <
p>An easy way to do that is demonstrated in the
0N/A <
code>ScanManager</
code> class. The ScanManager
0N/A has an internal private queue of pending notifications.
0N/A When a notification needs to be sent (
e.g. because the
0N/A ScanManager state is being switched), the notification
0N/A is simply prepared and put into the pending notification
0N/A The notification queue is then processed later on,
0N/A at the end of the method, when the processing is finally
0N/A completed and all the locks have been released.
0N/A <
br>At this point the notification queue might already
0N/A have been emptied by another thread - in which case
0N/A the pending notifications will have already been
0N/A removed from the queue. Which thread actually gets
0N/A to send the notifications is of no importance. The
0N/A important point is that all the locks detained by
0N/A your MBean code in that thread were released before
0N/A the notification was sent.
0N/A <
p>In our example the <
code>ScanManager</
code> class
0N/A <
li>Only calling <
code>sendNotification</
code>
0N/A in its private <
code>sendQueuedNotifications</
code>
0N/A <
li>Only calling <
code>sendQueuedNotifications</
code>
0N/A when all locks have been released.
0N/A <
li>Never calling a method that calls
0N/A <
code>sendQueuedNotifications</
code> from within
0N/A a synchronized block.</
li>
0N/A <
h4>Don't subclass Notification</
h4>
0N/A <
p>Another common best practice when you want
0N/A to improve interoperability is to use directly
0N/A the Notification base classes provided in the
0N/A JMX<
sup>TM</
sup> API. Do not create your own
0N/A subclasses of these standard classes.
0N/A <
p>Indeed, if you code your own subclass, a generic
0N/A client, like jconsole, will not be able to receive
0N/A that notification unless it has that custom
0N/A subclass in its classpath.
0N/A If you want your application to be interoperable, it is
0N/A therefore preferable not to subclass any of the standard
0N/A Notification classes. You can define your own
0N/A Notification type string, and if you need to send
0N/A additional data, you can put a CompositeData, or a
0N/A HashMap of serializable standard types in the
0N/A Notification's user data fields.
0N/A <
p>In this example, we are using directly the
0N/A standard notification classes:
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> and the <
a 0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBean</
a> both use directly
0N/A <
code>AttributeChangeNotification</
code> to notify
0N/A changes in their <
code>State</
code> attribute.
0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBean</
a>
0N/A also uses the base <
code>Notification</
code>
0N/A class directly in order to notify whenever
0N/A it finds a matching file.
0N/A <
br>In that case, we simply use the base
0N/A <
code>Notification</
code>
0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a> and <
a 0N/Atitle="The ResultLogManagerMXBean is in charge of managing result logs" 0N/A >ResultLogManagerMXBean</
a> also both use the base
0N/A <
code>Notification</
code> class.
0N/A <
p>Careful readers will have noted that the <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> and the <
a 0N/Atitle="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." 0N/A >DirectoryScannerMXBean</
a> both use the
0N/A <
code>AttributeChangeNotification</
code> class
0N/A to notify about their state change, whereas the
0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a> uses the base
0N/A <
code>Notification</
code> class.
0N/A <
p>In fact, this is because the semantics of these
0N/A notifications is not exactly the same - although
0N/A both denote a state change:
0N/A <
p>In the case of <
code>ScanManagerMXBean</
code>
0N/A and <
code>DirectoryScannerMXBean</
code>, the
0N/A notification which is emitted is more about a
0N/A state transition, from one state to another.
0N/A For instance, going from <
code>RUNNING</
code>
0N/A to <
code>STOPPED</
code>, or from
0N/A <
code>SCHEDULED</
code> to <
code>STOPPED</
code>.
0N/A <
br>In that case, the
0N/A <
code>AttributeChangeNotification</
code> was
0N/A more appropriate because it made it possible
0N/A to send the previous and the new value of the
0N/A state attribute, thus reflecting the whole
0N/A <
p>In the case of the <
code>ScanDirConfigMXBean</
code>
0N/A however, what is of interest is the state in
0N/A which the MBean has arrived. Using the base
0N/A <
code>Notification</
code> class with three different
0N/A notification type strings -
0N/A was therefore closer to what we wanted to model.
0N/A <
h3>Configuration MBeans</
h3>
0N/A <
p>A common practice when designing a management application is
0N/A to have an MBean, or a set of MBeans, dedicated to configuration.
0N/A Separating configuration from control and monitoring allows
0N/A more appropriate logic, and often simplifies the design and
0N/A implementation of the management interface.
0N/A In our example, the <
a 0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a> is dedicated to the application configuration.
0N/A <
p>The <
code>ScanDirConfigMXBean</
code> will let you interactively
0N/A modify, save, or load the application configuration. The modifications
0N/A will not be taken into account until it is applied, by invoking
0N/A <
code>applyConfiguration</
code> on the <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a>.
0N/A It is also possible to create many configurations, by creating as
0N/A many <
code>ScanDirConfigMXBean</
code>s, and then to choose and apply
0N/A one of these configurations by calling
0N/A <
p>In this way, all configurations aspects are gathered and concentrated
0N/A inside the <
code>ScanDirConfigMXBean</
code> instead of being scattered
0N/A throughout all the MBeans that compose the application.
0N/A <
p>In order to save and store the application configuration data, the
0N/A <
code>ScanDirConfigMXBean</
code> uses a set of XML serializable Java beans
0N/A simple Java beans which have been lightly annotated for XML binding.
0N/A <
p>It is worth noting that these same beans can also be handled by the
0N/A MXBean framework (our beans don't contain recursive data structures) and can
0N/A therefore be used directly as attributes and parameters of MXBeans, without
0N/A needing to be Java-serializable (the MXBean framework transform them in
0N/A CompositeData objects - which <
b>are</
b> serializable).
0N/A >ScanManagerConfig</
a> bean that we use to read from and write to the
0N/A XML configuration file is thus also used as attribute of the <
a 0N/Atitle="The ScanDirConfigMXBean is in charge of the configuration" 0N/A >ScanDirConfigMXBean</
a>. It is transformed into a <
code>CompositeData</
code>
0N/A by the MXBean framework, and can be easily introspected with
0N/A <
a href="#JConsole">jconsole</
a>.
0N/A <
h3>MBeans Must Be Thread-Safe</
h3>
0N/A <
p>A question often asked by newcomers to JMX technology
0N/A is whether the MBeanServer is thread-safe. Well, the MBeanServer <
b>is</
b>
0N/A thread safe, but it doesn't put any locks on the MBeans it contains. The
0N/A MBeans can be concurrently accessed by multiple threads, and must therefore
0N/A take care of their own thread safety.
0N/A <
p>In this example, we have been using two methods to ensure thread
0N/A safety for our MBeans: synchronized blocks, and semaphores.
0N/A <
p>Using synchronized blocks is probably the most common and easiest way
0N/A to implement thread safety in Java. When dealing with MBeans though, here
0N/A are a couple of rules to keep in mind:
0N/A <
li>Don't send notifications from within a synchronized block: there's
0N/A no way to tell whether the listener's code will be executed in the
0N/A same thread or a different thread, and holding a lock in these
0N/A conditions is therefore dangerous, as it could lead to deadlocks.</
li>
0N/A <
li>Also avoid invoking another MBean from a synchronized block
0N/A unless you are completely in control of both MBeans, and you can
0N/A ascertain that it won't lead to any deadlock. Indeed, if you invoke an
0N/A MBean exposed by another application, it can be sometime hard to
0N/A know with certainty whether holding a lock while invoking that
0N/A MBean will have any side effect. Maybe that MBean will make
0N/A further calls to other MBeans which will in turn try to call
0N/A your MBean, or maybe it will emit a
0N/A notification, and we'll be back to the considerations just
0N/A <
p>Another means of implementing thread-safe code is to use semaphores.
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> uses a semaphore called
0N/A <
code>sequencer</
code> to ensure
0N/A that critical code sections are not executed concurrently. In this
0N/A semaphore before entering the critical section. If the
0N/A section. If it returns false, we throw an IllegalStateException, stating
0N/A that we couldn't acquire the lock. The code looks like this:
0N/A throw new IllegalStateException("resource locked");
0N/A // critical code here ...
0N/A // will be released, even if exceptions or errors are raised!
0N/A the semaphore is already locked makes it safer to call other MBeans
0N/A from within the critical section: in potential deadlock situations
0N/A the calling code will get the <
code>IllegalStateException</
code>
0N/A instead of being blocked on the deadlocked lock.
0N/A <
p>It is worth noting that each of these techniques has its own
0N/A advantages and disadvantages - which can make one of them more or less
0N/A appropriate depending on the inner logic of the MBean you're implementing.
0N/A <
p>Careful readers will also have noted that we used
0N/A <
code>IllegalStateException</
code> directly, instead of defining
0N/A our own subclass of RuntimeException, which could have had a more
0N/A precise semantics. If you define a new exception for your JMX application,
0N/A you must keep in mind that your client will need to have the class
0N/A of your exception in its classpath to get that exception.
0N/A Otherwise your client will get a completely different exception, indicating a
0N/A deserialization issue.
0N/A <
h3>Waiting for Notifications</
h3>
0N/A <
p>Implementing code that needs to wait for notifications is sometimes
0N/A difficult. Because notifications are asynchronous, doing something
0N/A // register a notification listener
0N/A // start a management action
0N/A // wait for a notification
0N/A // do something based on whether the expected notification
0N/A is not always trivial. However, there's a very easy way to do that: use
0N/A a blocking queue of notifications.
0N/A final BlockingQueue<Notification> notifQueue =
0N/A new LinkedBlockingQueue<Notification>();
0N/A final NotificationListener listener = new NotificationListener() {
0N/A public void handleNotification(Notification notification,
0N/A // Just put the received notification in the queue.
0N/A // It will be consumed later on.
0N/A } catch (InterruptedException ex) {
0N/A // register the listener - possibly also as a JMXConnectionNotification
0N/A // listener to get Notification Lost notification
0N/A // start management action
0N/A // wait for notification
0N/A while (expected notif not received and delay not expired) {
0N/A // if expected notif, do something
0N/A // if expected notification not received do something else.
0N/A <
p>You will note that this is a technique we've been using in the <
a 0N/Atitle="The ScanDirAgent class defines a main method for the scandir application" 0N/A >ScanDirAgent</
a> class and in the example unit tests.
0N/A <
h3>Holding hard references to other MBeans: proxy or direct reference?</
h3>
0N/A <
p>We have seen that MXBeans will let you return proxy references to other
0N/A MXBeans. But should that MXBean hold a direct reference to the MXBeans it
0N/A relates to, or would it be better for it to hold only a proxy?
0N/A As a general rule it is better when an MBean reference is
0N/A only held by the MBeanServer. It is a better design
0N/A to hold a reference to a proxy, rather than to hold
0N/A a hard reference to an MBean. However there are two cases
0N/A when holding a hard reference might be preferred:
0N/A <
li>When MBean A needs to call a method of method B which
0N/A is not part of its MBean interface</
li>
0N/A <
li>When the overhead of going through the MBeanServer
0N/A plus the MXBean framework is too great (frequently-called
0N/A method, with creation of OpenType)</
li>
0N/A However - holding a hard reference is only advisable
0N/A when both MBeans are created by the same piece of code,
0N/A and the application can ensure that the life cycle
0N/A of each MBean is consistent with regard to the other.
0N/A <
p>In our example, the <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> holds only proxy references to the <
a 0N/A >ScanDirConfigMXBean</
a> and the <
a 0N/A >DirectoryScannerMXBeans</
a>. <
br>
0N/A However it holds a direct reference to the <
a 0N/A >ResultLogManager</
a>. This makes it possible to pass a direct
0N/A reference to the <
code>DirectoryScannerMXBeans</
code>,
0N/A which can then log their results
0N/A more efficiently, and would also make it possible to remove
0N/A the <
code>log</
code> method from the <
a 0N/A >ResultLogManagerMXBean</
a> interface - leaving it in the
0N/A <
code>ResultLogManager</
code> class (possibly as a package method)
0N/A should we wish to do so.
0N/A <
h3>Agent Class</
h3>
0N/Atitle="The ScanDirAgent class defines a main method for the scandir application" 0N/A >ScanDirAgent</
a> is the Agent class for the <
i>scandir</
i> application.
0N/A This class contains the <
code>main</
code> method to start a standalone
0N/A <
i>scandir</
i> application.
0N/A <
p>The <
code>main</
code> method simply registers a <
a 0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a> in the platform MBeanServer, and then waits
0N/A When the <
code>ScanManagerMXBean</
code> state is switched to
0N/A <
code>ScanManagerMXBean</
code> is unregistered, and the application
0N/A terminates (
i.e. the main thread completes).
0N/A <
p>Standalone JMX applications usually have an Agent class that contain
0N/A their <
code>main</
code> method, which performs all the MBean
0N/A However, it is usually not a bad idea if that class can
0N/A be easily turned into an MBean. Indeed, this will make your
0N/A application easier to integrate in an environment where it would
0N/A no longer be standalone and would no longer control the implementation
0N/A of <
code>main</
code>. In our example the Agent
0N/A class could be easily turned into an MBean, exposing its three
0N/A <
code>init</
code>, <
code>waitForClose</
code> and <
code>cleanup</
code>
0N/A method. However we didn't go as far as turning it into an MBean since
0N/A the application can be already easily started by registering an instance
0N/Atitle="The ScanManagerMXBean is the main MBean of the scandir application" 0N/A >ScanManagerMXBean</
a>.
0N/A <
h3>Secure Client Class</
h3>
0N/Atitle="The ScanDirClient class is a very short example of secure programatic client" 0N/A >ScanDirClient</
a> is an example class that shows how a
0N/A programmatic client can connect to a secured <
i>scandir</
i> application.
0N/A This class contains a <
code>main</
code> method which creates and
0N/A configures a <
code>JMXConnector</
code> client to connect with
0N/A a secured <
i>scandir</
i> daemon. This class will not work with
0N/A the default unsecured agent since it requires mutual authentication.
0N/A <
p>How to secure a JMX <
i>scandir</
i> application and run
0N/A the secure <
code>ScanDirClient</
code> is discussed <
a href="#secure" 0N/A >later</
a> in this document.
0N/A <
p>The <
code>ScanDirClient</
code> is not really part of the
0N/A application - and is given here only for the sake of
0N/A <
h2><
a name="h2-Testing">Testing the <
i>scandir</
i> Example</
a></
h2>
0N/A <
p>Make sure that you have access to
junit.jar (either 3.8.1 or 3.8.2).
0N/A <
code>CLASSPATH</
code>.<
br>
0N/A Then in the example root directory (where the <
code>
build.xml</
code>
0N/A file is located) run the following command:
0N/A <
p>Alternatively you can open the jmx-scandir project with the
0N/A NetBeans IDE and test the jmx-scandir project from the
0N/A <
code>Run</
code> menu.
0N/A <
h2><
a name="h2-Running">Running the <
i>scandir</
i> Example</
a></
h2>
0N/A <
p>In the example root directory (where the <
code>
build.xml</
code>
0N/A file is located) run the following commands:
0N/A or simply <
pre>ant run</
pre>
0N/A <
p>This will run the example using the configuration
0N/A <
p>Alternatively you can open the jmx-scandir project with the
0N/A NetBeans IDE. You can run the example by
0N/A selecting the <
code>ScanDirAgent</
code> file
0N/A and run it with <
code>Run File</
code> in the
0N/A <
code>Run</
code> menu or simply
0N/A set the <
i>jmx-scandir</
i> project as main project and
0N/A select <
code>Run Main Project</
code> from the
0N/A main menu. Both targets will use the configuration
0N/A <
p>When the application is started, you can connect to
0N/A it with <
a href="#JConsole">jconsole</
a>.
0N/A <
u>Note:</
u> You can also run the <
i>scandir</
i>
0N/A application directly from the <
code>java</
code>
0N/A command line. Make sure to build the project jar
0N/A <
br>On Unix systems:
0N/A <
br>On Windows systems:
0N/A <
p><
code>ant jar<
br>
0N/A <
h2><
a name="h2-Playing">Playing with JConsole</
a></
h2>
0N/A <
p>Run the example as explained in the previous section, so
0N/A configuration file. Then start
0N/A jconsole. In the connection window choose the process that runs
0N/A <
table border="0" cellpadding="2" cellspacing="2">
0N/A title="jconsole connection window - connect to local process" 0N/A alt="jconsole connection window - connect to local process" 0N/A title="jconsole connection window - connect to local process" 0N/A alt="jconsole connection window - connect to local process" 0N/A <
p>Open the MBeans tab, and look for the
0N/A <
code>ScanDirConfigMXBean</
code>.
0N/A Click on its <
code>Attributes</
code> node and double click on its
0N/A <
code>Configuration</
code> attribute, to look at
0N/A the loaded configuration - values in bold can
0N/A be expanded by a double-click.
0N/A title="jconsole MBean tab: ScanDirConfigMXBean" 0N/A alt="jconsole MBean tab: ScanDirConfigMXBean" 0N/A <
p>Now go to the <
code>ScanManagerMXBean</
code>, click on
0N/A its <
code>Notifications</
code> node, and subscribe
0N/A for notifications. Then click on the
0N/A <
code>Operations</
code> node and invoke the
0N/A <
code>start()</
code> operation:
0N/A title="jconsole MBean tab: ScanDirConfigMXBean" 0N/A alt="jconsole MBean tab: ScanDirConfigMXBean" 0N/A <
p>You can see that the notifications counter was
0N/A incremented by three: you have just scheduled,
0N/A run, and completed a batch of directory scans.
0N/A <
p>Now go to the <
code>ResultLogManagerMXBean</
code>,
0N/A click on its <
code>Attributes</
code> node, and
0N/A expand its <
code>MemoryLog</
code> attribute:
0N/A title="jconsole MBean tab: ScanDirConfigMXBean" 0N/A alt="jconsole MBean tab: ScanDirConfigMXBean" 0N/A <
p>You can see that the directory scan results have
0N/A <
p>To make the application terminate go back to the
0N/A <
code>ScanManagerMXBean</
code> and invoke
0N/A <
code>close()</
code>. The <
code>ScanDirAgent</
code>
0N/A will receive the notification, step out of
0N/A the application main thread, and the application
0N/A <
p>This is of course a very limited scenario. Feel free
0N/A to improvise with all the features of the example, creating
0N/A a new configuration -
0N/A adding multiple directory scanners to that configuration -
0N/A then switching the <
code>ScanManagerMXBean</
code> current
0N/A configuration by changing the value of the <
i>ConfigurationMBean</
i>
0N/A - then applying the new configuration -
0N/A then scheduling repeated directory scans every 10 seconds -
0N/A subscribing for notifications, etc...
0N/A <
a name="secure"></
a>
0N/A <
h2><
a name="h2-Turning">Turning the example into a Secure JMX Application</
a></
h2>
0N/A <
p>In this section, we will see how to configure and
0N/A start the <
i>scandir</
i> example so that the JVM agent
0N/A is bootstrapped with a secure JMXConnectorServer. Indeed, until
0N/A now we have only used the insecure local connection,
0N/A which can only be used as long as both the client and
0N/A the server run on the same machine. This section will
0N/A explain how to start the <
code>ScanDirAgent</
code> so
0N/A that a real secure RMIConnectorServer is started at bootstrap.
0N/A href="#password-access">create our own password and access files</
a>,
0N/A <
a href="#keystore-truststore">provide a keystore and truststore</
a>,
0N/A <
a href="#start-secure-agent">start the ScanDirAgent with the
0N/A appropriate system properties</
a>.
0N/A <
h3>Configuring the JVM Agent for Secure Remote Connection</
h3>
0N/A JVM Agent</
a> for Secure Remote
0N/A Connection is to use your own <
a 0N/A In this example, we have copied the default
0N/A file to the example's <
code>
src/
etc</
code> directory and
0N/A <
li>We have set the RMI port to <
u>4545</
u> - this is just a
0N/A random port number we have picked up. Feel free to use your
0N/A own value suited to your environment.
0N/A <
pre># For setting the JMX RMI agent port use the following line
0N/A <
li>We have <
u>switched on</
u> SSL <
u>mutual authentication</
u>
0N/A <
pre># For RMI monitoring with SSL client authentication use the following line
0N/A <
li>We have also <
u>secured the RMI Registry</
u> with SSL
0N/A <
pre># For using an
SSL/
TLS <
b>protected</
b> RMI Registry use the following line
0N/A <
li>We have provided <
a 0N/A <
pre># For a non-default password file location use the following line
0N/A <
li>We have provided <
a 0N/A <
pre># For a non-default password file location use the following line
0N/A <
p>You will note that we haven't provided any value
0N/A for the other security properties, like
0N/A because these properties already default to a value
0N/A which enables security by default.
0N/A Note however that protecting the RMI Registry with SSL
0N/A improves the application security, but only as long as
0N/A mutual authentication is also switched on. Otherwise, just
0N/A anybody would be able to connect to the registry and
0N/A get the RMIServer stub.
0N/A <
p>We do recommend that you <
u>use the most secure configuration
0N/A when you deploy a JMX agent</
u> - which means <
u>switching on
0N/A SSL protection for the RMI registry</
u> <
b>and</
b> <
u>requiring
0N/A mutual authentication</
u>, as we show in this example.
0N/A system property to pass our <
a 0N/A file to the <
code>ScanDirAgent</
code>.
0N/A <
h3>Creating a password and access file</
h3>
0N/A <
p>As explained above, we have created our own
0N/A for <
a name="password-access">access control and authorization</
a>.
0N/A <
p>In the password file, we have defined two logins:
0N/A <
i>guest</
i> and <
i>admin</
i>. The password for
0N/A <
i>guest</
i> is <
i>guestpasswd</
i> and the password
0N/A for <
i>admin</
i> is <
i>adminpasswd</
i>.
0N/A <
p>In the access file, we have mapped these two logins
0N/A to access rights: the <
i>admin</
i> login has <
i>read-write</
i>
0N/A access, while the <
i>guest</
i> login only has <
i>read-only</
i>.
0N/A <
p>Before starting the <
code>ScanDirAgent</
code>, you will
0N/A need to restrict access permission to the password file,
0N/A in such a way that nobody but you can read it. Otherwise, the
0N/A JVM Agent will refuse to start the JMXConnectorServer, as it will
0N/A fear that security can be compromised if other parties can
0N/A have read access to the password file. How to restrict
0N/A read access to the password file is explained in detail
0N/A title="Using Password and Access Files" 0N/A <
p>As we have seen above, the location
0N/A of our access and password files is configured in our own <
a 0N/A <
h3>Keystore and Truststore</
h3>
0N/A <
p>Using SSL with mutual authentication means that both
0N/A client and server will need a <
a name="keystore-truststore" 0N/A >keystore and a truststore</
a>
0N/A to store their own certificates, and the certificates of
0N/A the parties they trust. Usually, client and server will
0N/A have their own keystore and truststore.
0N/A <
p>For the sake of simplicity - and to get you started
0N/A without the tedious necessity of creating your own keystore
0N/A and truststore, we are providing a dummy keystore and
0N/A truststore, containing a certificate self-signed by duke.
0N/A The password for our keystore is <
i>password</
i>, and the
0N/A password for our truststore is <
i>trustword</
i>.
0N/A We suggest that you first get the example running with the
0N/A keystore and truststore we are providing before attempting
0N/A to use your own keystore and truststore.
0N/A <
p>A secure application will obviously need to use its own
0N/A keystore and truststore, <
b><
u>and should not rely on the keystore
0N/A and truststore we are providing here!</
u></
b>
0N/A <
p>How to create your own keystore and truststore, is explained
0N/Atitle="Monitoring and Management Using JMX" 0N/A As shown <
a href="#start-secure-agent">later</
a>,
0N/A we will need to use <
a 0N/A >system properties</
a> to pass our truststore
0N/A and keystore to the <
code>ScanDirAgent</
code>.
0N/A <
h3>Starting a Secure <
i>scandir</
i> agent</
h3>
0N/A <
p>To start a <
a name="start-secure-agent" 0N/A >secure <
i>scandir</
i> agent</
a>, go to the
0N/A <
i>scandir</
i> example root directory and type the
0N/A following command:</
p>
0N/A <
p>On Windows Systems:
0N/A <
p>If you start jconsole now, you will see that you
0N/A are still able to connect to the agent using the
0N/A local connection. However, if you try to connect
0N/A through the remote connector, using
0N/A pair. Indeed, since the JMXConnectorServer is now protected with SSL,
0N/A jconsole must also be configured with the appropriate SSL parameters
0N/A so that it can authenticate the server and get authenticated by the
0N/A server too as the SSL configuration of the server requires mutual
0N/A <
p>The next section will discuss how to connect to the
0N/A <
h2><
a name="h2-Connecting">Connecting to the Secure JMX Application</
a></
h2>
0N/A <
p>We will now see how to connect to the secure agent,
0N/A using jconsole, and using a programmatic client.
0N/A <
h3>Using jconsole to connect to the secure agent</
h3>
0N/A <
p>The only special thing you need to do in order to
0N/A be able to connect to your secure agent with
0N/A jconsole, is to give it a keystore (containing
0N/A its client certificate) and a truststore (containing
0N/A the certificates of the servers it can trust).
0N/A pair on the client and server side - but this is
0N/A not what a real application would do.
0N/A Indeed a real application would have different
0N/A certificates for the client and the server, and
0N/A thus use different keystores (and probably truststores).
0N/A More information on SSL authentication can be obtained from the <
a 0N/A title="How SSL Works" 0N/A >Java<
sup>TM</
sup> Secure Socket Extension (JSSE) Reference Guide</
a>.
0N/A <
p>To start jconsole with our provided keystore and
0N/A truststore, go to the scandir example root directory and
0N/A type in the following command:
0N/A may help you debug connection problems if anything goes wrong.
0N/A <
p>In jconsole connection window, choose to connect to a
0N/A remote process, using the address <
i>localhost:4545</
i>
0N/A and the guest login:
0N/A alt="jconsole connection window"/></
a></
center>
0N/A <
p>You will see that the agent will let view all the
0N/A MBeans and their attributes, but will reject any
0N/A attribute modification or remote method invocation.
0N/A <
p><
u>Note:</
u> if jconsole fails to connect and show
0N/A you have probably misspelled some of the properties on jconsole
0N/A command line, or you didn't start jconsole from the
0N/A scandir example root directory where our <
code>truststore</
code>
0N/A and <
code>keystore</
code> files are located. This article - <
a 0N/A title="Troubleshooting connection problems in JConsole" 0N/A >Troubleshooting connection problems in JConsole</
a> - may help
0N/A you figure out what is going wrong.
0N/A <
h3>Writing a programmatic client to connect to the secure agent</
h3>
0N/A In this section we will show the steps involved in writing
0N/A a programmatic client that will connect to our secure agent.
0N/Atitle="The ScanDirClient class is a very short example of secure programatic client" 0N/A >ScanDirClient</
a> is an example class that shows how a
0N/A programmatic client can connect to a secured <
i>scandir</
i> application.
0N/A This class contains a <
code>main</
code> method which creates and
0N/A configures a <
code>JMXConnector</
code> client to connect with
0N/A the secured <
i>scandir</
i> agent.
0N/A <
p>The secure client differs only from a non secure client in
0N/A so far as it needs to use SSL RMI Factories and credentials to
0N/A connect to the secure agent. The steps required mainly involve:
0N/A <
li>Creating an empty environment map:
0N/A // Create an environment map to hold connection properties
0N/A // like credentials etc... We will later pass this map
0N/A // to the JMX Connector.
0N/A final Map<String,Object> env = new HashMap<String,Object>();
0N/A <
li>Putting the client's credentials in that map:
0N/A <
i>(here the client will log in as <
b>guest</
b>)</
i>
0N/A // Provide the credentials required by the server
0N/A // to successfully perform user authentication
0N/A final String[] credentials = new String[] { "guest" , "guestpasswd" };
0N/A <
li>Providing an <
code>SslRMIClientSocketFactory</
code> to interact
0N/A with the secure RMI Registry:
0N/A // by the
JNDI/
RMI Registry Service Provider to communicate with
0N/A new SslRMIClientSocketFactory());
0N/A <
li>Creating a JMXConnector and connecting with the
0N/A // Create the RMI connector client and
0N/A // connect it to the secure RMI connector server.
0N/A // args[0] is the server's host - localhost
0N/A // args[1] is the secure server port - 4545
0N/A "connect it to the RMI connector server");
0N/A final JMXServiceURL url = new JMXServiceURL(
0N/A "service:jmx:rmi:///
jndi/
rmi://"+args[0]+":"+args[1]+
0N/A <
p>For this to work, we also need to start the <
code>ScanDirClient</
code>
0N/A with the appropriate system properties that will point to our
0N/A <
code>keystore</
code> and <
code>truststore</
code>. To start the secure
0N/A client, go to the <
i>scandir</
i> example root directory and type
0N/A the following command:
0N/A <
p><
code>ant jar<
br>
0N/A <
p>You should be seeing this trace:
0N/A<
center><
table width="90%" border="0" bgcolor="#eeeeee">
0N/AInitialize the environment map
0N/ACreate the RMI connector client and connect it to the RMI connector server
0N/AGet the MBeanServerConnection
0N/AGet ScanDirConfigMXBean from ScanManagerMXBean
0N/AGet 'Configuration' attribute on ScanDirConfigMXBean
0N/A <InitialResultLogConfig>
0N/A <LogFileMaxRecords>2048</LogFileMaxRecords>
0N/A <MemoryMaxRecords>128</MemoryMaxRecords>
0N/A </InitialResultLogConfig>
0N/A <DirectoryScannerList>
0N/A <DirectoryScanner name="scan-build">
0N/A <Actions>NOTIFY LOGRESULT</Actions>
0N/A <FilePattern>.*\.class</FilePattern>
0N/A <SizeExceedsMaxBytes>4096</SizeExceedsMaxBytes>
0N/A <RootDirectory>build</RootDirectory>
0N/A </DirectoryScanner>
0N/A </DirectoryScannerList>
0N/AInvoke 'close' on ScanManagerMXBean
0N/AInvalid access level for requested MBeanServer operation.
0N/AClose the connection to the server
0N/A</
td></
tr></
table></
center>
0N/A <
p>If the <
code>ScanDirClient</
code> fails to connect with
0N/A the secure agent, then this article - <
a 0N/A title="Troubleshooting connection problems in JConsole" 0N/A >Troubleshooting connection problems in JConsole</
a> - may help
0N/A you figure out what is going wrong. Indeed the connection steps
0N/A performed by the <
code>ScanDirClient</
code> are very similar to
0N/A those performed by <
code>jconsole</
code>, and the problems you
0N/A could encounter are identical. Just remember that
0N/A <
code>jconsole</
code> needs the extra <
code>-J</
code> flag to pass
0N/A system properties to the VM, which is not needed with regular
0N/A <
code>java</
code> launcher invocations.
0N/A <
h2><
a name="h2-Conclusion">Conclusion</
a></
h2>
0N/A In this document, we have presented an advanced
0N/A JMX example, and shown how to run a secure
0N/A JMX agent in a production environment.
0N/A We have also shown how to connect to such a
0N/A secure agent with both jconsole and a programmatic
0N/A client. We have also discuss various JMX
0N/A design-patterns and best practices.
0N/A Readers who would wish to learn more about JMX, and
0N/A Monitoring and Management of the JVM, are invited
0N/A to follow the links given in reference below.
0N/A <
h2><
a name="h2-References">References</
a></
h2>
0N/A >JMX Best Practices</
a>: This document describes best practices that
0N/A have been identified for modeling using the JMX API. </
li>
0N/A >Monitoring and Management Using JMX</
a>: How to enable, configure, and
0N/A connect to the JVM JMX agent.</
li>
0N/A <
li><
a name="JConsole"><
a 0N/A>Using JConsole</
a>: JConsole is a JMX-Compliant monitoring tool which allows
0N/A you to interact graphically with your own MBeans.
0N/A >Monitoring and Management for the Java Platform</
a>: The Java Platform
0N/A Standard Edition (Java SE) 6 provides comprehensive monitoring and
0N/A management support for the Java platform. </
li>
0N/A >List of JMX-related Blogs</
a>: This page provides links to the
0N/A different web logs written by members of the Sun team working on the
0N/A title="The JSSE Reference Guide" 0N/A >Java<
sup>TM</
sup> Secure Socket Extension (JSSE) Reference Guide</
a>:
0N/A comprehensive documentation about the Java<
sup>TM</
sup> Secure Socket
0N/A >Java SE 6 Documentation Index</
a>: This document covers the
0N/A Java<
sup>TM</
sup> Platform, Standard Edition 6 JDK.</
li>