FeatureAvailability.javaAPI DocGlassfish v2 API11893Fri May 04 22:32:06 BST 2007com.sun.enterprise.util


public final class FeatureAvailability extends Object
Central registry of available features for fine-grained dependency enforcement in a threaded environment.

Providers of features can register the availability (initializated and ready-to-use) of a particular feature, upon which other code depends. See {@link #addFeature}.

Code that requires an initialized and ready-to-use feature should call {@link #waitForFeature}--the calling thread will block until that feature is available.

Feature names are arbitrary and *should not* be defined as 'public static final String' in this class unless they are of general system interest. Features that are not of general interest can and should still be registered through this mechanism, but the names of those features and the associated data can be defined in a more appropriate place.

Provider Example

...provider runs in its own thread...
FeatureAvailability.registerFeature( FeatureAvailability.MBEAN_SERVER_FEATURE, mbeanServer );

Client Example
(arbitrary number of clients, multiple calls OK)

...client runs until feature is needed...
final MBeanServer mbeanServer = (MBeanServer)
FeatureAvailability.waitForFeature( FeatureAvailability.MBEAN_SERVER_FEATURE );

To see how long client code is blocking, set the {@link #DEBUG_ENABLED} flag to true.

Fields Summary
private static final FeatureAvailability
private final Map
private final Map
public static final String
feature stating that the AdminContext is available. Result data is the AdminContext
public static final String
feature stating that the MBeanServer is available. Result data is the MBeanServer
public static final String
feature stating that the SunoneInterceptor is active. Associated data should be ignored.
public static final String
feature stating that the com.sun.appserv:category=config MBeans are available. Result data should not be used
public static final String
feature stating that the AMX MBean Loader is available (but not AMX). Data should not be used
public static final String
feature stating that the AMX BootUtil class is available. Data should not be used
public static final String
feature stating that the CallFlow feature is available. Data should not be used Data is of type com.sun.enterprise.admin.monitor.callflow.Agent
public static final String
Feature stating that the server has started, meaning that the main initialization code has been run; specific features could be initializing on separate threads, or could be initialized lazily. No data is associated with this feature.
private static final boolean
Constructors Summary
private FeatureAvailability()

        mFeatures   = new HashMap<String,Object>();
        mLatches    = new HashMap<String,CountDownLatch>();
        //mDebug      = new AMXDebugHelper( "--FeatureAvailability--" );
        //mDebug.setEchoToStdOut( true );
Methods Summary
private voiddebug(java.lang.Object args)
Internal use, should be replaced with use of when build-order problems are resolved. Set DEBUG_ENABLED to true to see output.

        if ( DEBUG_ENABLED )
            String msg  = "";
            for( int i = 0; i < args.length - 1; ++i )
                msg = msg + args[i] + " ";
            msg = msg + args[args.length-1];
            System.out.println( msg );
public static com.sun.enterprise.util.FeatureAvailabilitygetInstance()

 return INSTANCE; 
MBeanServer is created very early and is available via this method exept for code that executes prior to the JVM calling main(). As it is of interest in many areas, an explicit method call is provided.

NON-BLOCKING--returns current value, can be null

the MBeanServer used by all AppServer MBeans

        return (MBeanServer)mFeatures.get( MBEAN_SERVER_FEATURE );
public synchronized voidregisterFeature(java.lang.String featureName, java.lang.Object data)
Register a named feature as being ready for use. The data value can be a dummy value, or can be something useful to the caller of {@link #waitForFeature}.

Do not register a feature until its facilities are ready for use.

Features should generally be fine-grained, not coarse. For example, the AdminService is a coarsely-defined feature which initializes dozens of things; code that requires the presence of one of those things should arrange for a name feature for that. Examples of this include the MBeanServer, the AdminContext, com.sun.appserv:category=config MBeans, etc.

featureName arbitrary name for the feature, to be used by clients in {@link waitForFeature}
data arbitrary data of possible interest to clients

        if ( mFeatures.get( featureName ) != null )
            debug( "addFeature: already added: " + featureName );
            throw new IllegalStateException();
        if ( data == null )
            System.out.println( "addFeature: data is null for: " + featureName );
            throw new IllegalArgumentException();
        mFeatures.put( featureName, data );
        debug( "********** FeatureAvailability.addFeature: " + featureName + ", data = " + data + "**********");

        if ( mLatches.containsKey( featureName ) )
            final CountDownLatch latch  = mLatches.remove( featureName );
            latch.countDown();  // let all blocked threads proceed
            debug( "addFeature: released latch for: " + featureName );
public java.lang.ObjectwaitForFeature(java.lang.String featureName, java.lang.String callerInfo)
Block until the specified feature is available.

featureName the name of the desired feature
callerInfo arbitrary caller info for debugging purposes

        CountDownLatch    latch = null;
        Object            data  = null;

        // working with mFeatures and mLatches together; must synchronize for this
        synchronized( this )
            data = mFeatures.get( featureName );
            if ( data == null )
                // feature not yet available, calling thread will have to wait
                latch   = mLatches.get( featureName );
                if ( latch == null )
                    latch   = new CountDownLatch( 1 );
                    mLatches.put( featureName, latch );
        assert( (data == null && latch != null) || (data != null && latch == null) );

        // if we had to create a CountDownLatch, calling thread must now await()
        if ( latch != null )
            final long start    = System.currentTimeMillis();
                debug( "waitForFeature: \"" + featureName + "\" by " + callerInfo );
                final long startNanos   = System.nanoTime();
                final long elapsedNanos = System.nanoTime() - startNanos;
                if ( elapsedNanos > 1000 * 1000 )  // 1 millisecond
                    debug( "FeatureAvailability.waitForFeature: waited ",
                        "" + elapsedNanos,
                        " for feature \"", featureName, "\" by \"", callerInfo, "\"" );
            catch ( java.lang.InterruptedException e)
                debug( "waitForFeature: ERROR: ", e );
                throw new Error( e );
            data    = mFeatures.get( featureName );
        return data;
MBeanServer is created very early and is available via this method exept for code that executes prior to the JVM calling main(). As it is of interest in many areas, an explicit method call is provided. BLOCKING--returns onlyl when MBeansServer becomes available.

the MBeanServer used by all AppServer MBeans

        MBeanServer server = getMBeanServer();
        if ( server == null )
            server = (MBeanServer)waitForFeature( MBEAN_SERVER_FEATURE,
                "waitForMBeanServer from " +  ExceptionUtil.getStackTrace() );
        return server;