FileDocCategorySizeDatePackage
MonitoringStatsImplBase.javaAPI DocGlassfish v2 API26750Fri May 04 22:23:32 BST 2007com.sun.enterprise.management.monitor

MonitoringStatsImplBase

public abstract class MonitoringStatsImplBase extends MonitoringImplBase
Base implementation class for Monitoring MBeans that provide Stats.

Fields Summary
private MBeanInfo
mMBeanInfo
private final com.sun.appserv.management.util.jmx.AttributeNameMapper
mFieldNameMapper
private final com.sun.appserv.management.util.jmx.AttributeNameMapper
mStatisticNameMapper
private Set
mStatisticNames
private static final String
GET
The prefix of a getter method.
private static final String
STATISTIC_DELIM
The delimiter between a Statistic name and its field value when exposed as an Attribute.
private static final Set
IGNORE_MISSING_SUFFIXES
protected static final String[]
STD_FIELDS
protected static final String[]
STD_STATISTICS
private static final boolean
BUG_STATISTIC_NAMES
A bug in the underlying MBeans is present.
private final Class[]
STATS_IMPL_INTERFACES
private static final Set
LONG_FIELDS
JSR 77 defines these fields as having type "long", so we must define them that way as well, in spite of the underlying bug in the old monitoring MBeans, which declares them all as Strings.
private static final MBeanInfo
EMPTY_MBEAN_INFO
Constructors Summary
public MonitoringStatsImplBase(String j2eeType, com.sun.enterprise.management.support.Delegate delegate)

		super( j2eeType, delegate );
		
		mMBeanInfo	= null;
		
		mFieldNameMapper		= new AttributeNameMapperImpl();
		mStatisticNameMapper	= new AttributeNameMapperImpl();
		
		mStatisticNames	= null;
	
public MonitoringStatsImplBase(String j2eeType)

		this( j2eeType, null );
	
Methods Summary
protected final javax.management.j2ee.statistics.Statistic[]checkDuplicateStatistics(com.sun.enterprise.management.support.Delegate d, javax.management.j2ee.statistics.Statistic[] statistics)

		// check to see if any names are duplicated
		final Set<String>	actualNames	= new HashSet<String>();
		for ( int i = 0; i < statistics.length; ++i )
		{
			final String	name	= statistics[ i ].getName();
			
			if ( actualNames.contains( name ) )
			{
				throw new RuntimeException( 
					"MonitoringStatsImplBase.checkDuplicateStatistics: " +
					getObjectName() +
						"Statistic " + StringUtil.quote( name ) + " is duplicated in getStatistics(): " +
					 	" as supplied from Delegate of " + StringUtil.quote( getObjectName() )+
					 	", please see bug #6179364"  );
			}
			else
			{
				actualNames.add( name );
			}
		}
		
		if ( actualNames.size() != statistics.length )
		{
			final String[] claimedNames = (String[])d.invoke( "getStatisticNames", null,  null );
		
			final Set<String>	missingNames	= GSetUtil.newStringSet( claimedNames );
			missingNames.removeAll( actualNames );
			
			throw new RuntimeException(
				"MonitoringStatsImplBase.getStatisticsFromDelegateRaw: " + missingNames.size() + 
				" Statistic names as found in Statistics from getStatistics() are missing: {" +
				toString( missingNames ) +
			 	"} from Delegate of " + StringUtil.quote( getObjectName() ) + ", please see bug #6179364" );
		}
		
		return( statistics );
	
private voidcheckUnderlyingMBean()

		assert( BUG_STATISTIC_NAMES ); 
                
		if ( BUG_STATISTIC_NAMES  /* && ! getJ2EEType().equals( "X-BeanMethodMonitor" ) */ )
		{
		    final Delegate  delegate    = getDelegate();
		    
            if ( delegate == null) return;
            
			final String[]	claimedNames	= getMonitoringMBeanDelegate().getStatisticNames();
			if ( claimedNames == null )
			{
			    throw new RuntimeException( "Delegate " + 
			        " used by AMX MBean " + getObjectName() +
			        " returned null StatisticNames array" );
			}
			else if ( claimedNames.length == 0 )
			{
			    throw new RuntimeException( "Delegate " + 
			        " used by AMX MBean " + getObjectName() +
			        " returned empty StatisticNames array" );
			}

			final Statistic[]	statistics	= getMonitoringMBeanDelegate().getStatistics();
			if ( statistics == null )
			{
			    throw new RuntimeException( "Delegate " + 
			        " used by AMX MBean " + getObjectName() +
			        " returned null Statistics array" );
			}
			else if ( statistics.length == 0 )
			{
			    throw new RuntimeException( "Delegate " + 
			        " used by AMX MBean " + getObjectName() +
			        " returned empty Statistics array" );
			}
			   
			try
			{
				final Set<String>		actualSet	= new HashSet<String>();
				
				final String[]	namesFromGetStatistics	= new String[ statistics.length ];
				
				for( int i = 0; i < statistics.length; ++i )
				{
					final String	name	= StringUtil.upperCaseFirstLetter( statistics[ i ].getName() );
					namesFromGetStatistics[ i ]	= name;
					
					if ( ! actualSet.contains( name ) )
					{
						actualSet.add( name );
					}
					else
					{
						logWarning( "MBean delegate " + 
						    " for " + getObjectName() +
							" returns Statistic with duplicate name: " + name +
							" from getStatistics() call.\n" );
					}
				}
				
				final Set<String>	claimedSet	= GSetUtil.newStringSet( claimedNames );
				if ( ! claimedSet.equals( actualSet ) )
				{
					final Set<String>	missing	= new HashSet<String>( claimedSet );
					missing.removeAll( actualSet );
					
					// assume workarounds are in place
					final String msg = "\nMBean delegate " + " for " + getObjectName() +
						" does not provide Statistic(s): " + missing + " from getStatistics() call, " +
					"\ngetStatisticNames() = " + toString( claimedSet ) + 
					"\nnames from getStatistics() = " + toString( namesFromGetStatistics ) + "\n";
					
	                AMXDebug.getInstance().getOutput(
	                    "MonitoringStatsImplBase.checkUnderlyingMBean" ).println( msg );
					logFine( msg );
				}
			}
			catch( Exception e )
			{
				final Throwable rootCause	= ExceptionUtil.getRootCause( e );
				logWarning( "MBean delegate " + 
				    " doesn't work, used by AMX MBean: " +
					getObjectName() + "\n" +
					rootCause.getClass().getName() + "\n" +
					ExceptionUtil.getStackTrace( rootCause ) );
			}
		}
	
private synchronized javax.management.MBeanInfocreateMBeanInfo()
Create MBeanInfo by taking default MBeanInfo and adding Attributes to it corresponding to all available Statistics.

		final MBeanInfo	baseMBeanInfo	= super.getMBeanInfo();
		
		MBeanInfo	mbeanInfo	= baseMBeanInfo;
		
		if ( getMBeanServer() != null && getDelegate() != null )
		{
			assert( getDelegate() != null ) : "null delegate for: " + getObjectName();
			
			final Map<String,MBeanAttributeInfo>
			    newAttrs	= new HashMap<String,MBeanAttributeInfo>();
			
			final Statistic[]	statistics	= getStats().getStatistics();
			for( int i = 0; i < statistics.length; ++i )
			{
				final Map<String,MBeanAttributeInfo> attrInfos	=
				    statisticToMBeanAttributeInfos( statistics[ i ] );
				
				newAttrs.putAll( attrInfos );
			}
			
			final MBeanAttributeInfo[]	dynamicAttrInfos	=
				new MBeanAttributeInfo[ newAttrs.keySet().size() ];
			newAttrs.values().toArray( dynamicAttrInfos );
			
			final MBeanAttributeInfo[]	attrInfos	=
				JMXUtil.mergeMBeanAttributeInfos( dynamicAttrInfos, baseMBeanInfo.getAttributes() );
			
			mbeanInfo	= JMXUtil.newMBeanInfo( baseMBeanInfo, attrInfos );
		}
		
		return( mbeanInfo );
	
protected com.sun.appserv.management.j2ee.statistics.StatsImplcreateStatsImpl()

	
			            		     				          	 
	  	
	
	
		 
	
	
		return new StatsImpl( getStatisticsFromDelegate() );
	
private voiddebug(java.lang.String s)

		System.out.println( s );
	
protected java.lang.StringderivedToOriginalStatisticName(java.lang.String derivedName)

		return( getStatisticNameMapper().derivedToOriginal( derivedName ) );
	
private java.lang.ClassdetermineFieldType(java.lang.String fieldName, java.lang.Object value)
Determine the Java class of a field.

	
			      	 
		 
	
		 	
		 	 
	
		Class	theClass	= String.class;
		
		if ( value != null )
		{
			theClass	= ClassUtil.ObjectClassToPrimitiveClass( value.getClass() );
		}
		else if ( LONG_FIELDS.contains( fieldName ) )
		{
			theClass	= long.class;
		}
		
		return( theClass );
	
protected java.lang.ObjectgetAttributeFromStatistic(java.lang.String statisticName, java.lang.String fieldName)
Get an Attribute value by looking for a corresponding Statistic.

param
statisticName as seen in the MBeanInfo of this MBean
param
fieldName as seen in the MBeanInfo of this MBean

		try
		{
			final Statistic s	= getStatistic( statisticName );
			assert( s instanceof MapStatistic );
			
			final String	methodName	= JMXUtil.GET + fieldName;
			final Method	m	= s.getClass().getMethod( methodName, (Class[])null);
			
			//final MapStatisticImpl	ms	= new MapStatisticImpl( s );
			final Object result	= m.invoke( s, (Object[])null );
			return( result );
		}
		catch( Exception e )
		{
		    debug( "getAttributeFromStatistic: exception getting statistic " +
		        statisticName + e  + "\n" + 
		        ExceptionUtil.getStackTrace( ExceptionUtil.getRootCause( e ) ) );
			throw new AttributeNotFoundException( statisticName );
		}
	
protected java.lang.ObjectgetAttributeManually(java.lang.String name)
Handle getting of artificial Attributes which are derived from Statistics.

param
name the Attribute name

		final int	idx	= name.indexOf( STATISTIC_DELIM );
		
		Object	result	= null;
		
		if ( idx > 0 )
		{
			// Attribute name is of the form <statistic-name>_<field-name>
			final String	statisticName	= name.substring( 0, idx );
			final String	fieldName	= name.substring( idx + 1, name.length() );
			
			result	= getAttributeFromStatistic( statisticName, fieldName );
		}
		else
		{
		    result  = super.getAttributeManually( name );
		}
		
		return( result );
	
protected final com.sun.appserv.management.util.jmx.AttributeNameMappergetFieldNameMapper()

		return( mFieldNameMapper );
	
public synchronized javax.management.MBeanInfogetMBeanInfo()

		
		  
	
	
		if ( mMBeanInfo == null )
		{
			try
			{
				mMBeanInfo	= createMBeanInfo();
			}
			catch( Throwable t )
			{
				// if we throw an exception, it will kill the MBeanServer's ability
				// to function
				final Throwable rootCause	= ExceptionUtil.getRootCause( t );
				
				// when an old mbean gets unregistered, this object does too,
				// but the MBeanServer calls getMBeanInfo() before unregistering us,
				// putting this MBean in the awkward position of supplying MBeanInfo
				// from a delegate that has disappeared.
				if ( ! ( rootCause instanceof InstanceNotFoundException) )
				{
					getMBeanLogger().warning( "can't create MBeanInfo for: " + getObjectName() +
						"\n" + rootCause.getClass() + ": " + rootCause.getMessage() + ":\n" +
						ExceptionUtil.getStackTrace( rootCause ) );
				}
				
				mMBeanInfo	= EMPTY_MBEAN_INFO;
			}
		}
		
		return( mMBeanInfo );
	
protected com.sun.enterprise.management.monitor.MonitoringStatsImplBase$OldMonitoringMBeangetMonitoringMBeanDelegate()
Get the underlying Delegate. Note that this proxy may not actually implement all the routines in MonitoringStats; we use only a few however, so that is OK.

		return (OldMonitoringMBean)getDelegateProxy(OldMonitoringMBean.class);
	
public javax.management.openmbean.CompositeDataSupportgetOpenStatistic(java.lang.String name)

		final Statistic statistic = getStatistic( name );
		
		try
		{
			return J2EEUtil.statisticToCompositeData(statistic);
		}
		catch(OpenDataException e)
		{
			throw new RuntimeException(e);
		}
	
public javax.management.openmbean.CompositeDataSupport[]getOpenStatistics(java.lang.String[] names)

		final CompositeDataSupport[] result	= new CompositeDataSupport[names.length];
		
		for(int i = 0; i < names.length; i++)
		{
			result[ i ] = getOpenStatistic( names[ i ] );
		}
		return result;
	
public javax.management.openmbean.CompositeDataSupportgetOpenStats()

		final Stats	stats	= getStats();
		
		CompositeDataSupport	result	= null;
		// can't make a CompositeDataSupport if there are no Statistics
		if ( stats.getStatisticNames().length != 0 )
		{
			try
			{
				result	= J2EEUtil.statsToCompositeData( stats );
			}
			catch(OpenDataException e)
			{
				throw new RuntimeException(e);
			}
		}
		else
		{
			logWarning( "No Statistics available for: " + getObjectName() );
		}
		
		return( result );
	
public javax.management.j2ee.statistics.StatisticgetStatistic(java.lang.String name)

		final Stats		stats = getStats();
		
		return stats.getStatistic( name );
	
protected final com.sun.appserv.management.util.jmx.AttributeNameMappergetStatisticNameMapper()

		return( mStatisticNameMapper );
	
public java.lang.String[]getStatisticNames()
Gets the names of all the Statistics.

return
a String[] of statistic names

		return( GSetUtil.toStringArray( mStatisticNames ) );
	
public javax.management.j2ee.statistics.Statistic[]getStatistics(java.lang.String[] desiredNames)

		final Stats			stats	= getStats();
		final Statistic[]	result	= new Statistic[ desiredNames.length ];
		
		for( int i = 0; i < desiredNames.length; ++i )
		{
			final Statistic	statistic	= stats.getStatistic( desiredNames[ i ] );
			
			// OK to return null if not found--see Javadoc
			result[ i ]	= statistic;
		}
		
		return( result );
	
protected final javax.management.j2ee.statistics.Statistic[]getStatisticsFromDelegate()

	    if ( getDelegate() == null )
	    {
	        throw new NullPointerException();
	    }
		return( getStatisticsFromDelegate( getDelegate() ) );
	
protected javax.management.j2ee.statistics.Statistic[]getStatisticsFromDelegate(com.sun.enterprise.management.support.Delegate d)
Get all Statistics from the delegate (our only available call API). Statistic names are translated appropriately.

		try
		{
			final Statistic[] statistics = getStatisticsFromDelegateRaw( d );
			
			// translate the names to be the ones we expose in MBeanInfo
			for( int i = 0; i < statistics.length; ++i )
			{
				final Statistic	origStatistic	= statistics[ i ];
			
				final MapStatistic	m	= new MapStatisticImpl( origStatistic );
				
				final String	convertedName	= originalToDerivedStatisticName( origStatistic.getName() );
				if ( ! convertedName.equals( origStatistic.getName() ) )
				{
					m.setName( convertedName );
				}
				
				final Class<? extends Statistic> theClass	=
				    StatisticFactory.getInterface( origStatistic );
				assert( theClass != null );
				
				// this will create one which implements the requisite interfaces
				statistics[ i ]	= StatisticFactory.create( theClass, m.asMap() );
				
				assert( theClass.isAssignableFrom( statistics[ i ].getClass() ));
			}
			
			return( statistics );
		}
		catch (Exception e)
		{
			final Throwable	rootCause	= ExceptionUtil.getRootCause( e );
			
			if ( ! ( rootCause instanceof InstanceNotFoundException ) )
			{
				// don't rethrow--will make MBeanServer unuseable as it has a bug if we throw
				// an exception of of getMBeanInfo() which halts any further processing of the query
				//NOTE: WARNING_CHANGED_TO_FINE	
				logWarning( "Can't get Statistics from delegate for " + getObjectName() +
					"\n" + rootCause.getMessage() + "\n" + ExceptionUtil.getStackTrace( rootCause ) );
			}
			throw new RuntimeException( e );
		}
	
protected javax.management.j2ee.statistics.Statistic[]getStatisticsFromDelegateRaw(com.sun.enterprise.management.support.Delegate d)

	    try
	    {
    		final Statistic[] statistics = (Statistic[])d.invoke( "getStatistics", null,  null );
    		
    		checkDuplicateStatistics( d, statistics );
    		
    		return( statistics );
		}
		catch( Exception e )
		{
		    final Throwable rootCause   = ExceptionUtil.getRootCause( e );
		    
		    logWarning( "MonitoringStatsImplBase: the com.sun.appserv Delegate MBean for AMX MBean " +
		        getObjectName() + " threw an exception: " + rootCause +
		    ", stack = \n" + ExceptionUtil.getStackTrace( rootCause ) );
		}
		return new Statistic[0];
	
public StatsgetStats()

		final Class	statsInterface	= getStatsInterface();
		assert( statsInterface == null || Stats.class.isAssignableFrom( statsInterface ) );
		
		Class[] implementedInterfaces	= null;
		if ( statsInterface == null )
		{
			implementedInterfaces	= STATS_IMPL_INTERFACES;
			logInfo( "getStats: no Stats interface found for " + getObjectName() );
		}
		else
		{
			implementedInterfaces	= (Class[])
				ArrayUtil.newArray( STATS_IMPL_INTERFACES, statsInterface );
		}
		
		final StatsImpl			impl	= createStatsImpl();
		final ClassLoader		classLoader	= this.getClass().getClassLoader();
		
		final Stats stats	= (Stats)
			Proxy.newProxyInstance( classLoader, implementedInterfaces, impl );
	
	
	/*try
	{
		serializeTest( stats );
	} catch( Throwable t )
	{
		System.out.println( "getStats: Stats proxy serialization FAILED for " + getObjectName() );
		ExceptionUtil.getRootCause( t ).printStackTrace();
	}
	*/
		
		return( stats );
	
protected abstract java.lang.ClassgetStatsInterface()
Get the specific type of Stats interface (if any) that should be implemented by a Stats returned from getStats().

return
an interface, or null if the interface is generic Stats

public java.lang.StringgetStatsInterfaceName()

		return( getStatsInterface().getName() );
	
protected voidhandleMissingOriginals(java.util.Set missingOriginals)
We don't map any of the Attributes derived from statistics.

	    
		             	 
	     
	    
	
	    final Set<String>   stillMissing    = new HashSet<String>();
	    
	    for( final String name : missingOriginals )
	    {
	        final int idx   = name.lastIndexOf( '-" );
	        final String suffix = name.substring( idx + 1, name.length() );
	        
	        if ( ! IGNORE_MISSING_SUFFIXES.contains( suffix ) )
	        {
	            stillMissing.add( name );
	        }
	    }
        
        super.handleMissingOriginals( stillMissing );
	
protected voidinitFieldNameMapper()
Initialize the field-name mapping for any names that required special conversion.

	
			        		 	 
		 
	
	
		final AttributeNameMapper	m	= getFieldNameMapper();
		
		assert( (STD_FIELDS.length % 2) == 0 );
		for( int i = 0; i < STD_FIELDS.length - 1; ++i )
		{
			m.addMapping( STD_FIELDS[ i ], STD_FIELDS[ i + 1 ] );
		}
	
protected voidinitStatisticNameMapper()
Initialize the Statistic-name mapping for any names that required special conversion.

	
			        		 	 
		 
	
	
		final AttributeNameMapper	m	= getStatisticNameMapper();
		
		final String[]	mappings	= STD_STATISTICS;
		
		for( int i = 0; i < mappings.length -1; ++i )
		{
			m.addMapping( mappings[ i ], mappings[ i + 1 ] );
		}
	
private final java.lang.String[]initStatisticNames()

		String[]	names	= null;
		
		if ( BUG_STATISTIC_NAMES )
		{
			names	= getStats().getStatisticNames();
			if ( names == null || names.length == 0 )
			{
			    throw new RuntimeException( "Stats are null or empty for: " + getObjectName());
			}
		}
		else
		{
			names	= originalToDerivedStatisticNames( getMonitoringMBeanDelegate().getStatisticNames() );
		}
		
		return( names );
	
private java.lang.StringmakeAttributeName(java.lang.String statisticName, java.lang.String fieldName)
Given a Statistic-name and a field-name, create an Attribute name.

param
statisticName Statistic-name
param
fieldName
return
a name suitable for an Attribute

		final String	attributeName	= statisticName + STATISTIC_DELIM + fieldName;

		return( attributeName );
	
protected java.lang.StringoriginalToDerivedStatisticName(java.lang.String underlyingName)
Convert a Statistic-name from its underlying name to the one we expose.

param
underlyingName

		String		result	= getStatisticNameMapper().originalToDerived( underlyingName );
		result	= StringUtil.upperCaseFirstLetter( result );
		
		return( result );
	
private java.lang.String[]originalToDerivedStatisticNames(java.lang.String[] names)

	
	
		 
	    
	
		final String[]	derived	= new String[ names.length ];
		
		for( int i = 0; i < names.length; ++i )
		{
			derived[ i ]	= originalToDerivedStatisticName( names[ i ] );
		}
		
		return( derived );
	
protected javax.management.ObjectNamepreRegisterHook(javax.management.ObjectName objectName)

		initFieldNameMapper();
		initStatisticNameMapper();
		
		// ensure that it gets generated anew now that we are registered and can access everything
		refresh();
		
		assert( MonitoringStats.class.isAssignableFrom( getInterface() )  ) :
			"MBean extends MonitoringStatsImpl but does not have MonitoringStats interface: " + getObjectName();
		
		if ( BUG_STATISTIC_NAMES )
		{
			checkUnderlyingMBean();
		}
		
		mStatisticNames	= GSetUtil.newUnmodifiableStringSet( initStatisticNames() );
	    
	    return objectName;
	
public final booleanrefresh()

		mMBeanInfo	= null;
		clearAttributeInfos();
		
		return( true );
	
private java.util.MapstatisticToMBeanAttributeInfos(javax.management.j2ee.statistics.Statistic s)
Convert a single Statistic to MBeanAttributeInfo.

return
a Map, keyed by the Attribute name, value of MBeanAttributeInfo

		final Map<String,Object>	src	= new MapStatisticImpl( s ).asMap();
		
		final String	statisticName	= s.getName();
		
		final Map<String,MBeanAttributeInfo>	result	= new HashMap<String,MBeanAttributeInfo>();
		for( final String fieldName : src.keySet() )
		{
			final Object	value	= src.get( fieldName );
			// if the value is null, always make it a String
			final String	type	= determineFieldType( fieldName, value ).getName();
			
			final String	attributeName	= makeAttributeName( statisticName, fieldName );
			
			final MBeanAttributeInfo	attributeInfo	= new MBeanAttributeInfo( attributeName, type, "",
												true, false, false );
			result.put( attributeName, attributeInfo );
		}
		return( result );