FileDocCategorySizeDatePackage
AMXProxyHandler.javaAPI DocGlassfish v2 API33422Fri May 25 13:24:12 BST 2007com.sun.appserv.management.client.handler

AMXProxyHandler

public class AMXProxyHandler extends com.sun.appserv.management.util.jmx.MBeanProxyHandler implements com.sun.appserv.management.base.Extra
Extends MBeanProxyHandler by also supporting the functionality required of an AMX.

THREAD SAFE

Fields Summary
protected final PerMBeanCache
mCache
private boolean
mCheckedForInvariantMBeanInfo
protected static final String
DEBUG_ID
private static final String
CREATE
private static final String
GET
private static final String
MAP_SUFFIX
private static final String
SET_SUFFIX
private static final String
LIST_SUFFIX
private static final String
OBJECT_NAME_MAP_SUFFIX
private static final String
OBJECT_NAME_SET_SUFFIX
private static final String
OBJECT_NAME_LIST_SUFFIX
private static final String
OBJECT_NAME_SUFFIX
private static final String
CONTAINEE_J2EE_TYPES
private static final String
CONTAINER
private static final String
DOMAIN_ROOT
private static final String
MBEAN_INFO
private static final String
ATTRIBUTE_NAMES
private static final String
J2EE_NAME
private static final String
J2EE_TYPE
public static final String
ADD_NOTIFICATION_LISTENER
public static final String
REMOVE_NOTIFICATION_LISTENER
private static final String
QUERY
private static final String
STRING
private static final String[]
EMPTY_SIG
private static final String[]
STRING_SIG
private static final String[]
STRING2_SIG
private static final String
GET_SINGLETON_CONTAINEE
private static final String
GET_CONTAINEE
private static final String
GET_SINGLETON_CONTAINEE_OBJECT_NAME
private static final String[]
GET_SINGLETON_CONTAINEE_OBJECT_NAME_SIG1
private static final String[]
GET_SINGLETON_CONTAINEE_OBJECT_NAME_SIG2
private static final String[]
GET_OBJECT_NAMES_SIG_EMPTY
private static final String[]
GET_OBJECT_NAMES_SIG_STRING
private static final Map
EMPTY_String_AMX
private static final Class[]
NOTIFICATION_LISTENER_SIG1
private static final Class[]
NOTIFICATION_LISTENER_SIG2
private static final Set
CACHED_ATTRIBUTE_NAMES
The values of these Attributes are cached forever. Proxies are handled separately because the API will be getXXX() wherease the Attribute name will be XXXObjectName.
private static final String
GET_MBEAN_INFO
private static final String
GET_J2EE_TYPE
private static final String
GET_J2EE_NAME
private static final String
GET_ATTRIBUTE_NAMES
private static final String
GET_CONTAINER
private static final String
GET_EXTRA
private static final String
GET_ALL_ATTRIBUTES
private static final String
GET_DOMAIN_ROOT
private static final String
GET_OBJECT_NAME
private static final Set
SPECIAL_METHOD_NAMES
These Attributes are handled specially. For example, J2EE_TYPE and J2EE_NAME are part of the ObjectName.
Constructors Summary
protected AMXProxyHandler(com.sun.appserv.management.client.ConnectionSource connectionSource, ObjectName proxiedMBeanObjectName)
Create a new AMX proxy.

param
connectionSource the connection
param
proxiedMBeanObjectName the ObjectName of the proxied MBean

		super( connectionSource, proxiedMBeanObjectName );
		
        mDebug  = AMXDebug.getInstance().getOutput( getDebugID() );
		
		mCache	= new PerMBeanCache();
		
		setProxyLogger( AMXClientLogger.getInstance() );
	
Methods Summary
private java.lang.String_getInterfaceName()

		return( (String)getCachedAttributeValue( AMXAttributes.ATTR_INTERFACE_NAME ) );
	
private synchronized javax.management.MBeanInfo_getMBeanInfo()

	
	
	
		  
	
		 
		  
	
		MBeanInfo	mbeanInfo	= null;
        
		if ( ! mCheckedForInvariantMBeanInfo )
		{
			mCheckedForInvariantMBeanInfo	= true;
			
			// see if target has the boolean which tells us if caching is OK
			try
			{
				final Boolean	cacheIt	= (Boolean)
					getAttribute( AMXAttributes.ATTR_MBEAN_INFO_IS_INVARIANT );
				setMBeanInfoIsInvariant( cacheIt.booleanValue() );
				cacheMBeanInfo( cacheIt.booleanValue() );
				
			}
			catch( Exception e )
			{
				// not found, or other problem, have to assume we can't cache it
				cacheMBeanInfo( false );
				setMBeanInfoIsInvariant( false );
			}
		}

		mbeanInfo	= getMBeanInfo( getCacheMBeanInfo() );
		
		return( mbeanInfo );
	
protected java.lang.Object_invoke(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)

		debugMethod( method.getName(), args );
		
   		// clients can retain proxies that go invalid if their corresponding
   		// MBeans are removed.
   		if ( ! targetIsValid() )
   		{
   			throw new InstanceNotFoundException( getTargetObjectName().toString() );
   		}
   		
   		Object	result	= null;
   		
		final String	methodName	= method.getName();
		final int		numArgs	= args == null ? 0 : args.length;
		
		boolean	handled	= false;
		
   		if ( SPECIAL_METHOD_NAMES.contains( methodName ) )
   		{
   			handled	= true;
   			result	= handleSpecialMethod( myProxy, method, args );
   		}
   		else if ( JMXUtil.isIsOrGetter( method ) )
   		{
   			assert( ! handled );
   		
   			final String	attrName	= JMXUtil.getAttributeName( method );
   			
   			if ( CACHED_ATTRIBUTE_NAMES.contains( attrName ) )
   			{
   				result	= getCachedAttributeValue( attrName );
   				handled	= true;
   			}
   		}
   		
   		if ( ! handled )
   		{
	   		if ( isSingleProxyGetter( method,  numArgs) )
	   		{
   				result	= invokeSingleProxyGetter( myProxy, method, args );
	   		}
	   		else if ( isProxySetGetter( method, numArgs ) )
	   		{
	   			result	= invokeProxySetGetter( myProxy, method, args );
	   		}
	   		else if ( isProxyMapGetter( method, numArgs ) )
	   		{
	   			result	= invokeProxyMapGetter( myProxy, method, args );
	   		}
	   		else if ( isProxyListGetter( method, numArgs ) )
	   		{
	   			result	= invokeProxyListGetter( myProxy, method, args );
	   		}
	   		else if ( isProxyCreator( method ) )
	   		{
	   			result	= invokeProxyCreator( method, args );
	   		}
	   		else
	   		{
   				result	= super.invoke( myProxy, method, args );
	   		}
   		}

        if ( getDebug() )
        {
    		debug( AMXDebug.methodString( methodName, args ) +
    		    " => " + toString( result ) );
		}
		
   		return( result );
   	
protected voidaddNotificationListener(java.lang.Object[] args)

   		final NotificationListener	listener	= (NotificationListener)args[ 0 ];
   		final NotificationFilter	filter		= (NotificationFilter)(args.length <= 1 ? null : args[ 1 ]);
   		final Object				handback	= args.length <= 1 ? null : args[ 2 ];
   		
   		getConnection().addNotificationListener(
   			getTargetObjectName(), listener, filter, handback );
   	
protected voidcacheAttribute(javax.management.Attribute attr)

		mCache.cacheAttribute( attr );
	
private voidcacheProxy(java.lang.String key, com.sun.appserv.management.base.AMX proxy)
A proxy cached by ObjectName can safely be shared globally, since the ObjectNames are unique per connection. But non-ObjectName keys may actually conflict from like MBeans

		mCache.cacheItem( key, proxy );
	
protected static java.lang.StringconvertMethodName(java.lang.String srcName, java.lang.String srcSuffix, java.lang.String resultSuffix)

		if ( ! srcName.endsWith( srcSuffix ) )
		{
			throw new IllegalArgumentException( srcName + " does not end with " + srcSuffix );
		}
		final String	baseName	= srcName.substring( 0, srcName.lastIndexOf( srcSuffix ) );
		
		return( baseName + resultSuffix );
	
protected synchronized com.sun.appserv.management.base.AMXcreateProxy(javax.management.ObjectName objectName)

	

		  
	
		 	 
	
   		return( getProxyFactory().getProxy( objectName, AMX.class ) );
	
public java.util.MapgetAllAttributes()

		Map<String,Object>	result	= Collections.emptyMap();
		
		try
		{
			final String[]	names	= getAttributeNames();
			
			final AttributeList	attrs	= getAttributes(names );
			
			result	= JMXUtil.attributeListToValueMap( attrs );
		}
		catch( Exception e )
		{
			throw new RuntimeException( e );
		}
		return( result );
	
public java.lang.String[]getAttributeNames()

		final String	attrName	= "AttributeNames";
		
		Attribute	attr	= null;
		try
		{
			attr	= getCachedAttribute( attrName );
		}
		catch( AttributeNotFoundException e )
		{
			// it's supposed to be there!
			attr	= null;
		}
		catch( Exception e )
		{
			throw new RuntimeException( e );
		}
		
		String[]	names	= null;
		if ( attr == null )
		{
			final MBeanInfo	mbeanInfo	= getMBeanInfo();
		
			names	= JMXUtil.getAttributeNames( mbeanInfo.getAttributes() );
			if ( getMBeanInfoIsInvariant() )
			{
				// only cache if MBeanInfo is invariant
				cacheAttribute( new Attribute( attrName, names ) );
			}
		}
		else
		{
			names	= (String[])attr.getValue();
		}
		
		return( names );
	
protected javax.management.AttributegetCachedAttribute(java.lang.String attrName)
Get an Attribute, first from the cache, but if not in the cache, fetching a new copy, then caching it. This routine should only be used on invariant Attributes.

		Attribute	attr	= mCache.getCachedAttribute( attrName );
		
		if ( attr == null )
		{
			final MBeanServerConnection	conn	= getConnection();
				
			final Object value	= getConnection().getAttribute( getTargetObjectName(), attrName );
			attr	= new Attribute( attrName, value );
			mCache.cacheAttribute( attr );
		}
		
		return( attr );
	
protected java.lang.ObjectgetCachedAttributeValue(java.lang.String attrName)

		final Attribute	attr	= getCachedAttribute( attrName );
		
		assert( attr != null ) : "getCachedAttributeValue: null for " + attrName;
		return( attr == null ? null : attr.getValue() );
	
private com.sun.appserv.management.base.AMXgetCachedProxy(java.lang.Object key)
All proxies cached by ObjectName get cached by the ProxyFactory. Proxies keyed by other values may not be unique and need to be cached as items in mCache.

		AMX	proxy	= null;
		
		if ( key instanceof ObjectName )
		{
			proxy	= getProxyFactory().getProxy( (ObjectName)key, AMX.class );
		}
		else
		{
			proxy	= Util.asAMX(mCache.getCachedItem( key ) );
		}
		
		if ( proxy != null )
		{
			final AMXProxyHandler	handler	= (AMXProxyHandler)Proxy.getInvocationHandler( proxy );
			if ( ! handler.targetIsValid() )
			{
				debug( "removing cached proxy for key: ", key );
				mCache.remove( key );
				proxy	= null;
			}
		}
		
		return( proxy );
	
synchronized com.sun.appserv.management.base.ContainergetContainer(com.sun.appserv.management.base.AMX myProxy)
Get the proxy which is the parent of this one.

		Container	containerProxy	= null;
		
		if ( ! ( myProxy instanceof DomainRoot ) )
		{
            final ObjectName objectName = getContainerObjectName();
            
            // a few MBeans propogated from other instances, such as Logging,
            // do not have a Container.
            if ( objectName != null )
            {
                containerProxy =
                    getProxyFactory().getProxy( objectName, Container.class );
            }
		}
		
		return( containerProxy );
	
protected javax.management.ObjectNamegetContainerObjectName()


		 
	
		  
	
		return( (ObjectName)getCachedAttributeValue( AMXAttributes.ATTR_CONTAINER_OBJECT_NAME ) );
	
protected java.lang.StringgetDebugID()

	
	
	     
	
	
	    return DEBUG_ID;
	
private final com.sun.appserv.management.DomainRootgetDomainRoot()
Get the proxy corresponding to the DomainMBean for the domain to which this proxy corresponds.

		return( getProxyFactory().getDomainRoot( ) );
	
public java.lang.StringgetInterfaceName()

		try
		{
			return( _getInterfaceName() );
		}
		catch( Exception e )
		{
			throw new RuntimeException( e );
		}
	
private java.lang.StringgetJ2EEType(java.lang.Class c)

		return( (String)ClassUtil.getFieldValue( c, "J2EE_TYPE" ) );
	
public javax.management.MBeanInfogetMBeanInfo()

		try
		{
			return( _getMBeanInfo() );
		}
		catch( Exception e )
		{
			throw new RuntimeException( e );
		}
	
public javax.management.ObjectNamegetObjectName()

		return( getTargetObjectName() );
	
public com.sun.appserv.management.client.ProxyFactorygetProxyFactory()

		return( ProxyFactory.getInstance( getConnectionSource() ) );
	
protected java.lang.ClassgetProxyInterface(javax.management.ObjectName objectName)

		// by fetching a proxy this way, it may already exist, with an already-cached
		// interface.
		final AMX	proxy	= getProxyFactory().getProxy( objectName, AMX.class );
		
		final Class	proxyInterface	= ClassUtil.getClassFromName( Util.getExtra( proxy ).getInterfaceName() );
		
		return( proxyInterface );
	
private static java.lang.String[]getStringSig(java.lang.reflect.Method method)

		final Class[]	sig	= method.getParameterTypes();
		final String[]	stringSig	= ClassUtil.classnamesFromSignature( sig );
		return( stringSig );
	
private java.lang.ObjecthandleSpecialMethod(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)
Handle a "special" method; one that requires special handling and/or can be dealt with on the client side and/or can be handled most efficiently by special-casing it.

	
			          		            		  	 
		 
	
		 		
    	 		
		 		 
		   
	
		final String	methodName	= method.getName();
		final int		numArgs	= args == null ? 0 : args.length;
		Object	result	= null;
		boolean	handled	= true;
		
		if ( numArgs == 0 )
		{
		    if ( methodName.equals( GET_CONTAINER )  )
			{
				result	= getContainer( Util.asAMX(myProxy) );
			}
			else if ( methodName.equals( GET_EXTRA ) )
			{
				assert( this instanceof Extra );
				result	= this;
			}
			else if ( methodName.equals( GET_OBJECT_NAME ) )
			{
				result	= getTargetObjectName();
			}
			else if ( methodName.equals( GET_DOMAIN_ROOT ) )
			{
				result	= getDomainRoot( );
			}
			else if ( methodName.equals( GET_ATTRIBUTE_NAMES ) )
			{
				result	= getAttributeNames();
			}
			else if ( methodName.equals( GET_J2EE_TYPE ) )
			{
				result	= Util.getJ2EEType( getTargetObjectName() );
			}
			else if ( methodName.equals( GET_J2EE_NAME ) )
			{
				result	= Util.getName( getTargetObjectName() );
			} 
			else if ( methodName.equals( GET_ALL_ATTRIBUTES ) )
			{
				result	= getAllAttributes();
			}
			else
			{
				handled	= false;
			}
		}
		else if ( numArgs == 1 && methodName.equals( "equals" ) )
		{
		    return equals( args[ 0 ] );
		}
		else
		{
			final Class[]	signature	= method.getParameterTypes();
		
			if ( methodName.equals( ADD_NOTIFICATION_LISTENER ) &&
						(	ClassUtil.sigsEqual( NOTIFICATION_LISTENER_SIG1, signature ) ||
							ClassUtil.sigsEqual( NOTIFICATION_LISTENER_SIG2, signature ) )
					)
			{
				addNotificationListener( args );
			}
			else if ( methodName.equals( REMOVE_NOTIFICATION_LISTENER ) &&
						(	ClassUtil.sigsEqual( NOTIFICATION_LISTENER_SIG1, signature ) ||
							ClassUtil.sigsEqual( NOTIFICATION_LISTENER_SIG2, signature ) )
					)
			{
				removeNotificationListener( args );
			}
			else
			{
				handled	= false;
			}
		}
		
		if ( ! handled )
		{
			assert( false );
			throw new RuntimeException( "unknown method: " + method );
		}
		
		return( result );
	
public final java.lang.Objectinvoke(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)

   		try
   		{
   			final Object result = _invoke( myProxy, method, args );
   			
	   		assert( result == null ||
	   			ClassUtil.IsPrimitiveClass( method.getReturnType() ) ||
	   			method.getReturnType().isAssignableFrom( result.getClass() ) ) :
	   				method.getName() + ": result of type " + result.getClass().getName() +
	   				" not assignable to " + method.getReturnType().getName() + ", " +
	   				"interfaces: " + toString( result.getClass().getInterfaces() +
	   				", ObjectName = " + JMXUtil.toString( getTargetObjectName() ) );
	   				
	   	    return result;
   		}
   		catch( IOException e )
   		{
   			getProxyFactory().checkConnection();
   			throw e;
   		}
   		catch( InstanceNotFoundException e )
   		{
   			checkValid();
   			throw e;
   		}
   	
com.sun.appserv.management.base.AMXinvokeProxyCreator(java.lang.reflect.Method method, java.lang.Object[] args)

		final String	methodName	= method.getName();
		
		final String[]	stringSig	= getStringSig( method );
		final ObjectName	objectName	= (ObjectName)invokeTarget( methodName, args, stringSig );
		assert( objectName != null ) :
			"received null ObjectName from: " + methodName + " on target " + getTargetObjectName();
		
		final AMX	proxy	= createProxy( objectName );
		assert( getProxyFactory().getProxy( Util.getExtra( proxy ).getObjectName(),AMX.class, false ) == proxy );
		
		return( proxy );
	
private java.util.ListinvokeProxyListGetter(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)

		// get the List<ObjectName> from the MBean
		final String	remoteNAME	=
			convertMethodName( method.getName(), LIST_SUFFIX, OBJECT_NAME_LIST_SUFFIX );
		final List<ObjectName>	objectNames	= TypeCast.asList(
		    invokeTarget( remoteNAME, args, getStringSig( method ) ) );
		
		final List<AMX>	result	= getProxyFactory().toProxyList( objectNames );
		
		return( result );
	
private java.util.MapinvokeProxyMapGetter(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)

	
		 
	
		 	
    	 	
    	 	 
		    
		  
	
		final int	argCount	= args == null ? 0 : args.length;
		
		// turn getXXXObjectNameMap() into getXXXMap()
		final String	methodName	= method.getName();
		final String	getObjectNameMapName	=
			convertMethodName( methodName, MAP_SUFFIX, OBJECT_NAME_MAP_SUFFIX );
		
		final MBeanServerConnection	conn	= getConnection();
		
		final Map<String,?> m = TypeCast.asMap( 
		    invokeTarget( getObjectNameMapName, args, getStringSig( method ) ) );
		assert( m != null ) :
			"mbean " + getTargetObjectName() + " returned null Map for " + getObjectNameMapName;
		
		/*
			The Map may be either a:
			- Map of <name>=<ObjectName>
			- Map of <j2eeType>=<Map of <name>=<ObjectName>
		 */
		Map<String,?>	result	= null;
		if ( m.keySet().size() != 0 )
		{
		    final ProxyFactory  proxyFactory    = getProxyFactory();
		
			final Object firstValue	= m.values().iterator().next();
			
			if ( firstValue instanceof ObjectName )
			{
				// it's <name>=<ObjectName>
				final Map<String,ObjectName>  onm = TypeCast.asMap( m );
				final Map<String,AMX> proxyMap	= proxyFactory.toProxyMap( onm );
				result  = proxyMap;
			}
			else if ( firstValue instanceof Map )
			{
				final Map<String,Map<String,ObjectName>> objectNameMaps = TypeCast.asMap( m );
				final Map<String,Map<String,AMX>> proxyMaps	= new HashMap<String,Map<String,AMX>>();
				
				for ( final String j2eeType : objectNameMaps.keySet() )
				{
					final Map<String,ObjectName> objectNameMap	= objectNameMaps.get( j2eeType );
					final Map<String,AMX> proxyMap	= proxyFactory.toProxyMap( objectNameMap );
					proxyMaps.put( j2eeType, proxyMap ); 	
				}
				
				result  = proxyMaps;
			}
			else
			{
			    throw new IllegalArgumentException();
			}
		}
		else
		{
		    result  = EMPTY_String_AMX;
		}
		
		return( result );
	
private java.util.SetinvokeProxySetGetter(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)
The method is one that requests a Set of Proxies. Create the proxies by asking the target MBean for the ObjectNames. Then generate proxies of the appropriate type for each resulting ObjectName.

		assert( Set.class.isAssignableFrom( method.getReturnType() ) );
	
		final String	methodName	= method.getName();
		
		final String	getObjectNamesName	=
			convertMethodName( methodName, SET_SUFFIX, OBJECT_NAME_SET_SUFFIX );
		
		final MBeanServerConnection	conn	= getConnection();
		
		final String[]	stringSig	= getStringSig( method );
		// ask the MBean for an ObjectName corresponding to an id (name)
		final Set<ObjectName>	objectNames	= TypeCast.asSet( invokeTarget( getObjectNamesName, args, stringSig ) );
		
		final Set<AMX>	proxies	= getProxyFactory().toProxySet( objectNames );
		
		return( proxies );
	
com.sun.appserv.management.base.AMXinvokeSingleProxyGetter(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)
The method is one that requests a Proxy. Create the proxy by asking the target MBean for the appropriate ObjectName. The resulting Proxy will implement the interface given as the return type of the Method.

		// use the methodName as the key for the cache
		final String	methodName	= method.getName();
		final int		numArgs	= (args == null) ? 0 : args.length;
		
		final String	argString	= args == null ? "" : ArrayStringifier.stringify( args, "_" );
		final String 	cacheKey	= methodName + argString;
		
		AMX		proxy	= getCachedProxy( cacheKey );
	
		if ( proxy == null )
		{
			final Class		returnClass	= method.getReturnType();
			ObjectName		objectName	= null;
			final String	j2eeType	= getJ2EEType( returnClass );
				
			if ( numArgs == 0 )	// of the form getXXX() eg getSSLConfig()
			{
				final String newMethodName	= proxyGetterToObjectNameGetter( methodName );
				objectName	= (ObjectName) invokeTarget( newMethodName, null, EMPTY_SIG);
			}
			else if ( numArgs == 1 && args[ 0 ].getClass() == String.class )
			{
				final String newMethodName	= proxyGetterToObjectNameGetter( methodName );
				objectName	= (ObjectName) invokeTarget( newMethodName, args, STRING_SIG );
			}
			else if ( (methodName.equals( GET_SINGLETON_CONTAINEE )  ||
					methodName.equals( GET_CONTAINEE )) && numArgs == 2 )
			{
				// getContainee( j2eeType, name )
				final String newMethodName	= proxyGetterToObjectNameGetter( methodName );
				
				objectName	= (ObjectName)
					invokeTarget( newMethodName, args, GET_SINGLETON_CONTAINEE_OBJECT_NAME_SIG2 );
			}
			else
			{
				getProxyLogger().warning( "Unknown form of proxy getter: " + method );
				assert( false );
				throw new IllegalArgumentException();
			}
				
			if ( objectName != null )
			{
				proxy	= createProxy(  objectName );
			}
			
			// the underlying object may not exist, this occurs normally sometimes
			if ( proxy != null )
			{
				if ( cacheKey != null )
				{
					//debug( "CACHING: " + cacheKey + " => " + Util.getExtra( proxy ).getObjectName);
					cacheProxy( cacheKey, proxy );
				}
				else
				{
					//debug( "NOT CACHING: " + Util.getExtra( proxy ).getObjectName);
				}
			}
			else
			{
				getProxyLogger().fine( "invokeSingleProxyGetter: NULL ObjectName for: " +
				    methodName + "()" );
		    }
		}
		else
		{
			//debug( "FOUND CACHED using \"" + cacheKey  + "\": " + Util.getExtra( proxy ).getObjectName);
		}
		
		return( proxy );
	
private java.lang.ObjectinvokeTarget(java.lang.String methodName, java.lang.Object[] args, java.lang.String[] sig)

	    final int   numArgs = args == null ? 0 : args.length;
	    
	    Object  result  = null;
	    
	    if ( numArgs == 0 &&
	        methodName.startsWith( GET ) )
	    {
	        final String    attributeName   = StringUtil.stripPrefix( methodName, GET );
	        result  = getConnection().getAttribute( getTargetObjectName(), attributeName );
	    }
	    else
	    {
	        result  = getConnection().invoke( getTargetObjectName(), methodName, args, sig );
	    }
	    
		return result;
	
protected static booleanisProxyCreator(java.lang.reflect.Method method)

		final String	methodName	= method.getName();
		
		return( methodName.startsWith( CREATE ) &&
			AMX.class.isAssignableFrom( method.getReturnType() ) );
	
protected static booleanisProxyListGetter(java.lang.reflect.Method method, int argCount)
Return true if the method is one that is requesting a List of AMX object.

		boolean	isProxyListGetter	= false;
		
		final String	name	= method.getName();
		if ( ( name.startsWith( GET ) || name.startsWith( QUERY ) ) &&
			name.endsWith( LIST_SUFFIX ) && 
			(! name.endsWith( OBJECT_NAME_LIST_SUFFIX )) && 
			argCount <= 1 &&
			List.class.isAssignableFrom( method.getReturnType() ) )
		{
			isProxyListGetter	= true;
		}
		
		return( isProxyListGetter );
	
protected static booleanisProxyMapGetter(java.lang.reflect.Method method, int argCount)
Return true if the method is one that is requesting a Map of AMX object.

		boolean	isProxyMapGetter	= false;
		
		final String	name	= method.getName();
		if ( name.startsWith( GET ) &&
			name.endsWith( MAP_SUFFIX ) && 
			(! name.endsWith( OBJECT_NAME_MAP_SUFFIX )) && 
			argCount <= 1 &&
			Map.class.isAssignableFrom( method.getReturnType() ) )
		{
			isProxyMapGetter	= true;
		}
		
		return( isProxyMapGetter );
	
protected static booleanisProxySetGetter(java.lang.reflect.Method method, int argCount)

return
true if the method is one that is requesting a Set of AMX.

		boolean	isProxySetGetter	= false;
		
		final String	name	= method.getName();
		if ( ( name.startsWith( GET ) || name.startsWith( QUERY ) ) &&
			name.endsWith( SET_SUFFIX ) && 
			!name.endsWith( OBJECT_NAME_SET_SUFFIX ) && 
			argCount <= 2 &&
			Set.class.isAssignableFrom( method.getReturnType() ) )
		{
			isProxySetGetter	= true;
		}
		
		return( isProxySetGetter );
	
protected static booleanisSingleProxyGetter(java.lang.reflect.Method method, int argCount)
Return true if the method is one that is requesting a single AMX object. Such methods are client-side methods and do not operate on the target MBean.

		boolean	isProxyGetter	= false;
		
		final String	name	= method.getName();
		if ( ( name.startsWith( GET ) || name.startsWith( QUERY ) ) &&
			argCount <= 2 &&
			AMX.class.isAssignableFrom( method.getReturnType() ) )
		{
			isProxyGetter	= true;
		}
		
		return( isProxyGetter );
	
private static java.lang.StringproxyGetterToObjectNameGetter(java.lang.String methodName)

		return( methodName + OBJECT_NAME_SUFFIX );
	
protected voidremoveNotificationListener(java.lang.Object[] args)

   		final NotificationListener	listener	= (NotificationListener)args[ 0 ];
   		
   		// important:
   		// this form removes the same listener registered with different filters and/or handbacks
   		if ( args.length == 1 )
   		{
   		    getConnection().removeNotificationListener( getTargetObjectName(), listener );
   		}
   		else
   		{
       		final NotificationFilter filter		= (NotificationFilter)args[ 1 ];
       		final Object             handback	= args[ 2 ];
       		
       		getConnection().removeNotificationListener(
       			getTargetObjectName(), listener, filter, handback );
   	    }
   	
private static java.lang.StringtoString(java.lang.Object o)

		String result  = o == null ? "null" : SmartStringifier.toString( o );
		
        final int   MAX_LENGTH  = 256;
        if ( result.length() > MAX_LENGTH )
        {
            result  = result.substring( 0, MAX_LENGTH - 1 ) + "...";
        }
        
        return result;