Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Developer's Guide

- Previous: Chapter 15 Using the JavaMail API
- Next: Appendix A Deployment Descriptor Files

# 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

- AMX MBeans

- Proxies

- Connecting to the Domain Administration Server

- Examining AMX Code Samples

- Running the AMX Samples

# 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 instance, a cluster of such instances, or a manageable entity within a server instance. 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:

- They all implement the `com.sun.appserv.management.base.AMX` interface.

- They all have a `j2eeType` and `name` property within their `ObjectName` (see `com.sun.appserv.management.base.XTypes` and `com.sun.appserv.management.j2ee.J2EETypes` for the available values of the `j2eeType` property).

- All MBeans that logically contain other MBeans implement the `com.sun.appserv.management.base.Container` interface.

- JSR 77 MBeans that have a corresponding configuration or monitoring peer expose it via `getConfigPeer()` or `getMonitoringPeer()`. However, there are many configuration and monitoring MBeans that do not correspond to JSR 77 MBeans.

## 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:

- Dotted names via `MonitoringDottedNames` and `ConfigDottedNames`

- Attributes on MBeans via `getAttribute(s)` and `setAttributes(s)` (from the standard JMX API)

- Getters/setters within the MBean’s interface class, for example, `getPort()`, `setPort()`, and so on.

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}`.

Note –

An application or module MBean has two `enabled` attributes. Which `enabled` attribute to look up for the state of the application or module depends on the target. If the target is `domain`, look up the attribute under application or module itself. If the target is not domain, look up the attribute under the `application-ref`.

To look up an application in JConsole, select the following:

`com.sun.appserv` -> `j2ee-application` -> app-name -> `server` -> `config`

To look up a module in JConsole, select the following:

`com.sun.appserv` -> module-type -> module-name -> `server` -> `config`

To look up an `application-ref` in JConsole, select the following:

`com.sun.appserv` -> `application-ref` -> app-or-module-name -> `server` -> `config`

The attributes, including `enabled`, are listed under `config`.

# 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:

- Starting an Application Server

- Deploying an Archive

- Displaying the AMX MBean Hierarchy

- Setting Monitoring States

- Accessing AMX MBeans

- Accessing and Displaying the Attributes of an AMX MBean

- Listing AMX MBean Properties

- Querying

- Monitoring Attribute Changes

- Undeploying Modules

- Stopping an Application Server

## 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:

- `AMX.getDomainRoot()` obtains the Application Server domain to which `j2eeDomain` belongs.

- `DomainRoot.getJ2EEDomain()` obtains the J2EE domain for `j2eeDomain`.

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 –

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:

- `J2EE_TYPE_KEY` MBeans called `ResourceConfig`

- `J2EE_TYPE_KEY` MBeans called `ServerConfig`

- All `SSL_CONFIG` MBeans

- All `CLUSTER_CONFIG` 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:

- `appserv-admin.jar` - The JAR file containing the AMX interfaces needed for your client. This file is found in install-dir`/lib/`. No other classes from this JAR file should be used by your program.

- `jmxri.jar` - The runtime libraries for the JMX Reference Implementation. If you are using JDK 1.5, these are already in the JDK.

- `jmxremote.jar` - The runtime libraries for the JMX Remote API. If you are using JDK 1.5, these are already in the JDK.

- `j2ee.jar` - The runtime libraries for the J2EE Platform. This file is found in install-dir`/lib/`. This JAR file is needed only if you intend to use any of the J2EE Management Statistic classes (`javax.management.j2ee.*`).

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

- Previous: Chapter 15 Using the JavaMail API
- Next: Appendix A Deployment Descriptor Files

- © 2010, Oracle Corporation and/or its affiliates