FeatureAvailabilitypublic 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 | INSTANCE | private final Map | mFeatures | private final Map | mLatches | public static final String | ADMIN_CONTEXT_FEATUREfeature stating that the AdminContext is available. Result data is the AdminContext | public static final String | MBEAN_SERVER_FEATUREfeature stating that the MBeanServer is available. Result data is the MBeanServer | public static final String | SUN_ONE_INTERCEPTOR_FEATUREfeature stating that the SunoneInterceptor is active. Associated data should be ignored. | public static final String | COM_SUN_APPSERV_CONFIG_MBEANS_FEATUREfeature stating that the com.sun.appserv:category=config MBeans are available.
Result data should not be used | public static final String | AMX_LOADER_FEATUREfeature stating that the AMX MBean Loader is available (but not AMX). Data should not be used | public static final String | AMX_BOOT_UTIL_FEATUREfeature stating that the AMX BootUtil class is available. Data should not be used | public static final String | CALL_FLOW_FEATUREfeature 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 | SERVER_STARTED_FEATUREFeature 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 | DEBUG_ENABLED |
Constructors Summary |
---|
private FeatureAvailability()
mFeatures = new HashMap<String,Object>();
mLatches = new HashMap<String,CountDownLatch>();
//mDebug = new AMXDebugHelper( "--FeatureAvailability--" );
//mDebug.setEchoToStdOut( true );
|
Methods Summary |
---|
private void | debug(java.lang.Object args)Internal use, should be replaced with use of
com.sun.appserv.management.helper.AMXDebugHelper 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.FeatureAvailability | getInstance() return INSTANCE;
| public javax.management.MBeanServer | getMBeanServer()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
return (MBeanServer)mFeatures.get( MBEAN_SERVER_FEATURE );
| public synchronized void | registerFeature(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.
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.Object | waitForFeature(java.lang.String featureName, java.lang.String callerInfo)Block until the specified feature is available.
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();
try
{
debug( "waitForFeature: \"" + featureName + "\" by " + callerInfo );
final long startNanos = System.nanoTime();
latch.await();
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;
| public javax.management.MBeanServer | waitForMBeanServer()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.
MBeanServer server = getMBeanServer();
if ( server == null )
{
server = (MBeanServer)waitForFeature( MBEAN_SERVER_FEATURE,
"waitForMBeanServer from " + ExceptionUtil.getStackTrace() );
}
return server;
|
|