Sun Java System Application Server Platform Edition 8.2 Developer's Guide

Chapter 16 Using the Java Management Extensions (JMX) API

The Sun JavaTM System Application Server uses Java Management Extensions (JMXTM) technology for monitoring, management and notification purposes. Management and monitoring of the Application Server is performed by the Application Server Management Extensions (AMX), which exposes managed resources for remote management via the JMX Application Programming Interface (API).

The Application Server incorporates the JMX 1.2 Reference Implementation, that was developed by the Java Community Process as Java Specification Request (JSR) 3, and the JMX Remote API 1.0 Reference Implementation (JSR 160).

This chapter assumes some familiarity with the JMX technology, but the AMX interfaces can be used for the most part without understanding JMX.

The JMX specifications and Reference Implementations are available for download at http://java.sun.com/products/JavaManagement/download.html.

This chapter contains the following topics:

About AMX

This section describes the Application Server Management eXtensions (AMX). AMX is an API that exposes all of the Application Server configuration and monitoring MBeans as easy-to-use client-side dynamic proxies implementing the AMX interfaces.

Full API documentation for the AMX API is provided in the following Application Server package:

com.sun.appserv.management

The Application Server is based around the concept of administration domains, which consist of one or more managed resources. A managed resource can be an Application Server or a manageable entity within a server. A managed resource is of a particular type, and each resource type exposes a set of attributes and administrative operations that change the resource’s state.

Managed resources are exposed as JMX management beans, or MBeans. While the MBeans can be accessed via standard JMX APIs (for example, MBeanServerConnection), most users find the use of the AMX client-side dynamic proxies much more convenient.

All the vital components of the Application Server are visible for monitoring and management via AMX. You can use third-party tools to perform all common administrative tasks programmatically, based on the JMX and JMX Remote API standards.

The AMX API consists of a set of proxy interfaces. MBeans are registered in the JMX runtime contained in the Domain Administration Server (DAS). AMX provides routines to obtain proxies for MBeans, starting with a root-level domain MBean.

You can navigate generically through the MBean hierarchy using the com.sun.appserv.management.base.Container interface. When using AMX, the interfaces defined are implemented by client-side dynamic proxies, but they also implicitly define the MBeanInfo that is made available by the MBean or MBeans corresponding to it. Certain operations defined in the interface might have a different return type or a slightly different name when accessed through the MBean directly. This results from the fact that direct access to JMX requires the use of ObjectName, whereas use of the AMX interfaces is via strongly typed proxies implementing the interface(s).

AMX MBeans

All AMX MBeans are represented as interfaces in a subpackage of com.sun.appserv.management and are implemented by dynamic proxies on the client-side. While you can access AMX MBeans directly through standard JMX APIs, most users find the use of AMX interface (proxy) classes to be most convenient.

An AMX MBean belongs to an application server domain. There is exactly one domain per DAS. Thus all MBeans accessible through the DAS belong to a single Application Server administrative domain. All MBeans in an Application Server administrative domain, and hence within the DAS, belong to the JMX domain amx. Any MBeans that do not have the JMX domain amx are not part of AMX, and are neither documented nor supported for use by clients. All AMX MBeans can be reached navigationally through the DomainRoot.

AMX defines different types of MBean, namely, configuration MBeans, monitoring MBeans, utility MBeans and J2EE management (JSR 77) MBeans. These MBeans are logically related in the following ways:

Configuration MBeans

Configuration information for a given Application Server domain is stored in a central repository that is shared by all instances in that domain. The central repository can only be written to by the DAS. However, configuration information in the central repository is made available to administration clients via AMX MBeans.

The configuration MBeans are those that modify the underlying domain.xml or related files. Collectively, they form a model representing the configuration and deployment repository and the operations that can be performed on them.

The Group Attribute of configuration MBeans, obtained from getGroup(), has a value of com.sun.appserv.management.base.AMX.GROUP_CONFIGURATION.

Monitoring MBeans

Monitoring MBeans provide transient monitoring information about all the vital components of the Application Server.

The Group Attribute of monitoring MBeans, obtained from getGroup(), has a value of com.sun.appserv.management.base.AMX.GROUP_MONITORING.

Utility MBeans

Utility MBeans provide commonly used services to the Application Server.

The Group Attribute of utility MBeans, obtained from getGroup(), has a value of com.sun.appserv.management.base.AMX.GROUP_UTILITY.

J2EE Management MBeans

The J2EE management MBeans implement, and in some cases extend, the management hierarchy as defined by JSR 77, which specifies the management model for the whole J2EE platform. One of the management APIs implemented in JSR 77 is the JMX API.

The implementation of JSR 77 in AMX offers access to and monitoring of MBeans via J2EE management MBeans, by using the getMonitoringPeer() and getConfigPeer() methods.

The J2EE management MBeans can be thought of as the central hub from which other MBeans are obtained.

The Group Attribute of J2EE management MBeans, obtained from getGroup(), has a value of com.sun.appserv.management.base.AMX.GROUP_JSR77.

Other MBeans

MBeans that do not fit into one of the above four categories have the value com.sun.appserv.management.base.AMX.GROUP_OTHER. One such example is com.sun.appserv.management.deploy.DeploymentMgr.

MBean Notifications

All AMX MBeans that emit Notifications place a java.util.Map within the userData field of a standard Notification, which can be obtained via Notification.getUserData(). Within the map are zero or more items, which vary according to the Notification type. Each Notification type, and the data available within the Notification, is defined in its respective MBean or in an appropriate place.

Note that certain standard Notifications, such as javax.management.AttributeChangeNotification do not and cannot follow this behavior.

Access to MBean Attributes

An AMX MBean Attribute is accessible in three ways:

All dotted names that are accessible via the command line interface are available as Attributes within a single MBean. This includes properties, which are Attributes beginning with the prefix property., for example, server.property.myproperty.


Note –

Certain attributes that may be of a specific type, such as int, are declared as java.lang.String. This is because the value of the attribute may be a template of a form such as ${HTTP_LISTENER_PORT}.


Proxies

Proxies are an important part of the AMX API, and enhance ease-of-use for the programmer.

While JMX MBeans can be used directly, client-side proxies are offered to facilitate navigation through the MBean hierarchy. In some cases, proxies also function as support or helper objects to simplify the use of the MBeans.

See the API documentation for the com.sun.appserv.management package and its sub-packages for more information about using proxies. The API documentation explains the use of AMX with proxies. If you are using JMX directly (for example, via MBeanServerConnection), the return type, argument types and method names might vary as needed for the difference between a strongly-typed proxy interface and generic MBeanServerConnection/ObjectName interface.

Connecting to the Domain Administration Server

As stated in Configuration MBeans, the AMX API allows client applications to connect to Application Server instances via the DAS. All AMX connections are established to the DAS only: AMX does not support direct connections to individual server instances. This makes it simple to interact with all servers, clusters, and so on, with a single connection.

Sample code for connecting to the DAS is shown in Connecting to the DAS.

Examining AMX Code Samples

The following example uses of AMX are discussed in this document:

Connecting to the DAS

The connection to the DAS is shown in the following code.


Example 16–1 Connecting to the DAS

[...]
public static AppserverConnectionSource
    connect(
        final String host,
        final int port,
        final String user,
        final String password,
        final TLSParams tlsParams )
        throws IOException
        {
            final String info = "host=" + host + ", port=" + port +
                ", user=" + user + ", password=" + password +
                ", tls=" + (tlsParams != null);

            SampleUtil.println( "Connecting...:" + info );

            final AppserverConnectionSource conn    =
                new AppserverConnectionSource(
                    AppserverConnectionSource.PROTOCOL_RMI,
                    host, port, user, password, tlsParams, null);

            conn.getJMXConnector( false );

            SampleUtil.println( "Connected: " + info );

            return( conn );
        }
[...]

A connection to the DAS is obtained via an instance of the com.sun.appserv.management.client.AppserverConnectionSource class. For the connection to be established, you must know the name of the host and port number on which the DAS is running, and have the correct user name, password and TLS parameters.

Once the connection to the DAS is established, DomainRoot is obtained as follows:

DomainRoot domainRoot = appserverConnectionSource.getDomainRoot();

This DomainRoot instance is a client-side dynamic proxy to the MBean amx:j2eeType=X-DomainRoot,name=amx.

See the API documentation for com.sun.appserv.management.client.AppserverConnectionSource for further details about connecting to the DAS using the AppserverConnectionSource class.

However, if you prefer to work with standard JMX, instead of getting DomainRoot, you can get the MBeanServerConnection or JMXConnector, as shown:

MBeanServerConnection conn =
appserverConnectionSource.getMBeanServerConnection( false );
JMXConnector jmxConn =
appserverConnectionSource.getJMXConnector( false );

Starting an Application Server

The startServer() method demonstrates how to start an Application Server.


Example 16–2 Starting an Application Server

[...]
startServer( final String serverName )
{
    final J2EEServer server    = getJ2EEServer( serverName );

    server.start();
}
[...]

This method retrieves and starts an application server instance named server. The server is an instance of the com.sun.appserv.management.j2see.J2EEServer interface, and is obtained by calling another method, getJ2EEServer(), shown in the following code.


Example 16–3 Obtaining a Named J2EE server instance

[...]
getJ2EEServer( final String serverName )
{
    final J2EEDomain j2eeDomain = getDomainRoot().getJ2EEDomain();
    final Map servers = j2eeDomain.getServerMap();
    final J2EEServer server = (J2EEServer)servers.get( serverName );
        if ( server == null )
        {
            throw new IllegalArgumentException( serverName );
        }
    return( server );
}
[...]

To obtain a J2EE server instance, the getJ2EEServer() method first of all obtains an instance of the J2EEDomain interface by calling the com.sun.appserv.management.base.AMX.getDomainRoot() and com.sun.appserv.management.DomainRoot.getJ2EEDomain() methods. The two methods called establish the following:

The J2EEServer instance is then started by a call to the start() method. The com.sun.appserv.management.j2ee.StateManageable.start() method can be used to start any state manageable object.

Deploying an Archive

The uploadArchive() and deploy() methods demonstrate how to upload and deploy a J2EE archive file.


Example 16–4 Uploading an archive

[...]
uploadArchive ( final File archive  ) throws IOException
{
    final FileInputStream input = new FileInputStream( archive );
    final long length = input.available();
    final DeploymentMgr mgr = getDomainRoot().getDeploymentMgr();
    final Object uploadID = mgr.initiateFileUpload( length );
    try
    {
        [...]
    }
    finally
    {
        input.close();
    }
    return( uploadID );
}
[...]

The uploadArchive() method creates a standard Java FileInputStream instance called input, to upload the archive archive. It then obtains the AMX deployment manager running in the application server domain, by calling the DomainRoot.getDeploymentMgr() method.

A call to com.sun.appserv.management.deploy.initiateFileUpload starts the upload of archive. The initiateFileUpload() method automatically issues an upload ID, that uploadArchive() returns when it is called by deploy().


Example 16–5 Deploying an archive

[...]
deploy ( final File archive ) throws IOException
{
    final Object uploadID = uploadArchive(archive);
    final DeploymentMgr mgr    = getDomainRoot().getDeploymentMgr();
    final Object deployID = mgr.initDeploy( );
    final DeployNotificationListener myListener =
        new DeployNotificationListener( deployID);
    mgr.addNotificationListener( myListener, null, null);
    try
    {
        final Map    options  = new HashMap();
        options.put( DeploymentMgr.DEPLOY_OPTION_VERIFY_KEY,
            Boolean.TRUE.toString() );
        options.put( DeploymentMgr.DEPLOY_OPTION_DESCRIPTION_KEY,
            "description" );
        mgr.startDeploy( deployID, uploadID, null, null);
        while ( ! myListener.isCompleted() )
        {
            try
            {
                println( "deploy: waiting for deploy of " + archive);
                Thread.sleep( 1000 );
            }
            catch( InterruptedException e )
            {
            }
        }
        final DeploymentStatus status = myListener.getDeploymentStatus();
        println( "Deployment result: " + getStageStatusString(
            status.getStageStatus() ) );
        if ( status.getStageThrowable() != null )
        {
            status.getStageThrowable().printStackTrace();
        }
    }
    finally
    {
        try
        {
            mgr.removeNotificationListener( myListener );
        }
        catch( Exception e )
        {
        }
    }
}
[...]

The deploy() method calls uploadArchive to get the upload ID for archive. It then identifies the deployment manager by calling DomainRoot.getDeploymentMgr(). A call to DeploymentMgr.initDeploy() initializes the deployment and obtains a deployment ID, which is used to track the progress of the deployment.

A JMX notification listener, myListener, is created and activated to listen for notifications regarding the deployment of deployID.

Deployment is started by calling the DeploymentMgr.startDeploy() method and providing it with the deployID and uploadID.

While the deployment is continuing, myListener listens for the completion notification and DeploymentStatus keeps you informed of the status of the deployment by regularly calling its getStageStatus() method. Once the deployment is complete, the listener is closed down.


Caution – Caution –

Some of the behavior of the com.sun.appserv.management.deploy API is unpredictable, and it should be used with caution.


Displaying the AMX MBean Hierarchy

The displayAMX() method demonstrates how to display the AMX MBean hierarchy.


Example 16–6 Displaying the AMX MBean Hierarchy

[...]
displayAMX(
    final AMX amx,
    final int indentCount )
{
    final String indent = getIndent( indentCount );
    final String j2eeType = amx.getJ2EEType();
    final String name = amx.getName();
    if ( name.equals( AMX.NO_NAME ) )
    {
        println( indent + j2eeType );
    }
    else
    {
        println( indent + j2eeType + "=" + name );
    }
}
private void
displayHierarchy(
    final Collection amxSet,
    final int indentCount )
{
    final Iterator    iter    = amxSet.iterator();
    while ( iter.hasNext() )
    {
        final AMX amx = (AMX)iter.next();
        displayHierarchy( amx, indentCount );
    }
}
public void
displayHierarchy(
    final AMX amx,
    final int    indentCount )
{
    displayAMX( amx, indentCount );
    if ( amx instanceof Container )
    {
        final Map m = ((Container)amx).getMultiContaineeMap( null );
        final Set deferred = new HashSet();
        final Iterator mapsIter = m.values().iterator();
        while ( mapsIter.hasNext() )
        {
            final Map instancesMap = (Map)mapsIter.next();
            final AMX first = (AMX)instancesMap.values().iterator().next();
            if ( first instanceof Container )
            {
                deferred.add( instancesMap );
            }
            else
            {
                displayHierarchy( instancesMap.values(), indentCount + 2);
            }
        }
        // display deferred items
        final Iterator iter = deferred.iterator();
        while ( iter.hasNext() )
        {
            final Map instancesMap = (Map)iter.next();
            displayHierarchy( instancesMap.values(), indentCount + 2);
        }
    }
}
public void displayHierarchy()
{
    displayHierarchy( getDomainRoot(), 0);
}
public void
displayHierarchy( final String j2eeType )
{
    final Set items = getQueryMgr().queryJ2EETypeSet( j2eeType );
    if ( items.size() == 0 )
    {
        println( "No {@link AMX} of j2eeType "
            + SampleUtil.quote( j2eeType ) + " found" );
    }
    else
    {
        displayHierarchy( items, 0);
    }
}
[...]

The displayAMX() method obtains the J2EE type and the name of an AMX MBean by calling AMX.getJ2EEType and AMX.getName respectively.

The displayHierarchy() method defines a standard Java Collection instance, amxSet, which collects instances of AMX MBeans.

To display the hierarchy of MBeans within a particular MBean in the collection, displayHierarchy() checks whether the MBean is an instance of Container. If so, it creates a set of the MBeans it contains by calling the com.sun.appserv.management.base.Container.getMultiContaineeMap() method.

The MBean hierarchy for a particular J2EE type is displayed by calling the com.sun.appserv.management.base.QueryMgr.queryJ2EETypeSet(), and passing the result to displayHierarchy().

To display the entire AMX MBean hierarchy in a domain, displayHierarchy() calls getDomainRoot() to obtain the root AMX MBean in the domain.

Setting Monitoring States

The setMonitoring() method demonstrates how to set monitoring states.


Example 16–7 Setting Monitoring States

[...]
private static final Set LEGAL_MON =
    Collections.unmodifiableSet( SampleUtil.newSet( new String[]
{
    ModuleMonitoringLevelValues.HIGH,
    ModuleMonitoringLevelValues.LOW,
    ModuleMonitoringLevelValues.OFF,
} ));
public void setMonitoring(
    final String configName,
    final String state )
{
    if ( ! LEGAL_MON.contains( state ) )
    {
        throw new IllegalArgumentException( state );
    }
    final ConfigConfig config =
        (ConfigConfig)getDomainConfig().
        getConfigConfigMap().get( configName );
    final ModuleMonitoringLevelsConfig mon =
        config.getMonitoringServiceConfig().
        getModuleMonitoringLevelsConfig();
    mon.setConnectorConnectionPool( state );
    mon.setThreadPool( state );
    mon.setHTTPService( state );
    mon.setJDBCConnectionPool( state );
    mon.setORB( state );
    mon.setTransactionService( state );
    mon.setWebContainer( state );
    mon.setEJBContainer( state );
}
[...]

The AMX API defines three levels of monitoring in com.sun.appserv.management.config.ModuleMonitoringLevelValues, namely, HIGH, LOW, and OFF.

In this example, the configuration element being monitored is named configName. The com.sun.appserv.management.config.ConfigConfig interface is used to configure the config element for configName in the domain.xml file.

An instance of com.sun.appserv.management.config.ModuleMonitoringLevelsConfig is created to configure the module-monitoring-levels element for configName in the domain.xml file.

The ModuleMonitoringLevelsConfig instance created then calls each of its set methods to change their states to state.

The above is performed by running the set-monitoring command when you run SimpleMain, stating the name of the configuration element to be monitored and the monitoring state to one of HIGH, LOW or OFF.

Accessing AMX MBeans

The handleList() method demonstrates how to access many (but not all) configuration elements.


Example 16–8 Accessing AMX MBeans

[...]
handleList()
{
    final DomainConfig dcp = getDomainConfig();
    println( "\n--- Top-level --- \n" );
    displayMap( "ConfigConfig", dcp.getConfigConfigMap() );
    displayMap( "ServerConfig", dcp.getServerConfigMap() );
    displayMap( "StandaloneServerConfig",
        dcp.getStandaloneServerConfigMap() );
    displayMap( "ClusteredServerConfig",
        dcp.getClusteredServerConfigMap() );
    displayMap( "ClusterConfig", dcp.getClusterConfigMap() );
    println( "\n--- DeployedItems --- \n" );
    displayMap( "J2EEApplicationConfig",
        dcp.getJ2EEApplicationConfigMap() );
    displayMap( "EJBModuleConfig",
        dcp.getEJBModuleConfigMap() );
    displayMap( "WebModuleConfig",
        dcp.getWebModuleConfigMap() );
    displayMap( "RARModuleConfig",
        dcp.getRARModuleConfigMap() );
    displayMap( "AppClientModuleConfig",
        dcp.getAppClientModuleConfigMap() );
    displayMap( "LifecycleModuleConfig",
        dcp.getLifecycleModuleConfigMap() );
    println( "\n--- Resources --- \n" );
    displayMap( "CustomResourceConfig",
        dcp.getCustomResourceConfigMap() );
    displayMap( "PersistenceManagerFactoryResourceConfig",
        dcp.getPersistenceManagerFactoryResourceConfigMap() );
    displayMap( "JNDIResourceConfig",
        dcp.getJNDIResourceConfigMap() );
    displayMap( "JMSResourceConfig",
        dcp.getJMSResourceConfigMap() );
    displayMap( "JDBCResourceConfig",
        dcp.getJDBCResourceConfigMap() );
    displayMap( "ConnectorResourceConfig",
        dcp.getConnectorResourceConfigMap() );
    displayMap( "JDBCConnectionPoolConfig",
        dcp.getJDBCConnectionPoolConfigMap() );
    displayMap( "PersistenceManagerFactoryResourceConfig",
        dcp.getPersistenceManagerFactoryResourceConfigMap() );
    displayMap( "ConnectorConnectionPoolConfig",
        dcp.getConnectorConnectionPoolConfigMap() );
    displayMap( "AdminObjectResourceConfig",
        dcp.getAdminObjectResourceConfigMap() );
    displayMap( "ResourceAdapterConfig",
        dcp.getResourceAdapterConfigMap() );
    displayMap( "MailResourceConfig",
        dcp.getMailResourceConfigMap() );
    final ConfigConfig config =
        (ConfigConfig)dcp.getConfigConfigMap().get( "server-config" );
    println( "\n--- HTTPService --- \n" );
    final HTTPServiceConfig httpService = config.getHTTPServiceConfig();
    displayMap( "HTTPListeners",
        httpService.getHTTPListenerConfigMap() );
    displayMap( "VirtualServers",
        httpService.getVirtualServerConfigMap() );
}
[...]

The handleList() method makes use of the displayMap() method, which simply prints out the key value pairs.

The handleList() method identifies the configuration for a domain by calling the DomainRoot.getDomainConfig() method. This DomainConfig instance then calls each of its getXXXMap() methods in turn, to obtain a Map for each type of AMX MBean. The Map returned by each getter is displayed by displayMap().

Similarly, the AMX MBeans representing the http-service element are displayed as Maps by calling the getXXXMap() methods of the com.sun.appserv.management.config.HTTPServiceConfig interface, and passing them to displayMap().

Accessing and Displaying the Attributes of an AMX MBean

The displayAllAttributes() method demonstrates how to access and display the attributes of an AMX MBean.


Example 16–9 Accessing and Displaying the Attributes of an AMX MBean

[...]
displayAllAttributes( final AMX item )
{
    println( "\n--- Attributes for " + item.getJ2EEType() +
        "=" + item.getName() + " ---" );
    final Extra extra = Util.getExtra( item );
    final Map attrs    = extra.getAllAttributes();
    final Iterator iter = attrs.keySet().iterator();
    while ( iter.hasNext() )
    {
        final String name = (String)iter.next();
        final Object value = attrs.get( name );
        println( name + "=" + toString( value ) );
    }
}
public void
displayAllAttributes( final String j2eeType )
{
    final Set items = queryForJ2EEType( j2eeType );
    if ( items.size() == 0 )
    {
        println( "No {@link AMX} of j2eeType "
            + SampleUtil.quote( j2eeType ) + " found" );
    }
    else
    {
        final Iterator iter= items.iterator();
        while ( iter.hasNext() )
        {
            final AMX amx = (AMX)iter.next();
            displayAllAttributes( amx );
            println( "" );
        }
    }
}
[...]

The displayAllAttributes() method calls the AMX.getName() and AMX.getJ2EEType() methods for an AMX MBean and prints the results onscreen. It then gets all the attributes for that MBean by calling com.sun.appserv.management.base.Extra.getAllAttributes() on the Extra instance returned by com.sun.appserv.management.base.Util.getExtra(). This is repeated for every MBean.

The attributes of AMX MBeans of a certain J2EE type can be displayed by specifying the J2EE type when the command is run. In this case, displayAllAttributes() calls queryForJ2EEType(). The queryForJ2EEType() method calls the com.sun.appserv.management.base.QueryManager.queryPropSet() method on the specified J2EE type to identify all elements of that type in the domain.

Listing AMX MBean Properties

The displayAllProperties() demonstrates how to list AMX MBean properties.


Example 16–10 Listing AMX MBean Properties

[...]
getProperties( final PropertiesAccess pa )
{
    final HashMap m = new HashMap();
    final String[] names = pa.getPropertyNames();
    for( int i = 0; i < names.length; ++i )
    {
        m.put( names[ i ], pa.getPropertyValue( names[ i ] ) );
    }
    return( m );
}
public void
displayAllProperties( )
{
    final Iterator iter    = getQueryMgr().queryAllSet().iterator();
    while ( iter.hasNext() )
    {
        final AMX amx = (AMX)iter.next();
        if ( amx instanceof PropertiesAccess )
        {
            final PropertiesAccess pa = (PropertiesAccess)amx;
            final Map    props    = getProperties( pa );
            if ( props.keySet().size() != 0 )
            {
                println( "\nProperties for:
                    " + Util.getObjectName( AMX)pa ) );
                println( SampleUtil.mapToString(getProperties(pa), "\n") );
            }
        }
    }
}
[...]

The displayAllProperties() method uses another Samples method, getProperties(). This method creates an instance of the com.sun.appserv.management.config.PropertiesAccess interface, and calls its getPropertyNames() method to obtain the names of all the properties for a given AMX MBean. For each property name obtained, its corresponding value is obtained by calling PropertiesAccess.getPropertyValue().

The displayAllProperties() method calls the com.sun.appserv.management.base.QueryMgr.queryAllSet() method to obtain a set of all the AMX MBeans present in the domain. All AMX MBeans that have properties obligatorily extend the PropertiesAccess interface. Any MBean found to extend PropertiesAccess is passed to the getProperties() method, and the list of property values returned is printed onscreen.

Querying

The demoQuery() method demonstrates how to issue queries.

The demoQuery() method uses other methods that are defined by Samples, namely displayWild(), and displayJ2EEType(). The displayWild() method is shown in the following code.


Example 16–11 Querying and displaying wild cards

[...]
queryWild(
    final String propertyName,
    final String propertyValue)
{
    final String[] propNames = new String[] { propertyName };
    final String[] propValues = new String[]{ propertyValue };
    final Set amxs = getQueryMgr().queryWildSet( propNames, propValues );
    return( amxs );
}
public Set
displayWild(
    final String propertyName,
    final String propertyValue)
{
    final Set items = queryWild( propertyName, propertyValue );
    println( "\n--- Queried for " + propertyName + "="
        + propertyValue + " ---" );
    final Iterator    iter    = items.iterator();
    while ( iter.hasNext() )
    {
        final AMX    item    = (AMX)iter.next();
        println( "j2eeType=" + item.getJ2EEType() + ",
            " + "name=" + item.getName() );
    }
}
[...]

The displayWild() method calls queryWild(), to obtain all the AMX MBeans that have object names matching propertyName and propertyValue. To do so, queryWild() calls the com.sun.appserv.management.base.QueryMgr.queryWildSet() method. The queryWildSet() method returns the list of AMX MBeans with object names matching the wild card strings.

For each MBean returned, the displayWild() calls AMX.getJ2EEType() to identify its J2EE type, and prints the result onscreen.

In code that is not shown here, the displayJ2EEType() method calls the queryForJ2EEType() method, which was seen in Accessing and Displaying the Attributes of an AMX MBean, to identify MBeans of a certain J2EE type and print their object names onscreen.


Example 16–12 Querying

[...]
demoQuery()
{
    displayWild( AMX.J2EE_TYPE_KEY, "X-*ResourceConfig" );
    displayWild( AMX.J2EE_TYPE_KEY, "X-*ServerConfig" );
    displayJ2EEType( XTypes.SSL_CONFIG );
    displayJ2EEType( XTypes.CLUSTER_CONFIG );
}
[...]

In the demoQuery() method, the displayWild() and displayJ2EEType() methods are called to find the following MBeans:

Monitoring Attribute Changes

The demoJMXMonitor() demonstrates how to monitor attribute changes.


Example 16–13 Monitoring Attribute Changes

[...]
demoJMXMonitor() throws InstanceNotFoundException, IOException
{
    final JMXMonitorMgr mgr = getDomainRoot().getJMXMonitorMgr();
    final String attrName = "SampleString";
    final String attrValue = "hello";
    final SampleListener sampleListener = new SampleListener();
    final MBeanServerConnection conn =
        Util.getExtra( mgr ).getConnectionSource()
        .getExistingMBeanServerConnection();
    conn.addNotificationListener(
        getMBeanServerDelegateObjectName(),
        sampleListener, null, null );
    final Sample sample = (Sample)getDomainRoot()
        .getContainee( XTypes.SAMPLE );
    final String monitorName = "SampleStringMonitor";
    AMXStringMonitor mon = null;
    try
    {
        try { mgr.remove( monitorName ); }
        catch( Exception e ) {}
        mon = mgr.createStringMonitor( monitorName );
        waitMBeanServerNotification( sampleListener,
            MBeanServerNotification.REGISTRATION_NOTIFICATION,
            Util.getObjectName( mon ) );
        sample.addAttribute( attrName, attrValue );
        mon.addNotificationListener( sampleListener, null, null);
        mon.setObservedAttribute( attrName );
        mon.setStringToCompare( attrValue );
        mon.setNotifyDiffer( true );
        mon.setNotifyMatch( true );
        mon.addObservedObject( Util.getObjectName( sample ) );
        final StdAttributesAccess attrs = Util.getExtra( sample);
        attrs.setAttribute( new Attribute(attrName, "goodbye") );
        attrs.setAttribute( new Attribute(attrName, attrValue) );
        sample.removeAttribute( attrName );
        final Map notifs = sampleListener.getNotifsReceived();
        waitNumNotifs( notifs,
            AttributeChangeNotification.ATTRIBUTE_CHANGE, 4 );
    }
    catch( Throwable t )
    {
        t.printStackTrace();
    }
    finally
    {
        try
        {
            mon.removeNotificationListener( sampleListener );
            if ( mon != null )
            {
                mgr.remove( mon.getName() );
                waitMBeanServerNotification( sampleListener,
                    MBeanServerNotification
                    .UNREGISTRATION_NOTIFICATION,
                    Util.getObjectName( mon ) );
            }
            conn.removeNotificationListener(
            getMBeanServerDelegateObjectName(),
            sampleListener );
        }
        catch( ListenerNotFoundException e )
        {
        }
    }
}
[...]

The demoJmx() method demonstrates the implementation of a JMX monitor MBean, that listens for changes in a certain attribute. This is achieved in the following stages:

  1. A com.sun.appserv.management.monitor.JMXMonitorMgr instance is obtained using the DomainRoot.getJMXMonitorMgr() method.

  2. A SampleListener JMX notification listener that is provided in the sample package is instantiated.

  3. A connection to the domain’s MBean server is obtained by calling com.sun.appserv.management.client.ConnectionSource. getExistingMBeanServerConnection() on the JMXMonitorMgr instance’s Extra information.

  4. The SampleListener notification listener is added to the MBean server connection, with an MBean server delegate obtained from getMBeanServerDelegateObject(). The notification listener is now in place on the MBean server connection.

  5. An AMX MBean, sample, of the type SAMPLE is obtained by calling the com.sun.appserv.management.base.Container.getContainee() method on an instance of the Sample interface. The Sample interface defines a basic AMX MBean.

  6. An AMXStringMonitor, an AMX-compatible JMX StringMonitorMBean, is instantiated by calling createStringMonitor on the JMXMonitorMgr instance created above. The AMXStringMonitor instance then calls waitMBeanServerNotification(). The waitMBeanServerNotification() method waits for MBean server notifications of the type REGISTRATION_NOTIFICATION from the SampleListener instance that is listening on the MBean server connection.

  7. An attribute of name attrName and value attrValue is added to the AMX MBean sample.

  8. Various methods of the AMXStringMonitor instance are called, to add a listener, and to set the value to be observed, the object to be observed, and so on.

  9. Access to the sample MBean’s attributes is obtained by passing the sample MBean’s Extra information to an instance of com.sun.appserv.management.base.StdAttributesAccess. The StdAttributesAccess.setAttribute() method is then called to change the values of these attributes.

  10. The AMXStringMonitor then calls the sample notification listener’s getNotifsReceived() method to retrieve the notifications that resulted from the calls to setAttribute() above. The waitNumNotifs() method waits until four ATTRIBUTE_CHANGE notifications have been received before exiting.

  11. The notification listener is then removed and the monitor is closed down.

Undeploying Modules

The undeploy() method demonstrates how to undeploy a module.


Example 16–14 Undeploying Modules

[...]
undeploy ( final String moduleName ) throws IOException
{
    final DeploymentMgr mgr = getDomainRoot().getDeploymentMgr();

    final Map statusData = mgr.undeploy( moduleName, null );
    final DeploymentStatus status =
        DeploymentSupport.mapToDeploymentStatus( statusData );
    println( "Undeployment result: "
        + getStageStatusString(status.getStageStatus()));
    if ( status.getStageThrowable() != null )
    {
        status.getStageThrowable().printStackTrace();
    }
}
[...]

The undeploy() method obtains the DeploymentMgr instance for the domain in the same way that deploy() does so. It then calls the DeploymentMgr.undeploy() method for a named module.

Stopping an Application Server

The stopServer() method demonstrates how to stop an application server. The stopServer() method simply calls the getJ2EEServer() method on a given server instance, and then calls J2EEServer.stop().

Running the AMX Samples

To set up your development environment for using AMX, you must ensure that your Java classpath contains the following Java archive (JAR) files:

Start your Java application in a manner similar to this:

export JAR_PATH=install-dir/lib/
export CP="$JAR_PATH/j2ee.jar:$JAR_PATH/appserv-admin.jar"
java -cp $CP com.mycompany.MyClientMain