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