2
|
1 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
2 |
|
|
3 |
<html>
|
|
4 |
<head>
|
|
5 |
<!--
|
|
6 |
Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
|
|
7 |
|
|
8 |
Redistribution and use in source and binary forms, with or without
|
|
9 |
modification, are permitted provided that the following conditions
|
|
10 |
are met:
|
|
11 |
|
|
12 |
- Redistributions of source code must retain the above copyright
|
|
13 |
notice, this list of conditions and the following disclaimer.
|
|
14 |
|
|
15 |
- Redistributions in binary form must reproduce the above copyright
|
|
16 |
notice, this list of conditions and the following disclaimer in the
|
|
17 |
documentation and/or other materials provided with the distribution.
|
|
18 |
|
|
19 |
- Neither the name of Sun Microsystems nor the names of its
|
|
20 |
contributors may be used to endorse or promote products derived
|
|
21 |
from this software without specific prior written permission.
|
|
22 |
|
|
23 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
24 |
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
25 |
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
26 |
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
27 |
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
28 |
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
29 |
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
30 |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
31 |
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
32 |
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
33 |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
34 |
-->
|
|
35 |
|
|
36 |
<title>JMX(TM) "scandir" Example</title>
|
|
37 |
</head>
|
|
38 |
<body>
|
|
39 |
|
|
40 |
<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>
|
|
41 |
|
|
42 |
<h2><a name="h2-Introduction">Introduction</a></h2>
|
|
43 |
<ul>
|
|
44 |
<p>The JMX <i>scandir</i> example is an application that
|
|
45 |
scans parts of a filesystem - e.g. a set of directories
|
|
46 |
used by a number of lab machines when running tests - in
|
|
47 |
order to clean up and optimize disk space by removing
|
|
48 |
obsolete files - e.g. files that are leaked by the test
|
|
49 |
suites running on those machines, like coredump files, or
|
|
50 |
temporary files that might remain after a test crash.
|
|
51 |
It could also serve as a basis for an application that
|
|
52 |
would monitor disk usage and suggest removal of old big
|
|
53 |
long-unaccessed files.
|
|
54 |
</p>
|
|
55 |
<p>The JMX <i>scandir</i> example does not however implement
|
|
56 |
the full fledged logic that such an application might
|
|
57 |
have. It implements a subset of this logic which is
|
|
58 |
sufficient to demonstrate common patterns and
|
|
59 |
solutions used when implementing a monitoring and
|
|
60 |
management interface for an application with JMX
|
|
61 |
Technology.</p>
|
|
62 |
<p>This example is an advanced JMX example, which presents
|
|
63 |
advanced JMX concepts. It is assumed that the reader is already
|
|
64 |
familiar with the JMX API. Newcomers to JMX Technology are
|
|
65 |
invited to have a look at the <a
|
|
66 |
href="http://java.sun.com/javase/6/docs/technotes/guides/jmx/"
|
|
67 |
>JMX API Overview, Tutorial and Examples</a> before going any further.
|
|
68 |
</p>
|
|
69 |
<p></p>
|
|
70 |
<hr>
|
|
71 |
<blockquote>
|
|
72 |
<u>Note:</u> This example was developed using <a
|
|
73 |
href="http://www.netbeans.org">NetBeans 5.0 IDE</a>. The instructions
|
|
74 |
given in this document to build, run, and test the example assume that
|
|
75 |
you have at your disposal:
|
|
76 |
<ul><li>either <a href="http://www.netbeans.org">NetBeans 5.0 IDE</a>,</li>
|
|
77 |
<li>or <a href="http://ant.apache.org/">Apache Ant 1.6.5</a> and
|
|
78 |
<a href="http://sourceforge.net/projects/junit/">JUnit 3.8.1 or
|
|
79 |
3.8.2</a><br>
|
|
80 |
(JUnit is only needed to run the example's unit tests).
|
|
81 |
</li>
|
|
82 |
</ul>
|
|
83 |
<p><a name="setup">In order to build the example</a>,
|
|
84 |
<u>you may need to copy the jmx-scandir</u>
|
|
85 |
directory to somewhere where you have write permissions.
|
|
86 |
<br>In that case, you will need to update the <i>nbjdk.home</i> variable
|
|
87 |
in the copied <i><a href="build.properties">build.properties</a></i>
|
|
88 |
file located at the root of the copied project directory.
|
|
89 |
Please make sure that this variable points to the JDK 6 home directory.
|
|
90 |
</p>
|
|
91 |
<p>If you wish to run the testsuite from within the <a
|
|
92 |
href="http://www.netbeans.org">NetBeans IDE</a> you will also have
|
|
93 |
to set the <i>libs.junit.classpath</i> variable in
|
|
94 |
<a href="build.properties">build.properties</a>.
|
|
95 |
The <i>libs.junit.classpath</i> variable should point to your
|
|
96 |
<a href="http://sourceforge.net/projects/junit/">junit.jar</a>,
|
|
97 |
version 3.8.1 or 3.8.2.
|
|
98 |
</p>
|
|
99 |
</blockquote>
|
|
100 |
<hr>
|
|
101 |
<p></p>
|
|
102 |
<p><u>Table Of Contents:</u></p>
|
|
103 |
<p><center>[<a href="#h2-Generating">Generating the Java Documentation</a>]
|
|
104 |
[<a href="#h2-Overview">Overview of the <i>scandir</i> Example</a>]
|
|
105 |
[<a href="#h2-API-Doc">API Documentation and Sources</a>]
|
|
106 |
[<a href="#h2-Patterns">Patterns, Best Practices, and Common Pitfalls</a>]
|
|
107 |
[<a href="#h2-Testing">Testing the <i>scandir</i> Example</a>]
|
|
108 |
[<a href="#h2-Running">Running the <i>scandir</i> Example</a>]
|
|
109 |
[<a href="#h2-Playing">Playing with JConsole</a>]
|
|
110 |
[<a href="#h2-Turning">Turning the example into a Secure JMX Application</a>]
|
|
111 |
[<a href="#h2-Connecting">Connecting to the Secure JMX Application</a>]
|
|
112 |
[<a href="#h2-Conclusion">Conclusion</a>]
|
|
113 |
[<a href="#h2-References">References</a>]</center></p>
|
|
114 |
|
|
115 |
</ul>
|
|
116 |
<h2><a name="h2-Generating">Generating the Java Documentation</a></h2>
|
|
117 |
|
|
118 |
<ul>
|
|
119 |
<p>Before reading further, you will need to generate the
|
|
120 |
Java Documentation for the example's sources.</p>
|
|
121 |
<p>In the example root directory (where the <code>build.xml</code>
|
|
122 |
file is located) run the following command:
|
|
123 |
<pre>ant javadoc</pre>
|
|
124 |
</p>
|
|
125 |
<p>Alternatively you can open the jmx-scandir project with the
|
|
126 |
NetBeans IDE and generate the Javadoc from its <code>Build</code>
|
|
127 |
menu.
|
|
128 |
</p>
|
|
129 |
<p>If building the documentation fails, please make sure to read the
|
|
130 |
<a href="#setup">note</a> at the beginning of this document.</p>
|
|
131 |
</ul>
|
|
132 |
|
|
133 |
<h2><a name="h2-Overview">Overview of the <i>scandir</i> Example</a></h2>
|
|
134 |
|
|
135 |
<ul>
|
|
136 |
<p>The JMX <i>scandir</i> example is built around the
|
|
137 |
following MBeans:</p>
|
|
138 |
<ul>
|
|
139 |
<li>The first MBean we will present here is the
|
|
140 |
<a
|
|
141 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
142 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
143 |
>DirectoryScannerMXBean</a>. <br>A
|
|
144 |
<code>DirectoryScannerMXBean</code> is an MBean that scans a
|
|
145 |
file system starting at a given root directory, and then looks
|
|
146 |
for files that match the given criteria. When such a file is
|
|
147 |
found, the <code>DirectoryScannerMXBean</code> takes the
|
|
148 |
action for which it was configured: emit a notification,
|
|
149 |
<i>and/or</i> log a <code>record</code> for this file,
|
|
150 |
<i>and/or</i> delete that file. The code that would actually
|
|
151 |
delete the file is commented out - so that nothing valuable is
|
|
152 |
lost if the example is run by mistake on the wrong set of
|
|
153 |
directories.<br> <code>DirectoryScannerMXBeans</code> are
|
|
154 |
created by the <a
|
|
155 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
156 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
157 |
>ScanManagerMXBean</a> - see next item on the list, from its
|
|
158 |
configuration.
|
|
159 |
</li>
|
|
160 |
<li>
|
|
161 |
The <a
|
|
162 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
163 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
164 |
>ScanManagerMXBean</a> is the actual entry point of the
|
|
165 |
application. It reads the application's
|
|
166 |
configuration, and from that configuration,
|
|
167 |
will create a <a
|
|
168 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManager.html"
|
|
169 |
title="The ResultLogManager is in charge of managing result logs"
|
|
170 |
>ResultLogManager</a> and some <a
|
|
171 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
172 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
173 |
>DirectoryScannerMXBeans</a>.
|
|
174 |
<br>The <code>ScanManagerMXBean</code> lets you start, stop, and
|
|
175 |
schedule directory scans. The
|
|
176 |
<code>ScanManagerMXBean</code> is a singleton
|
|
177 |
MBean: there can be at most one instance of such
|
|
178 |
an MBean registered in a given MBeanServer.
|
|
179 |
</li>
|
|
180 |
<li>The <a
|
|
181 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
182 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
183 |
>ScanDirConfigMXBean</a> is an MBean which is able to
|
|
184 |
load/save the configuration to/from an XML file. It
|
|
185 |
will also let you modify that configuration - by e.g.
|
|
186 |
creating new directory scanners in there.
|
|
187 |
The corresponding MBeans will be created later, only
|
|
188 |
when you later
|
|
189 |
ask the <code><a
|
|
190 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
191 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
192 |
>ScanManagerMXBean</a> </code> to apply the
|
|
193 |
configuration again.<br>
|
|
194 |
The <code>ScanDirConfigMXBean</code> is created by the
|
|
195 |
<code>ScanManagerMXBean</code>, when the
|
|
196 |
<code>ScanManagerMXBean</code> is registered.
|
|
197 |
It is also possible to create an alternate
|
|
198 |
<code>ScanDirConfigMXBean</code>, and to switch the
|
|
199 |
<code>ScanDirConfigMXBean</code> to use one or the other
|
|
200 |
configuration.
|
|
201 |
<br>An example of XML configuration file is given
|
|
202 |
<a href="src/etc/testconfig.xml"
|
|
203 |
title="An Example Of Configuration"
|
|
204 |
>here</a>. Although you could edit such a file by
|
|
205 |
hand, it is easier to do it programmatically (or
|
|
206 |
with <a href="#JConsole">JConsole</a>) through
|
|
207 |
the <code>ScanDirConfigMXBean</code> interface.
|
|
208 |
</li>
|
|
209 |
<li>The <a
|
|
210 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
211 |
title="The ResultLogManagerMXBean is in charge of managing result logs"
|
|
212 |
>ResultLogManagerMXBean</a> is in charge of managing result logs.
|
|
213 |
<br>Directory Scanners can be configured to log a
|
|
214 |
<a
|
|
215 |
href="dist/javadoc/com/sun/jmx/examples/scandir/config/ResultRecord.html"
|
|
216 |
title="A ResultRecord contains information about a file matching the criteria of a Directory Scanner"
|
|
217 |
>ResultRecord</a> whenever they take action upon a file that
|
|
218 |
matches their criteria. The <code>ResultLogManagerMXBean</code> is
|
|
219 |
responsible for logging these result records.
|
|
220 |
The <code>ResultLogManagerMXBean</code> can be configured to log
|
|
221 |
such records to a flat file, or into a log held in memory, or
|
|
222 |
both. Both logs (file and memory) can be configured with a
|
|
223 |
maximum capacity.
|
|
224 |
<br>When the maximum capacity of the memory
|
|
225 |
log is reached, its first entry (i.e. its oldest entry) is
|
|
226 |
removed to make place for the latest one.
|
|
227 |
<br>When the maximum
|
|
228 |
capacity of the file log is reached, the file is
|
|
229 |
renamed by appending a tilde '~' to its name and a
|
|
230 |
new result log is created.
|
|
231 |
<br>The <code>ResultLogManagerMXBean</code>
|
|
232 |
will let you interactively clear these result logs, change their
|
|
233 |
capacity, and decide where (memory or file) to log.
|
|
234 |
The memory log is useful in that its content can be interactively
|
|
235 |
returned by the <code>ResultLogManagerMXBean</code>, while
|
|
236 |
the file log doesn't have this facility.<br>
|
|
237 |
The result logs are intended to be used by e.g. an offline
|
|
238 |
program that would take some actions on the files that
|
|
239 |
matched the scan criteria:
|
|
240 |
<br>The <i>scandir</i> application
|
|
241 |
could be configured to only produce logs (i.e. takes no
|
|
242 |
action but logging the matching files), and the real
|
|
243 |
action could be performed by another program or module (e.g. mail the result log to the engineer who
|
|
244 |
maintains the lab, or parse that log and delete all the
|
|
245 |
files listed there, or parse the log and prepare and send
|
|
246 |
a single mail to each owner of matching files, containing
|
|
247 |
the list of files they should consider deleting).<br>
|
|
248 |
The <code>ResultLogManagerMXBean</code> is a singleton
|
|
249 |
MBean created by the <code><a
|
|
250 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
251 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
252 |
>ScanManagerMXBean</a> </code>
|
|
253 |
which reads and writes its configuration from the
|
|
254 |
<code><a
|
|
255 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
256 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
257 |
>ScanDirConfigMXBean</a></code>.
|
|
258 |
</li>
|
|
259 |
</ul>
|
|
260 |
<p>An application <code>main()</code> method is
|
|
261 |
provided in the <a
|
|
262 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html"
|
|
263 |
>ScanDirAgent</a> class. The <code>main()</code> simply registers
|
|
264 |
a <code><a
|
|
265 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
266 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
267 |
>ScanManagerMXBean</a> </code> in the platform MBeanServer, and
|
|
268 |
then waits for someone to call <code>close()</code> on the
|
|
269 |
<code>ScanManagerMXBean</code>.
|
|
270 |
</p>
|
|
271 |
<p>When the <code>ScanManagerMXBean</code> is registered, it
|
|
272 |
will create a default <code><a
|
|
273 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
274 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
275 |
>ScanDirConfigMXBean</a></code> bound
|
|
276 |
to a default XML config file.
|
|
277 |
</p>
|
|
278 |
<p>The application's default XML config file is determined as
|
|
279 |
follows:
|
|
280 |
<ol>
|
|
281 |
<li>If the property <code>scandir.config.file</code> is
|
|
282 |
defined, the default application file will be the
|
|
283 |
file pointed to by this property. If that file
|
|
284 |
doesn't exist, it will be created when
|
|
285 |
<code>ScanDirConfigMXBean.save()</code> is
|
|
286 |
invoked.
|
|
287 |
</li>
|
|
288 |
<li>Otherwise the application config file is
|
|
289 |
assumed to be a file called <code>jmx-scandir.xml</code>,
|
|
290 |
located in the user's directory (as defined by
|
|
291 |
the System property <code>user.home</code>).
|
|
292 |
If that file doesn't exists, it will be created when
|
|
293 |
<code>ScanDirConfigMXBean.save()</code> is
|
|
294 |
invoked.
|
|
295 |
</li>
|
|
296 |
</ol>
|
|
297 |
<p>It is worth noting that this project is defined to
|
|
298 |
run with the following properties:
|
|
299 |
<pre>-Djava.util.logging.config.file=logging.properties</pre>
|
|
300 |
<pre>-Dscandir.config.file=src/etc/testconfig.xml</pre>
|
|
301 |
With <code>ScanDirAgent</code> defined as the project's
|
|
302 |
main class. Hence when you invoke from the NetBeans IDE
|
|
303 |
<i>Run Project</i> on the <i>jmx-scandir</i> project,
|
|
304 |
or <i>Run file</i> on the <code>ScanDirAgent</code>, the
|
|
305 |
application starts with the test configuration provided in
|
|
306 |
<a href="src/etc/testconfig.xml"
|
|
307 |
title="An Example Of Configuration"
|
|
308 |
>src/etc/testconfig.xml</a>
|
|
309 |
</p>
|
|
310 |
</ul>
|
|
311 |
<h2><a name="h2-API-Doc">API Documentation and Sources</a></h2>
|
|
312 |
<ul>
|
|
313 |
<p>Once generated, the Javadoc of example classes can
|
|
314 |
be found starting from <a href="dist/javadoc/index.html"
|
|
315 |
title="The API Documentation"
|
|
316 |
><code>dist/javadoc/index.html</code></a>.</p>
|
|
317 |
<p>You can view the sources in the <a
|
|
318 |
href="src"
|
|
319 |
title="The Example Source Tree"
|
|
320 |
><code>src</code></a> subdirectory.</p>
|
|
321 |
</ul>
|
|
322 |
<h2><a name="h2-Patterns">Patterns, Best Practices, and Common Pitfalls</a></h2>
|
|
323 |
<ul>
|
|
324 |
<p>This section discusses some common patterns and
|
|
325 |
design choices that this example demonstrates, and some pitfalls that
|
|
326 |
it avoids.
|
|
327 |
</ul>
|
|
328 |
<h3>MBeans or MXBeans?</h3>
|
|
329 |
<ul>
|
|
330 |
<p>What is an MXBean? MXBeans made their appearance in
|
|
331 |
J2SE 5.0 (Tiger), with the Management and Monitoring
|
|
332 |
API of the JVM. However, Java SE 6 is the first
|
|
333 |
Java SE release that contains a standard framework which
|
|
334 |
makes it possible to create and register your own MXBeans.
|
|
335 |
</p>
|
|
336 |
<p>MXBeans are a special kind of MBean, which once registered
|
|
337 |
in the MBeanServer, get automatically transformed into
|
|
338 |
OpenMBeans. From a developer point of view, nothing changes:
|
|
339 |
A Wombat MBean can become an MXBean simply by renaming
|
|
340 |
its <code>WombatMBean</code> interface into <code>WombatMXBean</code>.</p>
|
|
341 |
<p>Using MXBeans rather than plain Standard MBean brings its
|
|
342 |
own advantages:</p>
|
|
343 |
<ul>
|
|
344 |
<li>
|
|
345 |
Generic tools, like JConsole, will be able to
|
|
346 |
display and interact with your MXBeans nicely, even
|
|
347 |
if your MXBean interfaces reference custom types
|
|
348 |
- e.g. custom Java enums. This is because all the types
|
|
349 |
exposed by your MXBeans are converted to Open Types.
|
|
350 |
Just look at the <a
|
|
351 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
352 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
353 |
>ScanDirConfigMXBean</a> with JConsole and you will
|
|
354 |
understand the benefits.
|
|
355 |
</li>
|
|
356 |
<li>
|
|
357 |
When writing a programmatic client, you can obtain
|
|
358 |
a proxy that implements the original MXBean interface,
|
|
359 |
and forget about the Open Type conversion.
|
|
360 |
The JUnit unit tests that come with this example
|
|
361 |
use this feature very widely. Have a look at them.
|
|
362 |
</li>
|
|
363 |
<li>
|
|
364 |
The MXBean framework also lets you nicely navigate
|
|
365 |
from one MXBean to another: your MXBeans can
|
|
366 |
have attributes and parameters which are proxies
|
|
367 |
to other MXBeans! We demonstrate this in the
|
|
368 |
<a
|
|
369 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
370 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
371 |
>ScanManagerMXBean</a> which exposes a list
|
|
372 |
of <code><a
|
|
373 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
374 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
375 |
>DirectoryScannerMXBean</a></code> and points
|
|
376 |
towards a <code><a
|
|
377 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
378 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
379 |
>ScanDirConfigMXBean</a></code>.
|
|
380 |
</li>
|
|
381 |
</ul>
|
|
382 |
<p>In short, MXBeans are so much easier to use that
|
|
383 |
this example doesn't even have a single regular
|
|
384 |
Standard MBean.
|
|
385 |
</p>
|
|
386 |
<p>See also <a
|
|
387 |
href="http://weblogs.java.net/blog/emcmanus/archive/2006/02/what_is_an_mxbe.html"
|
|
388 |
title="What is an MXBean?"
|
|
389 |
>What is an MXBean?</a>
|
|
390 |
and <a
|
|
391 |
href="http://weblogs.java.net/blog/emcmanus/archive/2006/06/intermxbean_ref.html"
|
|
392 |
title="Inter-MXBean references"
|
|
393 |
>Inter-MXBean References</a>.
|
|
394 |
</p>
|
|
395 |
<blockquote><u>Hint:</u> In order to simplify the task of coding a
|
|
396 |
JMX programmatic client, we recommend that getters, setters, and
|
|
397 |
operations defined in MBean and MXBean interfaces throw
|
|
398 |
<code>IOException</code>. Proxy objects will then be able
|
|
399 |
to rethrow directly any <code>IOException</code> received from
|
|
400 |
their underlying MBean Server connection, without wrapping
|
|
401 |
them into <code>UndeclaredThrowableExceptions</code>.<br>
|
|
402 |
Since the life cycle of the proxy object is not directly tied to
|
|
403 |
the life cycle of the MBean it proxies, you may also want to
|
|
404 |
have all methods in the MBean or MXBean interface throw
|
|
405 |
<code>InstanceNotFoundException</code> or more generally
|
|
406 |
<code>JMException</code>.
|
|
407 |
</blockquote>
|
|
408 |
</ul>
|
|
409 |
<h3>MBean Names - aka ObjectNames</h3>
|
|
410 |
<ul>
|
|
411 |
<p>As you must know if you've been studying JMX, MBeans are
|
|
412 |
named objects. The names of MBeans are represented by
|
|
413 |
instances of <code>ObjectName</code>. An ObjectName is
|
|
414 |
composed of a <i>domain</i>, followed by a colon ':',
|
|
415 |
followed by a comma-separated list of <i>key=value</i>
|
|
416 |
pairs.<br>
|
|
417 |
The ordering of the <i>key=value</i> pairs is not
|
|
418 |
important, but <code>ObjectNames</code> are case sensitive
|
|
419 |
(both keys and values are case sensitive) and <b>white space
|
|
420 |
is not ignored</b>.<br>
|
|
421 |
A common pitfall for JMX beginners is to inadvertently
|
|
422 |
insert white space after commas into an ObjectName,
|
|
423 |
and expect that two ObjectNames which differ only by such white
|
|
424 |
space will be considered identical. This is not the
|
|
425 |
case.<br>
|
|
426 |
As an example, the ObjectName '<b><code>D:k1=v1, k2=v2, k3=v3</code></b>' has
|
|
427 |
three keys, which are '<b><code>k1</code></b>', '<b><code> k2</code></b>',
|
|
428 |
and '<b><code> k3</code></b>': beware
|
|
429 |
of the space in the name of the second and third
|
|
430 |
keys!<br>
|
|
431 |
It is therefore a different ObjectName from
|
|
432 |
'<b><code>D:k1=v1,k2=v2,k3=v3</code></b>' (the keys are now
|
|
433 |
'<b><code>k1</code></b>', '<b><code>k2</code></b>', and
|
|
434 |
'<b><code>k3</code></b>'), but the same ObjectName as
|
|
435 |
'<b><code>D: k2=v2, k3=v3,k1=v1</code></b>', and yet different
|
|
436 |
from '<b><code>D:k2=v2, k3=v3, k1=v1</code></b>'!
|
|
437 |
<p>In this example, we are following the rules
|
|
438 |
for ObjectName suggested in the <a
|
|
439 |
href="http://java.sun.com/products/JavaManagement/best-practices.html"
|
|
440 |
>JMX Best Practices</a>:</p>
|
|
441 |
<ul>
|
|
442 |
<li>ObjectNames should be <a
|
|
443 |
href="http://java.sun.com/products/JavaManagement/best-practices.html#mozTocId654884"
|
|
444 |
>predictable</a>
|
|
445 |
</li>
|
|
446 |
<li>The domain part of our ObjectNames starts with a Java
|
|
447 |
package name
|
|
448 |
</li>
|
|
449 |
<li>Our ObjectNames contain a <code>type=</code>
|
|
450 |
key property. This property is different for every
|
|
451 |
object type in our domain.
|
|
452 |
</li>
|
|
453 |
<li>For every ObjectName with a given type, we have the same set of key
|
|
454 |
properties with the same syntax and semantics for their values - in
|
|
455 |
fact we only use an additional <code>name=</code> key.
|
|
456 |
</li>
|
|
457 |
<li>When there can only be one instance of a given type
|
|
458 |
there aren't any other key properties than <code>type=</code>.
|
|
459 |
The ObjectNames of the <a
|
|
460 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
461 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
462 |
>ScanManagerMXBean</a> and <a
|
|
463 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
464 |
title="The ResultLogManagerMXBean is in charge of managing result logs"
|
|
465 |
>ResultLogManagerMXBean</a>, which are both singleton MBeans, are
|
|
466 |
composed in this way.
|
|
467 |
</li>
|
|
468 |
<li>When there can be several instances of a given type,
|
|
469 |
we differentiate them by further key properties.
|
|
470 |
To achieve this, we are using the most usual key property
|
|
471 |
in addition to <code>type=</code>: the <code>name=</code> key.
|
|
472 |
In this example, a key property list of the form
|
|
473 |
<code>type=X,name=Y</code> is always enough to uniquely name
|
|
474 |
an MBean. Tools like jconsole are usually aware
|
|
475 |
of the semantics of the <code>type=</code> key and
|
|
476 |
<code>name=</code> key, and are therefore able to
|
|
477 |
display this form of name in a way that
|
|
478 |
is easier to read than other name forms.
|
|
479 |
</li>
|
|
480 |
</ul>
|
|
481 |
<p>The rules listed above are implemented by a couple
|
|
482 |
of static helper functions in the <a
|
|
483 |
href="src/com/sun/jmx/examples/scandir/ScanManager.java"
|
|
484 |
title="ScanManager.java"
|
|
485 |
>ScanManager</a> class. See the code of the
|
|
486 |
<b><code>makeSingletonName</code></b> and
|
|
487 |
<b><code>makeMBeanName</code></b> methods.
|
|
488 |
</p>
|
|
489 |
</ul>
|
|
490 |
<h3>Inter MBean Navigation</h3>
|
|
491 |
<ul>
|
|
492 |
<p>One of the most common problems that needs to be solved
|
|
493 |
when designing a management interface with JMX is to
|
|
494 |
choose a representation for inter-MBean relationships.<br>
|
|
495 |
Prior to Java 6, there were basically three possible
|
|
496 |
choices:</p>
|
|
497 |
<ul>
|
|
498 |
<li><b>Make the relation appear in the ObjectName</b>.
|
|
499 |
For instance, if MBean B was contained in
|
|
500 |
MBean A, you could choose to name MBean B so
|
|
501 |
that its parent relationship with MBean A
|
|
502 |
appeared in its name. <br>
|
|
503 |
The obvious limitation of this solution is that
|
|
504 |
it only allows to model one such relation (an
|
|
505 |
MBean has only one name) and the relation must
|
|
506 |
be fixed - it cannot change during the life of
|
|
507 |
the MBean since the name of an MBean cannot
|
|
508 |
change.<br>
|
|
509 |
This scheme is therefore mostly used when
|
|
510 |
the application MBeans are modeling objects
|
|
511 |
which are conceptually contained within
|
|
512 |
each other in a tree-like structure.
|
|
513 |
<br>For instance, most MBean names defined by
|
|
514 |
<a href="http://jcp.org/en/jsr/detail?id=77"
|
|
515 |
>J2EE Management (JSR 77)</a> follow
|
|
516 |
this scheme.
|
|
517 |
</li>
|
|
518 |
<li><b>Design getters and setters (or operations) which
|
|
519 |
return <code>ObjectName</code> or
|
|
520 |
<code>ObjectName[]</code> values</b>. The ObjectNames
|
|
521 |
point to the MBeans which are related to that
|
|
522 |
object. For instance , <a
|
|
523 |
href="http://glassfish.dev.java.net/"
|
|
524 |
title="Open Source Java EE 5 Application Server"
|
|
525 |
>GlassFish</a>
|
|
526 |
defines MBeans which also use this pattern.
|
|
527 |
</li>
|
|
528 |
<li><b>Use the JMX RelationService</b>. The JMX RelationService
|
|
529 |
is quite powerful, but simple relationships often
|
|
530 |
do not justify that overhead.
|
|
531 |
</li>
|
|
532 |
</ul>
|
|
533 |
<p>In Java 6, these three possibilities still remain, but
|
|
534 |
the new MXBean framework brings up an interesting
|
|
535 |
alternative. Instead of returning an ObjectName or
|
|
536 |
an ObjectName array, <b>an MXBean can return a proxy</b>
|
|
537 |
to its related MXBeans. This is how we have chosen to
|
|
538 |
implement our inter MBean relationships in this
|
|
539 |
example:
|
|
540 |
<br>For instance the
|
|
541 |
<code>ScanManagerMXBean</code>/<code>DirectoryScannerMXBean</code>
|
|
542 |
relationship and the
|
|
543 |
<code>ScanManagerMXBean</code>/<code>ScanDirConfigMXBean</code>
|
|
544 |
relationships are implemented in this way.
|
|
545 |
<p>
|
|
546 |
The additional benefit, as compared to returning ObjectNames or
|
|
547 |
using the RelationService is that interface type of the MBeans
|
|
548 |
which are pointed to by the relationship becomes directly
|
|
549 |
apparent. The method:
|
|
550 |
<pre>
|
|
551 |
public Map<String,DirectoryScannerMXBean> getDirectoryScanners();
|
|
552 |
</pre>
|
|
553 |
makes it immediately obvious that the MBeans to which we point are
|
|
554 |
<a
|
|
555 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
556 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
557 |
>DirectoryScannerMXBeans</a>. It would have been much less obvious in prior
|
|
558 |
versions of Java SE, were the returned type would have had to be
|
|
559 |
<code>Map<String,ObjectName></code>, or
|
|
560 |
even worse just <code>Map</code>.
|
|
561 |
</p>
|
|
562 |
<p>However, it must be clear that the behaviour will be
|
|
563 |
quite different when an MXBean is returned as compared
|
|
564 |
to when a simple bean is returned.
|
|
565 |
</p>
|
|
566 |
<p>When an MXBean is returned, the remote client sees either
|
|
567 |
an ObjectName, if it is a generic client like jconsole, or
|
|
568 |
a proxy to a remote MXBean, if the client is working with the
|
|
569 |
MXBean interface. Invoking an operation on one of the
|
|
570 |
proxy returned by a method such as
|
|
571 |
<code>getDirectoryScanners</code> will cause the
|
|
572 |
MBean to be invoked on the remote server side.
|
|
573 |
</p>
|
|
574 |
<p>If <code>getDirectoryScanners</code> were
|
|
575 |
defined as:
|
|
576 |
<pre>
|
|
577 |
public Map<String,DirectoryScannerConfig> getDirectoryScanners();
|
|
578 |
</pre>
|
|
579 |
then invoking a method on one of the returned objects
|
|
580 |
would have absolutely no effect on the remote
|
|
581 |
server side - because the returned objects in this
|
|
582 |
case would simply be a bunch of serialized data objects.
|
|
583 |
</p>
|
|
584 |
<p>It is worth noting that although an MXBean interface
|
|
585 |
can have getters and operations which return an MXBean
|
|
586 |
interface, a regular standard MBean shouldn't have
|
|
587 |
any getters or methods which return MBean interfaces or
|
|
588 |
MXBean interfaces.
|
|
589 |
</p>
|
|
590 |
<p>For more information see also <a
|
|
591 |
href="http://weblogs.java.net/blog/emcmanus/archive/2006/06/intermxbean_ref.html"
|
|
592 |
title="Inter-MXBean references"
|
|
593 |
>Inter-MXBean References</a>.
|
|
594 |
</p>
|
|
595 |
</ul>
|
|
596 |
<h3>The MBeanRegistration interface, or how an MBean can
|
|
597 |
know or provide its own name</h3>
|
|
598 |
<ul>
|
|
599 |
<p>
|
|
600 |
Sometimes, an MBean needs to have a reference to the
|
|
601 |
MBeanServer in which it is registered, or needs to know
|
|
602 |
with which ObjectName it has been registered.
|
|
603 |
</p>
|
|
604 |
<p>
|
|
605 |
Sometimes also, an MBean may need to perform some
|
|
606 |
checks before being registered, or will need
|
|
607 |
to carry out some actions right after it has been
|
|
608 |
successfully registered in the MBeanServer.
|
|
609 |
</p>
|
|
610 |
<p>
|
|
611 |
Sometimes again, an MBean may need to perform some
|
|
612 |
checks, or some cleaning actions, just before, or
|
|
613 |
just after, it is unregistered.
|
|
614 |
</p>
|
|
615 |
<p>
|
|
616 |
When an MBean has such needs, the easiest solution
|
|
617 |
for it is to implement the <code>MBeanRegistration</code>
|
|
618 |
interface.
|
|
619 |
</p>
|
|
620 |
<p>The <code>MBeanRegistration</code> interface is a callback
|
|
621 |
interface which defines pre and post registration and
|
|
622 |
unregistration callbacks.
|
|
623 |
</p>
|
|
624 |
<p>
|
|
625 |
When an MBean implementing this interface is created
|
|
626 |
(with <code>createMBean</code>) or registered
|
|
627 |
(with <code>registerMBean</code>) in an MBeanServer,
|
|
628 |
the MBeanServer will call the <code>preRegister</code>
|
|
629 |
and <code>postRegister</code> method implemented by
|
|
630 |
the MBean. The <code>preRegister</code> method
|
|
631 |
has an <code>MBeanServer</code> and <code>ObjectName</code>
|
|
632 |
parameter, which are passed by the MBeanServer to the
|
|
633 |
MBean. The MBean can store the reference it is being passed
|
|
634 |
in a private instance variable for later use.
|
|
635 |
</p>
|
|
636 |
<p>
|
|
637 |
Most of the MXBeans we have defined in this example
|
|
638 |
implement the <code>MBeanRegistration</code> interface. The table
|
|
639 |
below show how our MBeans use this interface to control
|
|
640 |
their own names, make sanity checks, perform
|
|
641 |
initialization steps or cleanup actions.
|
|
642 |
</p>
|
|
643 |
<p><br><center>
|
|
644 |
<table border="1" cellpadding="4" cellspacing="2"
|
|
645 |
bgcolor="#eeeeee" width="95%">
|
|
646 |
<thead>
|
|
647 |
<tr bgcolor="#cecece">
|
|
648 |
<th width="20%">MBean Requirement</th>
|
|
649 |
<th>callback</th>
|
|
650 |
<th>use case example</th>
|
|
651 |
</tr>
|
|
652 |
</thead>
|
|
653 |
<tbody>
|
|
654 |
<tr>
|
|
655 |
<td bgcolor="#dedede">get a reference to the MBeanServer</td>
|
|
656 |
<td><code>preRegister</code></td>
|
|
657 |
<td bgcolor="#fafafa">The <a
|
|
658 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
659 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
660 |
>ScanManagerMXBean</a> needs a reference
|
|
661 |
to the MBeanServer in order to create and
|
|
662 |
register other MBeans, such as the
|
|
663 |
<a
|
|
664 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
665 |
title="The ResultLogManagerMXBean is in charge of managing result logs"
|
|
666 |
>ResultLogManagerMXBean</a>, and the
|
|
667 |
<a
|
|
668 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
669 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
670 |
>DirectoryScannerMXBeans</a>.
|
|
671 |
</td>
|
|
672 |
</tr>
|
|
673 |
<tr>
|
|
674 |
<td bgcolor="#dedede">reject registration if conditions are
|
|
675 |
not met.
|
|
676 |
</td>
|
|
677 |
<td><code>preRegister</code></td>
|
|
678 |
<td bgcolor="#fafafa">The <a
|
|
679 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
680 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
681 |
>ScanManagerMXBean</a> will throw
|
|
682 |
an IllegalArgumentException in <code>preRegister</code>
|
|
683 |
if the ObjectName it is being passed is
|
|
684 |
illegal. Throwing an exception in
|
|
685 |
<code>preRegister</code> makes the registration fail.
|
|
686 |
</td>
|
|
687 |
</tr>
|
|
688 |
<tr>
|
|
689 |
<td bgcolor="#dedede">get my client-assigned MBean name</td>
|
|
690 |
<td><code>preRegister</code></td>
|
|
691 |
<td bgcolor="#fafafa">The <a
|
|
692 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
693 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
694 |
>ScanDirConfigMXBean</a> propagates the
|
|
695 |
value of the <code>name=</code> property of
|
|
696 |
the ObjectName it is given into its
|
|
697 |
ScanManagerConfig bean.
|
|
698 |
</td>
|
|
699 |
</tr>
|
|
700 |
<tr>
|
|
701 |
<td bgcolor="#dedede">provide my own default ObjectName if none
|
|
702 |
was given to the MBeanServer
|
|
703 |
</td>
|
|
704 |
<td><code>preRegister</code></td>
|
|
705 |
<td bgcolor="#fafafa">The name that is returned by <code>preRegister</code>
|
|
706 |
is the ObjectName with which the MBean will be
|
|
707 |
eventually registered.
|
|
708 |
The <a
|
|
709 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
710 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
711 |
>ScanDirConfigMXBean</a> is able to suggest
|
|
712 |
a value for its own ObjectName if none was
|
|
713 |
provided. Similarly, the <a
|
|
714 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
715 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
716 |
>ScanManagerMXBean</a>
|
|
717 |
always returns its singleton ObjectName
|
|
718 |
defined by <a
|
|
719 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html#SCAN_MANAGER_NAME"
|
|
720 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
721 |
>ScanManagerMXBean.SCAN_MANAGER_NAME</a>.
|
|
722 |
</td>
|
|
723 |
</tr>
|
|
724 |
<tr>
|
|
725 |
<td bgcolor="#dedede">perform initialization steps</td>
|
|
726 |
<td><code>preRegister</code></td>
|
|
727 |
<td bgcolor="#fafafa">The <a
|
|
728 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
729 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
730 |
>ScanDirConfigMXBean</a> uses <code>preRegister</code>
|
|
731 |
to initialize its internal ScanManagerConfig bean.
|
|
732 |
</td>
|
|
733 |
</tr>
|
|
734 |
<tr>
|
|
735 |
<td bgcolor="#dedede">perform initialization steps, once it is
|
|
736 |
known that the registration was successful.
|
|
737 |
</td>
|
|
738 |
<td><code>postRegister</code></td>
|
|
739 |
<td bgcolor="#fafafa">The <code>postRegister</code> method
|
|
740 |
can be used to implement
|
|
741 |
initialization steps that need to be done once it
|
|
742 |
is known that the registration was successful, or to
|
|
743 |
undo any action performed by <code>preRegister</code> once it
|
|
744 |
is known that registration was not successful.
|
|
745 |
The <code>postRegister</code> method has a Boolean parameter
|
|
746 |
which tells the MBean whether it was or wasn't
|
|
747 |
successfully registered in the MBeanServer.
|
|
748 |
The <a
|
|
749 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
750 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
751 |
>ScanManagerMXBean</a> uses <code>postRegister</code> to create
|
|
752 |
and register other MBeans, such as the
|
|
753 |
<a
|
|
754 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
755 |
title="The ResultLogManagerMXBean is in charge of managing result logs"
|
|
756 |
>ResultLogManagerMXBean</a> and the default
|
|
757 |
<a
|
|
758 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
759 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
760 |
>ScanDirConfigMXBean</a>.
|
|
761 |
Note that <code>postRegister</code> is not expected to throw any
|
|
762 |
exception. If an exception needs to be thrown, it should
|
|
763 |
be thrown in <code>preRegister</code>.
|
|
764 |
</td>
|
|
765 |
</tr>
|
|
766 |
<tr>
|
|
767 |
<td bgcolor="#dedede">check whether the MBean can be deregistered</td>
|
|
768 |
<td><code>preDeregister</code></td>
|
|
769 |
<td bgcolor="#fafafa">The <a
|
|
770 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
771 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
772 |
>ScanManagerMXBean</a> uses this method to verify
|
|
773 |
that its state allows it to be deregistered.
|
|
774 |
In particular, it will refuse to be deregistered
|
|
775 |
if it is in the RUNNING or SCHEDULED state.
|
|
776 |
If <code>preDeregister</code> throws an exception, the unregisterMBean
|
|
777 |
call will fail and the MBean will remain registered in
|
|
778 |
the MBeanServer.
|
|
779 |
Take particular care when implementing business logic
|
|
780 |
in this method: if the logic you implement has an
|
|
781 |
unfortunate bug which makes it always throw an
|
|
782 |
exception, you will never be able to unregister
|
|
783 |
that MBean.
|
|
784 |
</td>
|
|
785 |
</tr>
|
|
786 |
<tr>
|
|
787 |
<td bgcolor="#dedede">clean up resources, refusing to be deregistered if
|
|
788 |
it fails
|
|
789 |
</td>
|
|
790 |
<td><code>preDeregister</code></td>
|
|
791 |
<td bgcolor="#fafafa">The <a
|
|
792 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
793 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
794 |
>ScanManagerMXBean</a> uses this method to unregister
|
|
795 |
all the other MBeans it has created and registered in the
|
|
796 |
MBeanServer. This includes the <a
|
|
797 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
798 |
title="The ResultLogManagerMXBean is in charge of managing result logs"
|
|
799 |
>ResultLogManagerMXBean</a>, the
|
|
800 |
<a
|
|
801 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
802 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
803 |
>ScanDirConfigMXBeans</a> it has created, and the
|
|
804 |
<a
|
|
805 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
806 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
807 |
>DirectoryScannerMXBeans</a> it has created when
|
|
808 |
applying its configuration.
|
|
809 |
</td>
|
|
810 |
</tr>
|
|
811 |
<tr>
|
|
812 |
<td bgcolor="#dedede">clean up resources which need to be released in
|
|
813 |
a best-effort way, when it is known that the MBean is no
|
|
814 |
longer registered.
|
|
815 |
</td>
|
|
816 |
<td><code>postDeregister</code></td>
|
|
817 |
<td bgcolor="#fafafa"><code>postDeregister</code> is only called if the MBean was succesfully
|
|
818 |
unregistered.
|
|
819 |
The <a
|
|
820 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
821 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
822 |
>ScanManagerMXBean</a> uses this method to cancel
|
|
823 |
its internal java.util.Timer.
|
|
824 |
</td>
|
|
825 |
</tr>
|
|
826 |
</tbody>
|
|
827 |
</table>
|
|
828 |
</center><br></p>
|
|
829 |
</ul>
|
|
830 |
<h3>The Singleton MBean Pattern</h3>
|
|
831 |
<ul>
|
|
832 |
<p>
|
|
833 |
A singleton MBean is an MBean which can only have one
|
|
834 |
instance registered in a given MBeanServer. <br>
|
|
835 |
A singleton MBean usually has a well-known name,
|
|
836 |
which can be defined as a constant. In that case,
|
|
837 |
clients no longer need to call <code>new ObjectName(...)</code>
|
|
838 |
and catch the declared <code>MalformedObjectNameException</code>.
|
|
839 |
</p>
|
|
840 |
<p>There are already quite a few examples of singleton
|
|
841 |
MBeans in the java.lang.management API. The
|
|
842 |
ThreadingMXBean, ClassLoadingMXBean, RuntimeMXBean, etc.
|
|
843 |
are all singleton MBeans.
|
|
844 |
</p>
|
|
845 |
<p>In this example, we have two singleton MBeans:
|
|
846 |
The <code><a
|
|
847 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
848 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
849 |
>ScanManagerMXBean</a></code> and the
|
|
850 |
<code><a
|
|
851 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
852 |
title="The ResultLogManagerMXBean is in charge of managing result logs"
|
|
853 |
>ResultLogManagerMXBean</a></code>. But in fact,
|
|
854 |
the only real singleton MBean is the
|
|
855 |
<code>ScanManagerMXBean</code>. The
|
|
856 |
<code>ResultLogManagerMXBean</code> just happens to
|
|
857 |
be a singleton MBean because it has a 1-1 relationship
|
|
858 |
with the <code>ScanManagerMXBean</code>.
|
|
859 |
</p>
|
|
860 |
<p>The <code>ScanManagerMXBean</code> implements the
|
|
861 |
singleton MBean pattern in this way:
|
|
862 |
</p>
|
|
863 |
<ul>
|
|
864 |
<li>The <code>ScanManagerMXBean</code> name has a single
|
|
865 |
key property: <code>type=ScanManagerMXBean</code>.</li>
|
|
866 |
<li>Its name is defined by an ObjectName constant called
|
|
867 |
<code>SCAN_MANAGER_NAME</code> in the <code>ScanManager</code> class</li>
|
|
868 |
<li>The <code>ScanManagerMXBean</code> enforces its status of
|
|
869 |
singleton MBean. It will refuse to be registered
|
|
870 |
with a name other than
|
|
871 |
the <code>SCAN_MANAGER_NAME</code>. You can therefore depend on
|
|
872 |
the fact that the <code>ScanManagerMXBean</code> will always
|
|
873 |
be registered with its singleton <code>SCAN_MANAGER_NAME</code>
|
|
874 |
(see <code>preRegister</code>)
|
|
875 |
</li>
|
|
876 |
<li>You are not obliged to provide a name when you
|
|
877 |
register the <code>ScanManagerMXBean</code>: if you pass null,
|
|
878 |
then the <code>ScanManager</code> will be registered with
|
|
879 |
its singleton <code>SCAN_MANAGER_NAME</code>
|
|
880 |
(see <code>preRegister</code>).
|
|
881 |
</li>
|
|
882 |
<li>The <code>ScanManager</code> class has a no-arg static
|
|
883 |
<code>register</code> method that will register
|
|
884 |
the singleton instance in the Platform MBeanServer.
|
|
885 |
This static <code>register</code> method returns
|
|
886 |
a proxy to the registered singleton.
|
|
887 |
</li>
|
|
888 |
<li>The <code>ScanManager</code> class has also a static
|
|
889 |
<code>register</code> method that will create
|
|
890 |
a singleton instance in a (possibly remote)
|
|
891 |
MBeanServerConnection - using
|
|
892 |
<code>createMBean</code>.
|
|
893 |
This static <code>register</code> method
|
|
894 |
also returns a proxy to the registered singleton.
|
|
895 |
</li>
|
|
896 |
<li>Only the MBeanServer has a reference to the
|
|
897 |
singleton instance. The singleton instance is
|
|
898 |
not returned to the caller, and not kept
|
|
899 |
in any other static data structure.
|
|
900 |
</li>
|
|
901 |
</ul>
|
|
902 |
<p>
|
|
903 |
On the other hand, the <code><a
|
|
904 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
905 |
title="The ResultLogManagerMXBean is in charge of managing result logs"
|
|
906 |
>ResultLogManagerMXBean</a></code>
|
|
907 |
has a much more relaxed implementation of the pattern:
|
|
908 |
<br>It simply provides its own singleton name if it is
|
|
909 |
registered with a null ObjectName, but will not enforce
|
|
910 |
the use of that name.
|
|
911 |
</p>
|
|
912 |
<p>Note that all singleton MBean names in this example
|
|
913 |
are created using the <code>ScanManager.makeSingletonName</code>
|
|
914 |
method, which implements the pattern for ObjectNames suggested
|
|
915 |
in the JMX Best Practices.
|
|
916 |
</p>
|
|
917 |
</ul>
|
|
918 |
<h3>Managing the Life Cycle of dependent MBeans</h3>
|
|
919 |
<ul>
|
|
920 |
<p>A common task that many JMX applications have
|
|
921 |
is to manage the life cycle of MBeans registered
|
|
922 |
in the MBeanServer.</p>
|
|
923 |
<p>In this example, we have decided to follow a simple
|
|
924 |
pattern:</p>
|
|
925 |
<ul>
|
|
926 |
<li>The application is initialized simply
|
|
927 |
by registering the singleton
|
|
928 |
<a
|
|
929 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
930 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
931 |
>ScanManagerMXBean</a> in
|
|
932 |
the MBeanServer.
|
|
933 |
</li>
|
|
934 |
<li>The <code>ScanManagerMXBean</code> will then
|
|
935 |
in turn register any other MBean that the
|
|
936 |
application might need:
|
|
937 |
<ul>
|
|
938 |
<li>It creates and registers the singleton
|
|
939 |
<code><a
|
|
940 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
941 |
title="The ResultLogManagerMXBean is in charge of managing result logs"
|
|
942 |
>ResultLogManagerMXBean</a></code>
|
|
943 |
</li>
|
|
944 |
<li>It creates and registers the default
|
|
945 |
<code><a
|
|
946 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
947 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
948 |
>ScanDirConfigMXBean</a></code>
|
|
949 |
which loads the initial configuration
|
|
950 |
</li>
|
|
951 |
<li>It creates as many
|
|
952 |
<code><a
|
|
953 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
954 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
955 |
>DirectoryScannerMXBeans</a></code> as
|
|
956 |
needed when the configuration is applied
|
|
957 |
</li>
|
|
958 |
<li>It lets you create alternate
|
|
959 |
<code>ScanDirConfigMXBean</code>, to
|
|
960 |
which you can later switch in order
|
|
961 |
to apply a new alternate configuration.
|
|
962 |
</li>
|
|
963 |
</ul>
|
|
964 |
</li>
|
|
965 |
<li>When a new configuration is applied (or if the
|
|
966 |
current configuration is reapplied), the
|
|
967 |
<code>ScanManagerMXBean</code> will unregister
|
|
968 |
any <code>DirectoryScannerMXBeans</code> it has
|
|
969 |
previously registered, and will re-create
|
|
970 |
brand new <code>DirectoryScannerMXBeans</code>
|
|
971 |
from the applied configuration.
|
|
972 |
</li>
|
|
973 |
<li>When you unregister the <code>ScanManagerMXBean</code>,
|
|
974 |
it does all the cleanup for you, by unregistering
|
|
975 |
all the MBeans that it has created during the
|
|
976 |
course of the application.
|
|
977 |
</li>
|
|
978 |
</ul>
|
|
979 |
<p>The <code>ScanManagerMXBean</code> makes use of its
|
|
980 |
<code>MBeanRegistration</code> interface in order
|
|
981 |
to register the other MBeans it needs (see the
|
|
982 |
<code>ScanManager.postRegister</code> method) and to unregister
|
|
983 |
every MBean it has created (see the <code>ScanManager.preDeregister</code>
|
|
984 |
method).
|
|
985 |
</p>
|
|
986 |
<p>You will note that the <code>ScanManagerMXBean</code>
|
|
987 |
will only allow itself to be deregistered if it can be
|
|
988 |
closed - that is if there's no other action in
|
|
989 |
progress.
|
|
990 |
This is to make sure that the deregistration of
|
|
991 |
dependent MBeans will work smoothly.
|
|
992 |
<br>
|
|
993 |
The deregistration of related MBeans will happen
|
|
994 |
in the <code>ScanManager.preDeregister</code>
|
|
995 |
method.
|
|
996 |
<br>
|
|
997 |
If one of these MBeans could not be deregistered,
|
|
998 |
then the <code>ScanManagerMXBean</code> will throw
|
|
999 |
an exception, refusing to be deregistered.
|
|
1000 |
<br>This leaves you a chance to try to deregister it
|
|
1001 |
again later. Since the <code>ScanManagerMXBean</code>
|
|
1002 |
has switched its state to CLOSED before starting
|
|
1003 |
to unregister its dependent MBeans, it will refuse
|
|
1004 |
any further actions, ensuring that e.g. nobody
|
|
1005 |
can try to start it or schedule it while it
|
|
1006 |
is in that partially-deregistered state.
|
|
1007 |
</p>
|
|
1008 |
<p>Handling the LifeCycle of all the application's
|
|
1009 |
MBeans in a single MBean is usually a good design
|
|
1010 |
pattern, especially if the application is a
|
|
1011 |
module which is intended to share a JVM - or
|
|
1012 |
an MBeanServer - with other modules.
|
|
1013 |
</p>
|
|
1014 |
<p>This is specially useful if the application needs to
|
|
1015 |
be loaded and unloaded on demand: in that
|
|
1016 |
case, simply registering or unregistering the top level
|
|
1017 |
MBean (in our example the <code>ScanManagerMXBean</code>) does
|
|
1018 |
the trick.
|
|
1019 |
</p>
|
|
1020 |
</ul>
|
|
1021 |
<h3>Emitting Notifications</h3>
|
|
1022 |
<ul>
|
|
1023 |
<p>In order to emit notifications, an MBean must be
|
|
1024 |
an instance of <code>NotificationEmitter</code>.
|
|
1025 |
The <code>NotificationEmitter</code> interface defines methods
|
|
1026 |
that the MBeanServer will call on the MBean in order
|
|
1027 |
to register <code>NotificationListeners</code> with the MBean.
|
|
1028 |
</p>
|
|
1029 |
<p>It is worth noting that the MBean may not be
|
|
1030 |
invoked each time a JMX client wants to register
|
|
1031 |
a listener. For instance, the RMIConnectorServer
|
|
1032 |
registers <i>only once</i> a single listener with each MBean
|
|
1033 |
which is a <code>NotificationEmitter</code>.
|
|
1034 |
In that specific case, the listener may even be registered
|
|
1035 |
with the MBean before any client has actually subscribed
|
|
1036 |
for notifications from that particular MBean.
|
|
1037 |
</p>
|
|
1038 |
<p>An MBean can therefore make no assumption about
|
|
1039 |
which client or how many clients have registered for
|
|
1040 |
notifications.
|
|
1041 |
</p>
|
|
1042 |
<p>It is also worth noting that the logic of the
|
|
1043 |
methods defined in <code>NotificationEmitter</code> would not
|
|
1044 |
be trivial to implement from scratch. Fortunately
|
|
1045 |
the JMX API defines a helper class, called
|
|
1046 |
<code>NotificationBroadcasterSupport</code>, which
|
|
1047 |
provides an implementation for these methods.
|
|
1048 |
</p>
|
|
1049 |
<p>There are actually three ways for an MBean to
|
|
1050 |
implement <code>NotificationEmitter</code>, of which only two
|
|
1051 |
are recommended.
|
|
1052 |
</p>
|
|
1053 |
</ul>
|
|
1054 |
|
|
1055 |
<h4>Extending NotificationBroadcasterSupport</h4>
|
|
1056 |
<ul>
|
|
1057 |
<p>This is the simplest way of coding an MBean which
|
|
1058 |
is a <code>NotificationEmitter</code>:
|
|
1059 |
</p>
|
|
1060 |
<p>Simply extend <code>NotificationBroadcasterSupport</code>,
|
|
1061 |
then override its <code>getNotificationInfo</code> method
|
|
1062 |
which returns the <code>MBeanNotificationInfo[]</code> array
|
|
1063 |
that should be included in your MBean's <code>MBeanInfo</code>
|
|
1064 |
and that's it.
|
|
1065 |
<br>You just need to call the <code>sendNotification</code> method
|
|
1066 |
inherited from <code>NotificationBroadcasterSupport</code> whenever
|
|
1067 |
your MBean needs to send a notification.
|
|
1068 |
</p>
|
|
1069 |
<p>In our example, both the <a
|
|
1070 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
1071 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
1072 |
>ScanDirConfigMXBean</a> and <a
|
|
1073 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
1074 |
title="The ResultLogManagerMXBean is in charge of managing result logs"
|
|
1075 |
>ResultLogManagerMXBean</a> extend
|
|
1076 |
<code>NotificationBroadcasterSupport</code> in order
|
|
1077 |
to send notifications.
|
|
1078 |
</p>
|
|
1079 |
</ul>
|
|
1080 |
<h4>The Delegation Pattern: delegating to a
|
|
1081 |
NotificationBroadcasterSupport delegate</h4>
|
|
1082 |
<ul>
|
|
1083 |
<p>There may be cases however where delegating to a
|
|
1084 |
wrapped <code>NotificationBroadcasterSupport</code>
|
|
1085 |
object may be preferred to extending
|
|
1086 |
<code>NotificationBroadcasterSupport</code>.
|
|
1087 |
</p>
|
|
1088 |
<p>For instance, if your MBeans already derive from
|
|
1089 |
some base class, extending <code>NotificationBroadcasterSupport</code>
|
|
1090 |
might not be an option.
|
|
1091 |
</p>
|
|
1092 |
<p>Similarly, if you do not want to have the inherited
|
|
1093 |
<code>public void sendNotification(Notification notification)</code>
|
|
1094 |
method appear in the Javadoc of the concrete class of your
|
|
1095 |
MBean, you may want to consider using the delegation
|
|
1096 |
pattern instead of extending
|
|
1097 |
<code>NotificationBroadcasterSupport</code>
|
|
1098 |
</p>
|
|
1099 |
<p>In our example both the <a
|
|
1100 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
1101 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
1102 |
>ScanManagerMXBean</a> and the <a
|
|
1103 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
1104 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
1105 |
>DirectoryScannerMXBean</a> use the delegation
|
|
1106 |
pattern rather than extending
|
|
1107 |
<code>NotificationBroadcasterSupport</code>.
|
|
1108 |
In the end, choosing between one or the other method
|
|
1109 |
is more a question of taste, although the delegation
|
|
1110 |
pattern could be considered more flexible since it
|
|
1111 |
doesn't require extending any given superclass.
|
|
1112 |
</p>
|
|
1113 |
<p>It may be also worth noting that some tools like
|
|
1114 |
the JMX Module of <a
|
|
1115 |
href="http://www.netbeans.org"
|
|
1116 |
>NetBeans IDE</a>, will be able to
|
|
1117 |
generate for you all the code that delegates to a
|
|
1118 |
wrapped <code>NotificationBroadcasterSupport</code>.
|
|
1119 |
</p>
|
|
1120 |
</ul>
|
|
1121 |
|
|
1122 |
<h4>Implementing NotificationEmitter from scratch</h4>
|
|
1123 |
<ul>
|
|
1124 |
<p>This is the last possibility for an MBean that
|
|
1125 |
needs to send notifications: simply implement
|
|
1126 |
<code>NotificationEmitter</code> from scratch. This is highly
|
|
1127 |
discouraged since that logic is not trivial, and
|
|
1128 |
already provided by
|
|
1129 |
<code>NotificationBroadcasterSupport</code> anyway.
|
|
1130 |
</p>
|
|
1131 |
</ul>
|
|
1132 |
|
|
1133 |
<h4>Beware of Synchronization Locks</h4>
|
|
1134 |
<ul>
|
|
1135 |
|
|
1136 |
<p>One thing you must keep in mind when sending
|
|
1137 |
notifications is not to send them from within
|
|
1138 |
a synchronized block, or while holding a lock on
|
|
1139 |
some resource.</p>
|
|
1140 |
<p>Indeed, what happens when you send a notification
|
|
1141 |
may vary greatly depending on whether the client
|
|
1142 |
which has registered for notifications has done
|
|
1143 |
so through a <code>JMXConnector</code> (like the
|
|
1144 |
<code>JMXRMIConnector</code>)
|
|
1145 |
or through a direct reference to the MBeanServer
|
|
1146 |
(by calling
|
|
1147 |
<code>MBeanServer.addNotificationListener</code>).
|
|
1148 |
</p>
|
|
1149 |
<p>In this latter case, the listener will be invoked
|
|
1150 |
synchronously in the same thread that your MBean is
|
|
1151 |
using to send its notification. If by misfortune, the
|
|
1152 |
code of that listener now re-enters your MBean through a
|
|
1153 |
call that flows through a JMXConnector, a deadlock
|
|
1154 |
could occur. It is therefore very important to release
|
|
1155 |
any lock you may have before calling
|
|
1156 |
<code>sendNotification</code>.</p>
|
|
1157 |
<p>An easy way to do that is demonstrated in the
|
|
1158 |
<code>ScanManager</code> class. The ScanManager
|
|
1159 |
has an internal private queue of pending notifications.
|
|
1160 |
When a notification needs to be sent (e.g. because the
|
|
1161 |
ScanManager state is being switched), the notification
|
|
1162 |
is simply prepared and put into the pending notification
|
|
1163 |
queue.
|
|
1164 |
The notification queue is then processed later on,
|
|
1165 |
at the end of the method, when the processing is finally
|
|
1166 |
completed and all the locks have been released.
|
|
1167 |
<br>At this point the notification queue might already
|
|
1168 |
have been emptied by another thread - in which case
|
|
1169 |
the pending notifications will have already been
|
|
1170 |
removed from the queue. Which thread actually gets
|
|
1171 |
to send the notifications is of no importance. The
|
|
1172 |
important point is that all the locks detained by
|
|
1173 |
your MBean code in that thread were released before
|
|
1174 |
the notification was sent.
|
|
1175 |
</p>
|
|
1176 |
<p>In our example the <code>ScanManager</code> class
|
|
1177 |
ensures this by:
|
|
1178 |
<ul>
|
|
1179 |
<li>Only calling <code>sendNotification</code>
|
|
1180 |
in its private <code>sendQueuedNotifications</code>
|
|
1181 |
method.
|
|
1182 |
</li>
|
|
1183 |
<li>Only calling <code>sendQueuedNotifications</code>
|
|
1184 |
when all locks have been released.
|
|
1185 |
</li>
|
|
1186 |
<li>Never calling a method that calls
|
|
1187 |
<code>sendQueuedNotifications</code> from within
|
|
1188 |
a synchronized block.</li>
|
|
1189 |
</ul>
|
|
1190 |
</p>
|
|
1191 |
</ul>
|
|
1192 |
|
|
1193 |
|
|
1194 |
|
|
1195 |
<h4>Don't subclass Notification</h4>
|
|
1196 |
<ul>
|
|
1197 |
<p>Another common best practice when you want
|
|
1198 |
to improve interoperability is to use directly
|
|
1199 |
the Notification base classes provided in the
|
|
1200 |
JMX<sup>TM</sup> API. Do not create your own
|
|
1201 |
subclasses of these standard classes.
|
|
1202 |
</p>
|
|
1203 |
<p>Indeed, if you code your own subclass, a generic
|
|
1204 |
client, like jconsole, will not be able to receive
|
|
1205 |
that notification unless it has that custom
|
|
1206 |
subclass in its classpath.
|
|
1207 |
</p>
|
|
1208 |
<p>
|
|
1209 |
If you want your application to be interoperable, it is
|
|
1210 |
therefore preferable not to subclass any of the standard
|
|
1211 |
Notification classes. You can define your own
|
|
1212 |
Notification type string, and if you need to send
|
|
1213 |
additional data, you can put a CompositeData, or a
|
|
1214 |
HashMap of serializable standard types in the
|
|
1215 |
Notification's user data fields.
|
|
1216 |
</p>
|
|
1217 |
<p>In this example, we are using directly the
|
|
1218 |
standard notification classes:
|
|
1219 |
<ul>
|
|
1220 |
<li>The <a
|
|
1221 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
1222 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
1223 |
>ScanManagerMXBean</a> and the <a
|
|
1224 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
1225 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
1226 |
>DirectoryScannerMXBean</a> both use directly
|
|
1227 |
<code>AttributeChangeNotification</code> to notify
|
|
1228 |
changes in their <code>State</code> attribute.
|
|
1229 |
</li>
|
|
1230 |
<li>The <a
|
|
1231 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
1232 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
1233 |
>DirectoryScannerMXBean</a>
|
|
1234 |
also uses the base <code>Notification</code>
|
|
1235 |
class directly in order to notify whenever
|
|
1236 |
it finds a matching file.
|
|
1237 |
<br>In that case, we simply use the base
|
|
1238 |
<code>Notification</code>
|
|
1239 |
class with a new
|
|
1240 |
<b><code>com.sun.jmx.examples.scandir.filematch</code></b>
|
|
1241 |
type.
|
|
1242 |
</li>
|
|
1243 |
<li>The <a
|
|
1244 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
1245 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
1246 |
>ScanDirConfigMXBean</a> and <a
|
|
1247 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
1248 |
title="The ResultLogManagerMXBean is in charge of managing result logs"
|
|
1249 |
>ResultLogManagerMXBean</a> also both use the base
|
|
1250 |
<code>Notification</code> class.
|
|
1251 |
</li>
|
|
1252 |
</ul>
|
|
1253 |
<p>Careful readers will have noted that the <a
|
|
1254 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
1255 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
1256 |
>ScanManagerMXBean</a> and the <a
|
|
1257 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
1258 |
title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root."
|
|
1259 |
>DirectoryScannerMXBean</a> both use the
|
|
1260 |
<code>AttributeChangeNotification</code> class
|
|
1261 |
to notify about their state change, whereas the
|
|
1262 |
<a
|
|
1263 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
1264 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
1265 |
>ScanDirConfigMXBean</a> uses the base
|
|
1266 |
<code>Notification</code> class.
|
|
1267 |
</p>
|
|
1268 |
<p>In fact, this is because the semantics of these
|
|
1269 |
notifications is not exactly the same - although
|
|
1270 |
both denote a state change:
|
|
1271 |
<ul>
|
|
1272 |
<p>In the case of <code>ScanManagerMXBean</code>
|
|
1273 |
and <code>DirectoryScannerMXBean</code>, the
|
|
1274 |
notification which is emitted is more about a
|
|
1275 |
state transition, from one state to another.
|
|
1276 |
For instance, going from <code>RUNNING</code>
|
|
1277 |
to <code>STOPPED</code>, or from
|
|
1278 |
<code>SCHEDULED</code> to <code>STOPPED</code>.
|
|
1279 |
<br>In that case, the
|
|
1280 |
<code>AttributeChangeNotification</code> was
|
|
1281 |
more appropriate because it made it possible
|
|
1282 |
to send the previous and the new value of the
|
|
1283 |
state attribute, thus reflecting the whole
|
|
1284 |
state transition.
|
|
1285 |
</p>
|
|
1286 |
<p>In the case of the <code>ScanDirConfigMXBean</code>
|
|
1287 |
however, what is of interest is the state in
|
|
1288 |
which the MBean has arrived. Using the base
|
|
1289 |
<code>Notification</code> class with three different
|
|
1290 |
notification type strings -
|
|
1291 |
<b><code>com.sun.jmx.examples.scandir.config.loaded</code></b>,
|
|
1292 |
<b><code>com.sun.jmx.examples.scandir.config.modified</code></b>,
|
|
1293 |
and
|
|
1294 |
<b><code>com.sun.jmx.examples.scandir.config.saved</code></b> -
|
|
1295 |
was therefore closer to what we wanted to model.
|
|
1296 |
</p>
|
|
1297 |
</ul>
|
|
1298 |
</p>
|
|
1299 |
</ul>
|
|
1300 |
|
|
1301 |
<h3>Configuration MBeans</h3>
|
|
1302 |
<ul>
|
|
1303 |
<p>A common practice when designing a management application is
|
|
1304 |
to have an MBean, or a set of MBeans, dedicated to configuration.
|
|
1305 |
Separating configuration from control and monitoring allows
|
|
1306 |
more appropriate logic, and often simplifies the design and
|
|
1307 |
implementation of the management interface.
|
|
1308 |
</p>
|
|
1309 |
<p>
|
|
1310 |
In our example, the <a
|
|
1311 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
1312 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
1313 |
>ScanDirConfigMXBean</a> is dedicated to the application configuration.
|
|
1314 |
</p>
|
|
1315 |
<p>The <code>ScanDirConfigMXBean</code> will let you interactively
|
|
1316 |
modify, save, or load the application configuration. The modifications
|
|
1317 |
will not be taken into account until it is applied, by invoking
|
|
1318 |
<code>applyConfiguration</code> on the <a
|
|
1319 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
1320 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
1321 |
>ScanManagerMXBean</a>.
|
|
1322 |
It is also possible to create many configurations, by creating as
|
|
1323 |
many <code>ScanDirConfigMXBean</code>s, and then to choose and apply
|
|
1324 |
one of these configurations by calling
|
|
1325 |
<code>ScanManagerMXBean.setConfigurationMBean</code> and then
|
|
1326 |
<code>ScanManagerMXBean.applyConfiguration</code>.
|
|
1327 |
</p>
|
|
1328 |
<p>In this way, all configurations aspects are gathered and concentrated
|
|
1329 |
inside the <code>ScanDirConfigMXBean</code> instead of being scattered
|
|
1330 |
throughout all the MBeans that compose the application.
|
|
1331 |
</p>
|
|
1332 |
<p>In order to save and store the application configuration data, the
|
|
1333 |
<code>ScanDirConfigMXBean</code> uses a set of XML serializable Java beans
|
|
1334 |
defined in the <a
|
|
1335 |
href="dist/javadoc/com/sun/jmx/examples/scandir/config/package-summary.html"
|
|
1336 |
title="The com.sun.jmx.examples.scandir.config package defines XML serializable beans"
|
|
1337 |
>com.sun.jmx.examples.scandir.config</a> package. These beans are very
|
|
1338 |
simple Java beans which have been lightly annotated for XML binding.
|
|
1339 |
</p>
|
|
1340 |
<p>It is worth noting that these same beans can also be handled by the
|
|
1341 |
MXBean framework (our beans don't contain recursive data structures) and can
|
|
1342 |
therefore be used directly as attributes and parameters of MXBeans, without
|
|
1343 |
needing to be Java-serializable (the MXBean framework transform them in
|
|
1344 |
CompositeData objects - which <b>are</b> serializable).
|
|
1345 |
</p>
|
|
1346 |
<p>The same <a
|
|
1347 |
href="dist/javadoc/com/sun/jmx/examples/scandir/config/ScanManagerConfig.html"
|
|
1348 |
title="The com.sun.jmx.examples.scandir.config package defines XML serializable beans"
|
|
1349 |
>ScanManagerConfig</a> bean that we use to read from and write to the
|
|
1350 |
XML configuration file is thus also used as attribute of the <a
|
|
1351 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
1352 |
title="The ScanDirConfigMXBean is in charge of the configuration"
|
|
1353 |
>ScanDirConfigMXBean</a>. It is transformed into a <code>CompositeData</code>
|
|
1354 |
by the MXBean framework, and can be easily introspected with
|
|
1355 |
<a href="#JConsole">jconsole</a>.
|
|
1356 |
</p>
|
|
1357 |
</ul>
|
|
1358 |
<h3>MBeans Must Be Thread-Safe</h3>
|
|
1359 |
<ul>
|
|
1360 |
<p>A question often asked by newcomers to JMX technology
|
|
1361 |
is whether the MBeanServer is thread-safe. Well, the MBeanServer <b>is</b>
|
|
1362 |
thread safe, but it doesn't put any locks on the MBeans it contains. The
|
|
1363 |
MBeans can be concurrently accessed by multiple threads, and must therefore
|
|
1364 |
take care of their own thread safety.
|
|
1365 |
</p>
|
|
1366 |
<p>In this example, we have been using two methods to ensure thread
|
|
1367 |
safety for our MBeans: synchronized blocks, and semaphores.
|
|
1368 |
</p>
|
|
1369 |
<p>Using synchronized blocks is probably the most common and easiest way
|
|
1370 |
to implement thread safety in Java. When dealing with MBeans though, here
|
|
1371 |
are a couple of rules to keep in mind:
|
|
1372 |
<ul>
|
|
1373 |
<li>Don't send notifications from within a synchronized block: there's
|
|
1374 |
no way to tell whether the listener's code will be executed in the
|
|
1375 |
same thread or a different thread, and holding a lock in these
|
|
1376 |
conditions is therefore dangerous, as it could lead to deadlocks.</li>
|
|
1377 |
<li>Also avoid invoking another MBean from a synchronized block
|
|
1378 |
unless you are completely in control of both MBeans, and you can
|
|
1379 |
ascertain that it won't lead to any deadlock. Indeed, if you invoke an
|
|
1380 |
MBean exposed by another application, it can be sometime hard to
|
|
1381 |
know with certainty whether holding a lock while invoking that
|
|
1382 |
MBean will have any side effect. Maybe that MBean will make
|
|
1383 |
further calls to other MBeans which will in turn try to call
|
|
1384 |
your MBean, or maybe it will emit a
|
|
1385 |
notification, and we'll be back to the considerations just
|
|
1386 |
above.</li>
|
|
1387 |
</ul>
|
|
1388 |
</p>
|
|
1389 |
<p>Another means of implementing thread-safe code is to use semaphores.
|
|
1390 |
The <a
|
|
1391 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
1392 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
1393 |
>ScanManagerMXBean</a> uses a semaphore called
|
|
1394 |
<code>sequencer</code> to ensure
|
|
1395 |
that critical code sections are not executed concurrently. In this
|
|
1396 |
MBean, we use <code>Semaphore.tryAcquire</code> to lock the sequencer
|
|
1397 |
semaphore before entering the critical section. If the
|
|
1398 |
<code>Semaphore.tryAcquire</code> returns true then we enter the critical
|
|
1399 |
section. If it returns false, we throw an IllegalStateException, stating
|
|
1400 |
that we couldn't acquire the lock. The code looks like this:
|
|
1401 |
<pre>
|
|
1402 |
if (!sequencer.tryAcquire())
|
|
1403 |
throw new IllegalStateException("resource locked");
|
|
1404 |
try {
|
|
1405 |
// critical code here ...
|
|
1406 |
} finally {
|
|
1407 |
// Always use try/finally to ensure that the semaphore
|
|
1408 |
// will be released, even if exceptions or errors are raised!
|
|
1409 |
sequencer.release();
|
|
1410 |
}
|
|
1411 |
</pre>
|
|
1412 |
</p>
|
|
1413 |
<p>Using <code>Semaphore.tryAcquire</code> and throwing an exception if
|
|
1414 |
the semaphore is already locked makes it safer to call other MBeans
|
|
1415 |
from within the critical section: in potential deadlock situations
|
|
1416 |
the calling code will get the <code>IllegalStateException</code>
|
|
1417 |
instead of being blocked on the deadlocked lock.
|
|
1418 |
</p>
|
|
1419 |
<p>It is worth noting that each of these techniques has its own
|
|
1420 |
advantages and disadvantages - which can make one of them more or less
|
|
1421 |
appropriate depending on the inner logic of the MBean you're implementing.
|
|
1422 |
</p>
|
|
1423 |
<p>Careful readers will also have noted that we used
|
|
1424 |
<code>IllegalStateException</code> directly, instead of defining
|
|
1425 |
our own subclass of RuntimeException, which could have had a more
|
|
1426 |
precise semantics. If you define a new exception for your JMX application,
|
|
1427 |
you must keep in mind that your client will need to have the class
|
|
1428 |
of your exception in its classpath to get that exception.
|
|
1429 |
Otherwise your client will get a completely different exception, indicating a
|
|
1430 |
deserialization issue.
|
|
1431 |
</p>
|
|
1432 |
</ul>
|
|
1433 |
|
|
1434 |
<h3>Waiting for Notifications</h3>
|
|
1435 |
<ul>
|
|
1436 |
<p>Implementing code that needs to wait for notifications is sometimes
|
|
1437 |
difficult. Because notifications are asynchronous, doing something
|
|
1438 |
like:
|
|
1439 |
<pre>
|
|
1440 |
// register a notification listener
|
|
1441 |
...
|
|
1442 |
// start a management action
|
|
1443 |
...
|
|
1444 |
// wait for a notification
|
|
1445 |
...
|
|
1446 |
// do something based on whether the expected notification
|
|
1447 |
// is received
|
|
1448 |
...
|
|
1449 |
</pre>
|
|
1450 |
is not always trivial. However, there's a very easy way to do that: use
|
|
1451 |
a blocking queue of notifications.
|
|
1452 |
<pre>
|
|
1453 |
final BlockingQueue<Notification> notifQueue =
|
|
1454 |
new LinkedBlockingQueue<Notification>();
|
|
1455 |
|
|
1456 |
final NotificationListener listener = new NotificationListener() {
|
|
1457 |
public void handleNotification(Notification notification,
|
|
1458 |
Object handback) {
|
|
1459 |
try {
|
|
1460 |
// Just put the received notification in the queue.
|
|
1461 |
// It will be consumed later on.
|
|
1462 |
//
|
|
1463 |
notifQueue.put(notification);
|
|
1464 |
} catch (InterruptedException ex) {
|
|
1465 |
// OK
|
|
1466 |
}
|
|
1467 |
}
|
|
1468 |
};
|
|
1469 |
|
|
1470 |
// register the listener - possibly also as a JMXConnectionNotification
|
|
1471 |
// listener to get Notification Lost notification
|
|
1472 |
...
|
|
1473 |
// start management action
|
|
1474 |
...
|
|
1475 |
// wait for notification
|
|
1476 |
while (expected notif not received and delay not expired) {
|
|
1477 |
Notification n = notifQueue.poll(3,TimeUnit.SECONDS);
|
|
1478 |
// if expected notif, do something
|
|
1479 |
...
|
|
1480 |
}
|
|
1481 |
// if expected notification not received do something else.
|
|
1482 |
....
|
|
1483 |
</pre>
|
|
1484 |
</p>
|
|
1485 |
<p>You will note that this is a technique we've been using in the <a
|
|
1486 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html"
|
|
1487 |
title="The ScanDirAgent class defines a main method for the scandir application"
|
|
1488 |
>ScanDirAgent</a> class and in the example unit tests.
|
|
1489 |
</p>
|
|
1490 |
</ul>
|
|
1491 |
|
|
1492 |
<h3>Holding hard references to other MBeans: proxy or direct reference?</h3>
|
|
1493 |
<ul>
|
|
1494 |
<p>We have seen that MXBeans will let you return proxy references to other
|
|
1495 |
MXBeans. But should that MXBean hold a direct reference to the MXBeans it
|
|
1496 |
relates to, or would it be better for it to hold only a proxy?
|
|
1497 |
</p>
|
|
1498 |
<p>
|
|
1499 |
As a general rule it is better when an MBean reference is
|
|
1500 |
only held by the MBeanServer. It is a better design
|
|
1501 |
to hold a reference to a proxy, rather than to hold
|
|
1502 |
a hard reference to an MBean. However there are two cases
|
|
1503 |
when holding a hard reference might be preferred:
|
|
1504 |
<ol>
|
|
1505 |
<li>When MBean A needs to call a method of method B which
|
|
1506 |
is not part of its MBean interface</li>
|
|
1507 |
<li>When the overhead of going through the MBeanServer
|
|
1508 |
plus the MXBean framework is too great (frequently-called
|
|
1509 |
method, with creation of OpenType)</li>
|
|
1510 |
</ol>
|
|
1511 |
However - holding a hard reference is only advisable
|
|
1512 |
when both MBeans are created by the same piece of code,
|
|
1513 |
and the application can ensure that the life cycle
|
|
1514 |
of each MBean is consistent with regard to the other.
|
|
1515 |
</p>
|
|
1516 |
<p>In our example, the <a
|
|
1517 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
1518 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
1519 |
>ScanManagerMXBean</a> holds only proxy references to the <a
|
|
1520 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html"
|
|
1521 |
>ScanDirConfigMXBean</a> and the <a
|
|
1522 |
href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html"
|
|
1523 |
>DirectoryScannerMXBeans</a>. <br>
|
|
1524 |
However it holds a direct reference to the <a
|
|
1525 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManager.html"
|
|
1526 |
>ResultLogManager</a>. This makes it possible to pass a direct
|
|
1527 |
reference to the <code>DirectoryScannerMXBeans</code>,
|
|
1528 |
which can then log their results
|
|
1529 |
more efficiently, and would also make it possible to remove
|
|
1530 |
the <code>log</code> method from the <a
|
|
1531 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html"
|
|
1532 |
>ResultLogManagerMXBean</a> interface - leaving it in the
|
|
1533 |
<code>ResultLogManager</code> class (possibly as a package method)
|
|
1534 |
should we wish to do so.
|
|
1535 |
</p>
|
|
1536 |
|
|
1537 |
</ul>
|
|
1538 |
|
|
1539 |
<h3>Agent Class</h3>
|
|
1540 |
<ul>
|
|
1541 |
<p>The <a
|
|
1542 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html"
|
|
1543 |
title="The ScanDirAgent class defines a main method for the scandir application"
|
|
1544 |
>ScanDirAgent</a> is the Agent class for the <i>scandir</i> application.
|
|
1545 |
This class contains the <code>main</code> method to start a standalone
|
|
1546 |
<i>scandir</i> application.
|
|
1547 |
</p>
|
|
1548 |
<p>The <code>main</code> method simply registers a <a
|
|
1549 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
1550 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
1551 |
>ScanManagerMXBean</a> in the platform MBeanServer, and then waits
|
|
1552 |
for someone to call <code>ScanManagerMXBean.close</code>.
|
|
1553 |
</p>
|
|
1554 |
<p>
|
|
1555 |
When the <code>ScanManagerMXBean</code> state is switched to
|
|
1556 |
<code>ScanManagerMXBean.ScanState.CLOSED</code>, the
|
|
1557 |
<code>ScanManagerMXBean</code> is unregistered, and the application
|
|
1558 |
terminates (i.e. the main thread completes).
|
|
1559 |
</p>
|
|
1560 |
<p>Standalone JMX applications usually have an Agent class that contain
|
|
1561 |
their <code>main</code> method, which performs all the MBean
|
|
1562 |
registration steps.
|
|
1563 |
However, it is usually not a bad idea if that class can
|
|
1564 |
be easily turned into an MBean. Indeed, this will make your
|
|
1565 |
application easier to integrate in an environment where it would
|
|
1566 |
no longer be standalone and would no longer control the implementation
|
|
1567 |
of <code>main</code>. In our example the Agent
|
|
1568 |
class could be easily turned into an MBean, exposing its three
|
|
1569 |
<code>init</code>, <code>waitForClose</code> and <code>cleanup</code>
|
|
1570 |
method. However we didn't go as far as turning it into an MBean since
|
|
1571 |
the application can be already easily started by registering an instance
|
|
1572 |
of <a
|
|
1573 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html"
|
|
1574 |
title="The ScanManagerMXBean is the main MBean of the scandir application"
|
|
1575 |
>ScanManagerMXBean</a>.
|
|
1576 |
</p>
|
|
1577 |
</ul>
|
|
1578 |
<h3>Secure Client Class</h3>
|
|
1579 |
<ul>
|
|
1580 |
<p>The <a
|
|
1581 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirClient.html"
|
|
1582 |
title="The ScanDirClient class is a very short example of secure programatic client"
|
|
1583 |
>ScanDirClient</a> is an example class that shows how a
|
|
1584 |
programmatic client can connect to a secured <i>scandir</i> application.
|
|
1585 |
This class contains a <code>main</code> method which creates and
|
|
1586 |
configures a <code>JMXConnector</code> client to connect with
|
|
1587 |
a secured <i>scandir</i> daemon. This class will not work with
|
|
1588 |
the default unsecured agent since it requires mutual authentication.
|
|
1589 |
</p>
|
|
1590 |
<p>How to secure a JMX <i>scandir</i> application and run
|
|
1591 |
the secure <code>ScanDirClient</code> is discussed <a href="#secure"
|
|
1592 |
>later</a> in this document.
|
|
1593 |
</p>
|
|
1594 |
<p>The <code>ScanDirClient</code> is not really part of the
|
|
1595 |
application - and is given here only for the sake of
|
|
1596 |
the example.
|
|
1597 |
</p>
|
|
1598 |
</ul>
|
|
1599 |
|
|
1600 |
<h2><a name="h2-Testing">Testing the <i>scandir</i> Example</a></h2>
|
|
1601 |
<ul>
|
|
1602 |
<p>Make sure that you have access to junit.jar (either 3.8.1 or 3.8.2).
|
|
1603 |
Make sure also that you have junit.jar in your
|
|
1604 |
<code>CLASSPATH</code>.<br>
|
|
1605 |
Then in the example root directory (where the <code>build.xml</code>
|
|
1606 |
file is located) run the following command:
|
|
1607 |
<pre>ant test -Dlibs.junit.classpath=<i><u>path to junit jar (either 3.8.1 or 3.8.2)</u></i></pre>
|
|
1608 |
</p>
|
|
1609 |
<p>Alternatively you can open the jmx-scandir project with the
|
|
1610 |
NetBeans IDE and test the jmx-scandir project from the
|
|
1611 |
<code>Run</code> menu.
|
|
1612 |
</p>
|
|
1613 |
|
|
1614 |
</ul>
|
|
1615 |
|
|
1616 |
<h2><a name="h2-Running">Running the <i>scandir</i> Example</a></h2>
|
|
1617 |
<ul>
|
|
1618 |
<p>In the example root directory (where the <code>build.xml</code>
|
|
1619 |
file is located) run the following commands:
|
|
1620 |
<pre>ant jar
|
|
1621 |
ant run-single -Drun.class=com.sun.jmx.examples.scandir.ScanDirAgent -Djavac.includes=src</pre>
|
|
1622 |
or simply <pre>ant run</pre>
|
|
1623 |
</p>
|
|
1624 |
|
|
1625 |
<p>This will run the example using the configuration
|
|
1626 |
file provided in the src/etc directory.
|
|
1627 |
</p>
|
|
1628 |
<p>Alternatively you can open the jmx-scandir project with the
|
|
1629 |
NetBeans IDE. You can run the example by
|
|
1630 |
selecting the <code>ScanDirAgent</code> file
|
|
1631 |
and run it with <code>Run File</code> in the
|
|
1632 |
<code>Run</code> menu or simply
|
|
1633 |
set the <i>jmx-scandir</i> project as main project and
|
|
1634 |
select <code>Run Main Project</code> from the
|
|
1635 |
main menu. Both targets will use the configuration
|
|
1636 |
file provided in the src/etc directory.
|
|
1637 |
</p>
|
|
1638 |
<p>When the application is started, you can connect to
|
|
1639 |
it with <a href="#JConsole">jconsole</a>.
|
|
1640 |
</p>
|
|
1641 |
<blockquote>
|
|
1642 |
<u>Note:</u> You can also run the <i>scandir</i>
|
|
1643 |
application directly from the <code>java</code>
|
|
1644 |
command line. Make sure to build the project jar
|
|
1645 |
first.
|
|
1646 |
<br>On Unix systems:
|
|
1647 |
<pre>ant jar
|
|
1648 |
java -Djava.util.logging.config.file=logging.properties \
|
|
1649 |
-Dscandir.config.file=src/etc/testconfig.xml \
|
|
1650 |
-jar dist/jmx-scandir.jar</pre>
|
|
1651 |
<br>On Windows systems:
|
|
1652 |
<p><code>ant jar<br>
|
|
1653 |
java -Djava.util.logging.config.file=logging.properties
|
|
1654 |
-Dscandir.config.file=src\etc\testconfig.xml
|
|
1655 |
-jar dist\jmx-scandir.jar</code></p>
|
|
1656 |
</blockquote>
|
|
1657 |
</ul>
|
|
1658 |
|
|
1659 |
<h2><a name="h2-Playing">Playing with JConsole</a></h2>
|
|
1660 |
<ul>
|
|
1661 |
<p>Run the example as explained in the previous section, so
|
|
1662 |
that it uses the provided <code>src/etc/testconfig.xml</code>
|
|
1663 |
configuration file. Then start
|
|
1664 |
jconsole. In the connection window choose the process that runs
|
|
1665 |
<code>com.sun.jmx.examples.scandir.ScanDirAgent</code> or
|
|
1666 |
<code>jmx-scandir.jar</code>.
|
|
1667 |
</p>
|
|
1668 |
<p><center>
|
|
1669 |
<table border="0" cellpadding="2" cellspacing="2">
|
|
1670 |
<tr><td>
|
|
1671 |
<a href="docfiles/connect-local-ant-run.jpg"
|
|
1672 |
title="jconsole connection window - connect to local process"
|
|
1673 |
><img height="440"
|
|
1674 |
src="docfiles/connect-local-ant-run.jpg"
|
|
1675 |
alt="jconsole connection window - connect to local process"
|
|
1676 |
/></a>
|
|
1677 |
</td>
|
|
1678 |
<td>
|
|
1679 |
<a href="docfiles/connect-local-java-jar.jpg"
|
|
1680 |
title="jconsole connection window - connect to local process"
|
|
1681 |
><img height="440"
|
|
1682 |
src="docfiles/connect-local-java-jar.jpg"
|
|
1683 |
alt="jconsole connection window - connect to local process"
|
|
1684 |
/></a>
|
|
1685 |
</td></tr></table>
|
|
1686 |
</center>
|
|
1687 |
</p>
|
|
1688 |
<p>Open the MBeans tab, and look for the
|
|
1689 |
<code>ScanDirConfigMXBean</code>.
|
|
1690 |
Click on its <code>Attributes</code> node and double click on its
|
|
1691 |
<code>Configuration</code> attribute, to look at
|
|
1692 |
the loaded configuration - values in bold can
|
|
1693 |
be expanded by a double-click.
|
|
1694 |
</p>
|
|
1695 |
<p><center><a href="docfiles/scandir-config.jpg"
|
|
1696 |
title="jconsole MBean tab: ScanDirConfigMXBean"
|
|
1697 |
><img
|
|
1698 |
src="docfiles/scandir-config.jpg"
|
|
1699 |
alt="jconsole MBean tab: ScanDirConfigMXBean"
|
|
1700 |
/></a></center>
|
|
1701 |
</p>
|
|
1702 |
<p>Now go to the <code>ScanManagerMXBean</code>, click on
|
|
1703 |
its <code>Notifications</code> node, and subscribe
|
|
1704 |
for notifications. Then click on the
|
|
1705 |
<code>Operations</code> node and invoke the
|
|
1706 |
<code>start()</code> operation:
|
|
1707 |
</p>
|
|
1708 |
<p><center><a href="docfiles/scandir-start.jpg"
|
|
1709 |
title="jconsole MBean tab: ScanDirConfigMXBean"
|
|
1710 |
><img
|
|
1711 |
src="docfiles/scandir-start.jpg"
|
|
1712 |
alt="jconsole MBean tab: ScanDirConfigMXBean"
|
|
1713 |
/></a></center>
|
|
1714 |
</p>
|
|
1715 |
<p>You can see that the notifications counter was
|
|
1716 |
incremented by three: you have just scheduled,
|
|
1717 |
run, and completed a batch of directory scans.
|
|
1718 |
</p>
|
|
1719 |
<p>Now go to the <code>ResultLogManagerMXBean</code>,
|
|
1720 |
click on its <code>Attributes</code> node, and
|
|
1721 |
expand its <code>MemoryLog</code> attribute:
|
|
1722 |
</p>
|
|
1723 |
<p><center><a href="docfiles/scandir-result.jpg"
|
|
1724 |
title="jconsole MBean tab: ScanDirConfigMXBean"
|
|
1725 |
><img
|
|
1726 |
src="docfiles/scandir-result.jpg"
|
|
1727 |
alt="jconsole MBean tab: ScanDirConfigMXBean"
|
|
1728 |
/></a></center>
|
|
1729 |
</p>
|
|
1730 |
<p>You can see that the directory scan results have
|
|
1731 |
been logged.</p>
|
|
1732 |
<p>To make the application terminate go back to the
|
|
1733 |
<code>ScanManagerMXBean</code> and invoke
|
|
1734 |
<code>close()</code>. The <code>ScanDirAgent</code>
|
|
1735 |
will receive the notification, step out of
|
|
1736 |
the application main thread, and the application
|
|
1737 |
will terminate.
|
|
1738 |
</p>
|
|
1739 |
<p>This is of course a very limited scenario. Feel free
|
|
1740 |
to improvise with all the features of the example, creating
|
|
1741 |
a new configuration -
|
|
1742 |
<code>ScanManagerMXBean.createOtherConfigurationMBean</code> -
|
|
1743 |
adding multiple directory scanners to that configuration -
|
|
1744 |
<code>ScanDirConfigMXBean.addDirectoryScanner</code> -
|
|
1745 |
then switching the <code>ScanManagerMXBean</code> current
|
|
1746 |
configuration by changing the value of the <i>ConfigurationMBean</i>
|
|
1747 |
attribute - <code>ScanManagerMXBean.setConfigurationMBean</code>
|
|
1748 |
- then applying the new configuration -
|
|
1749 |
<code>ScanManagerMXBean.applyConfiguration(true)</code> -
|
|
1750 |
then scheduling repeated directory scans every 10 seconds -
|
|
1751 |
<code>ScanManagerMXBean.schedule(0,10000)</code> -
|
|
1752 |
subscribing for notifications, etc...
|
|
1753 |
</p>
|
|
1754 |
</ul>
|
|
1755 |
|
|
1756 |
<a name="secure"></a>
|
|
1757 |
<h2><a name="h2-Turning">Turning the example into a Secure JMX Application</a></h2>
|
|
1758 |
<ul>
|
|
1759 |
<p>In this section, we will see how to configure and
|
|
1760 |
start the <i>scandir</i> example so that the JVM agent
|
|
1761 |
is bootstrapped with a secure JMXConnectorServer. Indeed, until
|
|
1762 |
now we have only used the insecure local connection,
|
|
1763 |
which can only be used as long as both the client and
|
|
1764 |
the server run on the same machine. This section will
|
|
1765 |
explain how to start the <code>ScanDirAgent</code> so
|
|
1766 |
that a real secure RMIConnectorServer is started at bootstrap.
|
|
1767 |
</p>
|
|
1768 |
<p>To achieve this we will: <a href="#management.properties"
|
|
1769 |
>provide our own management.properties</a>, <a
|
|
1770 |
href="#password-access">create our own password and access files</a>,
|
|
1771 |
<a href="#keystore-truststore">provide a keystore and truststore</a>,
|
|
1772 |
<a href="#start-secure-agent">start the ScanDirAgent with the
|
|
1773 |
appropriate system properties</a>.
|
|
1774 |
</ul>
|
|
1775 |
<h3>Configuring the JVM Agent for Secure Remote Connection</h3>
|
|
1776 |
<ul>
|
|
1777 |
<p>The easiest way to <a name="management.properties">configure the
|
|
1778 |
JVM Agent</a> for Secure Remote
|
|
1779 |
Connection is to use your own <a
|
|
1780 |
href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#properties"
|
|
1781 |
title="This page describes the properties you can put in your management.properties file"
|
|
1782 |
>management.properties</a> file.
|
|
1783 |
In this example, we have copied the default
|
|
1784 |
<code>$JRE/lib/management/management.properties</code>
|
|
1785 |
file to the example's <code>src/etc</code> directory and
|
|
1786 |
modified it in <a href="src/etc/management.properties"
|
|
1787 |
title="our modified management.properties"
|
|
1788 |
>this way</a>:
|
|
1789 |
<ul>
|
|
1790 |
<li>We have set the RMI port to <u>4545</u> - this is just a
|
|
1791 |
random port number we have picked up. Feel free to use your
|
|
1792 |
own value suited to your environment.
|
|
1793 |
<pre># For setting the JMX RMI agent port use the following line
|
|
1794 |
com.sun.management.jmxremote.port=<b>4545</b></pre>
|
|
1795 |
</li>
|
|
1796 |
<li>We have <u>switched on</u> SSL <u>mutual authentication</u>
|
|
1797 |
<pre># For RMI monitoring with SSL client authentication use the following line
|
|
1798 |
com.sun.management.jmxremote.ssl.<b>need.client.auth</b>=<b>true</b></pre>
|
|
1799 |
</li>
|
|
1800 |
<li>We have also <u>secured the RMI Registry</u> with SSL
|
|
1801 |
<pre># For using an SSL/TLS <b>protected</b> RMI Registry use the following line
|
|
1802 |
com.sun.management.jmxremote.<b>registry.ssl</b>=<b>true</b></pre>
|
|
1803 |
</li>
|
|
1804 |
<li>We have provided <a
|
|
1805 |
href="src/etc/password.properties">our own password file</a>
|
|
1806 |
<pre># For a non-default password file location use the following line
|
|
1807 |
com.sun.management.jmxremote.password.file=<i>src/etc/password.properties</i></pre>
|
|
1808 |
</li>
|
|
1809 |
<li>We have provided <a
|
|
1810 |
href="src/etc/access.properties">our own access file</a>
|
|
1811 |
<pre># For a non-default password file location use the following line
|
|
1812 |
com.sun.management.jmxremote.access.file=<i>src/etc/access.properties</i></pre>
|
|
1813 |
</li>
|
|
1814 |
</ul>
|
|
1815 |
<p>You will note that we haven't provided any value
|
|
1816 |
for the other security properties, like
|
|
1817 |
<code>com.sun.management.jmxremote.authenticate=true</code>,
|
|
1818 |
because these properties already default to a value
|
|
1819 |
which enables security by default.
|
|
1820 |
Note however that protecting the RMI Registry with SSL
|
|
1821 |
improves the application security, but only as long as
|
|
1822 |
mutual authentication is also switched on. Otherwise, just
|
|
1823 |
anybody would be able to connect to the registry and
|
|
1824 |
get the RMIServer stub.
|
|
1825 |
</p>
|
|
1826 |
<p>We do recommend that you <u>use the most secure configuration
|
|
1827 |
when you deploy a JMX agent</u> - which means <u>switching on
|
|
1828 |
SSL protection for the RMI registry</u> <b>and</b> <u>requiring
|
|
1829 |
mutual authentication</u>, as we show in this example.
|
|
1830 |
</p>
|
|
1831 |
<p>We will use the <code>com.sun.management.config.file</code>
|
|
1832 |
system property to pass our <a
|
|
1833 |
href="src/etc/management.properties">management.properties</a>
|
|
1834 |
file to the <code>ScanDirAgent</code>.
|
|
1835 |
</p>
|
|
1836 |
</ul>
|
|
1837 |
|
|
1838 |
<h3>Creating a password and access file</h3>
|
|
1839 |
<ul>
|
|
1840 |
<p>As explained above, we have created our own
|
|
1841 |
<a href="src/etc/password.properties">password file</a>
|
|
1842 |
and <a href="src/etc/access.properties">access file</a>
|
|
1843 |
for <a name="password-access">access control and authorization</a>.
|
|
1844 |
</p>
|
|
1845 |
<p>In the password file, we have defined two logins:
|
|
1846 |
<i>guest</i> and <i>admin</i>. The password for
|
|
1847 |
<i>guest</i> is <i>guestpasswd</i> and the password
|
|
1848 |
for <i>admin</i> is <i>adminpasswd</i>.
|
|
1849 |
</p>
|
|
1850 |
<p>In the access file, we have mapped these two logins
|
|
1851 |
to access rights: the <i>admin</i> login has <i>read-write</i>
|
|
1852 |
access, while the <i>guest</i> login only has <i>read-only</i>.
|
|
1853 |
</p>
|
|
1854 |
<p>Before starting the <code>ScanDirAgent</code>, you will
|
|
1855 |
need to restrict access permission to the password file,
|
|
1856 |
in such a way that nobody but you can read it. Otherwise, the
|
|
1857 |
JVM Agent will refuse to start the JMXConnectorServer, as it will
|
|
1858 |
fear that security can be compromised if other parties can
|
|
1859 |
have read access to the password file. How to restrict
|
|
1860 |
read access to the password file is explained in detail
|
|
1861 |
<a href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#PasswordAccessFiles"
|
|
1862 |
title="Using Password and Access Files"
|
|
1863 |
>here</a>.
|
|
1864 |
</p>
|
|
1865 |
<p>As we have seen above, the location
|
|
1866 |
of our access and password files is configured in our own <a
|
|
1867 |
href="src/etc/management.properties">management.properties</a>
|
|
1868 |
file.
|
|
1869 |
</p>
|
|
1870 |
</ul>
|
|
1871 |
<h3>Keystore and Truststore</h3>
|
|
1872 |
<ul>
|
|
1873 |
<p>Using SSL with mutual authentication means that both
|
|
1874 |
client and server will need a <a name="keystore-truststore"
|
|
1875 |
>keystore and a truststore</a>
|
|
1876 |
to store their own certificates, and the certificates of
|
|
1877 |
the parties they trust. Usually, client and server will
|
|
1878 |
have their own keystore and truststore.
|
|
1879 |
</p>
|
|
1880 |
<p>For the sake of simplicity - and to get you started
|
|
1881 |
without the tedious necessity of creating your own keystore
|
|
1882 |
and truststore, we are providing a dummy keystore and
|
|
1883 |
truststore, containing a certificate self-signed by duke.
|
|
1884 |
The password for our keystore is <i>password</i>, and the
|
|
1885 |
password for our truststore is <i>trustword</i>.
|
|
1886 |
We suggest that you first get the example running with the
|
|
1887 |
keystore and truststore we are providing before attempting
|
|
1888 |
to use your own keystore and truststore.
|
|
1889 |
</p>
|
|
1890 |
<p>A secure application will obviously need to use its own
|
|
1891 |
keystore and truststore, <b><u>and should not rely on the keystore
|
|
1892 |
and truststore we are providing here!</u></b>
|
|
1893 |
</p>
|
|
1894 |
<p>How to create your own keystore and truststore, is explained
|
|
1895 |
in <a
|
|
1896 |
href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#SSL_enabled"
|
|
1897 |
title="Monitoring and Management Using JMX"
|
|
1898 |
>here</a>.
|
|
1899 |
As shown <a href="#start-secure-agent">later</a>,
|
|
1900 |
we will need to use <a
|
|
1901 |
href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#SSL_enabled"
|
|
1902 |
>system properties</a> to pass our truststore
|
|
1903 |
and keystore to the <code>ScanDirAgent</code>.
|
|
1904 |
</p>
|
|
1905 |
</ul>
|
|
1906 |
<h3>Starting a Secure <i>scandir</i> agent</h3>
|
|
1907 |
<ul>
|
|
1908 |
<p>To start a <a name="start-secure-agent"
|
|
1909 |
>secure <i>scandir</i> agent</a>, go to the
|
|
1910 |
<i>scandir</i> example root directory and type the
|
|
1911 |
following command:</p>
|
|
1912 |
<p>On Unix Systems:
|
|
1913 |
<pre>ant jar
|
|
1914 |
java \
|
|
1915 |
-Djava.util.logging.config.file=logging.properties \
|
|
1916 |
-Djavax.net.ssl.keyStore=keystore \
|
|
1917 |
-Djavax.net.ssl.keyStorePassword=password \
|
|
1918 |
-Djavax.net.ssl.trustStore=truststore \
|
|
1919 |
-Djavax.net.ssl.trustStorePassword=trustword \
|
|
1920 |
-Dcom.sun.management.config.file=src/etc/management.properties \
|
|
1921 |
-Dscandir.config.file=src/etc/testconfig.xml \
|
|
1922 |
-jar dist/jmx-scandir.jar</pre>
|
|
1923 |
</p>
|
|
1924 |
<p>On Windows Systems:
|
|
1925 |
<p><code>ant jar<br>
|
|
1926 |
java
|
|
1927 |
-Djava.util.logging.config.file=logging.properties
|
|
1928 |
-Djavax.net.ssl.keyStore=keystore
|
|
1929 |
-Djavax.net.ssl.keyStorePassword=password
|
|
1930 |
-Djavax.net.ssl.trustStore=truststore
|
|
1931 |
-Djavax.net.ssl.trustStorePassword=trustword
|
|
1932 |
-Dcom.sun.management.config.file=src\etc\management.properties
|
|
1933 |
-Dscandir.config.file=src\etc\testconfig.xml
|
|
1934 |
-jar dist\jmx-scandir.jar</code></p>
|
|
1935 |
</p>
|
|
1936 |
<p>If you start jconsole now, you will see that you
|
|
1937 |
are still able to connect to the agent using the
|
|
1938 |
local connection. However, if you try to connect
|
|
1939 |
through the remote connector, using
|
|
1940 |
<a href="docfiles/remote-connection.jpg">localhost:4545</a>,
|
|
1941 |
the connection will <a href="docfiles/remote-connection-failed.jpg"
|
|
1942 |
>fail</a>, even if you provide a correct login/password
|
|
1943 |
pair. Indeed, since the JMXConnectorServer is now protected with SSL,
|
|
1944 |
jconsole must also be configured with the appropriate SSL parameters
|
|
1945 |
so that it can authenticate the server and get authenticated by the
|
|
1946 |
server too as the SSL configuration of the server requires mutual
|
|
1947 |
authentication.
|
|
1948 |
</p>
|
|
1949 |
<p>The next section will discuss how to connect to the
|
|
1950 |
secure agent.
|
|
1951 |
</p>
|
|
1952 |
</ul>
|
|
1953 |
|
|
1954 |
<h2><a name="h2-Connecting">Connecting to the Secure JMX Application</a></h2>
|
|
1955 |
<ul>
|
|
1956 |
<p>We will now see how to connect to the secure agent,
|
|
1957 |
using jconsole, and using a programmatic client.
|
|
1958 |
</p>
|
|
1959 |
</ul>
|
|
1960 |
|
|
1961 |
<h3>Using jconsole to connect to the secure agent</h3>
|
|
1962 |
<ul>
|
|
1963 |
<p>The only special thing you need to do in order to
|
|
1964 |
be able to connect to your secure agent with
|
|
1965 |
jconsole, is to give it a keystore (containing
|
|
1966 |
its client certificate) and a truststore (containing
|
|
1967 |
the certificates of the servers it can trust).
|
|
1968 |
In our example, we use the same keystore/truststore
|
|
1969 |
pair on the client and server side - but this is
|
|
1970 |
not what a real application would do.
|
|
1971 |
Indeed a real application would have different
|
|
1972 |
certificates for the client and the server, and
|
|
1973 |
thus use different keystores (and probably truststores).
|
|
1974 |
More information on SSL authentication can be obtained from the <a
|
|
1975 |
href="http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#HowSSLWorks"
|
|
1976 |
title="How SSL Works"
|
|
1977 |
>Java<sup>TM</sup> Secure Socket Extension (JSSE) Reference Guide</a>.
|
|
1978 |
</p>
|
|
1979 |
<p>To start jconsole with our provided keystore and
|
|
1980 |
truststore, go to the scandir example root directory and
|
|
1981 |
type in the following command:
|
|
1982 |
<p><code>jconsole
|
|
1983 |
-J-Djava.util.logging.config.file=logging.properties
|
|
1984 |
-J-Djavax.net.ssl.keyStore=keystore
|
|
1985 |
-J-Djavax.net.ssl.keyStorePassword=password
|
|
1986 |
-J-Djavax.net.ssl.trustStore=truststore
|
|
1987 |
-J-Djavax.net.ssl.trustStorePassword=trustword</code></p>
|
|
1988 |
</p>
|
|
1989 |
<p>The <code>-J-Djava.util.logging.config.file=logging.properties</code>
|
|
1990 |
flag is not mandatory, but passing a <code>logging.properties</code>
|
|
1991 |
may help you debug connection problems if anything goes wrong.
|
|
1992 |
</p>
|
|
1993 |
<p>In jconsole connection window, choose to connect to a
|
|
1994 |
remote process, using the address <i>localhost:4545</i>
|
|
1995 |
and the guest login:
|
|
1996 |
</p>
|
|
1997 |
<p><center><a href="docfiles/remote-connection.jpg"
|
|
1998 |
><img src="docfiles/remote-connection.jpg"
|
|
1999 |
alt="jconsole connection window"/></a></center>
|
|
2000 |
</p>
|
|
2001 |
<p>You will see that the agent will let view all the
|
|
2002 |
MBeans and their attributes, but will reject any
|
|
2003 |
attribute modification or remote method invocation.
|
|
2004 |
</p>
|
|
2005 |
<hr>
|
|
2006 |
<p><u>Note:</u> if jconsole fails to connect and show
|
|
2007 |
you <a href="docfiles/remote-connection-failed.jpg">this screen</a>
|
|
2008 |
you have probably misspelled some of the properties on jconsole
|
|
2009 |
command line, or you didn't start jconsole from the
|
|
2010 |
scandir example root directory where our <code>truststore</code>
|
|
2011 |
and <code>keystore</code> files are located. This article - <a
|
|
2012 |
href="http://blogs.sun.com/roller/page/jmxetc?entry=troubleshooting_connection_problems_in_jconsole"
|
|
2013 |
title="Troubleshooting connection problems in JConsole"
|
|
2014 |
>Troubleshooting connection problems in JConsole</a> - may help
|
|
2015 |
you figure out what is going wrong.
|
|
2016 |
</p>
|
|
2017 |
<hr>
|
|
2018 |
</ul>
|
|
2019 |
|
|
2020 |
<h3>Writing a programmatic client to connect to the secure agent</h3>
|
|
2021 |
<ul>
|
|
2022 |
<p>
|
|
2023 |
In this section we will show the steps involved in writing
|
|
2024 |
a programmatic client that will connect to our secure agent.
|
|
2025 |
</p>
|
|
2026 |
<p>The <a
|
|
2027 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirClient.html"
|
|
2028 |
title="The ScanDirClient class is a very short example of secure programatic client"
|
|
2029 |
>ScanDirClient</a> is an example class that shows how a
|
|
2030 |
programmatic client can connect to a secured <i>scandir</i> application.
|
|
2031 |
This class contains a <code>main</code> method which creates and
|
|
2032 |
configures a <code>JMXConnector</code> client to connect with
|
|
2033 |
the secured <i>scandir</i> agent.
|
|
2034 |
</p>
|
|
2035 |
<p>The secure client differs only from a non secure client in
|
|
2036 |
so far as it needs to use SSL RMI Factories and credentials to
|
|
2037 |
connect to the secure agent. The steps required mainly involve:
|
|
2038 |
<ul>
|
|
2039 |
<li>Creating an empty environment map:
|
|
2040 |
<pre>
|
|
2041 |
// Create an environment map to hold connection properties
|
|
2042 |
// like credentials etc... We will later pass this map
|
|
2043 |
// to the JMX Connector.
|
|
2044 |
//
|
|
2045 |
System.out.println("\nInitialize the environment map");
|
|
2046 |
final Map<String,Object> env = new HashMap<String,Object>();
|
|
2047 |
</pre>
|
|
2048 |
</li>
|
|
2049 |
<li>Putting the client's credentials in that map:
|
|
2050 |
<i>(here the client will log in as <b>guest</b>)</i>
|
|
2051 |
<pre>
|
|
2052 |
// Provide the credentials required by the server
|
|
2053 |
// to successfully perform user authentication
|
|
2054 |
//
|
|
2055 |
final String[] credentials = new String[] { "guest" , "guestpasswd" };
|
|
2056 |
env.put("jmx.remote.credentials", credentials);
|
|
2057 |
</pre>
|
|
2058 |
</li>
|
|
2059 |
<li>Providing an <code>SslRMIClientSocketFactory</code> to interact
|
|
2060 |
with the secure RMI Registry:
|
|
2061 |
<pre>
|
|
2062 |
// Provide the SSL/TLS-based RMI Client Socket Factory required
|
|
2063 |
// by the JNDI/RMI Registry Service Provider to communicate with
|
|
2064 |
// the SSL/TLS-protected RMI Registry
|
|
2065 |
//
|
|
2066 |
env.put("com.sun.jndi.rmi.factory.socket",
|
|
2067 |
new SslRMIClientSocketFactory());
|
|
2068 |
</pre>
|
|
2069 |
</li>
|
|
2070 |
<li>Creating a JMXConnector and connecting with the
|
|
2071 |
secure server:
|
|
2072 |
<pre>
|
|
2073 |
// Create the RMI connector client and
|
|
2074 |
// connect it to the secure RMI connector server.
|
|
2075 |
// args[0] is the server's host - localhost
|
|
2076 |
// args[1] is the secure server port - 4545
|
|
2077 |
//
|
|
2078 |
System.out.println("\nCreate the RMI connector client and " +
|
|
2079 |
"connect it to the RMI connector server");
|
|
2080 |
final JMXServiceURL url = new JMXServiceURL(
|
|
2081 |
"service:jmx:rmi:///jndi/rmi://"+args[0]+":"+args[1]+
|
|
2082 |
"/jmxrmi");
|
|
2083 |
final JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
|
|
2084 |
</pre>
|
|
2085 |
</li>
|
|
2086 |
</ul>
|
|
2087 |
<p>For this to work, we also need to start the <code>ScanDirClient</code>
|
|
2088 |
with the appropriate system properties that will point to our
|
|
2089 |
<code>keystore</code> and <code>truststore</code>. To start the secure
|
|
2090 |
client, go to the <i>scandir</i> example root directory and type
|
|
2091 |
the following command:
|
|
2092 |
<p><code>ant jar<br>
|
|
2093 |
java
|
|
2094 |
-Djava.util.logging.config.file=logging.properties
|
|
2095 |
-Djavax.net.ssl.keyStore=keystore
|
|
2096 |
-Djavax.net.ssl.keyStorePassword=password
|
|
2097 |
-Djavax.net.ssl.trustStore=truststore
|
|
2098 |
-Djavax.net.ssl.trustStorePassword=trustword
|
|
2099 |
-classpath dist/jmx-scandir.jar
|
|
2100 |
com.sun.jmx.examples.scandir.ScanDirClient localhost 4545
|
|
2101 |
</code></p>
|
|
2102 |
</p>
|
|
2103 |
<p>You should be seeing this trace:
|
|
2104 |
<center><table width="90%" border="0" bgcolor="#eeeeee">
|
|
2105 |
<tr><td>
|
|
2106 |
<pre>
|
|
2107 |
Initialize the environment map
|
|
2108 |
|
|
2109 |
Create the RMI connector client and connect it to the RMI connector server
|
|
2110 |
Connecting to: service:jmx:rmi:///jndi/rmi://localhost:4545/jmxrmi
|
|
2111 |
|
|
2112 |
Get the MBeanServerConnection
|
|
2113 |
|
|
2114 |
Get ScanDirConfigMXBean from ScanManagerMXBean
|
|
2115 |
|
|
2116 |
Get 'Configuration' attribute on ScanDirConfigMXBean
|
|
2117 |
|
|
2118 |
Configuration:
|
|
2119 |
|
|
2120 |
<ScanManager xmlns="jmx:com.sun.jmx.examples.scandir.config" name="testconfig">
|
|
2121 |
<InitialResultLogConfig>
|
|
2122 |
<LogFileMaxRecords>2048</LogFileMaxRecords>
|
|
2123 |
<LogFileName>build/scandir.log</LogFileName>
|
|
2124 |
<MemoryMaxRecords>128</MemoryMaxRecords>
|
|
2125 |
</InitialResultLogConfig>
|
|
2126 |
<DirectoryScannerList>
|
|
2127 |
<DirectoryScanner name="scan-build">
|
|
2128 |
<Actions>NOTIFY LOGRESULT</Actions>
|
|
2129 |
<ExcludeFiles/>
|
|
2130 |
<IncludeFiles>
|
|
2131 |
<FileFilter>
|
|
2132 |
<FilePattern>.*\.class</FilePattern>
|
|
2133 |
<SizeExceedsMaxBytes>4096</SizeExceedsMaxBytes>
|
|
2134 |
</FileFilter>
|
|
2135 |
</IncludeFiles>
|
|
2136 |
<RootDirectory>build</RootDirectory>
|
|
2137 |
</DirectoryScanner>
|
|
2138 |
</DirectoryScannerList>
|
|
2139 |
</ScanManager>
|
|
2140 |
|
|
2141 |
Invoke 'close' on ScanManagerMXBean
|
|
2142 |
|
|
2143 |
Got expected security exception: java.lang.SecurityException: Access denied!
|
|
2144 |
Invalid access level for requested MBeanServer operation.
|
|
2145 |
|
|
2146 |
Close the connection to the server
|
|
2147 |
|
|
2148 |
Bye! Bye!
|
|
2149 |
</pre>
|
|
2150 |
</td></tr></table></center>
|
|
2151 |
<p>If the <code>ScanDirClient</code> fails to connect with
|
|
2152 |
the secure agent, then this article - <a
|
|
2153 |
href="http://blogs.sun.com/roller/page/jmxetc?entry=troubleshooting_connection_problems_in_jconsole"
|
|
2154 |
title="Troubleshooting connection problems in JConsole"
|
|
2155 |
>Troubleshooting connection problems in JConsole</a> - may help
|
|
2156 |
you figure out what is going wrong. Indeed the connection steps
|
|
2157 |
performed by the <code>ScanDirClient</code> are very similar to
|
|
2158 |
those performed by <code>jconsole</code>, and the problems you
|
|
2159 |
could encounter are identical. Just remember that
|
|
2160 |
<code>jconsole</code> needs the extra <code>-J</code> flag to pass
|
|
2161 |
system properties to the VM, which is not needed with regular
|
|
2162 |
<code>java</code> launcher invocations.
|
|
2163 |
</p>
|
|
2164 |
</ul>
|
|
2165 |
|
|
2166 |
<h2><a name="h2-Conclusion">Conclusion</a></h2>
|
|
2167 |
<ul>
|
|
2168 |
<p>
|
|
2169 |
In this document, we have presented an advanced
|
|
2170 |
JMX example, and shown how to run a secure
|
|
2171 |
JMX agent in a production environment.
|
|
2172 |
We have also shown how to connect to such a
|
|
2173 |
secure agent with both jconsole and a programmatic
|
|
2174 |
client. We have also discuss various JMX
|
|
2175 |
design-patterns and best practices.
|
|
2176 |
Readers who would wish to learn more about JMX, and
|
|
2177 |
Monitoring and Management of the JVM, are invited
|
|
2178 |
to follow the links given in reference below.
|
|
2179 |
</p>
|
|
2180 |
</ul>
|
|
2181 |
<h2><a name="h2-References">References</a></h2>
|
|
2182 |
<ol>
|
|
2183 |
<li><a href="http://java.sun.com/products/JavaManagement/best-practices.html"
|
|
2184 |
>JMX Best Practices</a>: This document describes best practices that
|
|
2185 |
have been identified for modeling using the JMX API. </li>
|
|
2186 |
<li><a href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html"
|
|
2187 |
>Monitoring and Management Using JMX</a>: How to enable, configure, and
|
|
2188 |
connect to the JVM JMX agent.</li>
|
|
2189 |
<li><a name="JConsole"><a
|
|
2190 |
href="http://java.sun.com/javase/6/docs/technotes/guides/management/jconsole.html"
|
|
2191 |
>Using JConsole</a>: JConsole is a JMX-Compliant monitoring tool which allows
|
|
2192 |
you to interact graphically with your own MBeans.
|
|
2193 |
</li>
|
|
2194 |
<li><a href="http://java.sun.com/javase/6/docs/technotes/guides/management/"
|
|
2195 |
>Monitoring and Management for the Java Platform</a>: The Java Platform
|
|
2196 |
Standard Edition (Java SE) 6 provides comprehensive monitoring and
|
|
2197 |
management support for the Java platform. </li>
|
|
2198 |
<li><a href="http://java.sun.com/products/JavaManagement/community/jmx_blogs.html"
|
|
2199 |
>List of JMX-related Blogs</a>: This page provides links to the
|
|
2200 |
different web logs written by members of the Sun team working on the
|
|
2201 |
JMX API.</li>
|
|
2202 |
<li><a
|
|
2203 |
href="http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#HowSSLWorks"
|
|
2204 |
title="The JSSE Reference Guide"
|
|
2205 |
>Java<sup>TM</sup> Secure Socket Extension (JSSE) Reference Guide</a>:
|
|
2206 |
comprehensive documentation about the Java<sup>TM</sup> Secure Socket
|
|
2207 |
Extension (JSSE)
|
|
2208 |
</li>
|
|
2209 |
<li><a href="http://java.sun.com/javase/6/docs/"
|
|
2210 |
>Java SE 6 Documentation Index</a>: This document covers the
|
|
2211 |
Java<sup>TM</sup> Platform, Standard Edition 6 JDK.</li>
|
|
2212 |
</ol>
|
|
2213 |
<p>
|
|
2214 |
<hr>
|
|
2215 |
<p>
|
|
2216 |
</body>
|
|
2217 |
</html>
|