1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<!--
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
Copyright (c) 2008-2018 Oracle and/or its affiliates. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 2 only ("GPL") or the Common Development
and Distribution License("CDDL") (collectively, the "License"). You
may not use this file except in compliance with the License. You can
obtain a copy of the License at
https://oss.oracle.com/licenses/CDDL+GPL-1.1
or LICENSE.txt. See the License for the specific
language governing permissions and limitations under the License.
When distributing the software, include this License Header Notice in each
file and include the License file at LICENSE.txt.
GPL Classpath Exception:
Oracle designates this particular file as subject to the "Classpath"
exception as provided by Oracle in the GPL Version 2 section of the License
file that accompanied this code.
Modifications:
If applicable, add the following below the License Header, with the fields
enclosed by brackets [] replaced by your own identifying information:
"Portions Copyright [year] [name of copyright owner]"
Contributor(s):
If you wish your version of this file to be governed by only the CDDL or
only the GPL Version 2, indicate your decision by adding "[Contributor]
elects to include this software in this distribution under the [CDDL or GPL
Version 2] license." If you don't indicate a single choice of license, a
recipient has the option to distribute your version of this file under
either the CDDL, the GPL Version 2 or to extend the choice of license to
its licensees as provided above. However, if you add GPL Version 2 code
and therefore, elected the GPL Version 2 license, then the option applies
only if the new code is made subject to such option by the copyright
holder.
-->
<!--
Document : FunctionalSpec
Created on : Nov 17, 2008, 4:25:47 PM
Author : ken
-->
<title>GMBAL Functional Spec</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style type="text/css" title="Amaya theme">
/* Modern style for Amaya Editor Lite */
/* default rules for the whole document */
body {
font-size: 12pt;
font-family: Helvetica, Arial, sans-serif;
font-weight: normal;
font-style: normal;
color: black;
background-color: white;
line-height: 1.2em;
margin-left: 4em;
margin-right: 2em;
}
/* paragraphs */
pre {
color: Green;
}
p {
padding: 0;
margin-top: 1em;
margin-bottom: 1em;
text-align: left;
}
/* headings */
h1 {
font-size: 180%;
font-weight: bold;
font-style: normal;
font-variant: small-caps;
text-align: left;
padding: 0;
margin-top: 1.7em;
margin-bottom: 1.7em;
}
h2 {
font-size: 150%;
font-weight: bold;
font-style: normal;
padding: 0;
margin-top: 1.5em;
margin-bottom: 1.1em;
}
h3 {
font-size: 130%;
font-weight: bold;
font-style: normal;
padding: 0;
margin-top: 1.3em;
margin-bottom: 1.1em;
}
h4 {
font-size: 110%;
font-weight: bold;
font-style: normal;
padding: 0;
margin-top: 1.1em;
margin-bottom: 1.1em;
}
h5 {
font-size: 100%;
font-weight: bold;
font-style: italic;
padding: 0;
margin-top: 1em;
margin-bottom: 1em;
}
h6 {
font-size: 100%;
font-weight: normal;
font-style: italic;
padding: 0;
margin-top: 1em;
margin-bottom: 1em;
}
/* divisions */
div {
padding: 0;
margin-top: 0em;
margin-bottom: 0em;
}
/* lists */
ul, ol {
padding: 0 0 0 3em;
margin-top: 1em;
margin-bottom: 1em;
}
ul ul, ol ol, ul ol, ol ul {
margin-top: 1em;
margin-bottom: 1em;
}
li {
padding: 0;
margin-top: 1em;
margin-bottom: 1em;
text-align: left;
}
li p {
margin-top: 1em;
margin-bottom: 1em;
}
dl {
padding: 0;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 1em;
}
dl dl {
margin-top: 0em;
margin-bottom: 0em;
}
dt {
padding: 0;
font-weight: bold;
margin-top: .3em;
margin-bottom: .3em;
}
dd {
padding: 0;
margin-top: .3em;
margin-left: 3em;
margin-bottom: .3em;
}
dl p {
margin-top: .3em;
margin-bottom: .3em;
}
/* inline */
strong {
font-weight: bold;
}
em {
font-style: italic;
}
code {
font-family: Courier New, Courier, monospace;
}
ins {
background-color: yellow;
text-decoration: underline;
}
del {
text-decoration: line-through;
}
/* anchors */
a[href] {
color: blue;
text-decoration: underline;
}
/* end */
</style>
</head>
<body>
<h1>GlassFish MBean Annotation Library (gmbal)</h1>
<h1>Functional Specification</h1>
by Ken Cavanaugh<br>
Version 1.0 (for GlassFish v3 FCS)<span
style="background-color: rgb(250, 255, 221);"></span><br>
12/11/09<span style="background-color: rgb(255, 249, 200);"></span><br>
<h2>1. Introduction</h2>
<p>The GlassFish MBean Annotation Library (gmbal, pronounced as in
"gumball")
is a runtime annotation processor that creates Open MBeans. This is
useful for
creating a management API for existing code with minimal effort.
It is
intended to be applied to existing modules (which may be OSGi bundles
in
GlassFish v3, or any other packaging model including standard jar
files), but
could be used anywhere that it is desired to combine the definition of
the
management API with the module API and implementation.</p>
<p>Note that gmbal is not limited to use in GlassFish. Gmbal is
completely independent of GlassFish, and may be used in a context where
GlassFIsh is not present. However, when a gmbal-enabled module in used
in
GlassFish V3, that module will automatically be manageable using
GlassFish V3
admin tools.</p>
<p>There are really two parts to creating a management API for a
module:
instrumenting the module implementation, and providing a client
interface that
may be accessed remotely. This is closely related to the AMX work in
GFv3. AMX defines the interface for AMX MBeans, and provides
tools and libraries for clients accessing AMX MBeans. Gmbal is a
library that provides a mechanism for implementing AMXv3-compliant
MBeans.<br>
</p>
<h3>1.1. Alignment with related projects</h3>
JMX is also defining similar annotations in JSR 255 for JDK 7.
The JSR 255 spec is available at the download <a
href="http://jcp.org/aboutJava/communityprocess/edr/jsr255/index.html">page</a>.
Gmbal is mostly aligned with the JSR 255
annotations.
<br>
<br>
The similarities include:<br>
<ul>
<li><a href="gmbal/javadoc/org/glassfish/gmbal/ManagedAttribute.html">@ManagedAttribute</a>
is the same, except that gmbal allows overriding the id.</li>
<li><a href="gmbal/javadoc/org/glassfish/gmbal/ManagedOperation.html">@ManagedOperation</a>
is the same, except that gmbal allows overriding the id.</li>
<li><a href="gmbal/javadoc/org/glassfish/gmbal/DescriptorKey.html">@DescriptorKey</a>
is the same.</li>
<li><a href="gmbal/javadoc/org/glassfish/gmbal/DescriptorFields.html">@DescriptorFields</a>
is the same.</li>
<li><a href="gmbal/javadoc/org/glassfish/gmbal/Description.html">@Description</a>
is similar to JSR 255, but does not support a bundleBaseName attribute.
The bundle is set in gmbal through the
ManagedObjectManager.setResourceBundle call.<br>
</li>
</ul>
Differences:<br>
<ul>
<li>The packaging is necessarily different: org.glassfish.gmbal for
gmbal, javax.management for JSR 255.</li>
<li>Gmbal uses <a
href="gmbal/javadoc/org/glassfish/gmbal/ManagedObject.html">@ManagedObject</a>
instead of @MBean (part of JSR 255) or <a
href="http://java.sun.com/javase/6/docs/api/javax/management/MXBean.html">@MXBean</a>.</li>
<li>Gmbal only supports attribute change notifications, so
the @NotificationInfo annotation (from JSR 255) does not exist in
Gmbal. See "<a href="#3.2.3._register_and_registerAtRoot">register
and registerAtRoot</a>" for a discussion on notification support.<br>
</li>
<li>Gmbal has an <a
href="gmbal/javadoc/org/glassfish/gmbal/ManagedData.html">@ManagedData</a>
annotation to define the mapping of data types into CompositeData,
while JSR 255 follows MXBeans and simply assumes that all methods that
follow the JavaBeans patterns define read-only attributes.</li>
<li>Gmbal supports an <a
href="gmbal/javadoc/org/glassfish/gmbal/MBeanType.html">@AMXMetadata</a>
annotation, but this is really just an extension to the descriptor
annotation mechanism borrowed from JMX ModelMBeans. The
@AMXMetadata annotation is provided to support AMX-specific metadata.</li>
<li>Gmbal includes <a
href="gmbal/javadoc/org/glassfish/gmbal/ParameterNames.html">@ParameterNames</a>
to provide reasonable names for the arguments on MBean
operations. JSR 255 does not currently have such a mechanism,
because JDK 7 will have an extension to Java reflection that captures
the argument names on methods.</li>
<li>Gmbal includes <a
href="gmbal/javadoc/org/glassfish/gmbal/ObjectNameKey.html">@NameValue</a>
to make it easy to define the value of the "name" field in the
ObjectName. This makes registration of object as MBeans slightly
simpler.</li>
<li>Gmbal includes <a
href="gmbal/javadoc/org/glassfish/gmbal/IncludeSubclass.html">@IncludeSubclass</a>,
which allows limited (and closed) polymorphism for CompositeData.
This partially solves the problem of mapping a group of types sharing
type Base that appear as (for example) attributes with type
List<Base>.</li>
<li>Gmbal includes <a
href="gmbal/javadoc/org/glassfish/gmbal/InheritedAttribute.html">@InheritedAttribute</a>(<a
href="gmbal/javadoc/org/glassfish/gmbal/InheritedAttributes.html">s</a>)
to allow using methods inherited from super classes or super interfaces
that cannot be annotated as attribute and operations.</li>
<li>Gmbal is more limited currently in mapping OpenType -> Java
type than JMX is, as this does not seem to be a feature that we need.<br>
</li>
</ul>
Note that there are two complimentary ways to define MBeans: MXBeans
and
annotations. MXBeans are somewhat more convenient to use in cases
where EVERY
method in a class or interface is part of the management interface,
whereas
annotations are more convenient for adding a management interface to
existing
code. But both mechanisms share most of the same rules for MXBean
mapping from
Java types to Open types as discussed in "<a
href="#4.3._OpenType_mapping_">OpenType Mapping</a>".<br>
<br>
AMX in GlassFish v3 is being generalized to define exactly what an
MBean must
do to be manageable in the GlassFish v3 admin tools (see Lloyd's <a
href="https://glassfish.dev.java.net/nonav/v3/admin/planning/V3Changes/V3_AMX_SPI.html">GlassFish
V3 AMX SPI</a> specification). Gmbal will follow all mandatory and most
of the
optional requirements of this specification so that any module that
uses gmbal
to define MBeans will automatically participate in the GFv3 admin tools
when run in a GFv3 container. However, this will not prevent
the use of
gmbal in these same modules as a standalone MBean definition library.<br>
<br>
This last point needs a little more explanation. The main
interface that
matters for running in or out of a GFv3 container is
ManagedObjectManagerFactory.create<span style="font-style: italic;">XXX</span>
(<span style="font-style: italic;">XXX</span> is either Standalone or
Federated).
The createStandalone method is needed for running outside of GFv3, and
takes
the domain name as an argument. createFedederated must be called inside
of
GFv3, and this requires the AMXv3-compliant ObjectName of the
ManagedObjectManager root
MBean's
parent. Calling the appropriate method is probably best handled
in most cases
by having an OSGi bundle for a module that is responsible for
integrating the
module into GFv3. <br>
<br>
For example, the orb-iiop bundle integrates the standalone ORB bundles
into GFv3. orb-iiop handles
registration of all of the GFv3-specific interceptors and other
initialization
when the GFv3 ORB instance is created. orb-iiop will also need to set
the ORB property com.sun.corba.ee.ORBGmbalRootParentName to the string
representation of the ObjectName of the ORB's gmbal root parent.
The ORB will then use this property to call either createStandalone (if
it is not set) or createFederated (with the value of the property as
the ObjectName passed into the call).<br>
<h3>1.2. Similar projects</h3>
Besides JSR 255 (discussed in the previous section), there are at least
two other
projects that also define MBeans using annotations.<br>
<br>
The Spring project also defines a set of <a
href="http://static.springframework.org/spring/docs/2.0.x/reference/jmx.html#jmx-interface-annotations">annotations</a>
to use for creating
MBeans. Eamonn McManus has pointed to this as one of the starting
points for JSR 255 in a blog <a
href="http://weblogs.java.net/blog/emcmanus/archive/2007/08/defining_mbeans.html">post</a>
from August 2007. JSR 255 and Spring share the @ManagedAttribute
and @ManagedOperation annotations, but the Spring annotations
include a description fields, whereas JSR 255 has moved the description
into a separate annotation (as I have
in gmbal as well).<br>
<br>
The WebObject project from INRIA in France has created the <a
href="http://spoon.gforge.inria.fr/SpoonJMX/Main">SpoonJMX</a>
project, which
also allows the use of annotations to define MBeans. SpoonJMX uses
@ManagedResource to define an MBean class. It
uses @ManagedAttribute and @ManagedOperation as in the other
systems. SpoonJMX defines a @ObjectKeyName annotation,
which I have adopted for use in gmbal as well under the name of
@NameValue. SpoonJMX also
defines more attributes on the annotations than
either gmbal or JSR 255.<br>
<h2>2. The Management Data Model</h2>
Gmbal supports a simple hierarchical model of management data as
defined in JSR
77 and AMX.<br>
<img style="width: 730px; height: 507px;" alt="Gmbal Class Diagram"
src="Gmbal.png"><br>
The components of the data model are as follows:<br>
<ul>
<li>A ManagedObjectManager acts as a container for all state related
to a particular usage of gmbal. This includes:
<ul>
<li>A domain to use for all ObjectNames created in this
ManagedObjectManager.</li>
<li>A rootParentName, which is the ObjectName of the parent of
the ManagedObjectManager.</li>
<li>A root object, which represents the top of the tree of MBean
managed by the ManagedObjectManager.<br>
</li>
</ul>
</li>
<li>From a POJO with annotations, an MBeanImpl is constructed, which
implements the dynamic MBean API. This dynamic MBean is
associated with additional classes:
<ul>
<li>0 or more Attributes, which may be getters or setters or both
(note that AMX will give as at least Name, Parent, and Children
attributes).<br>
</li>
<li>0 or more Operations, which may be invoked.</li>
<li>Metadata, represented by ModelMBeanInfoSupport (so that
metadata Descriptors are available on JDK 5 as well as JDK 6). The
Metadata is extensible through the use of the @DescriptorKey and
@DescriptorField meta-annotations.<br>
</li>
<li>A single parent MBeanImpl, which may be null (this is one end
of the contains relation).</li>
<li>0 or more child MBeanImpls (this is the other end of the
contains relation).</li>
<li>Following AMXv3, the ObjectName of the MBean will contain 3
name/value pairs:</li>
<ul>
<li>pp, which is the AMXv3 parent path, or the path name of the
parent of this MBean</li>
<li>type, which is derived from the Class using annotations or
other mechanisms</li>
<li>name, which is derived either from the registration call,
or a method on the object. The name is absent in the case of a
singleton. In any case, the type and name (if present) must be
unique within the scope of the parent.<br>
</li>
</ul>
</ul>
</li>
<li>Attributes and Operations have ids, which are generally derived
from the name of the annotated method as discussed <a
href="#4.1._Processing_of_method_names_for_IDs">here</a>, but the id
may also be specified in the @<a
href="gmbal/javadoc/org/glassfish/gmbal/ManagedAttribute.html">ManagedAttribute</a>
and @<a href="gmbal/javadoc/org/glassfish/gmbal/ManagedOperation.html">ManagedOperation</a>
annotations, as well as in the @<a
href="gmbal/javadoc/org/glassfish/gmbal/InheritedAttribute.html">InheritedAttribute</a>
annotation.<br>
</li>
</ul>
Note that all values consumed or produced by Attributes and Operations
are
instances of OpenTypes.<br>
<br>
This diagram is a simplification of the actual implementation of
gmbal. In
particular, the metadata, attributes, and operations are
maintained in a
MBeanSkeleton
class, which is shared by all MBeanImpls for instances of the same
class. The TypeConverter
that handles conversion between Java types and the corresponding
OpenType is also
not
included here.<br>
<h2>3. Interfaces</h2>
Javadocs are <a href="gmbal/javadoc/index.html">available</a> as part
of the
gmbal project. <br>
<br>
There are basically 3 elements to the gmbal API:<br>
<ol>
<li>class ManagedObjectManagerFactory, which provides factory methods
for creating instance of the ManagedObjectManager interface.</li>
<li>interface ManagedObjectManager, which provides
register/deregister methods (and a number of other capabilities).</li>
<li>A number of annotations.<br>
</li>
</ol>
Here is a summary of the annotations:<br>
<table style="text-align: left; width: 100%;" border="1" cellpadding="2"
cellspacing="2">
<tbody>
<tr>
<td style="vertical-align: top; font-weight: bold;">Annotation
Class<br>
</td>
<td style="vertical-align: top; font-weight: bold; width: 20%;">Annotation
Fields<br>
</td>
<td style="vertical-align: top; font-weight: bold;">Applicable
Element Type<br>
</td>
<td style="vertical-align: top;"><span style="font-weight: bold;">Relation
to JSR 255</span><br>
</td>
<td style="vertical-align: top; font-weight: bold;">Purpose<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@ManagedObject<br>
</td>
<td style="vertical-align: top;">none<br>
</td>
<td style="vertical-align: top;">Class or Interface<br>
</td>
<td style="vertical-align: top;">255 uses @MXBean<br>
</td>
<td style="vertical-align: top;">Defines a class whose instances
are processed into MBeans.<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@ManagedData<br>
</td>
<td style="vertical-align: top;">String name (defaults to class
name)<br>
</td>
<td style="vertical-align: top;">Class or Interface<br>
</td>
<td style="vertical-align: top;">MXBeans assume all methods are
in CompositeData<br>
</td>
<td style="vertical-align: top;">Defines a class whose instances
are process into Open data for Open Mbeans.<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@ManagedAttribute<br>
</td>
<td style="vertical-align: top;">String id (defaults to value
from Method name)<br>
</td>
<td style="vertical-align: top;">Method or field<br>
</td>
<td style="vertical-align: top;">Same<br>
</td>
<td style="vertical-align: top;">Defines a method or field that
represents
an attribute either in ManagedData or ManagedObject<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@ManagedOperation<br>
</td>
<td style="vertical-align: top;">String id (defaults to value
from Method name)<br>
Impact impact (defaults to UNKNOW; Impact enum corresponds to
MBeanOperationInfo impact values)<br>
</td>
<td style="vertical-align: top;">Method<br>
</td>
<td style="vertical-align: top;">Same<br>
</td>
<td style="vertical-align: top;">Defines a method that represents
an operation in ManagedObject <br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@Description<br>
</td>
<td style="vertical-align: top;">String value<br>
<br>
String key (the key to use in a generated resource bundle; default ""
means to derive key from name of annotated element)<br>
</td>
<td style="vertical-align: top;">Class, Interface, Method,
or Field<br>
</td>
<td style="vertical-align: top;">Same (but JSR 255 includes I18N)<br>
</td>
<td style="vertical-align: top;">Defines the descriptive text
associated with a Class, Interface, or Method. This may require I18N,
as discussed <a href="#4.2._I18N_support">here</a>.<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@IncludeSubclass<br>
</td>
<td style="vertical-align: top;">Class[] value<br>
</td>
<td style="vertical-align: top;">Class or Interface for
ManagedData<br>
</td>
<td style="vertical-align: top;">N/A<br>
</td>
<td style="vertical-align: top;">Lists subclasses of the
annotated class that should also be scanned for annotations which are
included only on instances of the appropriate type<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@NameValue<br>
</td>
<td style="vertical-align: top;">none<br>
</td>
<td style="vertical-align: top;">Method<br>
</td>
<td style="vertical-align: top;">N/A<br>
</td>
<td style="vertical-align: top;">Defines a method (must be a
getter) whose result is the value of the name attribute in the
ObjectName of the MBean for an instance of the class<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@ParameterNames<br>
</td>
<td style="vertical-align: top;">String[] value (defaults to "")
(if present, must have same length as number of arguments in the
annotated method)<br>
</td>
<td style="vertical-align: top;">Method<br>
</td>
<td style="vertical-align: top;">N/A (JSR 255 will take this
information from reflection, which will make arg names available in JDK
7)<br>
</td>
<td style="vertical-align: top;">Defines the method names to be
used on an MBean operation. If this annotation is not present or has
the default value, the names will be arg<span
style="font-style: italic;">Num, </span>where <span
style="font-style: italic;">Num</span> is the position of the argument
starting from 0<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@InheritedAttribute<br>
</td>
<td style="vertical-align: top;">
<ul>
<li>String description</li>
<li>String id (default "" which means take from method name)</li>
<li>String methodName (default "" which means use id)</li>
</ul>
one of methodName or id must NOT be ""<br>
<br>
</td>
<td style="vertical-align: top;">Class or Interface<br>
</td>
<td style="vertical-align: top;">N/A<br>
</td>
<td style="vertical-align: top;">Defines a method inherited from
a class that cannot be annotated as an attribute. See "<a
href="#3.2.8._addAnnotation">addAnnotation</a>" for a discussion of
the use of this annotation.<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@InheritedAttributes<br>
</td>
<td style="vertical-align: top;">InheritedAttribute[] value<br>
</td>
<td style="vertical-align: top;">Class or Interface<br>
</td>
<td style="vertical-align: top;">N/A<br>
</td>
<td style="vertical-align: top;">Allows including multiple
inherited attributes<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@AMXMetadata<br>
</td>
<td style="vertical-align: top;">
<ul>
<li>boolean isSingleton() (true if only one MBean of this
type is allowed as a child of another MBean)</li>
<li>String group() (value is the group for this mbean, defaults
to "other")</li>
<li>String[] subTypes() (value is the list of allowable types
for children of this bean)</li>
<li>String genericInterfaceName() (used in AMX proxy
construction)<br>
</li>
<li> boolean immutableInfo() (true if the MBeanInfo
can never change)</li>
<li>String interfaceClassName() (also used in AMX proxy
construction)<br>
</li>
<li>String type() (the type to use in an ObjectName or in an
admin CLI path expression: defaults to class name, but see
also <a href="#filterPrefix">stripPrefix</a>)</li>
</ul>
(This is just an application of @DescriptorKey, with a little
special support in the gmbal implementation)<br>
</td>
<td style="vertical-align: top;">Class or Interface<br>
</td>
<td style="vertical-align: top;">N/A (but JMX supports
descriptors; see below)<br>
</td>
<td style="vertical-align: top;">Adds GFv3 and AMX specific
metadata to be defined for MBeans (see "<a
href="#4.4._Metadata_support_">Metadata Support</a>" for more details).<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@DescriptorKey<br>
</td>
<td style="vertical-align: top;">String value<br>
</td>
<td style="vertical-align: top;">Annotation method<br>
</td>
<td style="vertical-align: top;">same as JSR 255<br>
</td>
<td style="vertical-align: top;">Define metadata that can be
added to any MBean (see "<a href="#4.4._Metadata_support_">Metadata
Support</a>" for details)<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">@DescriptorField<br>
</td>
<td style="vertical-align: top;">String value (must be name=value)<br>
</td>
<td style="vertical-align: top;">Class, Interface, or Method<br>
</td>
<td style="vertical-align: top;">same as JSR 255<br>
</td>
<td style="vertical-align: top;">Define metadata directly on
MBean (See "<a href="#4.4._Metadata_support_">Metadata Support</a>" for
details)<br>
</td>
</tr>
</tbody>
</table>
<br>
Note that @ManagedAttribute and @Description may be used on fields.
There is however a limitation: any such field MUST be final, and have a
known immutable type. This is necessary to guarantee that access
to the field is safe in the presence of multiple thread. The
legal types are basically the SimpleTypes from JMX OpenType, with a
couple of additions:<br>
<ul>
<li>The primitives (boolean, byte, char, short, int, long, float,
double) and the corresponding java.lang wrapper classes (Boolean, Byte,
Character, Short, Integer, Long, Float, Double).</li>
<li>String</li>
<li>BigDecimal, BigInteger</li>
<li>Date</li>
<li>ObjectName</li>
<li>Class</li>
<li>Number</li>
<li>Object<br>
</li>
</ul>
<h3>3.1. The ManagedObjectManagerFactory</h3>
The ManagedObjectManagerFactory is primarily used to create
ManagedObjectManagers. It is the only concrete class in the gmbal
API, which is defined in the package org.glassfish.gmbal.
Obviously the implementation has other concrete classes, but these are
contained in subpackages under org.glassfish.gmbal.<br>
<h4>3.1.1. getMethod</h4>
This is a simple wrapper around Class.getDeclaredMethod that converts
the
checked exceptions from getDeclaredMethod into unchecked
exceptions. It is
intended for use with the <a href="#addAnnotation">addAnnotation</a>
method.<br>
<h4><a name="3.1.2._create"></a>3.1.2. create</h4>
There are two versions of create: createStandalone( String ) and
createFederated( ObjectName ).
createStandalone( String ) is used to create a standalone hierarchy:
the String is the
domain to use for all ObjectNames created from the resulting
ManagedObjectManager. In this version, the root has no parent.<br>
<br>
createFederated( ObjectName ) is used to create a hierarchy of MBeans
that are rooted
under a parent MBean that is not managed by the created instance of
ManagedObjectManager. In this case, the parent of the
ManagedObjectManager is
identified by the object name (called the rootParentName) that is
passed to the
create call. Note that the root parent MBean MUST be managed by
the same
MBeanServer as the ManagedObjectManager. The ObjectName MUST be
an AMX-compliant ObjectName: in particular, it MUST define pp, type,
and
name attributes.<br>
<br>
Note that createFederated must obey the parent-child restriction in
AMX. That is, a child cannot be created<br>
before its parent has been created. It is possible that the root
parent ObjectName passed to createFederated does not correspond to a
valid MBean in the MBeanServer at the time that createFederated is
called. In this case, the Gmbal ManagedObjectManager
created by the createFederated call must defer registration of its
MBeans until after the root parent has been registered. The MOM
monitors the root parent in the MBeanServer, registering and
de-registering all MBeans in the mom's tree as the root parent is
registered and de-registered.<br>
<br>
For examples of the usage of these methods, see "<a
href="#4.6._Using_Gmbal_">Using Gmbal</a>".<br>
<h3>3.2. The ManagedObjectManager</h3>
The ManagedObjectManager is the main API for gmbal. It contains a
tree of
MBeans with a single root,<br>
which may optionally be federated into a large MBean hierarchy.<br>
<br>
The most important methods are createRoot, register, and
unregister. Any
application of gmbal must use these methods. For examples of the
usage of the key methods, see "<a href="#4.6._Using_Gmbal_">Using Gmbal</a>".<br>
<h4>3.2.1. createRoot</h4>
There are several methods to create a root in the
ManagedObjectManager.
createRoot() creates a root that simply acts as an AMX container.
Its type
and name are both set to GMBALROOT.<br>
<br>
createRoot( Object ) and createRoot( Object, String ) both use the
given object
as the root, and just as in the register methods, these methods create
an MBean
from the Object using the annotations on its class. The createRoot(
Object )
method will derive the name from the object itself by calling the
@NameValue method from the class. If no such method is
available, the
name is set to the type value. The second method allows the name
to specified
explicitly. This can be useful in case where either
@NameValue is not
used, or there are multiple ManagedObjectManager instances with the
same root
type that share the same parent. In this case, it is essential
that each root
have a distinct name.last. There is also a createRoot() method,
which creates a simple internal root that only provides the required
AMXv3 attributes.<br>
<br>
createRoot may only be called when the ManagedObjectManager does not
already
contain a root. This is true immediately after a
ManagedObjectManagerFactory.create call, or after unregistering the
root.<br>
<h4>3.2.2. getRoot</h4>
getRoot returns the current root of the ManagedObjectManager. If
no root is
available, getRoot throws an IllegalStateException.<br>
<h4><a name="3.2.3._register_and_registerAtRoot"></a>3.2.3. register
and registerAtRoot</h4>
There are two forms of register: register( Object parent, Object obj )
and
register( Object parent, Object obj, String name ). The first
form obtains
the name from obj (by using @NameValue),
the second allows explicit specification of the name. The
returned result is
an instance
of NotificationEmitter that may be used to register a
NoticationListener to
listen for attribute change notifications on the
MBean that was created for obj. <br>
<br>
There are also two forms of registerAtRoot: registerAtRoot( Object obj
) and
registerAtRoot( Object obj, String name). These methods are
exactly
equivalent to mom.register( mom.getRoot(), obj ) and mom.register(
mom.getRoot(), obj, name ). <br>
<br>
All of these methods can only be called after a successful createRoot
call.<br>
<h4><a name="3.2.4._unregister"></a>3.2.4. unregister</h4>
unregister( Object ) unregisters an object that was previously
registered. It
also deletes any children of the object in depth-first order.
Unregister
removes the generated MBean from the ManagedObjectManager and also
unregisters
the MBean from the ManagedObjectManager's MBeanServer.<br>
<br>
Unregister can only be called after a successful createRoot call.<br>
<h4>3.2.5. getObject/getObjectName</h4>
The register methods return a NotificationEmitter which can be used to
register
a NotificationListener to listen for attribute change events. But
sometimes
access to the ObjectName is needed. getObjectName returns the
ObjectName that
was created for an object that was passed to the register method.
getObject
is used to handle the opposite case: going from the ObjectName to the
registered Object. Note that in both case the registered Object
is the
implementation object passed to a register method, NOT the internally
created
dynamic MBean (which is not directly provided).<br>
<br>
These methods can only be called after a successful createRoot call.<br>
<h4>3.2.6. stripPrefix and stripPackagePrefix<a name="filterPrefix"></a></h4>
A type prefix is simply a prefix of a fully qualified Java class name.
By
default, the MBean ObjectName type field is set to the full qualified
class
name of the implementation class, stripped of the longest type prefix
of the
class name. For example, in CORBA the type prefixes are set to:<br>
<br>
<div style="margin-left: 40px;">
com.sun.corba.se<br>
com.sun.corba.se.spi<br>
com.sun.corba.se.spi.orbutil<br>
com.sun.corba.se.impl<br>
com.sun.corba.se.impl.orbutil<br>
<br>
</div>
This helps keep the ObjectNames to a reasonable length.
Applications of gmbal
are also free to specify the exact type name to use through an
annotation.<br>
<br>
stripPackagePrefix is used to indicate that ALL package prefixes should
be removed from the class name for the default type.<br>
<br>
These methods may only be called before a successful createRoot call.<br>
<h4>3.2.7. <a name="MBeanServer_and_ResourceBundle"></a>MBeanServer
and
ResourceBundle</h4>
Accessors (getter and setter) are provided for the MBeanServer and the
ResourceBundle.<br>
<br>
The MBeanServer is used for all register and unregister operations in
the
ManagedObjectManager instance. It defaults to the<br>
platform MBeanServer.<br>
<br>
The ResourceBundle is used to internationalize all descriptions.
If set, the
description value is used as a key in the resource bundle,<br>
otherwise the description value is taken as the actual description.<br>
<h4><a name="3.2.8._addAnnotation"></a>3.2.8. <a name="addAnnotation"></a>addAnnotation</h4>
The best way to explain this method is to start with an example.
CORBA
defines a class org.omg.PortableServer.Servant. The
definition of Servant is a standard, and so I cannot add annotations to
the
source code for Servant. Gmbal is flexible enough that we can put
the annotation almost anywhere, so what are the possible
subclasses of Servant? Mostly one subclass is used in GlassFish for
dynamic RMI-IIOP: ReflectiveTie,
but others are possible, including Ties generated by the idlj
compiler. We also cannot add non-standard
annotations to standard-compliant code generated by a code generator.<br>
<br>
This becomes an issue when adding annotations to things like the ORB's
POA,
which has a method:<br>
<pre>@ManagedData<br>Servant get_servant() { ... }<br></pre>
that I would like to use as an attribute. How should gmbal
represent Servant
in this case? I may want to represent the Servant as ManagedData,
using one or more methods (such as byte[]
_object_id()) on the Servant as attributes, but there is no place that
I can put an annotation for this.<br>
<br>
The solution I have adopted in gmbal is to allow annotations to be
added on
"dummy" classes, and then use ManagedObjectManager.addAnnotation
to add the annotation to the appropriate
type. For example, the above example can be handled by:<br>
<pre>@ManagedData<br>@InheritedAttributes( {<br> @InheritedAttribute( methodName="_object_id", id="objectId",<br> description="The Object Id for this Servant" ),<br> ... // several other methods<br>} )<br>public interface DummyServant {}<br><br>mom.addAnnotation( Servant.class, <br> DummyServant.class.getAnnotation( ManagedObject.class ) ) ;<br>mom.addAnnotation( Servant.class, <br> DummyServant.class.getAnnotation( InheritedAttributes.class ) ) ;<br></pre>
This behaves exactly as if the annotations on DummyServant were on
Servant,
allowing the appropriate annotation processing to take place.<br>
<br>
InheritedAttribute can also be used when it is desired to use a method
inherited from a super class as an attribute or operation. This
is useful in the case where the superclass is
a class that for whatever reason cannot be modified with an
annotation. For example, the GlassFish v3 ORB defines an
interface TaggedProfileTemplate (in com.sun.corba.se.spi.ior) as
follows:<br>
<pre>@ManagedData<br>@Description( "A template for creating a TaggedProfile" ) <br>@IncludeSubclass( { com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate.class } )<br>@InheritedAttribute( description="List of TaggedComponents for this template",<br> methodName="iterator", id="TaggedComponents" )<br>public interface TaggedProfileTemplate extends List<TaggedComponent>, <br> Identifiable, WriteContents, MakeImmutable<br>{ <br> ... <br>}<br></pre>
<p>Here the iterator method is inherited from
List<TaggedComponent>. The iterator() method then has type
Iterator<T>, where T is bound to TaggedComponent. This results in
a CompositeData attribute with id TaggedComponents, which returns an
OpenType which is an array of whatever TaggedComponent maps to
(CompositeData as discussed in "<a href="#4.7._Handling_Polymorphism">Handling
Polymorphism</a>").<br>
</p>
<h4>3.2.9. Debugging support</h4>
Gmbal is a fairly complex system, and it is possible to apply it in
ways that
lead to incorrect results. To avoid problems, following the suggested
patterns in "<a href="#4.6._Using_Gmbal_">Using Gmbal</a>" will
help. Mistakes such as using an @ManagedAttribute operation on a
method that is not a valid attribute should be obvious from the
exception thrown by the register call. But perhaps the problem is
simply that the MBean definition is not exactly what was expected, due
to the pattern of annotations across multiple class and interface
definitions. Some assistance may be needed from gmbal to see what
exactly is happening, and also to aid in identifying bugs in gmbal
itself.<br>
<br>
To help with these kinds of problems, gmbal has several features that
can be useful for
debugging:<br>
<ul>
<li>setRegistrationDebugLevel( RegistrationDebugLevel level ).
Here the level can be NONE, NORMAL, or FINE. When enabled, this
method causes detailed tracing (more detailed with FINE) of the
operations involved in registering an MBean.</li>
<li>setRuntimeDebugLevel( boolean flag ). If this is enabled,
the operations involved in getting or setting attributes or calling an
operation on an MBean are traced.</li>
<li>setTypelibDebug( int level ). This is used to trace typelib
operations. 1 traces only basic operation, while >1 gives full
details (produces a lot of output).<br>
</li>
<li>String dumpSkeleton( Object obj ). If obj is an object that
has been registered with the ManagedObjectManager, this returns a
String dump of the MBeanSkeleton object, which provides detailed
information about the exact attributes and operations supported by the
MBean.</li>
</ul>
These operations can be used to get useful information about the
operation of
gmbal. The setXXXDebugLevel methods currently dump<br>
information to System.out, but the code has a flag that can be set to
dump
information to a Logger. The Logger may become the <br>
default dump mechanism in the future.<br>
<h4><a name="3.2.10._Close"></a>3.2.10. Close</h4>
<p>The close call is provided to unregister all MBeans still registered
with the MBeanServer, and to release all internal state maintained by
the ManagedObjectManager. Note that the registered MBeans are
unregistered and destroyed bottom up, to preserve the AMX requirements
that children cannot exist without their parent existing (see section
5.1 "Parent must exist" of the <a
href="https://glassfish.dev.java.net/nonav/v3/admin/planning/V3Changes/V3_AMX_SPI.html">AMX
SPI specification</a>).<br>
</p>
<h4>3.2.11. suspendJMXRegistration/resumeJMXRegistration</h4>
It is sometimes useful to be able to suspend and resume registration of
gmbal-generated MBeans with the MBean server. This is mainly useful
when it is necessary to create one or more MBeans in a constructor in
order to avoid complex refactoring of the code. Normally
ManagedObjectManager.register( this ) should NOT be used in a
constructor, because it exposes a partially constructed object to the
MBean server, which may then invoke methods on the partially
constructed object in order to execute operations, or get or set
attributes. However, gmbal itself will NEVER invoke any method or
access any field of an object unless an MBean operation requires it, so
it is safe to pass partially constructed objects into gmbal itself. So
avoiding MBeanServer registration by suspending registration allows
this case to be handled easily.<br>
<br>
<h4>3.2.12. getAMXClient</h4>
This returns an AMXClient that is a convenient wrapper for accessing
the features of the MBean corresponding to the object passed to
getAMXClient.<br>
<br>
<h4>3.2.13. getDomain</h4>
This method returns the domain for all MBeans created in the mom.
This is either the domain passed to createStandalone, or the domain of
the ObjectName passed to createFederated.<br>
<br>
<h4>3.2.14. isManagedObject</h4>
This method is a convenience API that simply checks whether or not the
object passed to isManagedObject is annotated as a @ManagedObject or
not.<br>
<br>
<h4>3.2.15. suppressDuplicateRootReport<br>
</h4>
This controls the behavior of setting the MOM's root. If true, no
error is reported when the root has already been registered with the
JMX MBeanServer. This method was added to allow GFv3 monitoring
to avoid reporting an uninteresting error.<br>
<br>
<h2>4. Further notes on the API<br>
</h2>
There are a number of details about how the APIs work that require
further
discussion.<br>
<h3><a name="4.1._Processing_of_method_names_for_IDs"></a>4.1.
Processing of method names for IDs</h3>
The following rules are applied to generate attribute and operation IDs
from
method names:<br>
<br>
<ol>
<li>If the method is annotated with @ManagedAttribute:<br>
<ol>
<li>If the method is a getter (that is, it has no arguments and a
non-void result):
<ol>
<li>If the method name starts with "get" or "is", remote the
prefix. The rest of the method name is the attribute ID for an
attribute in a ManagedObject. If the attribute is in a
ManagedData, then the first character is forced to lower case.<br>
</li>
<li>Otherwise the method name is the id.<br>
</li>
</ol>
</li>
<li>If the method is a setter (that, has one argument and a void
result):
<ol>
<li>If the method name starts with "set", remove "set". The
rest of the method name is the attribute ID for an attribute in a
ManagedObject. If the attribute is in a ManagedData, then the
first character is forced to lower case. </li>
<li>Otherwise the method name is the id.</li>
</ol>
</li>
<li>Otherwise the method is not a valid attribute, and an
exception will be thrown<br>
</li>
</ol>
</li>
<li>If the method is annotated with @ManagedOperation:
<ol>
<li>The id is the method name.</li>
</ol>
</li>
</ol>
These rules are applied unless the ManagedAttribute or ManagedOperation
annotation has a non-default id attribute, in which case the id from
the annotation is used.<br>
<h3><a name="4.2._I18N_support"></a>4.2. I18N support</h3>
Gmbal supports I18N by supplying a ResourceBundle to the
ManagedObjectManager. If this option is used, all values of
@Description annotations must be resource bundle keys. The
appropriate
ResourceBundle must then be associated with the ManagedObjectManager
when the ManagedObjectManager is created.<br>
<br>
Note: this feature is not implemented in the GFv3 FCS version of Gmbal.<br>
<br>
<h3><a name="4.3._OpenType_mapping_"></a>4.3. OpenType mapping<br>
</h3>
Gmbal mostly follows the OpenType mapping rules for MXBeans (see the <a
href="http://java.sun.com/javase/6/docs/api/javax/management/MXBean.html#mapping-rules">Type
Mapping Rules</a>), but of course<br>
MXBeans are only available on JDK 6 and later, and gmbal supports JDK
5. There
are a few differences:<br>
<ol>
<li>Gmbal supports all Collection, Iterator, Iterable, and
Enumeration types where MXBeans support List, Set, and SortedSet.</li>
<li>Gmbal also maps Dictionary as well as Map to TabularType.</li>
<li>Gmbal maps all @ManagedObject types to ObjectName (in MXBeans,
this is any MXBean interface).</li>
<li>Gmbal only maps other types to CompositeData if the type has an
@ManagedData annotation. If not, gmbal maps the type to a String
using its toString() method.</li>
<li>Gmbal does not support reconstructing a Java type from
CompositeData. Gmbal could be extended in this area if necessary.</li>
<li>Gmbal will provide more support for converting generic types into
generic MBean types, which can be instantiated into specific MBeans
based on the actual type parameters supplied to an instance of the
generic type.</li>
</ol>
Gmbal does not currently provide support for setting attributes with
CompositeData values (but this would be easy to add, following
the rules used for MXBeans).<br>
<h3><a name="4.4._Metadata_support_"></a>4.4. Metadata support<br>
</h3>
Gmbal fully supports extensible metadata on MBeans by using the JMX
ModelMBean
Descriptor, which is available on JDK 5. JDK 6 has applied Descriptor
support to ALL MBean metadata, but gmbal must
continue to support JDK 5 for now. Gmbal supports the @DescriptorKey
and @DescriptorFields annotations defined in
JSR 255 for associating metadata with MBeans. Gmbal also defines
an annotation @AMXMetadata (which itself uses
the meta-annotation @DescriptorKey) in order to support the metadata
needed by AMX.<br>
<br>
@AMXMetadata can be used most easily on a simple mbean::<br>
<pre>@AMXMetadata<br>public interface MyBean1 { ... }<br></pre>
<p>In this case, MyBean1 is a singleton (only one of this type may
appear in the same parent), its MBean info never changes, the proxy
interface name defaults to a generic implementation, the group is
other, and the list of valid subtypes is empty, which means any type
may appear as a child. Note that
the @AMXMetadata annotation is not needed at all in this case. <br>
</p>
<p>Something like<br>
</p>
<pre>@AMXMetadata( isSingleton=false, type=Widget )<br>public interface MyBean2 { ... }<br></pre>
<p>defines an AMX MBean which is not a singleton. Also, the
type will be set to Widget in the ObjectName created for an instance of
MyBean2.<br>
</p>
The use of @DescriptorKey is discussed (with a good example) in the
Java 6 Javadoc for <a
href="http://java.sun.com/javase/6/docs/api/javax/management/DescriptorKey.html">DescriptorKey</a>.
Eamonn McManus discusses @DescriptorKey and @DescriptorFields in a
rather lengthy blog post "<a
href="http://weblogs.java.net/blog/emcmanus/archive/2007/08/defining_mbeans.html">Defining
MBeans with Annotations</a>". Either annotation allows
almost any sort of metadata to be added to MBeans defined by gmbal,
with no changes to gmbal required to add the additional metadata.<span
style="font-weight: bold;"></span>
<h3>4.5. AMX support for MBeans</h3>
Gmbal is fully compliant with all requirements and recommendations
of the
<a
href="https://glassfish.dev.java.net/nonav/v3/admin/planning/V3Changes/V3_AMX_SPI.html">GlassFish
v3 AMX SPI</a>.<br>
This includes:<br>
<ul>
<li>Creating ObjectNames according to the parent/child
hierarchy. Gmbal will never put anything in an ObjectName that is
not part of the AMX specification.</li>
<li>Supporting the MBeanInfo Descriptor. This is handled in
gmbal through the @AMXMetadata annotation.</li>
<li>All MBeans created using gmbal will include all of the attributes
defined in section 4.0 "Attributes" of the AMX SPI <a
href="https://glassfish.dev.java.net/nonav/v3/admin/planning/V3Changes/V3_AMX_SPI.html">spec</a>.</li>
<li>Gmbal will only use Open data types for MBean attribute values
and operation arguments and results. But gmbal will map most Java
data types to the appropriate Open data types, following the MXBean
specification (with some differences; see "<a
href="#4.3._OpenType_mapping_">OpenType mapping</a>").<br>
</li>
<li>Gmbal will support all of the behavior requirements of section 5
of the AMX SPI spec. This include support for
AttributeChangeNotification.<br>
</li>
</ul>
<h3><a name="4.6._Using_Gmbal_"></a>4.6. Using Gmbal<br>
</h3>
The basic usage of Gmbal is as follows:<br>
<ol>
<li>Add annotations to existing application objects (here application
means anything you want to manage, part of GFv3 or not) to expose
attributes and operations.</li>
<li>In some cases you may need to expose some data by defining new
methods. Currently all gmbal visible annotations must be public,
but I may relax that (at the cost of requiring an access check
permission for reflection).</li>
<li>In the initialization of a module, create an appropriate
ManagedObjectManager (call it mom). This requires thinking about
where in the federated hierarchy the root of the ManagedObjectManager
should live. In some cases, this may be different depending on
the environment in which the instrumented code runs.</li>
<li>Whenever an Object is created that requires a management
interface, register that object with the mom.</li>
<li>Whenever an Object is no longer needed, unregister that object
with the mom.</li>
<li>Whenever the module lifecycle ends, call mom.close() to clean up
the root object and any other remaining registered objects.</li>
</ol>
Here is an example of typical code for using gmbal. All examples are
taken from the experimental version of the GlassFish v3 ORB
(available in the <a
href="https://kenai.com/hg/gf-corba-v3-mirror%7Ecorba-gmbal">experimental</a>
ORB repository from the GFv3 ORB project on Kenai.com):<br>
<br>
First, from the
com.sun.corba.se.spi.orb.ORB.createORBManagedObjectManager method:<br>
<pre> // mom is declared the ORB object, which stays around the entire time the ORB is in use.<br> // Here I am using createStandalone. This needs to be replaced with a call to createFederated<br> // when running in GlassFish v3. This will be driven through the ORB configuration.<br> mom = ManagedObjectManagerFactory.createStandalone( "com.sun.corba" ) ;<br><br> // The ORB already has a system for setting debug options, so I just extended it for gmbal.<br> if (mbeanFineDebugFlag) {<br> mom.setRegistrationDebug( ManagedObjectManager.RegistrationDebugLevel.FINE ) ;<br> } else if (mbeanDebugFlag) {<br> mom.setRegistrationDebug( ManagedObjectManager.RegistrationDebugLevel.NORMAL ) ;<br> } else {<br> mom.setRegistrationDebug( ManagedObjectManager.RegistrationDebugLevel.NONE ) ;<br> }<br><br> mom.setRuntimeDebug( mbeanRuntimeDebugFlag ) ;<br><br> // Here I add all of the package prefixes that I do NOT want to see in ObjectNames.<br> // The longest match is stripped from the class name to create the default value for the<br> // type.<br> mom.stripPrefix( "com.sun.corba.se" ) ;<br> mom.stripPrefix( "com.sun.corba.se.spi" ) ;<br> mom.stripPrefix( "com.sun.corba.se.impl" ) ;<br> mom.stripPrefix( "com.sun.corba.se.spi.orbutil" ) ;<br> mom.stripPrefix( "com.sun.corba.se.impl.orbutil" ) ;<br></pre>
<pre> // Here I am using the guaranteed to be unique ORB id as the name of the topmost ORB mbean.<br> mom.createRoot( this, getUniqueOrbId() ) ;</pre>
<p><br>
In order to integrate the ORB with GlassFish v3, there is quite a
bit of GlassFish v3-specific code that initializes the ORB. This code
will need to be placed in an appropriate OSGi bundle (either in the EJB
remote bundle, or possible in a separate embedded ORB support bundle).
Then the ORB SPI needs to be extended to support a call like
setMBeanRootParent( ObjectName ). If this method is called (which
would normally only happen from inside the ORB support code in
GlassFish v3), the initialization sequence needs to call
ManagedObjectManagerFactory.createFederated instead of
createStandalone. Everything else stays exactly the same, giving
an easy way to run the ORB either in GlassFish v3, or standalone (for
example, as part of JDK 7, if we get to that).<br>
</p>
<p>Next we need to see an example of MBean creation code. Again
the example is from the GFv3 ORB, this time in the timer subsystem
(from the orblibrary package com.sun.corba.se.spi.orbutil.newtimer).
The timer subsystem defines a number of different interfaces (e.g.
Timer, TimerGroup, TimerFactory, StatsEventHandler among others),
instances of which are registered as MBeans. Each of these classes
extends a base interface called Named defined as follows:<br>
</p>
<pre>public interface Named {<br> /** Return the TimerFactory that created this Named.<br> */<br> @ManagedAttribute<br> @Description( "TimerFactory that created this Timer or TimerGroup" ) <br> TimerFactory factory() ;<br><br> /** A short name for this Controllable.<br> */<br> @ManagedAttribute<br> @NameValue<br> @Description( "Name of this Timer or TimerGroup" ) <br> String name() ;<br>}<br></pre>
<p>Note that the name() attribute carries the @NameValue
attribute. This simplifies the registration which takes place in
TimerFactoryImpl. The TimerFactoryImpl contains all of the
factory methods for creating the various timer interfaces mentioned
previously. TimerFactoryImpl defines several private methods as follows:<br>
</p>
<pre> private void manage( Named obj ) {<br> // Note that no extra parameters are needed here, because Named.getName<br> // is an NameValue.<br> if (mom != null) {<br> // System.out.println( "Registering " + obj ) ;<br> mom.registerAtRoot( obj ) ;<br> }<br> }<br><br> private void manage( Named parent, Named obj ) {<br> // Note that no extra parameters are needed here, because Named.getName<br> // is an NameValue.<br> if (mom != null) {<br> // System.out.println( "Registering " + obj ) ;<br> mom.register( parent, obj ) ;<br> }<br> }<br><br> private void unmanage( Named obj ) {<br> if (mom != null) <br> mom.unregister( obj ) ;<br> }<br></pre>
<p>These methods support the case where no ManagedObjectManager (mom)
is present, which may be a useful pattern in other cases. For example,
Grizzly must be able to run in as small a configuration as possible,
but Grizzly would like to have MBeans available as an option.
Consequently, the gmbal annotations and API (plus one small utility
class) are defined in the gmbal-api-only <a href="#7._Project_Details">bundle</a>
(about 14K). Another bundle (gmbal, about 240K) includes
everything in gmbal-api-only, plus a full implementation.
One of the bundles gmbal-api-only or gmbal needs to be present in
all cases, and all
of the code in this example requires ONLY gmbal-api-only. If <a
href="#7._Project_Details">gmbal</a> is NOT
available, ManagedObjectManagerFactory.<a href="#3.1.2._create">createStandalone</a>
and <a href="#3.1.2._create">createFederated</a> will return an
instance of a no-op implementation of ManagedObjectManager. This would
allow the above code to avoid the null check, which was required in an
older version of gmbal.<br>
</p>
<p>Now consider actually creating instances of various timer classes.
FIrst, the TimerManager is itself represented by an MBean, so it must
be registered. It is tempting to do this in the constructor (in fact,
this mistake has been made in the ORB). <span
style="font-weight: bold;">You should not do this!</span>
Calling mom.<a href="#3.2.3._register_and_registerAtRoot">register</a>(
this ) in the constructor violates one of the cardinal rules of Java
concurrent programming: do not publish objects before construction is
complete. As soon as the mom.register call returns, the MBean has
been registered with the ManagedObjectManager's MBeanServer, and this
means that remove invocations on unknown thread could arrive at any
moment, <span style="font-weight: bold;">including before the
constructor has returned</span>. Note that any method of an object that
is used at an attribute or operation <span style="font-weight: bold;">MUST
</span>be thread safe, as such a method can be invoked at any by one or
more threads from remote JMX connectors.<br>
</p>
<p>However, there are times when the constructor is the only reasonable
place to do the registration. This happen in situations where:<br>
</p>
<ul>
<li>There is a top-level constructor that initializes a large
hierarchy of objects.</li>
<li>The top-level constructor needs to create the
ManagedObjectManager and root before it initializes the other objects
that need a ManagedObjectManager.</li>
<li>Since creating the root registers an MBean, we don't normally
want to do this in the constructor</li>
</ul>
To avoid this problem, the ManagedObjectManager now supports
suspend/resume on registration of MBeans with the MBeanServer through
the methods suspendJMXRegistration() and resumeJMXRegistration(). When
registration is suspended, newly created MBeanImpl instances are kept
in a queue. Once resume is called, all enqueued MBeanImpl
instances are registered with the MBeanServer.<br>
<p>In the timer library case, the TimerFactory is constructed by a
TimerFactoryBuilder as follows:<br>
</p>
<pre> public synchronized static TimerFactory make( ManagedObjectManager mom, <br> String name, String description ) {<br><br> if (fmap.get( name ) != null)<br> throw new IllegalArgumentException(<br> "There is currently a TimerFactory named " + name ) ;<br><br> TimerFactory result = new TimerFactoryImpl( mom, name, description ) ;<br> fmap.put( name, result ) ;<br> <span
style="font-weight: bold; font-style: italic;">mom.register( result ) ; // registered AFTER construction as a child of mom's root</span><br> return result ;<br> }<br><br></pre>
<p>Here's an example of registering a TimerGroup (from TimerFactory):<br>
</p>
<pre> public synchronized TimerGroup makeTimerGroup( String name, <br> String description ) {<br><br> checkArgs( timerGroups.keySet(), name, description ) ;<br><br> TimerGroupImpl result = new TimerGroupImpl( nextIndex, this, name, <br> description ) ;<br> <span
style="font-style: italic;"> </span><span
style="font-weight: bold; font-style: italic;">manage( this, result ) ;</span><br><br> mapId( result ) ;<br> timerGroups.put( result.name(), result ) ;<br> add( result ) ; // Remember, a TimerFactory is a TimerGroup <br> // containing all<br> // Controllables that it creates!<br><br> return result ;<br> }<br></pre>
<p>Here the TimerGroup has an MBean that is registered as a child of
the TimerFactory. The TimerGroup interface itself is annotated as
follows:<br>
</p>
<pre>@ManagedObject<br>@Description( "A group of Timers or other TimerGroups, which may be enabled or disabled together" ) <br>public interface TimerGroup extends Controllable {<br> @ManagedOperation<br> @Description( "Add a new Timer or TimerGroup to this TimerGroup" ) <br> boolean add( Controllable con ) ;<br><br> @ManagedOperation<br> @Description( "Remove a new Timer or TimerGroup from this TimerGroup" ) <br> boolean remove( Controllable con ) ;<br>}<br></pre>
<p>Controllable is fairly complex, and defines a number of attributes:<br>
</p>
<pre>@ManagedObject<br>@IncludeSubclass( { Timer.class, TimerGroup.class, TimerFactory.class } ) <br>public interface Controllable extends Named {<br> /** A longer description giving some details of the meaning of this<br> * Controllable.<br> */<br> @ManagedAttribute<br> @Description( "The purpose of the Timer or TimerGroup" ) <br> String description() ;<br><br> /** A small id for this controllable. Each controllable created from<br> * the same TimerFactory will have a unique ID. All ids will be small<br> * integers starting at 0 (so indexing tables by timer ID is supported).<br> */<br> @ManagedAttribute<br> @Description( "An internal identifier for the Timer or TimerGroup" ) <br> int id() ;objectClass<br><br> /** Return an unmodifiable set of the contents of this Controllable.<br> * May always be empty for some subclasses of Controllable.<br> */<br> @ManagedAttribute<br> @Description( "Set of Timers or TimerGroups contained in a TimerGroup" )<br> Set<? extends Controllable> contents() ;<br><br> /** Enable this controllable. All Timers that are either enabled, or<br> * reachable via contents() from an enabled Controllable are activated,<br> * and will cause TimerEvents to be generated when passed to the<br> * TimerEventController enter and exit methods.<br> */ <br> @ManagedOperation<br> @Description( "Enable this Timer, or all Timers and TimerGroups contained in this TimerGroup" ) <br> void enable() ;<br><br> /** Disable this controllable.<br> */<br> @ManagedOperation<br> @Description( "Disable this Timer, or all Timers and TimerGroups contained in this TimerGroup" ) <br> void disable() ;<br><br> /** Return true if enable() was called, otherwise false if enable() was never<br> * called, or disable() was last called.<br> */<br> @ManagedOperation<br> @Description( "True if this Timer or TimerGroup is enabled" ) <br> boolean isEnabled() ;<br>}<br></pre>
<p>Because TimerGroup extends Controllable extends Named, the
TimerGroup inherits the name() attribute which is annotated with
@NameValue. This means that the result of calling timerGroup.name()
is used as the value of the name attribute in the ObjectName for the
MBean constructed for timerGroup.<br>
</p>
<p>Finally, when an object is no longer needed, the
ManagedObjectManager.<a href="#3.2.4._unregister">unregister</a> method
must be called. In some case this is handled through an explicit method
to
remove the object, e.g. for TimerEventHandle in the
TimerFactory.removeTimerEventHandler method:<br>
</p>
<pre> public synchronized void removeTimerEventHandler( <br> TimerEventHandler handler ) {<br><br> timerEventHandlers.remove( handler.name() ) ;<br> unmanage( handler ) ;<br> }<br></pre>
<p>If the mbeans should be registered as long as the module exists,
ManagedObjectManager.<a href="#3.2.10._Close">close</a>() can be used
to unregister everything. In the case of the ORB, the close call should
happen in the ORB.destroy code. <br>
</p>
<h3><a name="4.7._Handling_Polymorphism"></a>4.7. Handling Polymorphism</h3>
There are cases where an attribute has a type defined by a base class
or
interface, but the actual implementation can be one of several
different classes. For example, the ORB has a TaggedComponent
interface, representing part of the data in a remote reference, and
there are several concrete subclasses of TaggedComponent
that are used. This is not a problem for @ManagedObject classes,
since they are reference by ObjectNames, and an
ObjectName can reference any type of MBean. But this does
not work for @ManagedData, because @ManagedData is
mapped to a CompositeData type, and CompositeData does not support
polymorphism.<br>
<br>
Gmbal supports a limit form of polymorphism to handle this case using
the
@IncludeSubclass annotation. @IncludeSubclass gives the
subclasses of a @ManagedData type which themselves can contribute
attributes to the CompositeData for the parent class. Gmbal
generates a CompositeData type that contains the union of
all fields in all of the subclasses. At runtime, only those attributes
actually present in a particular instance of the
@ManagedData class are present in the CompositeData for the
instance. In this way, gmbal supports a limit form of
polymorphism under a closed-world assumption.<br>
<br>
Here is an example from the CORBA case:<br>
<br>
first, the base interface:<br>
<pre>/** Generic interface for all tagged components. Users of the ORB may<br>* create implementations of this class and also corresponding factories<br>* of type TaggedComponentFactory. The factories can be registered with an<br>* ORB instance, in which case they will be used to unmarshal IORs containing<br>* the registered tagged component.<br>*/<br>@ManagedData<br>@Description( "Base class for all TaggedComponents" )<br>@IncludeSubclass( { AlternateIIOPAddressComponent.class, <br> CodeSetsComponent.class, JavaCodebaseComponent.class,<br> MaxStreamFormatVersionComponent.class, ORBTypeComponent.class,<br> RequestPartitioningComponent.class,<br> GenericTaggedComponent.class } )<br>public interface TaggedComponent extends Identifiable<br>{<br> org.omg.IOP.TaggedComponent getIOPComponent( ORB orb ) ;<br>}<br></pre>
<p>then, an example of two of the subclasses:<br>
</p>
<pre>@ManagedData<br>@Description( "Component containing an alternate IIOP address to use" )<br>public interface AlternateIIOPAddressComponent extends TaggedComponent<br>{<br> @ManagedAttribute<br> @Description( "The Alternate address" ) <br> public IIOPAddress getAddress() ;<br>}<br><br>@ManagedData<br>@Description( "Component representing Codebase URLs for downloading code" )<br>public interface JavaCodebaseComponent extends TaggedComponent <br>{<br> @ManagedAttribute<br> @Description( "List of URLs in the codebase" ) <br> public String getURLs() ;<br>}<br></pre>
<p>The result of this is that any reference to the TaggedComponent type
in a @ManagedObject will mapped to CompositeData with the Address and
URLs attributes. However, the actual CompositeData to which an
instance of TaggedComponent is mapped will only have Address if it isA
AlternateIIOPAddressComponent, otherwise that attribute will be
unavailable. If TaggedComponent defined any attributes, those
attributes would be present in all instance of CompositeData
representing a TaggedComponent (in this case the
org.omg.IOP.TaggedComponent type is simply not interesting enough to
expose as an Attribute).<br>
</p>
<h3><a name="L2005" id="L2005"></a>4.8. Issues with generic types</h3>
<p>This is best explained with an example. Suppose we have
interfaces defined
as follows:<br>
</p>
<pre>@ManagedData<br>public interface ExampleData<S,T> {<br> S getInfo() ;<br><br> List<T> getData() ;<br>}<br><br>public interface Example<S,T> {<br> @ManagedAttribute<br> ExampleData<S,T> getInfo() ;<br>}<br><br>@ManagedObject<br>public interface MyBean extends Example<Date,List<String>> {<br>}<br></pre>
What sort of MBean should we create for MyBean? If we just use
reflection on
MyBean, we find an attribute info that returns an
ExampleData<S,T>, which would turn into a CompositeData with
two attributes:<br>
<ul>
<li>id=info, type=Object (since type is type variable S)</li>
<li>id=data, type=Object (since type is type variable T)<br>
</li>
</ul>
But we actually have a lot more information than this: if we "evaluate"
the
types, we see that MyBean extends
Example<Data,List<String>>, so the Example.getInfo method
has type MethodData<Date,List<String>>, and so
MyBean.getInfo returns a composite data with 2 attributes:<br>
<ul>
<li>id=info, type=Date</li>
<li>id=data, type=List<List<String>></li>
</ul>
So instead of erasing the types, we evaluate the type variable by
replacing the
type variables with the types used to instantiate them. Another
way of looking at this is that annotating a
generic interface or class with @ManagedData or @ManagedObject is
basically creating a template for creating the actual
CompositeData or Open MBean.<br>
<h3>4.9. Issues with recursive types</h3>
CompositeData cannot be defined directly from class definitions that
have
recursive types. Here is an example of the problem:<br>
<pre>@ManagedData<br>public interface A {<br> @ManagedAttribute<br> B getB() ;<br>}<br><br>@ManagedData<br>public interface B {<br> @ManagedAttribute<br> A getA() ;<br>}<br></pre>
The problem here is that we need to construct an instance of
CompositeType to
represent the OpenType to which A and B are mapped. But
CompositeData is immutable, so in order to construct the
CompositeType for A, we need the CompositeType of B, which can't be
constructed without using the CompositeType of A. So a
direct mapping fails here, and gmbal will detect this problem and throw
an exception.<br>
<br>
The way to work around the problem is to add a level of indirection so
that one
of the classes refers to the other indirectly. For example, support A
has a convenient String name attribute we can use (which
is a key for instances of A). Then the above can be expressed as:<br>
<pre>@ManagedData <br>public interface A {<br> @ManagedAttribute<br> String getName() ;<br><br> @ManagedAttribute<br> B getB() ;<br>}<br><br>@ManagedData<br>public interface B {<br> @ManagedAttribute( id="A" ) <br> String getARef() ; // returns getA().getName()<br><br> A getA() ;<br>}<br></pre>
In this way the relationship between A and B can still be represented
in the
management API without needing recursive references between different
data types that are represented with
CompositeData.<br>
<br>
Note that it is possible to automate this to some extent, but I
currently have
no plans to extend gmbal to automatically handle this problem.<br>
<h3>4.10 Method call order requirements</h3>
As noted in the methods on the ManagedObjectManager, there are
constraints on the order in which certain methods may be called. This
is done to avoid problems where some MBeans are created, then other
methods are called (like addAnnotation or stripPrefix) which could
change the attributes, operations, ObjectNames, or metadata on any
Gmbal MBean that has already been created. This divides the
methods up into 3 categories:<br>
<ul>
<li>Methods that can only be called before the first successful call
to a createRoot method: <br>
</li>
<ul>
<li>the 3 createRoot methods<br>
</li>
<li>stripPrefix</li>
<li>stripPackagePrefix</li>
<li>setResourceBundle</li>
<li>setMBeanServer<br>
</li>
<li>addAnnotation</li>
</ul>
<li>Methods that can only be called after the first successful call
to a createRoot method:</li>
<ul>
<li>The 2 register methods</li>
<li>The 2 registerAtRoot methods</li>
</ul>
<ul>
<li>unregister</li>
<li>getRoot</li>
<li>getObject</li>
<li>getObjectName<br>
</li>
</ul>
<li>Methods that can be called at any time:</li>
<ul>
<li>getResourceBundle</li>
<li>getMBeanServer</li>
<li>getDomain<br>
</li>
<li>suspendJMXRegistration</li>
<li>resumeJMXRegistration</li>
<li>setRuntimeDebug</li>
<li>setRegistrationDebug</li>
<li>setTypelibDebug<br>
</li>
</ul>
</ul>
Any violation of this requirement results in an IllegalStateException.<br>
<h3>4.11. Computing the type name</h3>
The type name used in the ObjectName is computed as follows from the
class of the registered object:<br>
<ol>
<li>If the class contains a final static field of type String name
AMX_TYPE, the value of the field is the type.</li>
<li>Otherwise, if the class has an annotation @AMXMetadata and the
type field is not "", the type field is the type.</li>
<li>Otherwise, if the package prefix of the class name matches one of
the stripPrefix call arguments, that part of the package prefix is
removed from the full class name, and the remainder (minus the initial
dot) is the type name.</li>
<li>Otherwise, if stripPackagePrefix was called, the entire package
prefix is removed (if any), and the remaining class name is the type
name.</li>
<li>Otherwise, the full class name is the type name.</li>
</ol>
The same algorithm is used for determining the name of a CompositeData
type for @ManagedData, with a few slight differences:<br>
<ol>
<li>If the class contains a final static field of type String name
GMBAL_TYPE, the value of the field is the name.</li>
<li>Otherwise, if the class's @ManagedData annotation has a name
element with a value other than "", the value of the name element is
the name.</li>
<li>Otherwise, if the package prefix of the class name matches one of
the stripPrefix call arguments, that part of the package prefix is
removed from the full class name, and the remainder (minus the initial
dot) is the name.</li>
<li>Otherwise, if stripPackagePrefix was called, the entire package
prefix is removed (if any), and the remaining class name is the type
name.</li>
<li>Otherwise, the full class name is the name.</li>
</ol>
<h2>5. Dependencies</h2>
The only dependency that gmbal has is JDK 5. It does not require
anything
from JMX that is not in JDK 5. It also has no ant<br>
dependencies on
GlassFish v3 or
CORBA.<br>
<h2>6. Testing</h2>
All tests for gmbal are written in Java using JUnit, and reside in the
test
directory in the project.<br>
<br>
The following tests are currently available:<br>
<br>
<table style="text-align: left; width: 100%;" border="1" cellpadding="2"
cellspacing="2">
<tbody>
<tr>
<td style="vertical-align: top;"><span style="font-weight: bold;">Test
Package Name</span><br>
</td>
<td style="vertical-align: top;"><span style="font-weight: bold;">Tests
Included</span><br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal<br>
</td>
<td style="vertical-align: top;">ManagedObjectManager and basic
annotation processing<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.generic<br>
</td>
<td style="vertical-align: top;">Facet mechanism used for dynamic
inheritance<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.impl<br>
</td>
<td style="vertical-align: top;">TypeConverter test<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.logex<br>
</td>
<td style="vertical-align: top;">Testing the log wrapper generator<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.typelib<br>
</td>
<td style="vertical-align: top;">Tests the typelib (derived from
a JDK 7 test suite)<br>
</td>
</tr>
</tbody>
</table>
<br>
<h2><a name="7._Project_Details"></a>7. Project Details</h2>
The gmbal project is available in a mercurial workspace at <a
href="https://kenai.com/hg/gmbal%7Emaster">https://kenai.com/hg/gmbal~master.</a>
Note that gmbal will
NOT be built as part of the GFv3 build. This is
necessary because gmbal is also used outside of GFv3, and we need to
avoid
circular build dependencies (e.g. GFv3 dependsOn CORBA dependsOn gmbal,
which
creates a build loop if GFv3 also contains gmbal).<br>
<br>
gmbal uses the following Java packages:<br>
<table style="text-align: left; width: 100%;" border="1" cellpadding="2"
cellspacing="2">
<tbody>
<tr>
<td style="vertical-align: top;"><span style="font-weight: bold;">Package
Name</span><br>
</td>
<td style="vertical-align: top;"><span style="font-weight: bold;">OSGi
Bundle</span><br>
</td>
<td style="vertical-align: top;"><span style="font-weight: bold;">Purpose</span><br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal<br>
</td>
<td style="vertical-align: top;">gmbal-api-only, gmbal<br>
</td>
<td style="vertical-align: top;">all public interfaces<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.util<br>
</td>
<td style="vertical-align: top;">gmbal-api-only, gmbal<br>
</td>
<td style="vertical-align: top;">contains code needed to support
the API-Impl split (reflective construction of the implementation)<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.generic<br>
</td>
<td style="vertical-align: top;">gmbal<br>
</td>
<td style="vertical-align: top;">General-purpose code for
debugging, plus simple function programming support<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.impl<br>
</td>
<td style="vertical-align: top;">gmbal<br>
</td>
<td style="vertical-align: top;">The full implementation. <br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.logex<br>
</td>
<td style="vertical-align: top;">gmbal<br>
</td>
<td style="vertical-align: top;">Log wrapper code for logging
exceptions and managing other I18N data<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.tools.argparser<br>
</td>
<td style="vertical-align: top;">build only<br>
</td>
<td style="vertical-align: top;">argument parser used in
copyright utilities (from CORBA)<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.tools.file<br>
</td>
<td style="vertical-align: top;">build only<br>
</td>
<td style="vertical-align: top;">file handling utilities and
copyright process (from CORBA)<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">org.glassfish.gmbal.typelib<br>
</td>
<td style="vertical-align: top;">gmbal<br>
</td>
<td style="vertical-align: top;">utility library for type
evaluation<br>
</td>
</tr>
</tbody>
</table>
<br>
The gmbal project also contains the package
org.glassfish.probe.provider.annotations, which is present in gmbal so
that projects that are not part of GFv3 may support GlassFish
monitoring probes without depending at build-time or runtime on
anything other than a single probe bundle.<br>
<br>
The resulting OSGi bundles are currently (version 3.0-FCS) sized at:<br>
<br>
<table style="text-align: left; width: 100%;" border="1" cellpadding="2"
cellspacing="2">
<tbody>
<tr>
<td style="vertical-align: top;">gmbal-api-only<br>
</td>
<td style="vertical-align: top;">22 KBytes<br>
</td>
</tr>
<tr>
<td style="vertical-align: top;">gmbal<br>
</td>
<td style="vertical-align: top;">272 Kbytes<br>
</td>
</tr>
</tbody>
</table>
<br>
Any gmbal client needs to use either gmbal-api-only or gmbal, but not
both. Both bundles are available in the standard place in the
maven repository, with group ID org.glassfish.gmbal.<br>
<br>
The probe annotations are in the gfprobe-provider-client bundle, which
is currently 2576 bytes.
<br>
Source bundles are also provided for both gmbal (gmbal-source) and
grprobe-provider-client (gfprobe-provider-client-source).
</body>
</html>
|