1 /* 2 * @(#)MXBean.java 1.18 06/06/22 3 * 4 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 5 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 6 */ 7 8 package javax.management; 9 10 import java.lang.annotation.Documented; 11 import java.lang.annotation.ElementType; 12 import java.lang.annotation.Retention; 13 import java.lang.annotation.RetentionPolicy; 14 import java.lang.annotation.Target; 15 16 // remaining imports are for Javadoc 17 import java.beans.ConstructorProperties; 18 import java.io.InvalidObjectException; 19 import java.lang.management.MemoryUsage; 20 import java.lang.reflect.UndeclaredThrowableException; 21 import java.util.Arrays; 22 import java.util.List; 23 import javax.management.openmbean.ArrayType; 24 import javax.management.openmbean.CompositeData; 25 import javax.management.openmbean.CompositeDataInvocationHandler; 26 import javax.management.openmbean.CompositeDataSupport; 27 import javax.management.openmbean.CompositeDataView; 28 import javax.management.openmbean.CompositeType; 29 import javax.management.openmbean.OpenDataException; 30 import javax.management.openmbean.OpenMBeanInfo; 31 import javax.management.openmbean.OpenType; 32 import javax.management.openmbean.SimpleType; 33 import javax.management.openmbean.TabularData; 34 import javax.management.openmbean.TabularDataSupport; 35 import javax.management.openmbean.TabularType; 36 37 /** 38 <p>Annotation to mark an interface explicitly as being an MXBean 39 interface, or as not being an MXBean interface. By default, an 40 interface is an MXBean interface if its name ends with {@code 41 MXBean}, as in {@code SomethingMXBean}. The following interfaces 42 are MXBean interfaces:</p> 43 44 <pre> 45 public interface WhatsitMXBean {} 46 47 @MXBean 48 public interface Whatsit1Interface {} 49 50 @MXBean(true) 51 public interface Whatsit2Interface {} 52 </pre> 53 54 <p>The following interfaces are not MXBean interfaces:</p> 55 56 <pre> 57 public interface Whatsit3Interface{} 58 59 @MXBean(false) 60 public interface MisleadingMXBean {} 61 </pre> 62 63 <h3><a name="MXBean-spec">MXBean specification</a></h3> 64 65 <p>The MXBean concept provides a simple way to code an MBean 66 that only references a predefined set of types, the ones defined 67 by {@link javax.management.openmbean}. In this way, you can be 68 sure that your MBean will be usable by any client, including 69 remote clients, without any requirement that the client have 70 access to <em>model-specific classes</em> representing the types 71 of your MBeans.</p> 72 73 <p>The concepts are easier to understand by comparison with the 74 Standard MBean concept. Here is how a managed object might be 75 represented as a Standard MBean, and as an MXBean:</p> 76 77 <table border="1" cellpadding="5"> 78 <tr> 79 <th>Standard MBean</th><th>MXBean</th> 80 </tr> 81 <tr> 82 <td><pre> 83 public interface MemoryPool<b>MBean</b> { 84 String getName(); 85 MemoryUsage getUsage(); 86 // ... 87 } 88 </pre></td> 89 <td><pre> 90 public interface MemoryPool<b>MXBean</b> { 91 String getName(); 92 MemoryUsage getUsage(); 93 // ... 94 } 95 </pre></td> 96 </tr> 97 </table> 98 99 <p>As you can see, the definitions are very similar. The only 100 difference is that the convention for naming the interface is to use 101 <code><em>Something</em>MXBean</code> for MXBeans, rather than 102 <code><em>Something</em>MBean</code> for Standard MBeans.</p> 103 104 <p>In this managed object, there is an attribute called 105 <code>Usage</code> of type {@link MemoryUsage}. The point of an 106 attribute like this is that it gives a coherent snapshot of a set 107 of data items. For example, it might include the current amount 108 of used memory in the memory pool, and the current maximum of the 109 memory pool. If these were separate items, obtained with separate 110 {@link MBeanServer#getAttribute getAttribute} calls, then we could 111 get values seen at different times that were not consistent. We 112 might get a <code>used</code> value that was greater than the 113 <code>max</code> value.</p> 114 115 <p>So, we might define <code>MemoryUsage</code> like this:</p> 116 117 <table border="1" cellpadding="5"> 118 <tr> 119 <th>Standard MBean</th><th>MXBean</th> 120 </tr> 121 <tr> 122 <td><pre> 123 public class MemoryUsage <b>implements Serializable</b> { 124 // standard JavaBean conventions with getters 125 126 public MemoryUsage(long init, long used, 127 long committed, long max) {...} 128 long getInit() {...} 129 long getUsed() {...} 130 long getCommitted() {...} 131 long getMax() {...} 132 } 133 </pre></td> 134 <td><pre> 135 public class MemoryUsage { 136 // standard JavaBean conventions with getters 137 <b>@ConstructorProperties({"init", "used", "committed", "max"})</b> 138 public MemoryUsage(long init, long used, 139 long committed, long max) {...} 140 long getInit() {...} 141 long getUsed() {...} 142 long getCommitted() {...} 143 long getMax() {...} 144 } 145 </pre></td> 146 </tr> 147 </table> 148 149 <p>The definitions are the same in the two cases, except 150 that with the MXBean, <code>MemoryUsage</code> no longer needs to 151 be marked <code>Serializable</code> (though it can be). On 152 the other hand, we have added a {@code @ConstructorProperties} annotation 153 to link the constructor parameters to the corresponding getters. 154 We will see more about this below.</p> 155 156 <p><code>MemoryUsage</code> is a <em>model-specific class</em>. 157 With Standard MBeans, a client of the MBean Server cannot access the 158 <code>Usage</code> attribute if it does not know the class 159 <code>MemoryUsage</code>. Suppose the client is a generic console 160 based on JMX technology. Then the console would have to be 161 configured with the model-specific classes of every application it 162 might connect to. The problem is even worse for clients that are 163 not written in the Java language. Then there may not be any way 164 to tell the client what a <code>MemoryUsage</code> looks like.</p> 165 166 <p>This is where MXBeans differ from Standard MBeans. Although we 167 define the management interface in almost exactly the same way, 168 the MXBean framework <em>converts</em> model-specific classes into 169 standard classes from the Java platform. Using arrays and the 170 {@link javax.management.openmbean.CompositeData CompositeData} and 171 {@link javax.management.openmbean.TabularData TabularData} classes 172 from the standard {@link javax.management.openmbean} package, it 173 is possible to build data structures of arbitrary complexity 174 using only standard classes.</p> 175 176 <p>This becomes clearer if we compare what the clients of the two 177 models might look like:</p> 178 179 <table border="1" cellpadding="5"> 180 <tr> 181 <th>Standard MBean</th><th>MXBean</th> 182 </tr> 183 <tr> 184 <td><pre> 185 String name = (String) 186 mbeanServer.{@link MBeanServer#getAttribute 187 getAttribute}(objectName, "Name"); 188 <b>MemoryUsage</b> usage = (<b>MemoryUsage</b>) 189 mbeanServer.getAttribute(objectName, "Usage"); 190 <b>long used = usage.getUsed();</b> 191 </pre></td> 192 <td><pre> 193 String name = (String) 194 mbeanServer.{@link MBeanServer#getAttribute 195 getAttribute}(objectName, "Name"); 196 <b>{@link CompositeData}</b> usage = (<b>CompositeData</b>) 197 mbeanServer.getAttribute(objectName, "Usage"); 198 <b>long used = (Long) usage.{@link CompositeData#get get}("used");</b> 199 </pre></td> 200 </table> 201 202 <p>For attributes with simple types like <code>String</code>, the 203 code is the same. But for attributes with complex types, the 204 Standard MBean code requires the client to know the model-specific 205 class <code>MemoryUsage</code>, while the MXBean code requires no 206 non-standard classes.</p> 207 208 <p>The client code shown here is slightly more complicated for the 209 MXBean client. But, if the client does in fact know the model, 210 here the interface <code>MemoryPoolMXBean</code> and the 211 class <code>MemoryUsage</code>, then it can construct a 212 <em>proxy</em>. This is the recommended way to interact with 213 managed objects when you know the model beforehand, regardless 214 of whether you are using Standard MBeans or MXBeans:</p> 215 216 <table border="1" cellpadding="5"> 217 <tr> 218 <th>Standard MBean</th><th>MXBean</th> 219 </tr> 220 <tr> 221 <td><pre> 222 MemoryPool<b>MBean</b> proxy = 223 JMX.<b>{@link JMX#newMBeanProxy(MBeanServerConnection, ObjectName, 224 Class) newMBeanProxy}</b>( 225 mbeanServer, 226 objectName, 227 MemoryPool<b>MBean</b>.class); 228 String name = proxy.getName(); 229 MemoryUsage usage = proxy.getUsage(); 230 long used = usage.getUsed(); 231 </pre></td> 232 <td><pre> 233 MemoryPool<b>MXBean</b> proxy = 234 JMX.<b>{@link JMX#newMXBeanProxy(MBeanServerConnection, ObjectName, 235 Class) newMXBeanProxy}</b>( 236 mbeanServer, 237 objectName, 238 MemoryPool<b>MXBean</b>.class); 239 String name = proxy.getName(); 240 MemoryUsage usage = proxy.getUsage(); 241 long used = usage.getUsed(); 242 </pre></td> 243 </tr> 244 </table> 245 246 <p>Implementing the MemoryPool object works similarly for both 247 Standard MBeans and MXBeans.</p> 248 249 <table border="1" cellpadding="5"> 250 <tr> 251 <th>Standard MBean</th><th>MXBean</th> 252 </tr> 253 <tr> 254 <td><pre> 255 public class MemoryPool 256 implements MemoryPool<b>MBean</b> { 257 public String getName() {...} 258 public MemoryUsage getUsage() {...} 259 // ... 260 } 261 </pre></td> 262 <td><pre> 263 public class MemoryPool 264 implements MemoryPool<b>MXBean</b> { 265 public String getName() {...} 266 public MemoryUsage getUsage() {...} 267 // ... 268 } 269 </pre></td> 270 </tr> 271 </table> 272 273 <p>Registering the MBean in the MBean Server works in the same way 274 in both cases:</p> 275 276 <table border="1" cellpadding="5"> 277 <tr> 278 <th>Standard MBean</th><th>MXBean</th> 279 </tr> 280 <tr> 281 <td><pre> 282 { 283 MemoryPool<b>MBean</b> pool = new MemoryPool(); 284 mbeanServer.{@link MBeanServer#registerMBean 285 registerMBean}(pool, objectName); 286 } 287 </pre></td> 288 <td><pre> 289 { 290 MemoryPool<b>MXBean</b> pool = new MemoryPool(); 291 mbeanServer.{@link MBeanServer#registerMBean 292 registerMBean}(pool, objectName); 293 } 294 </pre></td> 295 </tr> 296 </table> 297 298 299 <h2><a name="mxbean-def">Definition of an MXBean</a></h2> 300 301 <p>An MXBean is a kind of MBean. An MXBean object can be 302 registered directly in the MBean Server, or it can be used as an 303 argument to {@link StandardMBean} and the resultant MBean 304 registered in the MBean Server.</p> 305 306 <p>When an object is registered in the MBean Server using the 307 {@code registerMBean} or {@code createMBean} methods of the 308 {@link MBeanServer} interface, the object's class is examined 309 to determine what type of MBean it is:</p> 310 311 <ul> 312 <li>If the class implements the interface {@link DynamicMBean} 313 then the MBean is a Dynamic MBean. Note that the class 314 {@code StandardMBean} implements this interface, so this 315 case applies to a Standard MBean or MXBean created using 316 the class {@code StandardMBean}.</li> 317 318 <li>Otherwise, if the class matches the Standard MBean naming 319 conventions, then the MBean is a Standard MBean.</li> 320 321 <li>Otherwise, it may be an MXBean. The set of interfaces 322 implemented by the object is examined for interfaces that: 323 324 <ul> 325 <li>have a class name <code><em>S</em>MXBean</code> where 326 <code><em>S</em></code> is any non-empty string, and 327 do not have an annotation {@code @MXBean(false)}; and/or</li> 328 <li>have an annotation {@code @MXBean(true)} 329 or just {@code @MXBean}.</li> 330 </ul> 331 332 If there is exactly one such interface, or if there is one 333 such interface that is a subinterface of all the others, then 334 the object is an MXBean. The interface in question is the 335 <em>MXBean interface</em>. In the example above, the MXBean 336 interface is {@code MemoryPoolMXBean}. 337 338 <li>If none of these conditions is met, the MBean is invalid and 339 the attempt to register it will generate {@link 340 NotCompliantMBeanException}. 341 </ul> 342 343 <p>Every Java type that appears as the parameter or return type of a 344 method in an MXBean interface must be <em>convertible</em> using 345 the rules below. Additionally, parameters must be 346 <em>reconstructible</em> as defined below.</p> 347 348 <p>An attempt to construct an MXBean that does not conform to the 349 above rules will produce an exception.</p> 350 351 352 <h2><a name="naming-conv">Naming conventions</a></h2> 353 354 <p>The same naming conventions are applied to the methods in an 355 MXBean as in a Standard MBean:</p> 356 357 <ol> 358 <li>A method <code><em>T</em> get<em>N</em>()</code>, where 359 <code><em>T</em></code> is a Java type (not <code>void</code>) 360 and <code><em>N</em></code> is a non-empty string, specifies 361 that there is a readable attribute called 362 <code><em>N</em></code>. The Java type and Open type of the 363 attribute are determined by the mapping rules below. 364 The method {@code final Class getClass()} inherited from {@code 365 Object} is ignored when looking for getters.</li> 366 367 <li>A method <code>boolean is<em>N</em>()</code> specifies that 368 there is a readable attribute called <code><em>N</em></code> 369 with Java type <code>boolean</code> and Open type 370 <code>SimpleType.Boolean</code>.</li> 371 372 <li>A method <code>void set<em>N</em>(<em>T</em> x)</code> 373 specifies that there is a writeable attribute called 374 <code><em>N</em></code>. The Java type and Open type of the 375 attribute are determined by the mapping rules below. (Of 376 course, the name <code>x</code> of the parameter is 377 irrelevant.)</li> 378 379 <li>Every other method specifies that there is an operation with 380 the same name as the method. The Java type and Open type of the 381 return value and of each parameter are determined by the mapping 382 rules below.</li> 383 </ol> 384 385 <p>The rules for <code>get<em>N</em></code> and 386 <code>is<em>N</em></code> collectively define the notion of a 387 <em>getter</em>. The rule for <code>set<em>N</em></code> defines 388 the notion of a <em>setter</em>.</p> 389 390 <p>It is an error for there to be two getters with the same name, or 391 two setters with the same name. If there is a getter and a setter 392 for the same name, then the type <code><em>T</em></code> in both 393 must be the same. In this case the attribute is read/write. If 394 there is only a getter or only a setter, the attribute is 395 read-only or write-only respectively.</p> 396 397 398 <h2><a name="mapping-rules">Type mapping rules</a></h2> 399 400 <p>An MXBean is a kind of Open MBean, as defined by the {@link 401 javax.management.openmbean} package. This means that the types of 402 attributes, operation parameters, and operation return values must 403 all be describable using <em>Open Types</em>, that is the four 404 standard subclasses of {@link javax.management.openmbean.OpenType}. 405 MXBeans achieve this by mapping Java types into Open Types.</p> 406 407 <p>For every Java type <em>J</em>, the MXBean mapping is described 408 by the following information:</p> 409 410 <ul> 411 <li>The corresponding Open Type, <em>opentype(J)</em>. This is 412 an instance of a subclass of {@link 413 javax.management.openmbean.OpenType}.</li> 414 <li>The <em>mapped</em> Java type, <em>opendata(J)</em>, which is 415 always the same for any given <em>opentype(J)</em>. This is a Java 416 class.</li> 417 <li>How a value is converted from type <em>J</em> to type 418 <em>opendata(J)</em>.</li> 419 <li>How a value is converted from type <em>opendata(J)</em> to 420 type <em>J</em>, if it can be.</li> 421 </ul> 422 423 <p>For example, for the Java type {@code List<String>}:</p> 424 425 <ul> 426 <li>The Open Type, <em>opentype(</em>{@code 427 List<String>}<em>)</em>, is {@link ArrayType}<code>(1, </code>{@link 428 SimpleType#STRING}<code>)</code>, representing a 1-dimensional 429 array of <code>String</code>s.</li> 430 <li>The mapped Java type, <em>opendata(</em>{@code 431 List<String>}<em>)</em>, is {@code String[]}.</li> 432 <li>A {@code List<String>} can be converted to a {@code String[]} 433 using {@link List#toArray(Object[]) List.toArray(new 434 String[0])}.</li> 435 <li>A {@code String[]} can be converted to a {@code List<String>} 436 using {@link Arrays#asList Arrays.asList}.</li> 437 </ul> 438 439 <p>If no mapping rules exist to derive <em>opentype(J)</em> from 440 <em>J</em>, then <em>J</em> cannot be the type of a method 441 parameter or return value in an MXBean interface.</p> 442 443 <p>If there is a way to convert <em>opendata(J)</em> back to 444 <em>J</em> then we say that <em>J</em> is 445 <em>reconstructible</em>. All method parameters in an MXBean 446 interface must be reconstructible, because when the MXBean 447 framework is invoking a method it will need to convert those 448 parameters from <em>opendata(J)</em> to <em>J</em>. In a proxy 449 generated by {@link JMX#newMXBeanProxy(MBeanServerConnection, 450 ObjectName, Class) JMX.newMXBeanProxy}, it is the return values 451 of the methods in the MXBean interface that must be 452 reconstructible.</p> 453 454 <p>Null values are allowed for all Java types and Open Types, 455 except primitive Java types where they are not possible. When 456 converting from type <em>J</em> to type <em>opendata(J)</em> or 457 from type <em>opendata(J)</em> to type <em>J</em>, a null value is 458 mapped to a null value.</p> 459 460 <p>The following table summarizes the type mapping rules.</p> 461 462 <table border="1" cellpadding="5"> 463 <tr> 464 <th>Java type <em>J</em></th> 465 <th><em>opentype(J)</em></th> 466 <th><em>opendata(J)</em></th> 467 </tr> 468 <tbody cellvalign="top"> 469 <tr> 470 <td>{@code int}, {@code boolean}, etc<br> 471 (the 8 primitive Java types)</td> 472 <td>{@code SimpleType.INTEGER},<br> 473 {@code SimpleType.BOOLEAN}, etc</td> 474 <td>{@code Integer}, {@code Boolean}, etc<br> 475 (the corresponding boxed types)</td> 476 </tr> 477 <tr> 478 <td>{@code Integer}, {@code ObjectName}, etc<br> 479 (the types covered by {@link SimpleType})</td> 480 <td>the corresponding {@code SimpleType}</td> 481 <td><em>J</em>, the same type</td> 482 </tr> 483 <tr> 484 <td>{@code int[]} etc<br> 485 (a one-dimensional array with<br> 486 primitive element type)</td> 487 <td>{@code ArrayType.getPrimitiveArrayType(int[].class)} etc</td> 488 <td><em>J</em>, the same type</td> 489 <tr> 490 <td><em>E</em>{@code []}<br> 491 (an array with non-primitive element type <em>E</em>; 492 this includes {@code int[][]}, where <em>E</em> is {@code int[]})</td> 493 <td>{@code ArrayType.getArrayType(}<em>opentype(E)</em>{@code )}</td> 494 <td><em>opendata(E)</em>{@code []}</td> 495 </tr> 496 <tr> 497 <td>{@code List<}<em>E</em>{@code >}<br> 498 {@code Set<}<em>E</em>{@code >}<br> 499 {@code SortedSet<}<em>E</em>{@code >} (see below)</td> 500 <td>same as for <em>E</em>{@code []}</td> 501 <td>same as for <em>E</em>{@code []}</td> 502 </tr> 503 <tr> 504 <td>An enumeration <em>E</em><br> 505 (declared in Java as {@code enum }<em>E</em> 506 {@code {...}})</td> 507 <td>{@code SimpleType.STRING}</td> 508 <td>{@code String}</td> 509 </tr> 510 <tr> 511 <td>{@code Map<}<em>K</em>,<em>V</em>{@code >}<br> 512 {@code SortedMap<}<em>K</em>,<em>V</em>{@code >}</td> 513 <td>{@link TabularType}<br> 514 (see below)</td> 515 <td>{@link TabularData}<br> 516 (see below)</td> 517 </tr> 518 <tr> 519 <td>An MXBean interface</td> 520 <td>{@code SimpleType.OBJECTNAME}<br> 521 (see below)</td> 522 <td>{@link ObjectName}<br> 523 (see below)</td> 524 </tr> 525 <tr> 526 <td>Any other type</td> 527 <td>{@link CompositeType}, 528 if possible<br> 529 (see below)</td> 530 <td>{@link CompositeData}</td> 531 </tbody> 532 </table> 533 534 <p>The following sections give further details of these rules.</p> 535 536 537 <h3>Mappings for primitive types</h3> 538 539 <p>The 8 primitive Java types 540 ({@code boolean}, {@code byte}, {@code short}, {@code int}, {@code 541 long}, {@code float}, {@code double}, {@code char}) are mapped to the 542 corresponding boxed types from {@code java.lang}, namely {@code 543 Boolean}, {@code Byte}, etc. The Open Type is the corresponding 544 {@code SimpleType}. Thus, <em>opentype(</em>{@code 545 long}<em>)</em> is {@code SimpleType.LONG}, and 546 <em>opendata(</em>{@code long}<em>)</em> is {@code 547 java.lang.Long}.</p> 548 549 <p>An array of primitive type such as {@code long[]} can be represented 550 directly as an Open Type. Thus, <em>openType(</em>{@code 551 long[]}<em>)</em> is {@code 552 ArrayType.getPrimitiveArrayType(long[].class)}, and 553 <em>opendata(</em>{@code long[]}<em>)</em> is {@code 554 long[]}.</p> 555 556 <p>In practice, the difference between a plain {@code int} and {@code 557 Integer}, etc, does not show up because operations in the JMX API 558 are always on Java objects, not primitives. However, the 559 difference <em>does</em> show up with arrays.</p> 560 561 562 <h3>Mappings for collections ({@code List<}<em>E</em>{@code >} etc)</h3> 563 564 <p>A {@code List<}<em>E</em>{@code >} or {@code 565 Set<}<em>E</em>{@code >}, such as {@code List<String>} or {@code 566 Set<ObjectName>}, is mapped in the same way as an array of the 567 same element type, such as {@code String[]} or {@code 568 ObjectName[]}.</p> 569 570 <p>A {@code SortedSet<}<em>E</em>{@code >} is also mapped in the 571 same way as an <em>E</em>{@code []}, but it is only convertible if 572 <em>E</em> is a class or interface that implements {@link 573 java.lang.Comparable}. Thus, a {@code SortedSet<String>} or 574 {@code SortedSet<Integer>} is convertible, but a {@code 575 SortedSet<int[]>} or {@code SortedSet<List<String>>} is not. The 576 conversion of a {@code SortedSet} instance will fail with an 577 {@code IllegalArgumentException} if it has a 578 non-null {@link java.util.SortedSet#comparator() 579 comparator()}.</p> 580 581 <p>A {@code List<}<em>E</em>{@code >} is reconstructed as a 582 {@code java.util.ArrayList<}<em>E</em>{@code >}; 583 a {@code Set<}<em>E</em>{@code >} as a 584 {@code java.util.HashSet<}<em>E</em>{@code >}; 585 a {@code SortedSet<}<em>E</em>{@code >} as a 586 {@code java.util.TreeSet<}<em>E</em>{@code >}.</p> 587 588 589 <h3>Mappings for maps ({@code Map<}<em>K</em>,<em>V</em>{@code >} etc)</h3> 590 591 <p>A {@code Map<}<em>K</em>,<em>V</em>{@code >} or {@code 592 SortedMap<}<em>K</em>,<em>V</em>{@code >}, for example {@code 593 Map<String,ObjectName>}, has Open Type {@link TabularType} and is mapped 594 to a {@link TabularData}. 595 The {@code TabularType} has two items called {@code key} and 596 {@code value}. The Open Type of {@code key} is 597 <em>opentype(K)</em>, and the Open Type of {@code value} is 598 <em>opentype(V)</em>. The index of the {@code TabularType} is the 599 single item {@code key}.</p> 600 601 <p>For example, the {@code TabularType} for a {@code 602 Map<String,ObjectName>} might be constructed with code like 603 this:</p> 604 605 <pre> 606 String typeName = 607 "java.util.Map<java.lang.String, javax.management.ObjectName>"; 608 String[] keyValue = 609 new String[] {"key", "value"}; 610 OpenType[] openTypes = 611 new OpenType[] {SimpleType.STRING, SimpleType.OBJECTNAME}; 612 CompositeType rowType = 613 new CompositeType(typeName, typeName, keyValue, keyValue, openTypes); 614 TabularType tabularType = 615 new TabularType(typeName, typeName, rowType, new String[] {"key"}); 616 </pre> 617 618 <p>The {@code typeName} here is determined by the <a HREF="#type-names"> 619 type name rules</a> detailed below. 620 621 <p>A {@code SortedMap<}<em>K</em>,<em>V</em>{@code >} is mapped in the 622 same way, but it is only convertible if 623 <em>K</em> is a class or interface that implements {@link 624 java.lang.Comparable}. Thus, a {@code SortedMap<String,int[]>} 625 is convertible, but a 626 {@code SortedMap<int[],String>} is not. The conversion of a 627 {@code SortedMap} instance will fail with an {@code 628 IllegalArgumentException} if it has a non-null {@link 629 java.util.SortedMap#comparator() comparator()}.</p> 630 631 <p>A {@code Map<}<em>K</em>,<em>V</em>{@code >} is reconstructed as 632 a {@code java.util.HashMap<}<em>K</em>,<em>V</em>{@code >}; 633 a {@code SortedMap<}<em>K</em>,<em>V</em>{@code >} as 634 a {@code java.util.TreeMap<}<em>K</em>,<em>V</em>{@code >}.</p> 635 636 <p>{@code TabularData} is an interface. The concrete class that is 637 used to represent a {@code Map<}<em>K</em>,<em>V</em>{@code >} as 638 Open Data is {@link TabularDataSupport}, 639 or another class implementing {@code 640 TabularData} that serializes as {@code TabularDataSupport}.</p> 641 642 643 <h3><a name="mxbean-map">Mappings for MXBean interfaces</a></h3> 644 645 <p>An MXBean interface, or a type referenced within an MXBean 646 interface, can reference another MXBean interface, <em>J</em>. 647 Then <em>opentype(J)</em> is {@code SimpleType.OBJECTNAME} and 648 <em>opendata(J)</em> is {@code ObjectName}.</p> 649 650 <p>For example, suppose you have two MXBean interfaces like this:</p> 651 652 <pre> 653 public interface ProductMXBean { 654 public ModuleMXBean[] getModules(); 655 } 656 657 public interface ModuleMXBean { 658 public ProductMXBean getProduct(); 659 } 660 </pre> 661 662 <p>The object implementing the {@code ModuleMXBean} interface 663 returns from its {@code getProduct} method an object 664 implementing the {@code ProductMXBean} interface. The 665 {@code ModuleMXBean} object and the returned {@code 666 ProductMXBean} objects must both be registered as MXBeans in the 667 same MBean Server.</p> 668 669 <p>The method {@code ModuleMXBean.getProduct()} defines an 670 attribute called {@code Product}. The Open Type for this 671 attribute is {@code SimpleType.OBJECTNAME}, and the corresponding 672 {@code ObjectName} value will be the name under which the 673 referenced {@code ProductMXBean} is registered in the MBean 674 Server.</p> 675 676 <p>If you make an MXBean proxy for a {@code ModuleMXBean} and 677 call its {@code getProduct()} method, the proxy will map the 678 {@code ObjectName} back into a {@code ProductMXBean} by making 679 another MXBean proxy. More formally, when a proxy made with 680 {@link JMX#newMXBeanProxy(MBeanServerConnection, ObjectName, 681 Class) 682 JMX.newMXBeanProxy(mbeanServerConnection, objectNameX, 683 interfaceX)} needs to map {@code objectNameY} back into {@code 684 interfaceY}, another MXBean interface, it does so with {@code 685 JMX.newMXBeanProxy(mbeanServerConnection, objectNameY, 686 interfaceY)}. The implementation may return a proxy that was 687 previously created by a call to {@code JMX.newMXBeanProxy} 688 with the same parameters, or it may create a new proxy.</p> 689 690 <p>The reverse mapping is illustrated by the following change to the 691 {@code ModuleMXBean} interface:</p> 692 693 <pre> 694 public interface ModuleMXBean { 695 public ProductMXBean getProduct(); 696 public void setProduct(ProductMXBean c); 697 } 698 </pre> 699 700 <p>The presence of the {@code setProduct} method now means that the 701 {@code Product} attribute is read/write. As before, the value 702 of this attribute is an {@code ObjectName}. When the attribute is 703 set, the {@code ObjectName} must be converted into the 704 {@code ProductMXBean} object that the {@code setProduct} method 705 expects. This object will be an MXBean proxy for the given 706 {@code ObjectName} in the same MBean Server.</p> 707 708 <p>If you make an MXBean proxy for a {@code ModuleMXBean} and 709 call its {@code setProduct} method, the proxy will map its 710 {@code ProductMXBean} argument back into an {@code ObjectName}. 711 This will only work if the argument is in fact another proxy, 712 for a {@code ProductMXBean} in the same {@code 713 MBeanServerConnection}. The proxy can have been returned from 714 another proxy (like {@code ModuleMXBean.getProduct()} which 715 returns a proxy for a {@code ProductMXBean}); or it can have 716 been created by {@link 717 JMX#newMXBeanProxy(MBeanServerConnection, ObjectName, Class) 718 JMX.newMXBeanProxy}; or it can have been created using {@link 719 java.lang.reflect.Proxy Proxy} with an invocation handler that 720 is {@link MBeanServerInvocationHandler} or a subclass.</p> 721 722 <p>If the same MXBean were registered under two different 723 {@code ObjectName}s, a reference to that MXBean from another 724 MXBean would be ambiguous. Therefore, if an MXBean object is 725 already registered in an MBean Server and an attempt is made to 726 register it in the same MBean Server under another name, the 727 result is an {@link InstanceAlreadyExistsException}. Registering 728 the same MBean object under more than one name is discouraged in 729 general, notably because it does not work well for MBeans that are 730 {@link NotificationBroadcaster}s.</p> 731 732 <h3><a name="composite-map">Mappings for other types</a></h3> 733 734 <p>Given a Java class or interface <em>J</em> that does not match the other 735 rules in the table above, the MXBean framework will attempt to map 736 it to a {@link CompositeType} as follows. The type name of this 737 {@code CompositeType} is determined by the <a HREF="#type-names"> 738 type name rules</a> below.</p> 739 740 <p>The class is examined for getters using the conventions 741 <a HREF="#naming-conv">above</a>. (Getters must be public 742 instance methods.) If there are no getters, or if 743 any getter has a type that is not convertible, then <em>J</em> is 744 not convertible.</p> 745 746 <p>If there is at least one getter and every getter has a 747 convertible type, then <em>opentype(J)</em> is a {@code 748 CompositeType} with one item for every getter. If the getter is 749 750 <blockquote> 751 <code><em>T</em> get<em>Name</em>()</code> 752 </blockquote> 753 754 then the item in the {@code CompositeType} is called {@code name} 755 and has type <em>opentype(T)</em>. For example, if the item is 756 757 <blockquote> 758 <code>String getOwner()</code> 759 </blockquote> 760 761 then the item is called {@code owner} and has Open Type {@code 762 SimpleType.STRING}. If the getter is 763 764 <blockquote> 765 <code>boolean is<em>Name</em>()</code> 766 </blockquote> 767 768 then the item in the {@code CompositeType} is called {@code name} 769 and has type {@code SimpleType.BOOLEAN}.</p> 770 771 <p>Notice that the first character (or code point) is converted to 772 lower case. This follows the Java Beans convention, which for 773 historical reasons is different from the Standard MBean 774 convention. In a Standard MBean or MXBean interface, a method 775 {@code getOwner} defines an attribute called {@code Owner}, while 776 in a Java Bean or mapped {@code CompositeType}, a method {@code 777 getOwner} defines a property or item called {@code owner}.</p> 778 779 <p>If two methods produce the same item name (for example, {@code 780 getOwner} and {@code isOwner}, or {@code getOwner} and {@code 781 getowner}) then the type is not convertible.</p> 782 783 <p>When the Open Type is {@code CompositeType}, the corresponding 784 mapped Java type (<em>opendata(J)</em>) is {@link 785 CompositeData}. The mapping from an instance of <em>J</em> to a 786 {@code CompositeData} corresponding to the {@code CompositeType} 787 just described is done as follows. First, if <em>J</em> 788 implements the interface {@link CompositeDataView}, then that 789 interface's {@link CompositeDataView#toCompositeData 790 toCompositeData} method is called to do the conversion. 791 Otherwise, the {@code CompositeData} is constructed by calling 792 the getter for each item and converting it to the corresponding 793 Open Data type. Thus, a getter such as</p> 794 795 <blockquote> 796 {@code List<String> getNames()} 797 </blockquote> 798 799 <p>will have been mapped to an item with name "{@code names}" and 800 Open Type {@code ArrayType(1, SimpleType.STRING)}. The conversion 801 to {@code CompositeData} will call {@code getNames()} and convert 802 the resultant {@code List<String>} into a {@code String[]} for the 803 item "{@code names}".</p> 804 805 <p>{@code CompositeData} is an interface. The concrete class that is 806 used to represent a type as Open Data is {@link 807 CompositeDataSupport}, or another class implementing {@code 808 CompositeData} that serializes as {@code 809 CompositeDataSupport}.</p> 810 811 812 <h4>Reconstructing an instance of Java type <em>J</em> from 813 a {@code CompositeData}</h4> 814 815 <p>If <em>opendata(J)</em> is {@code CompositeData} for a Java type 816 <em>J</em>, then either an instance of <em>J</em> can be 817 reconstructed from a {@code CompositeData}, or <em>J</em> is not 818 reconstructible. If any item in the {@code CompositeData} is not 819 reconstructible, then <em>J</em> is not reconstructible either.</p> 820 821 <p>For any given <em>J</em>, the following rules are consulted to 822 determine how to reconstruct instances of <em>J</em> from 823 {@code CompositeData}. The first applicable rule in the list is 824 the one that will be used.</p> 825 826 <ol> 827 828 <li><p>If <em>J</em> has a method<br> 829 {@code public static }<em>J </em>{@code from(CompositeData cd)}<br> 830 then that method is called to reconstruct an instance of 831 <em>J</em>.</p></li> 832 833 <li><p>Otherwise, if <em>J</em> has at least one public 834 constructor with a {@link ConstructorProperties} annotation, then one 835 of those constructors (not necessarily always the same one) 836 will be called to reconstruct an instance of <em>J</em>. 837 Every such annotation must list as many strings as the 838 constructor has parameters; each string must name a property 839 corresponding to a getter of <em>J</em>; and the type of this 840 getter must be the same as the corresponding constructor 841 parameter. It is not an error for there to be getters that 842 are not mentioned in the {@code ConstructorProperties} annotation 843 (these may correspond to information that is not needed to 844 reconstruct the object).</p> 845 846 <p>An instance of <em>J</em> is reconstructed by calling a 847 constructor with the appropriate reconstructed items from the 848 {@code CompositeData}. The constructor to be called will be 849 determined at runtime based on the items actually present in 850 the {@code CompositeData}, given that this {@code 851 CompositeData} might come from an earlier version of 852 <em>J</em> where not all the items were present. A 853 constructor is <em>applicable</em> if all the properties named 854 in its {@code ConstructorProperties} annotation are present as items 855 in the {@code CompositeData}. If no constructor is 856 applicable, then the attempt to reconstruct <em>J</em> fails.</p> 857 858 <p>For any possible combination of properties, it must be the 859 case that either (a) there are no applicable constructors, or 860 (b) there is exactly one applicable constructor, or (c) one of 861 the applicable constructors names a proper superset of the 862 properties named by each other applicable constructor. (In 863 other words, there should never be ambiguity over which 864 constructor to choose.) If this condition is not true, then 865 <em>J</em> is not reconstructible.</p></li> 866 867 <li><p>Otherwise, if <em>J</em> has a public no-arg constructor, and 868 for every getter in <em>J</em> with type 869 <em>T</em> and name <em>N</em> there is a corresponding setter 870 with the same name and type, then an instance of <em>J</em> is 871 constructed with the no-arg constructor and the setters are 872 called with the reconstructed items from the {@code CompositeData} 873 to restore the values. For example, if there is a method<br> 874 {@code public List<String> getNames()}<br> 875 then there must also be a method<br> 876 {@code public void setNames(List<String> names)}<br> 877 for this rule to apply.</p> 878 879 <p>If the {@code CompositeData} came from an earlier version of 880 <em>J</em>, some items might not be present. In this case, 881 the corresponding setters will not be called.</p></li> 882 883 <li><p>Otherwise, if <em>J</em> is an interface that has no methods 884 other than getters, an instance of <em>J</em> is constructed 885 using a {@link java.lang.reflect.Proxy} with a {@link 886 CompositeDataInvocationHandler} backed by the {@code 887 CompositeData} being converted.</p></li> 888 889 <li><p>Otherwise, <em>J</em> is not reconstructible.</p></li> 890 </ol> 891 892 <p>Here are examples showing different ways to code a type {@code 893 NamedNumber} that consists of an {@code int} and a {@code 894 String}. In each case, the {@code CompositeType} looks like this:</p> 895 896 <blockquote> 897 <pre> 898 {@link CompositeType}( 899 "NamedNumber", // typeName 900 "NamedNumber", // description 901 new String[] {"number", "name"}, // itemNames 902 new String[] {"number", "name"}, // itemDescriptions 903 new OpenType[] {SimpleType.INTEGER, 904 SimpleType.STRING} // itemTypes 905 ); 906 </pre> 907 </blockquote> 908 909 <ol> 910 <li>Static {@code from} method: 911 912 <blockquote> 913 <pre> 914 public class NamedNumber { 915 public int getNumber() {return number;} 916 public String getName() {return name;} 917 private NamedNumber(int number, String name) { 918 this.number = number; 919 this.name = name; 920 } 921 <b>public static NamedNumber from(CompositeData cd)</b> { 922 return new NamedNumber((Integer) cd.get("number"), 923 (String) cd.get("name")); 924 } 925 private final int number; 926 private final String name; 927 } 928 </pre> 929 </blockquote> 930 </li> 931 932 <li>Public constructor with <code>@ConstructorProperties</code> annotation: 933 934 <blockquote> 935 <pre> 936 public class NamedNumber { 937 public int getNumber() {return number;} 938 public String getName() {return name;} 939 <b>@ConstructorProperties({"number", "name"}) 940 public NamedNumber(int number, String name)</b> { 941 this.number = number; 942 this.name = name; 943 } 944 private final int number; 945 private final String name; 946 } 947 </pre> 948 </blockquote> 949 </li> 950 951 <li>Setter for every getter: 952 953 <blockquote> 954 <pre> 955 public class NamedNumber { 956 public int getNumber() {return number;} 957 public void <b>setNumber</b>(int number) {this.number = number;} 958 public String getName() {return name;} 959 public void <b>setName</b>(String name) {this.name = name;} 960 <b>public NamedNumber()</b> {} 961 private int number; 962 private String name; 963 } 964 </pre> 965 </blockquote> 966 </li> 967 968 <li>Interface with only getters: 969 970 <blockquote> 971 <pre> 972 public interface NamedNumber { 973 public int getNumber(); 974 public String getName(); 975 } 976 </pre> 977 </blockquote> 978 </li> 979 </ol> 980 981 <p>It is usually better for classes that simply represent a 982 collection of data to be <em>immutable</em>. An instance of an 983 immutable class cannot be changed after it has been constructed. 984 Notice that {@code CompositeData} itself is immutable. 985 Immutability has many advantages, notably with regard to 986 thread-safety and security. So the approach using setters should 987 generally be avoided if possible.</p> 988 989 990 <h3>Recursive types</h3> 991 992 <p>Recursive (self-referential) types cannot be used in MXBean 993 interfaces. This is a consequence of the immutability of {@link 994 CompositeType}. For example, the following type could not be the 995 type of an attribute, because it refers to itself:</p> 996 997 <pre> 998 public interface <b>Node</b> { 999 public String getName(); 1000 public int getPriority(); 1001 public <b>Node</b> getNext(); 1002} 1003</pre> 1004 1005 <p>It is always possible to rewrite recursive types like this so 1006 they are no longer recursive. Doing so may require introducing 1007 new types. For example:</p> 1008 1009 <pre> 1010public interface <b>NodeList</b> { 1011 public List<Node> getNodes(); 1012} 1013 1014public interface Node { 1015 public String getName(); 1016 public int getPriority(); 1017} 1018</pre> 1019 1020 <h3>MBeanInfo contents for an MXBean</h3> 1021 1022 <p>An MXBean is a type of Open MBean. However, for compatibility 1023 reasons, its {@link MBeanInfo} is not an {@link OpenMBeanInfo}. 1024 In particular, when the type of an attribute, parameter, or 1025 operation return value is a primitive type such as {@code int}, 1026 or is {@code void} (for a return type), then the attribute, 1027 parameter, or operation will be represented respectively by an 1028 {@link MBeanAttributeInfo}, {@link MBeanParameterInfo}, or 1029 {@link MBeanOperationInfo} whose {@code getType()} or {@code 1030 getReturnType()} returns the primitive name ("{@code int}" etc). 1031 This is so even though the mapping rules above specify that the 1032 <em>opendata</em> mapping is the wrapped type ({@code Integer} 1033 etc).</p> 1034 1035 <p>The array of public constructors returned by {@link 1036 MBeanInfo#getConstructors()} for an MXBean that is directly 1037 registered in the MBean Server will contain all of the public 1038 constructors of that MXBean. If the class of the MXBean is not 1039 public then its constructors are not considered public either. 1040 The list returned for an MXBean that is constructed using the 1041 {@link StandardMBean} class is derived in the same way as for 1042 Standard MBeans. Regardless of how the MXBean was constructed, 1043 its constructor parameters are not subject to MXBean mapping 1044 rules and do not have a corresponding {@code OpenType}.</p> 1045 1046 <p>The array of notification types returned by {@link 1047 MBeanInfo#getNotifications()} for an MXBean that is directly 1048 registered in the MBean Server will be empty if the MXBean does 1049 not implement the {@link NotificationBroadcaster} interface. 1050 Otherwise, it will be the result of calling {@link 1051 NotificationBroadcaster#getNotificationInfo()} at the time the MXBean 1052 was registered. Even if the result of this method changes 1053 subsequently, the result of {@code MBeanInfo.getNotifications()} 1054 will not. The list returned for an MXBean that is constructed 1055 using the {@link StandardMBean} or {@link StandardEmitterMBean} 1056 class is derived in the same way as for Standard MBeans.</p> 1057 1058 <p>The {@link Descriptor} for all of the 1059 {@code MBeanAttributeInfo}, {@code MBeanParameterInfo}, and 1060 {@code MBeanOperationInfo} objects contained in the {@code MBeanInfo} 1061 will have a field {@code openType} whose value is the {@link OpenType} 1062 specified by the mapping rules above. So even when {@code getType()} 1063 is "{@code int}", {@code getDescriptor().getField("openType")} will 1064 be {@link SimpleType#INTEGER}.</p> 1065 1066 <p>The {@code Descriptor} for each of these objects will also have a 1067 field {@code originalType} that is a string representing the Java type 1068 that appeared in the MXBean interface. The format of this string 1069 is described in the section <a HREF="#type-names">Type Names</a> 1070 below.</p> 1071 1072 <p>The {@code Descriptor} for the {@code MBeanInfo} will have a field 1073 {@code mxbean} whose value is the string "{@code true}".</p> 1074 1075 1076 <h3><a name="type-names">Type Names</a></h3> 1077 1078 <p>Sometimes the unmapped type <em>T</em> of a method parameter or 1079 return value in an MXBean must be represented as a string. If 1080 <em>T</em> is a non-generic type, this string is the value 1081 returned by {@link Class#getName()}. Otherwise it is the value of 1082 <em>genericstring(T)</em>, defined as follows: 1083 1084 <ul> 1085 1086 <li>If <em>T</em> is a non-generic non-array type, 1087 <em>genericstring(T)</em> is the value returned by {@link 1088 Class#getName()}, for example {@code "int"} or {@code 1089 "java.lang.String"}. 1090 1091 <li>If <em>T</em> is an array <em>E[]</em>, 1092 <em>genericstring(T)</em> is <em>genericstring(E)</em> followed 1093 by {@code "[]"}. For example, <em>genericstring({@code int[]})</em> 1094 is {@code "int[]"}, and <em>genericstring({@code 1095 List<String>[][]})</em> is {@code 1096 "java.util.List<java.lang.String>[][]"}. 1097 1098 <li>Otherwise, <em>T</em> is a parameterized type such as {@code 1099 List<String>} and <em>genericstring(T)</em> consists of the 1100 following: the fully-qualified name of the parameterized type as 1101 returned by {@code Class.getName()}; a left angle bracket ({@code 1102 "<"}); <em>genericstring(A)</em> where <em>A</em> is the first 1103 type parameter; if there is a second type parameter <em>B</em> 1104 then {@code ", "} (a comma and a single space) followed by 1105 <em>genericstring(B)</em>; a right angle bracket ({@code ">"}). 1106 1107 </ul> 1108 1109 <p>Note that if a method returns {@code int[]}, this will be 1110 represented by the string {@code "[I"} returned by {@code 1111 Class.getName()}, but if a method returns {@code List<int[]>}, 1112 this will be represented by the string {@code 1113 "java.util.List<int[]>"}. 1114 1115 <h3>Exceptions</h3> 1116 1117 <p>A problem with mapping <em>from</em> Java types <em>to</em> 1118 Open types is signaled with an {@link OpenDataException}. This 1119 can happen when an MXBean interface is being analyzed, for 1120 example if it references a type like {@link java.util.Random 1121 java.util.Random} that has no getters. Or it can happen when an 1122 instance is being converted (a return value from a method in an 1123 MXBean or a parameter to a method in an MXBean proxy), for 1124 example when converting from {@code SortedSet<String>} to {@code 1125 String[]} if the {@code SortedSet} has a non-null {@code 1126 Comparator}.</p> 1127 1128 <p>A problem with mapping <em>to</em> Java types <em>from</em> 1129 Open types is signaled with an {@link InvalidObjectException}. 1130 This can happen when an MXBean interface is being analyzed, for 1131 example if it references a type that is not 1132 <em>reconstructible</em> according to the rules above, in a 1133 context where a reconstructible type is required. Or it can 1134 happen when an instance is being converted (a parameter to a 1135 method in an MXBean or a return value from a method in an MXBean 1136 proxy), for example from a String to an Enum if there is no Enum 1137 constant with that name.</p> 1138 1139 <p>Depending on the context, the {@code OpenDataException} or 1140 {@code InvalidObjectException} may be wrapped in another 1141 exception such as {@link RuntimeMBeanException} or {@link 1142 UndeclaredThrowableException}. For every thrown exception, 1143 the condition <em>C</em> will be true: "<em>e</em> is {@code 1144 OpenDataException} or {@code InvalidObjectException} (as 1145 appropriate), or <em>C</em> is true of <em>e</em>.{@link 1146 Throwable#getCause() getCause()}".</p> 1147 1148 @since 1.6 1149*/ 1150 1151@Documented 1152@Retention(RetentionPolicy.RUNTIME) 1153@Target(ElementType.TYPE) 1154public @interface MXBean { 1155 /** 1156 True if the annotated interface is an MXBean interface. 1157 @return true if the annotated interface is an MXBean interface. 1158 */ 1159 boolean value() default true; 1160} 1161