by Lloyd L Chambers
This document provides an overview of the Glassfish AppServer Management Extensions (AMX) management API implementation in AppServer 9.0 . It assumes you have already read and understood AMX: Design and Use.
You should read section 1 and its subsections before proceeding to the later sections.
There are two top-level Java package names in AMX. All other packages are subpackages thereof:
For brevity in this document, class names might not use fully qualified package names . Implementation classes might drop the "com.sun.enterprise.management" portion, and interface classes might drop the "com.sun.appserv.management" portion.
For example, the following two class names are intended to be the same:
The context should usually be clear.
Delegation is heavily used in AMX for the configuration, monitoring and JSR 77 MBeans, though future changes may ultimately remove most of the delegation now used, by moving implementation code directly into the AMX MBeans themselves (or supporting objects used by the AMX MBeans).
From the perspective of an AMX MBean, the only interface involved for delegation is support.Delegate. Since AMX MBeans must support a JMX-style interface, they in turn can be completely implemented against a Delegate that supports the same type of facilities:
public interface Delegate
The class support.DelegateToMBeanDelegate implements Delegate by calling another MBean, specifically one of the MBeans found in the JMX domain com.sun.appserv. For example the AMX MBean amx:j2eeType=X-DomainConfig,name=na delegates to the MBean com.sun.appserv:type=domain,category=config.
AMX attributes are all consistently named, including the use of "camel case" and all-uppercase acronyms. Part of the role of the Delegate is to map the AMX Attribute name ("LogRoot") to the name within the com.sun.appserv Delegate ("log-root"). In some cases, this mapping is explicit, but in most cases an automatic algorithm is sufficient; this is implemented by AMXAttributeNameMapper[Impl].
AMX operations are also handled by the Delegate via supportsOperation() and invoke(). However, there are few operations in AMX to begin with, and even fewer that can be directly handled by the Delegate, because AMX uses an object-oriented model, whereas the com.sun.appserv MBeans tend to use a monolithic, function-oriented approach. For example, a com.sun.appserv MBean might include a "target name" (such as a server name) as one of the parameters, whereas in AMX the target is implicit, since every element exists as an appropriate MBean (eg a StandaloneServerConfig).
There is an "offline config" feature within AMX (not yet exposed) which makes use of another implementation of Delegate: offline.ConfigDelegate, which implements Delegate using the low-level Config API (com.sun.enterprise.config.ConfigContext, et al). This implementation will be the basis for a future conversion of AMX in which the com.sun.appserv MBeans are no longer used for configuration.
The beauty of the Delegate approach is that AMX MBeans require no modification whatsoever, whether they're running using DelegateToMBeanDelegate or ConfigDelegate (excepting creation and deletion of configuration elements, because the underlying APIs diverge).
The implementation class hierarchy has a close correspondence to the interface hierarchy. The following table shows some common base interfaces and their corresponding base implementation classes, from which many AMX MBeans extend:
Every AMX MBean implementation class follows a consistent naming pattern: the implementation class name is <interface-name>Impl. Here are just a few examples:
In general, implementations almost always use "Impl" as a suffix, even in internal implementation code. For example a commony used suffix is "ConfigFactory"; there are many classes which extend the base ConfigFactory class (not an interface in that case, but an actual base class).
AMX MBeans area loaded by support.Loader, implementing LoaderMBean. There are two implementations of LoaderMBean which both extend LoaderBase, support.Loader, designed to load MBeans in response to the registration and deregistration of com.sun.appserv MBeans, and offline.OfflineLoader, designed to load AMX MBeans (mainly AMXConfig MBeans) in "offline mode" (server not running).
1.4.1 com.sun.enterprise.management.support.Loader details
This loader is called by the internal startup code not long into the server startup process. It itself is an MBean, implementing LoaderMBean, and runs for the life of the server. When it is instantiated, it creates a LoaderRegThread, which handles registration and deregistration of AMX MBeans asynchronously. It also starts a DeferredRegistrationThread, which is used when registration of AMX MBeans must be deferred (due to out-of-order registration of com.sun.appserv MBeans).
When Loader.startHook() is called, all appropriate currently-registered com.sun.appserv MBeans are queued with the LoaderRegThread, which asynchronously registers appropriate corresponding AMX MBeans. This phase can take a number of seconds, as the rest of the server is also starting. In fact, it might complete after the server says it has started (in the log), thus the need for DomainRoot.getAMXReady().
Following its startup phase, in which it queues existing com.sun.appserv MBeans for processing with the LoaderRegThread, it then tracks (via JMX Notifications from the MBeanServerDelegateMBean) the registration or deregistration of com.sun.appserv MBeans which are used by AMX MBeans as Delegates. When a com.sun.appserv MBean is registered, Loader instantiates a DelegateToMBeanDelegate, then instantiates the appropriate AMX MBean, passing the Delegate instance to its constructor. The pair is inserted into an internal table which maps the com.sun.appserv ObjectName to the corresponding AMX ObjectName. When a com.sun.appserv MBean is deregistered, the corresponding AMX MBean (if any) is deregistered also by virtue of this table.
Subsequent activity is minimal, occuring only when MBeans need to come or go, such as when monitoring is enabled or disabled, when configuration is created or deleted, or when a server starts or stops.
Please note that there is a hack in Loader.handleNotification() [search for WORKAROUND_FOR_BUG_SRIDATTA_FOUND] which works around a problem in some internal server code by forcing synchronous loading when MBeanServerNotifications are received. This problem might or might not still exist; retesting should be done at some point, and the workaround removed if possible.
Deferred registration is necessary in cases when an MBean which logically contains another MBean has not yet been registered. The AMX hierarchy ostensibly maintains an invariant which requires that the Container for any AMX MBean must be registered prior to registration of any Containees. In practice, this invariant is difficult to enforce, and at times does not hold because there are certain flaws in some subsystems (such as the web server monitoring MBeans) which omit registration for one or more system apps. Nevertheless, the invariant holds for 99+% of the registered MBeans.
Deferred registration is handled by DeferredRegistrationThread, which checks periodically if conditions are suitable. A typical scenario in which registration is deferred occurs when a remote server starts up; its MBeans are cascaded into the DAS in arbitrary order. Usually a few seconds is sufficient for all out-of-order deferred registrations to complete; in some cases there appear to be cascading problems that miss one or more MBeans; this can result in periodic (and benign) log messages from DeferredRegistrationThread.
1.4.2 com.sun.enterprise.management.offline.OfflineLoader details
The MBeans are loaded synchronously by calling offline.AMXLoader, which traverses domain.xml via the low-level Config API. Because config elements cannot (yet) be created or deleted using offline.ConfigDelegate, the resulting registered MBeans do not come and go; no threads are created.
A useful enhancement (and one necessary to divorce AMXConfig MBeans from com.sun.appserv:category=config MBeans) would be to implement the createAbc() and removeAbc() methods [eg DomainConfig.createStandaloneServerConfig()] using the low-level Config API. Because there are no com.sun.appserv MBeans loaded in "offline" mode (these exist only in a running server), the various create/remote operations in AMX MBeans will fail if called; their Delegates are lacking the required methods to create or remove configuration elements.
A client using AMX may use JMX via MBeanServerConnection. This may well be the most useful approach for more generic applications, but is none too friendly for other uses. AMX solves this problem by making use of java.lang.reflect.Proxy.
Each AMX interface can be used via a corresponding Dynamic Client Proxy (DCP), which implements the AMX interface by storing the ObjectName and MBeanServerConnection of the target MBean and generically implementing all of the Attributes and operations defined by the corresponding AMX interface.
The key class involved is client.handler.AMXProxyHandler. Among other things, it deduces request for Attribute(s), calling MBeanServerConnection.get/setAttribute(s) appropriately. Operations are handled in a similar manner.
A key function of AMXProxyHandler is converting return values of type Map<String,ObjectName> or Set<ObjectName> into <T extends AMX> Map<String,T> and <T extends AMX>Set<AMX>, which are the types "seen" in the AMX interfaces. This is done as follows:
For example, DomainConfigImpl has an operation getClusterConfigObjectNameMap() returning Map<String,ObjectName>, which AMXProxyHandler returns to the client as Map<String,ClusterConfig>. Each ClusterConfig in the resulting Map is a Dynamic Client Proxy with an embedded MBeanServerConnection and ObjectName.
The client.handler.AMXProxyHandler class is extended by the base class ConverterHandler. The ConverterHandler subclasses exist in order to convert Map<String,Serializable> (the across-the-wire form for complex types) into appropriate implementations of AMX interfaces, such as WebServiceEndpointInfo, LogQueryResult, and a few others. The ProxyFactory class is responsible for creating the appropriate Dynamic Client Proxy instance, which could be AMXProxyHandler itself, or one of its ConverterHandler subclasses (created indirectly by ConverterHandlerFactory).
1.5.1 Caching in Dynamic Client Proxies
Certain items are cached within an AMX Dynamic Client Proxy.
In particular, MBeanInfo is cached, provided that the Attribute MBeanInfoIsInvariant is true. Nearly all AMX MBeans do in fact have invariant MBeanInfo, and so it is cached within the DCP. This is a good thing, since it is a relatively expensive operation not just to create the MBeanInfo, but to serialize it and pass it back over the wire. Exceptions to this invariant include ConfigDottedNames and MonitoringDottedNames, which refresh their MBeanInfo periodically (or upon request); the MBeanInfo consists of a large number of Attributes which depend upon the configuration and monitoring state, both of which can change dynamically.
Utility MBeans implement the marker interface Utility, and include BulkAccess, QueryMgr, NotificationServiceMgr, JMXMonitorMgr,Sample, DeploymentMgr, and UploadDownloadMgr. Such MBeans are Singletons; only one instance of them ever exists within the Domain Admin Server.
AMX implementation classes make very heavy use of utility methods—the author believing that any generally applicable method needed more than once should be coded and tested once, then reused everywhere it is needed, rather than the oft-seen sprinkling of repeated inline code. Because they are needed both on the server side and in client-side implementation code, they are part of the client API, and are thus available to implementors as well as being used internally.
Utility and convenience classes can be divided into two major categories:
General-purpose utilities are all (and always) found in one of the subpackages of com.sun.appserv.management.util. These packages include:
2. Adding a new AMX MBean
...to be continued...
2.X. AMX Unit tests
AMX development was and is greatly aided by these unit tests, which detect many different implementation flaws. They are easy to run, and it's easy to add new tests.
Please see glassfish/admin/mbeanapi-impl/tests/amx-unit-tests.html for details (you will need to check out the Glassfish code using cvs).