author | darcy |
Tue, 19 May 2015 13:30:03 -0700 | |
changeset 30678 | a8b7fd8ede97 |
parent 27565 | 729f9700483a |
permissions | -rw-r--r-- |
2 | 1 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
2 |
||
3 |
<html> |
|
4 |
<head> |
|
5 |
<!-- |
|
23010
6dadb192ad81
8029235: Update copyright year to match last edit in jdk8 jdk repository for 2013
lana
parents:
21278
diff
changeset
|
6 |
Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
||
5506 | 19 |
- Neither the name of Oracle nor the names of its |
2 | 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 |
||
30678 | 36 |
<title>JMX™ "scandir" Example</title> |
2 | 37 |
</head> |
38 |
<body> |
|
27565 | 39 |
|
30678 | 40 |
<h1><center>Java™ Management Extensions (JMX™) <i>scandir</i> Example</center></h1> |
27565 | 41 |
|
2 | 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> |
|
27565 | 62 |
<p>This example is an advanced JMX example, which presents |
2 | 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> |
|
27565 | 72 |
<u>Note:</u> This example was developed using <a |
2 | 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> |
|
27565 | 77 |
<li>or <a href="http://ant.apache.org/">Apache Ant 1.6.5</a> and |
2 | 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> |
|
27565 | 83 |
<p><a name="setup">In order to build the example</a>, |
2 | 84 |
<u>you may need to copy the jmx-scandir</u> |
27565 | 85 |
directory to somewhere where you have write permissions. |
2 | 86 |
<br>In that case, you will need to update the <i>nbjdk.home</i> variable |
27565 | 87 |
in the copied <i><a href="build.properties">build.properties</a></i> |
88 |
file located at the root of the copied project directory. |
|
2 | 89 |
Please make sure that this variable points to the JDK 6 home directory. |
90 |
</p> |
|
27565 | 91 |
<p>If you wish to run the testsuite from within the <a |
2 | 92 |
href="http://www.netbeans.org">NetBeans IDE</a> you will also have |
27565 | 93 |
to set the <i>libs.junit.classpath</i> variable in |
94 |
<a href="build.properties">build.properties</a>. |
|
2 | 95 |
The <i>libs.junit.classpath</i> variable should point to your |
27565 | 96 |
<a href="http://sourceforge.net/projects/junit/">junit.jar</a>, |
2 | 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> |
|
27565 | 119 |
<p>Before reading further, you will need to generate the |
2 | 120 |
Java Documentation for the example's sources.</p> |
27565 | 121 |
<p>In the example root directory (where the <code>build.xml</code> |
2 | 122 |
file is located) run the following command: |
123 |
<pre>ant javadoc</pre> |
|
124 |
</p> |
|
27565 | 125 |
<p>Alternatively you can open the jmx-scandir project with the |
2 | 126 |
NetBeans IDE and generate the Javadoc from its <code>Build</code> |
127 |
menu. |
|
128 |
</p> |
|
27565 | 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> |
|
2 | 131 |
</ul> |
27565 | 132 |
|
2 | 133 |
<h2><a name="h2-Overview">Overview of the <i>scandir</i> Example</a></h2> |
27565 | 134 |
|
2 | 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. |
|
27565 | 187 |
The corresponding MBeans will be created later, only |
2 | 188 |
when you later |
27565 | 189 |
ask the <code><a |
2 | 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 |
|
27565 | 223 |
maximum capacity. |
2 | 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 |
|
27565 | 230 |
new result log is created. |
2 | 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 |
|
27565 | 249 |
MBean created by the <code><a |
2 | 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 |
|
27565 | 261 |
provided in the <a |
2 | 262 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html" |
27565 | 263 |
>ScanDirAgent</a> class. The <code>main()</code> simply registers |
264 |
a <code><a |
|
2 | 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 |
|
27565 | 284 |
doesn't exist, it will be created when |
2 | 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 |
|
27565 | 291 |
the System property <code>user.home</code>). |
292 |
If that file doesn't exists, it will be created when |
|
2 | 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 |
|
27565 | 302 |
main class. Hence when you invoke from the NetBeans IDE |
303 |
<i>Run Project</i> on the <i>jmx-scandir</i> project, |
|
2 | 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> |
|
27565 | 323 |
<ul> |
2 | 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> |
|
27565 | 395 |
<blockquote><u>Hint:</u> In order to simplify the task of coding a |
2 | 396 |
JMX programmatic client, we recommend that getters, setters, and |
27565 | 397 |
operations defined in MBean and MXBean interfaces throw |
2 | 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> |
|
27565 | 402 |
Since the life cycle of the proxy object is not directly tied to |
2 | 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. |
|
27565 | 513 |
<br>For instance, most MBean names defined by |
2 | 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 |
|
27565 | 522 |
object. For instance , <a |
2 | 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 |
|
27565 | 607 |
to carry out some actions right after it has been |
2 | 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> |
|
27565 | 620 |
<p>The <code>MBeanRegistration</code> interface is a callback |
621 |
interface which defines pre and post registration and |
|
2 | 622 |
unregistration callbacks. |
623 |
</p> |
|
624 |
<p> |
|
625 |
When an MBean implementing this interface is created |
|
27565 | 626 |
(with <code>createMBean</code>) or registered |
2 | 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 |
|
27565 | 634 |
in a private instance variable for later use. |
2 | 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 |
|
27565 | 640 |
their own names, make sanity checks, perform |
2 | 641 |
initialization steps or cleanup actions. |
642 |
</p> |
|
643 |
<p><br><center> |
|
27565 | 644 |
<table border="1" cellpadding="4" cellspacing="2" |
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> |
|
27565 | 657 |
<td bgcolor="#fafafa">The <a |
658 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 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 |
|
27565 | 662 |
register other MBeans, such as the |
2 | 663 |
<a |
664 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" |
|
665 |
title="The ResultLogManagerMXBean is in charge of managing result logs" |
|
27565 | 666 |
>ResultLogManagerMXBean</a>, and the |
2 | 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> |
|
27565 | 678 |
<td bgcolor="#fafafa">The <a |
2 | 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 |
|
27565 | 684 |
illegal. Throwing an exception in |
2 | 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 |
|
27565 | 695 |
value of the <code>name=</code> property of |
2 | 696 |
the ObjectName it is given into its |
27565 | 697 |
ScanManagerConfig bean. |
2 | 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 |
|
27565 | 707 |
eventually registered. |
2 | 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 |
|
27565 | 713 |
provided. Similarly, the <a |
714 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 715 |
title="The ScanManagerMXBean is the main MBean of the scandir application" |
27565 | 716 |
>ScanManagerMXBean</a> |
2 | 717 |
always returns its singleton ObjectName |
27565 | 718 |
defined by <a |
719 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html#SCAN_MANAGER_NAME" |
|
2 | 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> |
|
27565 | 739 |
<td bgcolor="#fafafa">The <code>postRegister</code> method |
2 | 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. |
|
27565 | 748 |
The <a |
749 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 750 |
title="The ScanManagerMXBean is the main MBean of the scandir application" |
751 |
>ScanManagerMXBean</a> uses <code>postRegister</code> to create |
|
27565 | 752 |
and register other MBeans, such as the |
2 | 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> |
|
27565 | 769 |
<td bgcolor="#fafafa">The <a |
770 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 771 |
title="The ScanManagerMXBean is the main MBean of the scandir application" |
772 |
>ScanManagerMXBean</a> uses this method to verify |
|
27565 | 773 |
that its state allows it to be deregistered. |
2 | 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 |
|
27565 | 778 |
the MBeanServer. |
2 | 779 |
Take particular care when implementing business logic |
27565 | 780 |
in this method: if the logic you implement has an |
781 |
unfortunate bug which makes it always throw an |
|
2 | 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> |
|
27565 | 791 |
<td bgcolor="#fafafa">The <a |
792 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 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" |
|
27565 | 799 |
>ResultLogManagerMXBean</a>, the |
2 | 800 |
<a |
801 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" |
|
802 |
title="The ScanDirConfigMXBean is in charge of the configuration" |
|
27565 | 803 |
>ScanDirConfigMXBeans</a> it has created, and the |
2 | 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. |
|
27565 | 819 |
The <a |
820 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 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, |
|
27565 | 837 |
clients no longer need to call <code>new ObjectName(...)</code> |
2 | 838 |
and catch the declared <code>MalformedObjectNameException</code>. |
839 |
</p> |
|
840 |
<p>There are already quite a few examples of singleton |
|
27565 | 841 |
MBeans in the java.lang.management API. The |
2 | 842 |
ThreadingMXBean, ClassLoadingMXBean, RuntimeMXBean, etc. |
843 |
are all singleton MBeans. |
|
844 |
</p> |
|
845 |
<p>In this example, we have two singleton MBeans: |
|
27565 | 846 |
The <code><a |
847 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 848 |
title="The ScanManagerMXBean is the main MBean of the scandir application" |
27565 | 849 |
>ScanManagerMXBean</a></code> and the |
2 | 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, |
|
27565 | 854 |
the only real singleton MBean is the |
855 |
<code>ScanManagerMXBean</code>. The |
|
2 | 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> |
|
27565 | 864 |
<li>The <code>ScanManagerMXBean</code> name has a single |
2 | 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> |
|
27565 | 868 |
<li>The <code>ScanManagerMXBean</code> enforces its status of |
2 | 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 |
|
27565 | 872 |
the fact that the <code>ScanManagerMXBean</code> will always |
2 | 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> |
|
27565 | 882 |
<li>The <code>ScanManager</code> class has a no-arg static |
2 | 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> |
|
27565 | 888 |
<li>The <code>ScanManager</code> class has also a static |
2 | 889 |
<code>register</code> method that will create |
890 |
a singleton instance in a (possibly remote) |
|
27565 | 891 |
MBeanServerConnection - using |
2 | 892 |
<code>createMBean</code>. |
27565 | 893 |
This static <code>register</code> method |
2 | 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 |
|
27565 | 909 |
registered with a null ObjectName, but will not enforce |
2 | 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> |
|
27565 | 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" |
|
2 | 930 |
title="The ScanManagerMXBean is the main MBean of the scandir application" |
27565 | 931 |
>ScanManagerMXBean</a> in |
2 | 932 |
the MBeanServer. |
933 |
</li> |
|
934 |
<li>The <code>ScanManagerMXBean</code> will then |
|
27565 | 935 |
in turn register any other MBean that the |
2 | 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> |
|
27565 | 951 |
<li>It creates as many |
2 | 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> |
|
27565 | 958 |
<li>It lets you create alternate |
2 | 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 |
|
27565 | 966 |
current configuration is reapplied), the |
2 | 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> |
|
27565 | 987 |
will only allow itself to be deregistered if it can be |
2 | 988 |
closed - that is if there's no other action in |
27565 | 989 |
progress. |
2 | 990 |
This is to make sure that the deregistration of |
27565 | 991 |
dependent MBeans will work smoothly. |
2 | 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 |
|
27565 | 1010 |
pattern, especially if the application is a |
2 | 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 |
|
27565 | 1015 |
be loaded and unloaded on demand: in that |
1016 |
case, simply registering or unregistering the top level |
|
2 | 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 |
|
27565 | 1024 |
an instance of <code>NotificationEmitter</code>. |
1025 |
The <code>NotificationEmitter</code> interface defines methods |
|
2 | 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 |
|
27565 | 1032 |
registers <i>only once</i> a single listener with each MBean |
2 | 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> |
|
27565 | 1038 |
<p>An MBean can therefore make no assumption about |
2 | 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 |
|
27565 | 1045 |
the JMX API defines a helper class, called |
1046 |
<code>NotificationBroadcasterSupport</code>, which |
|
2 | 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> |
|
27565 | 1064 |
and that's it. |
2 | 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" |
|
27565 | 1075 |
>ResultLogManagerMXBean</a> extend |
2 | 1076 |
<code>NotificationBroadcasterSupport</code> in order |
1077 |
to send notifications. |
|
1078 |
</p> |
|
1079 |
</ul> |
|
27565 | 1080 |
<h4>The Delegation Pattern: delegating to a |
2 | 1081 |
NotificationBroadcasterSupport delegate</h4> |
1082 |
<ul> |
|
1083 |
<p>There may be cases however where delegating to a |
|
27565 | 1084 |
wrapped <code>NotificationBroadcasterSupport</code> |
1085 |
object may be preferred to extending |
|
2 | 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> |
|
27565 | 1092 |
<p>Similarly, if you do not want to have the inherited |
2 | 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 |
|
27565 | 1096 |
pattern instead of extending |
2 | 1097 |
<code>NotificationBroadcasterSupport</code> |
1098 |
</p> |
|
27565 | 1099 |
<p>In our example both the <a |
1100 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 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." |
|
27565 | 1105 |
>DirectoryScannerMXBean</a> use the delegation |
1106 |
pattern rather than extending |
|
2 | 1107 |
<code>NotificationBroadcasterSupport</code>. |
1108 |
In the end, choosing between one or the other method |
|
27565 | 1109 |
is more a question of taste, although the delegation |
2 | 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 |
|
27565 | 1114 |
the JMX Module of <a |
2 | 1115 |
href="http://www.netbeans.org" |
27565 | 1116 |
>NetBeans IDE</a>, will be able to |
2 | 1117 |
generate for you all the code that delegates to a |
1118 |
wrapped <code>NotificationBroadcasterSupport</code>. |
|
1119 |
</p> |
|
1120 |
</ul> |
|
27565 | 1121 |
|
2 | 1122 |
<h4>Implementing NotificationEmitter from scratch</h4> |
1123 |
<ul> |
|
1124 |
<p>This is the last possibility for an MBean that |
|
27565 | 1125 |
needs to send notifications: simply implement |
2 | 1126 |
<code>NotificationEmitter</code> from scratch. This is highly |
27565 | 1127 |
discouraged since that logic is not trivial, and |
1128 |
already provided by |
|
2 | 1129 |
<code>NotificationBroadcasterSupport</code> anyway. |
1130 |
</p> |
|
1131 |
</ul> |
|
27565 | 1132 |
|
2 | 1133 |
<h4>Beware of Synchronization Locks</h4> |
1134 |
<ul> |
|
27565 | 1135 |
|
2 | 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 |
|
27565 | 1143 |
so through a <code>JMXConnector</code> (like the |
2 | 1144 |
<code>JMXRMIConnector</code>) |
1145 |
or through a direct reference to the MBeanServer |
|
27565 | 1146 |
(by calling |
2 | 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 |
|
27565 | 1155 |
any lock you may have before calling |
2 | 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 |
|
27565 | 1163 |
queue. |
1164 |
The notification queue is then processed later on, |
|
2 | 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 |
|
27565 | 1170 |
removed from the queue. Which thread actually gets |
1171 |
to send the notifications is of no importance. The |
|
2 | 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> |
|
27565 | 1176 |
<p>In our example the <code>ScanManager</code> class |
2 | 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> |
|
27565 | 1186 |
<li>Never calling a method that calls |
2 | 1187 |
<code>sendQueuedNotifications</code> from within |
1188 |
a synchronized block.</li> |
|
1189 |
</ul> |
|
1190 |
</p> |
|
1191 |
</ul> |
|
27565 | 1192 |
|
1193 |
||
2 | 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 |
|
30678 | 1200 |
JMX™ API. Do not create your own |
2 | 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 |
|
27565 | 1205 |
that notification unless it has that custom |
2 | 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 |
|
27565 | 1211 |
Notification classes. You can define your own |
2 | 1212 |
Notification type string, and if you need to send |
27565 | 1213 |
additional data, you can put a CompositeData, or a |
1214 |
HashMap of serializable standard types in the |
|
2 | 1215 |
Notification's user data fields. |
1216 |
</p> |
|
27565 | 1217 |
<p>In this example, we are using directly the |
2 | 1218 |
standard notification classes: |
1219 |
<ul> |
|
27565 | 1220 |
<li>The <a |
1221 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 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> |
|
27565 | 1239 |
class with a new |
2 | 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" |
|
27565 | 1249 |
>ResultLogManagerMXBean</a> also both use the base |
2 | 1250 |
<code>Notification</code> class. |
1251 |
</li> |
|
1252 |
</ul> |
|
27565 | 1253 |
<p>Careful readers will have noted that the <a |
1254 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 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." |
|
27565 | 1259 |
>DirectoryScannerMXBean</a> both use the |
2 | 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> |
|
27565 | 1273 |
and <code>DirectoryScannerMXBean</code>, the |
2 | 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> |
|
27565 | 1277 |
to <code>STOPPED</code>, or from |
2 | 1278 |
<code>SCHEDULED</code> to <code>STOPPED</code>. |
27565 | 1279 |
<br>In that case, the |
2 | 1280 |
<code>AttributeChangeNotification</code> was |
1281 |
more appropriate because it made it possible |
|
27565 | 1282 |
to send the previous and the new value of the |
2 | 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 |
|
27565 | 1289 |
<code>Notification</code> class with three different |
1290 |
notification type strings - |
|
2 | 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 |
|
27565 | 1294 |
<b><code>com.sun.jmx.examples.scandir.config.saved</code></b> - |
2 | 1295 |
was therefore closer to what we wanted to model. |
1296 |
</p> |
|
1297 |
</ul> |
|
1298 |
</p> |
|
1299 |
</ul> |
|
27565 | 1300 |
|
2 | 1301 |
<h3>Configuration MBeans</h3> |
1302 |
<ul> |
|
1303 |
<p>A common practice when designing a management application is |
|
27565 | 1304 |
to have an MBean, or a set of MBeans, dedicated to configuration. |
2 | 1305 |
Separating configuration from control and monitoring allows |
27565 | 1306 |
more appropriate logic, and often simplifies the design and |
2 | 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> |
|
27565 | 1315 |
<p>The <code>ScanDirConfigMXBean</code> will let you interactively |
2 | 1316 |
modify, save, or load the application configuration. The modifications |
1317 |
will not be taken into account until it is applied, by invoking |
|
27565 | 1318 |
<code>applyConfiguration</code> on the <a |
1319 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 1320 |
title="The ScanManagerMXBean is the main MBean of the scandir application" |
27565 | 1321 |
>ScanManagerMXBean</a>. |
2 | 1322 |
It is also possible to create many configurations, by creating as |
1323 |
many <code>ScanDirConfigMXBean</code>s, and then to choose and apply |
|
27565 | 1324 |
one of these configurations by calling |
2 | 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 |
|
27565 | 1334 |
defined in the <a |
1335 |
href="dist/javadoc/com/sun/jmx/examples/scandir/config/package-summary.html" |
|
2 | 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 |
|
27565 | 1341 |
MXBean framework (our beans don't contain recursive data structures) and can |
2 | 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> |
|
27565 | 1346 |
<p>The same <a |
1347 |
href="dist/javadoc/com/sun/jmx/examples/scandir/config/ScanManagerConfig.html" |
|
2 | 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" |
|
27565 | 1353 |
>ScanDirConfigMXBean</a>. It is transformed into a <code>CompositeData</code> |
2 | 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 |
|
27565 | 1361 |
is whether the MBeanServer is thread-safe. Well, the MBeanServer <b>is</b> |
2 | 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 |
|
27565 | 1385 |
notification, and we'll be back to the considerations just |
2 | 1386 |
above.</li> |
1387 |
</ul> |
|
1388 |
</p> |
|
1389 |
<p>Another means of implementing thread-safe code is to use semaphores. |
|
27565 | 1390 |
The <a |
1391 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 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 |
|
27565 | 1397 |
semaphore before entering the critical section. If the |
2 | 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> |
|
27565 | 1419 |
<p>It is worth noting that each of these techniques has its own |
2 | 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> |
|
27565 | 1423 |
<p>Careful readers will also have noted that we used |
1424 |
<code>IllegalStateException</code> directly, instead of defining |
|
2 | 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 |
|
27565 | 1428 |
of your exception in its classpath to get that exception. |
2 | 1429 |
Otherwise your client will get a completely different exception, indicating a |
1430 |
deserialization issue. |
|
1431 |
</p> |
|
1432 |
</ul> |
|
27565 | 1433 |
|
2 | 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> |
|
27565 | 1453 |
final BlockingQueue<Notification> notifQueue = |
2 | 1454 |
new LinkedBlockingQueue<Notification>(); |
27565 | 1455 |
|
2 | 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> |
|
27565 | 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" |
|
2 | 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> |
|
27565 | 1491 |
|
2 | 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 |
|
27565 | 1503 |
when holding a hard reference might be preferred: |
2 | 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> |
|
27565 | 1516 |
<p>In our example, the <a |
1517 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 1518 |
title="The ScanManagerMXBean is the main MBean of the scandir application" |
27565 | 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" |
|
2 | 1523 |
>DirectoryScannerMXBeans</a>. <br> |
27565 | 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>, |
|
2 | 1528 |
which can then log their results |
1529 |
more efficiently, and would also make it possible to remove |
|
27565 | 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 |
|
2 | 1533 |
<code>ResultLogManager</code> class (possibly as a package method) |
1534 |
should we wish to do so. |
|
1535 |
</p> |
|
27565 | 1536 |
|
2 | 1537 |
</ul> |
1538 |
||
1539 |
<h3>Agent Class</h3> |
|
1540 |
<ul> |
|
27565 | 1541 |
<p>The <a |
1542 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html" |
|
2 | 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. |
|
27565 | 1545 |
This class contains the <code>main</code> method to start a standalone |
2 | 1546 |
<i>scandir</i> application. |
1547 |
</p> |
|
27565 | 1548 |
<p>The <code>main</code> method simply registers a <a |
1549 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 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> |
|
27565 | 1555 |
When the <code>ScanManagerMXBean</code> state is switched to |
1556 |
<code>ScanManagerMXBean.ScanState.CLOSED</code>, the |
|
2 | 1557 |
<code>ScanManagerMXBean</code> is unregistered, and the application |
1558 |
terminates (i.e. the main thread completes). |
|
1559 |
</p> |
|
27565 | 1560 |
<p>Standalone JMX applications usually have an Agent class that contain |
2 | 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 |
|
27565 | 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 |
|
2 | 1571 |
the application can be already easily started by registering an instance |
27565 | 1572 |
of <a |
1573 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" |
|
2 | 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> |
|
27565 | 1580 |
<p>The <a |
1581 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirClient.html" |
|
21278 | 1582 |
title="The ScanDirClient class is a very short example of secure programmatic client" |
2 | 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> |
|
27565 | 1599 |
|
2 | 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). |
|
27565 | 1603 |
Make sure also that you have junit.jar in your |
2 | 1604 |
<code>CLASSPATH</code>.<br> |
27565 | 1605 |
Then in the example root directory (where the <code>build.xml</code> |
2 | 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> |
|
27565 | 1609 |
<p>Alternatively you can open the jmx-scandir project with the |
1610 |
NetBeans IDE and test the jmx-scandir project from the |
|
2 | 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> |
|
27565 | 1618 |
<p>In the example root directory (where the <code>build.xml</code> |
2 | 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> |
|
27565 | 1624 |
|
2 | 1625 |
<p>This will run the example using the configuration |
1626 |
file provided in the src/etc directory. |
|
1627 |
</p> |
|
27565 | 1628 |
<p>Alternatively you can open the jmx-scandir project with the |
1629 |
NetBeans IDE. You can run the example by |
|
2 | 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> |
|
27565 | 1642 |
<u>Note:</u> You can also run the <i>scandir</i> |
1643 |
application directly from the <code>java</code> |
|
2 | 1644 |
command line. Make sure to build the project jar |
27565 | 1645 |
first. |
2 | 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> |
|
27565 | 1658 |
|
2 | 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 |
|
27565 | 1662 |
that it uses the provided <code>src/etc/testconfig.xml</code> |
2 | 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> |
|
27565 | 1688 |
<p>Open the MBeans tab, and look for the |
2 | 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" |
|
27565 | 1697 |
><img |
2 | 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 |
|
27565 | 1704 |
for notifications. Then click on the |
2 | 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" |
|
27565 | 1710 |
><img |
2 | 1711 |
src="docfiles/scandir-start.jpg" |
1712 |
alt="jconsole MBean tab: ScanDirConfigMXBean" |
|
1713 |
/></a></center> |
|
1714 |
</p> |
|
27565 | 1715 |
<p>You can see that the notifications counter was |
1716 |
incremented by three: you have just scheduled, |
|
2 | 1717 |
run, and completed a batch of directory scans. |
1718 |
</p> |
|
1719 |
<p>Now go to the <code>ResultLogManagerMXBean</code>, |
|
27565 | 1720 |
click on its <code>Attributes</code> node, and |
2 | 1721 |
expand its <code>MemoryLog</code> attribute: |
1722 |
</p> |
|
1723 |
<p><center><a href="docfiles/scandir-result.jpg" |
|
1724 |
title="jconsole MBean tab: ScanDirConfigMXBean" |
|
27565 | 1725 |
><img |
2 | 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> |
|
27565 | 1732 |
<p>To make the application terminate go back to the |
2 | 1733 |
<code>ScanManagerMXBean</code> and invoke |
1734 |
<code>close()</code>. The <code>ScanDirAgent</code> |
|
27565 | 1735 |
will receive the notification, step out of |
2 | 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 |
|
27565 | 1741 |
a new configuration - |
2 | 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> |
|
27565 | 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> - |
|
2 | 1752 |
subscribing for notifications, etc... |
1753 |
</p> |
|
1754 |
</ul> |
|
27565 | 1755 |
|
2 | 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 |
|
27565 | 1761 |
is bootstrapped with a secure JMXConnectorServer. Indeed, until |
1762 |
now we have only used the insecure local connection, |
|
2 | 1763 |
which can only be used as long as both the client and |
1764 |
the server run on the same machine. This section will |
|
27565 | 1765 |
explain how to start the <code>ScanDirAgent</code> so |
2 | 1766 |
that a real secure RMIConnectorServer is started at bootstrap. |
1767 |
</p> |
|
1768 |
<p>To achieve this we will: <a href="#management.properties" |
|
27565 | 1769 |
>provide our own management.properties</a>, <a |
2 | 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> |
|
27565 | 1777 |
<p>The easiest way to <a name="management.properties">configure the |
1778 |
JVM Agent</a> for Secure Remote |
|
2 | 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. |
|
27565 | 1783 |
In this example, we have copied the default |
1784 |
<code>$JRE/conf/management/management.properties</code> |
|
2 | 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> |
|
27565 | 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 |
|
2 | 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> |
|
27565 | 1804 |
<li>We have provided <a |
2 | 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> |
|
27565 | 1809 |
<li>We have provided <a |
2 | 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 |
|
27565 | 1816 |
for the other security properties, like |
2 | 1817 |
<code>com.sun.management.jmxremote.authenticate=true</code>, |
1818 |
because these properties already default to a value |
|
27565 | 1819 |
which enables security by default. |
2 | 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 |
|
27565 | 1823 |
anybody would be able to connect to the registry and |
2 | 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> |
|
27565 | 1832 |
system property to pass our <a |
2 | 1833 |
href="src/etc/management.properties">management.properties</a> |
1834 |
file to the <code>ScanDirAgent</code>. |
|
1835 |
</p> |
|
1836 |
</ul> |
|
27565 | 1837 |
|
2 | 1838 |
<h3>Creating a password and access file</h3> |
1839 |
<ul> |
|
1840 |
<p>As explained above, we have created our own |
|
27565 | 1841 |
<a href="src/etc/password.properties">password file</a> |
1842 |
and <a href="src/etc/access.properties">access file</a> |
|
2 | 1843 |
for <a name="password-access">access control and authorization</a>. |
1844 |
</p> |
|
27565 | 1845 |
<p>In the password file, we have defined two logins: |
1846 |
<i>guest</i> and <i>admin</i>. The password for |
|
2 | 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 |
|
27565 | 1855 |
need to restrict access permission to the password file, |
2 | 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 |
|
27565 | 1866 |
of our access and password files is configured in our own <a |
2 | 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 |
|
27565 | 1877 |
the parties they trust. Usually, client and server will |
1878 |
have their own keystore and truststore. |
|
2 | 1879 |
</p> |
1880 |
<p>For the sake of simplicity - and to get you started |
|
1881 |
without the tedious necessity of creating your own keystore |
|
27565 | 1882 |
and truststore, we are providing a dummy keystore and |
2 | 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 |
|
27565 | 1887 |
keystore and truststore we are providing before attempting |
2 | 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" |
|
27565 | 1898 |
>here</a>. |
1899 |
As shown <a href="#start-secure-agent">later</a>, |
|
1900 |
we will need to use <a |
|
2 | 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> |
|
27565 | 1926 |
java |
2 | 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 |
|
27565 | 1937 |
are still able to connect to the agent using the |
2 | 1938 |
local connection. However, if you try to connect |
27565 | 1939 |
through the remote connector, using |
1940 |
<a href="docfiles/remote-connection.jpg">localhost:4545</a>, |
|
2 | 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> |
|
27565 | 1949 |
<p>The next section will discuss how to connect to the |
2 | 1950 |
secure agent. |
1951 |
</p> |
|
1952 |
</ul> |
|
27565 | 1953 |
|
2 | 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> |
|
27565 | 1960 |
|
2 | 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. |
|
27565 | 1971 |
Indeed a real application would have different |
1972 |
certificates for the client and the server, and |
|
2 | 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" |
|
30678 | 1977 |
>Java™ Secure Socket Extension (JSSE) Reference Guide</a>. |
2 | 1978 |
</p> |
1979 |
<p>To start jconsole with our provided keystore and |
|
27565 | 1980 |
truststore, go to the scandir example root directory and |
2 | 1981 |
type in the following command: |
27565 | 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 |
|
2 | 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> |
|
27565 | 1993 |
<p>In jconsole connection window, choose to connect to a |
2 | 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 |
|
27565 | 2009 |
command line, or you didn't start jconsole from the |
2 | 2010 |
scandir example root directory where our <code>truststore</code> |
27565 | 2011 |
and <code>keystore</code> files are located. This article - <a |
2 | 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> |
|
27565 | 2019 |
|
2 | 2020 |
<h3>Writing a programmatic client to connect to the secure agent</h3> |
2021 |
<ul> |
|
2022 |
<p> |
|
27565 | 2023 |
In this section we will show the steps involved in writing |
2 | 2024 |
a programmatic client that will connect to our secure agent. |
2025 |
</p> |
|
27565 | 2026 |
<p>The <a |
2027 |
href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirClient.html" |
|
21278 | 2028 |
title="The ScanDirClient class is a very short example of secure programmatic client" |
2 | 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 |
|
27565 | 2033 |
the secured <i>scandir</i> agent. |
2 | 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: |
|
27565 | 2040 |
<pre> |
2 | 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> |
|
27565 | 2051 |
<pre> |
2 | 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: |
|
27565 | 2061 |
<pre> |
2 | 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( |
|
27565 | 2081 |
"service:jmx:rmi:///jndi/rmi://"+args[0]+":"+args[1]+ |
2 | 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> |
|
27565 | 2088 |
with the appropriate system properties that will point to our |
2089 |
<code>keystore</code> and <code>truststore</code>. To start the secure |
|
2 | 2090 |
client, go to the <i>scandir</i> example root directory and type |
2091 |
the following command: |
|
2092 |
<p><code>ant jar<br> |
|
27565 | 2093 |
java |
2094 |
-Djava.util.logging.config.file=logging.properties |
|
2 | 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 |
||
27565 | 2143 |
Got expected security exception: java.lang.SecurityException: Access denied! |
2 | 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> |
|
27565 | 2151 |
<p>If the <code>ScanDirClient</code> fails to connect with |
2152 |
the secure agent, then this article - <a |
|
2 | 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 |
|
27565 | 2159 |
could encounter are identical. Just remember that |
2 | 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> |
|
27565 | 2165 |
|
2 | 2166 |
<h2><a name="h2-Conclusion">Conclusion</a></h2> |
2167 |
<ul> |
|
2168 |
<p> |
|
27565 | 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. |
|
2 | 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" |
|
27565 | 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 |
|
2 | 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/" |
|
27565 | 2195 |
>Monitoring and Management for the Java Platform</a>: The Java Platform |
2196 |
Standard Edition (Java SE) 6 provides comprehensive monitoring and |
|
2 | 2197 |
management support for the Java platform. </li> |
2198 |
<li><a href="http://java.sun.com/products/JavaManagement/community/jmx_blogs.html" |
|
27565 | 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 |
|
2 | 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" |
|
30678 | 2205 |
>Java™ Secure Socket Extension (JSSE) Reference Guide</a>: |
2206 |
comprehensive documentation about the Java™ Secure Socket |
|
2 | 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 |
|
30678 | 2211 |
Java™ Platform, Standard Edition 6 JDK.</li> |
2 | 2212 |
</ol> |
2213 |
<p> |
|
2214 |
<hr> |
|
2215 |
<p> |
|
2216 |
</body> |
|
2217 |
</html> |