Package com.sun.enterprise.management.support

Source Code of com.sun.enterprise.management.support.AMXImplBase

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/*
* $Header: /cvs/glassfish/admin/mbeanapi-impl/src/java/com/sun/enterprise/management/support/AMXImplBase.java,v 1.23.6.1 2007/12/04 18:58:03 yaminikb Exp $
* $Revision: 1.23.6.1 $
* $Date: 2007/12/04 18:58:03 $
*/

package com.sun.enterprise.management.support;

import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.Collections;
import java.util.Iterator;
import java.util.Properties;
import java.util.HashSet;

import java.util.logging.Logger;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

import java.io.IOException;

import javax.management.*;

import com.sun.appserv.management.util.stringifier.SmartStringifier;
import com.sun.appserv.management.util.stringifier.ArrayStringifier;

import com.sun.appserv.management.base.AMX;
import com.sun.appserv.management.base.AMXDebug;
import com.sun.appserv.management.base.AMXAttributes;
import com.sun.appserv.management.base.Extra;
import com.sun.appserv.management.base.Container;
import com.sun.appserv.management.base.Singleton;
import com.sun.appserv.management.base.Utility;

import com.sun.appserv.management.base.QueryMgr;
import com.sun.appserv.management.base.XTypes;
import com.sun.enterprise.management.support.XTypesMapper;
import com.sun.enterprise.management.support.AllTypesMapper;

import com.sun.appserv.management.base.AMXLoggerBase;

import com.sun.appserv.management.config.NamedConfigElement;

import com.sun.appserv.management.base.QueryMgr;
import com.sun.appserv.management.DomainRoot;
import com.sun.appserv.management.base.Util;

import com.sun.appserv.management.client.ConnectionSource;
import com.sun.appserv.management.util.jmx.MBeanServerConnectionSource;
import com.sun.enterprise.management.support.AMXAttributeNameMapper;
import com.sun.appserv.management.util.jmx.Acronyms;
import com.sun.appserv.management.util.jmx.JMXUtil;

import com.sun.appserv.management.util.misc.ClassUtil;
import com.sun.appserv.management.util.misc.ExceptionUtil;
import com.sun.appserv.management.util.misc.GSetUtil;
import com.sun.appserv.management.util.misc.ThrowableMapper;
import com.sun.appserv.management.util.misc.StringUtil;
import com.sun.appserv.management.util.misc.CollectionUtil;

import com.sun.enterprise.management.support.ObjectNames;
import com.sun.enterprise.management.support.oldconfig.OldConfigProxies;
import com.sun.enterprise.management.support.TypeInfo;
import com.sun.enterprise.management.support.TypeInfos;
import com.sun.appserv.management.base.AMX;
import com.sun.appserv.management.base.Container;


import com.sun.appserv.management.client.ProxyFactory;

import com.sun.appserv.management.util.jmx.NotificationBuilder;
import com.sun.appserv.management.util.jmx.AttributeChangeNotificationBuilder;
import com.sun.appserv.management.util.jmx.stringifier.MBeanInfoStringifier;

import com.sun.appserv.management.util.misc.MapUtil;
import com.sun.appserv.management.config.AMXConfig;
import com.sun.appserv.management.config.PropertiesAccess;

import com.sun.appserv.management.j2ee.J2EETypes;

import com.sun.logging.LogDomains;

/**
  Base class from which all AMX MBeans should derive (but not "must").
  <p>
  Note that even though this base class implements a number of interfaces,
  the actual MBean interface supplied by the subclass construction-time
  determines which of these is actually exposed in the MBeanInfo.
  <p>
  A subclass should generally <b>not</b> implement get/setAttribute(s) as these
  calls are processed in this base class--
  <p>
  If a subclass implements a getter or setter Method it will be invoked automatically.
  If there is no getter or setter Method, then the getAttributeManually() or
  setAttributeManually() methods will be invoked; the subclass should implement
  these methods instead.
  <p>
  Method invocation is also handled automatically. If a Method cannot be found,
  the invokeManually() method is called; the subclass should implement this method.
  <p>
  Note that various optimizations are possible, but not implemented. These include
  caching Methods for each Attribute and for operations as well.  Careful testing
  should be done before complicating the code with such optimizations.
*/
public class AMXImplBase extends MBeanImplBase
  implements DynamicMBean, MBeanRegistration,
  AMX,
  NotificationEmitter, DelegateOwner
{
  protected static final String  GET  = "get";
  protected static final String  SET  = "set";
 
  /**
    The interface this MBean implements
  */
  private final Class      mInterface;
 
  /**
    The MBeanInfo
  */
  private final MBeanInfo    mMBeanInterfaceMBeanInfo;
 
  /**
    The parent MBean for this MBean.
        No need to make volatile; a recompute is OK if one thread doesn't yet see it.
  */
  private ObjectName    mCachedContainerObjectName;
 
  /**
    Flag to enable or disable whether AttributeChangeNotifications are
    emitted.
  */
  private final boolean      mEmitAttributeChangeNotifications;
 
 
  private volatile QueryMgr  mQueryMgr;
  private volatile AMX    mSelfProxy;
 
  private ConnectionSource  mConnectionSource;
 
  /**
    An optional Delegate
  */
  private final Delegate    mSuppliedDelegate;
  private volatile Delegate   mDelegate;
 
  private AMXAttributeNameMapper  mAttributeNameMapper  = null;
 
  private Map<String,MBeanAttributeInfo>      mAttributeInfos;
 
  private String      mFullType;
  private final String  mJ2EEType;
 
  protected CoverageInfo  mCoverage;
 
    /**
        Maps a j2eeType to a Map<String,Class>  which maps an Attribute name to a Class.
     */
    private static final Map<String,Map<String,Class>>  ATTRIBUTE_CLASSES =
        Collections.synchronizedMap( new HashMap<String,Map<String,Class>>() );
 
    protected Class
  getInterface( final String j2eeType )
  {
    return( AllTypesMapper.getInstance().getInterfaceForType( j2eeType ) );
  }
 
    protected String
  deduceJ2EEType( final Class c)
  {
    // it may extend the interface in which case its type is readily available
    String  j2eeType  = (String)ClassUtil.getFieldValue( c, "J2EE_TYPE" );
    if ( j2eeType == null )
    {
      final String  strippedName  = StringUtil.stripSuffix(
                        ClassUtil.stripPackageName( c.getName() ), "Impl" );
     
      if ( c.getPackage().getName().endsWith( ".j2ee" ) )
      {
        // j2ee standard type
        j2eeType  = strippedName;
      }
      else
      {
        j2eeType  = "X-" + strippedName;
      }
    }
   
    return( j2eeType );
  }

    protected
  AMXImplBase( String j2eeType, Delegate delegate )
  {
    this( j2eeType, null, delegate );
  }
 
    protected
  AMXImplBase()
  {
    this( null, null, null );
  }
 
    protected
  AMXImplBase( final Delegate delegate )
  {
    this( null, null, delegate );
  }


        protected boolean
    coverageActive()
    {
        return ! (mCoverage instanceof CoverageInfoDummy);
    }

        public final CoverageInfo
    getCoverageInfo()
    {
        mCoverage.setMBeanInfo( getMBeanInfo() );
        return mCoverage;
    }
   
        public final void
    clearCoverageInfo()
    {
        mCoverage.clear();
    }


        protected CoverageInfo
    createCoverageInfo( final boolean enable )
    {
        final CoverageInfo info   = enable ?
            new CoverageInfoImpl( getMBeanInfo() ) : new CoverageInfoDummy();
       
        clearCoverageInfo();
       
        return info;
    }
   
        public boolean
    enableCoverageInfo( final boolean enable )
    {
        final boolean   wasEnabled    = ! ( mCoverage instanceof CoverageInfoDummy);
       
        if ( enable != wasEnabled )
        {
            mCoverage   = createCoverageInfo( enable );
        }

        return wasEnabled;
    }
   
       private synchronized MBeanInfo
    getInterfaceMBeanInfo(
        final Class theInterface )
    {
    MBeanInfo info  = TypeInfos.getInstance().getMBeanInfoForInterface( theInterface );
        if ( false || getAMXDebug() )
        {
            debug( "Interface " + mInterface.getName() +
                " has MBeanInfo:\n" +
                MBeanInfoStringifier.DEFAULT.stringify( info ) );
               
            info   = addDebugMBeanInfo( info );
        }
       
        return info;
    }

   
  /**
    Construct a new implementation that implements the supplied mbeanInterface.
   
    @param j2eeTypeIn    (may be null) the j2eeType of this instance
    @param theInterface    (may be null) the public interface as seen on the client
    @param delegate      an MBean to which unknown requests are delegated
  */
    private
  AMXImplBase(
    final String    j2eeTypeIn,
    final Class      theInterface,
    final Delegate    delegate )
  {
    super();
       
        mCoverage   = new CoverageInfoDummy()// will change below...
       
    if ( delegate != null )
    {
      delegate.setOwner( this );
    }
   
    mJ2EEType  = j2eeTypeIn == null ?
              deduceJ2EEType( getClass() ): j2eeTypeIn;
             
    if ( getAMXDebug() && j2eeTypeIn != null )
    {
      final String  deducedJ2EEType  = deduceJ2EEType( getClass() );
     
      if ( ! deducedJ2EEType.equals( mJ2EEType ) )
      {
        debug( "warning: deducedj2eeType " + deducedJ2EEType +
          " does not match: " + j2eeTypeIn );
      }
    }
   
    mInterface  = theInterface == null ? getInterface( mJ2EEType ) : theInterface;
    if ( mInterface == null )
    {
        throw new Error( "AMXImplBase: can't get interface for j2eeType " + j2eeTypeIn  );
    }
   
    mCachedContainerObjectName  = null;
    mEmitAttributeChangeNotifications  = true;
    mQueryMgr      = null;
    mSelfProxy        = null;
   
   
    mSuppliedDelegate    = delegate;
    if ( mSuppliedDelegate instanceof DelegateBase )
    {
        ((DelegateBase)mSuppliedDelegate).setDebugOutput( getDebugOutput() );
    }

        ATTRIBUTE_CLASSES.put( mJ2EEType,
            Collections.synchronizedMap( new HashMap<String,Class>() ) );
     
    // initialization of mDelegate is deferred until later; the supplied delegate
    // may not be in a position to run yet
    mDelegate        = null;
    mAttributeNameMapper  = null;
   
    mAttributeInfos  = null;
    mFullType    = null;
   
    mMBeanInterfaceMBeanInfo  = getInterfaceMBeanInfo( mInterface );
  }
 
    public void
  delegateFailed( final Throwable t )
  {
    // the delegate has fatally failed
  }
 
 
        protected String
    getDebugID()
    {
        return ClassUtil.stripPackageName( this.getClass().getName() );
    }
   
    protected MBeanInfo
  getMBeanInfoFromInterface()
  {
    return( mMBeanInterfaceMBeanInfo );
  }
 
  /**
    Almost all MBeans don't change their MBeanInfo once it's created, making it
    possible to cache it on the client side.
  */
    public boolean
  getMBeanInfoIsInvariant()
  {
    return( true );
  }
   
    protected MBeanInfo
  removeUnsupportedMBeanInfo( final MBeanInfo info )
  {
    return( info );
  }
 
  /**
      Hook for subclass to modify anything in MBeanInfo.
   */
    protected MBeanInfo
  modifyMBeanInfo( final MBeanInfo info )
  {
    return( info );
  }
 
  /**
      Verify that the Delegate's interface is consistent with the MBeanInfo
      for this MBean.  Called by unit test code when AMX-DEBUG is enabled.
   */
        public String
    checkInterfaceAgainstDelegate()
    {
        final Delegate  delegate    = getDelegate();
        if ( ! ( getAMXDebug() && delegate != null) )
        {
            return null;
        }
       
        final String NEWLINE    = System.getProperty( "line.separator" );
        final String    result  = null;
       
        final MBeanInfo amxMBeanInfo    = getMBeanInfo();
       
       
        final Map<String,MBeanAttributeInfo> amxAttributeInfos   =
            JMXUtil.attributeInfosToMap( amxMBeanInfo.getAttributes() );
           
        // check that every Attribute in the Delegate exists in AMX
        final MBeanInfo delegateMBeanInfo    = delegate.getMBeanInfo();
        final MBeanAttributeInfo[] delegateAttributeInfos   = delegateMBeanInfo.getAttributes();
       
        //debug( "Delegate MBeanInfo: " + MBeanInfoStringifier.DEFAULT.stringify( delegateMBeanInfo ) );
       
        final StringBuilder builder = new StringBuilder();
        for( final MBeanAttributeInfo delegateAttrInfo : delegateAttributeInfos )
        {
            final String    delegateAttrName    = delegateAttrInfo.getName();
            assert( delegateAttrName != null ) :
                "delegate for " + getJ2EEType() + " supplied an MBeanAttributeInfo with a null name";
           
            try
            {
                final Object value  = delegateGetAttribute( delegateAttrName );
                // OK, we got the value.  Does AMX have it?
                if ( ! amxAttributeInfos.containsKey( delegateAttrName ) )
                {
                    builder.append( "Attribute " + quote( delegateAttrName ) +
                        " exists in Delegate, but not in AMX MBeanInfo" + NEWLINE );
                }
            }
            catch( Exception e )
            {
                builder.append( "Getting Attribute " +
                    quote( delegateAttrName ) +
                    " threw Exception: " + e + NEWLINE );
            }
        }
       
        // return empty string if nothing found
        return builder.length() == 0 ?
            "" : (getObjectName() + NEWLINE + builder.toString());
    }
 
   
  /**
      Subclass may override, but should call super.addDebugMBeanInfo().
      Add any additional debugging stuff to the MBeanInfo.
   */
    protected MBeanInfo
  addDebugMBeanInfo( final MBeanInfo origInfo )
  {
    final MBeanInfo debugInfo  =
      MBeanInfoConverter.getInstance().convert( AMXDebugStuff.class, null );
 
      return JMXUtil.mergeMBeanInfos( origInfo, debugInfo );
  }
 
 
 
  /**
    By default, the MBeanInfo is derived once from the MBean interface.
    Then certain items are removed, and optional debugging is added.
    This method should not cache the MBeanInfo because it may change
    dynamically.  The client-side proxies cache the MBeanInfo if
    getMBeanInfoIsInvariant() returns true.
  */
    public MBeanInfo
  getMBeanInfo()
  {
    MBeanInfo  mbeanInfo  = null;
 
    try
    {
      mbeanInfo  = getMBeanInfoFromInterface();
     
      final MBeanNotificationInfo[]    notifs  = getNotificationInfo();
      if ( notifs != null && notifs.length != 0 )
      {
          mbeanInfo   = JMXUtil.addNotificationInfos( mbeanInfo, notifs );
      }
    }
    catch( Exception e )
    {
      e.printStackTrace();
      throw new RuntimeException( e );
    }
   
    mbeanInfo   = removeUnsupportedMBeanInfo( mbeanInfo );
    mbeanInfo   = modifyMBeanInfo( mbeanInfo );
   
    return( mbeanInfo );
  }
 
 
    protected final boolean
  shouldEmitNotifications()
  {
    return( mEmitAttributeChangeNotifications && getListenerCount() != 0 );
  }
 
 
    public Delegate
  getDelegate()
  {
    return( mDelegate );
  }
 
    protected void
  setDelegate( final Delegate delegate )
  {
    mDelegate  = delegate;
  }
 
    protected boolean
  haveDelegate()
  {
    return( getDelegate() != null );
  }
 
    protected Object
  getDelegateProxy( final Class theInterface )
  {
    return( DelegateInvocationHandler.newProxyInstance( getDelegate(), theInterface ) );
  }
 
    public OldConfigProxies
  getOldConfigProxies()
  {
    return( OldConfigProxies.getInstance( getMBeanServer() ) );
  }
 
 
    protected AMXAttributeNameMapper
  getAttributeNameMapper()
  {
    return( mAttributeNameMapper );
  }
  private static final MBeanNotificationInfo[] EMPTY_NOTIFICATIONS = new MBeanNotificationInfo[ 0 ];
 
   /**
       Defined by NotificationBroadcaster.
      
    @return an empty array
     Subclass may wish to override this.
   */
    public MBeanNotificationInfo[]
  getNotificationInfo()
  {
    return( EMPTY_NOTIFICATIONS );
  }
 
 
  /**
    Get the value of a property within this MBean's ObjectName.
   
    @return the value of the specified property, or null if not found.
  */
    protected String
  getKeyProperty( final String key )
  {
    return( getObjectName().getKeyProperty( key ) );
  }
 
 
    public ProxyFactory
  getProxyFactory()
  {
    assert( mConnectionSource != null );
    return( ProxyFactory.getInstance( mConnectionSource, true ) );
  }
 
    public <T extends AMX> T
  getProxy( final ObjectName objectName, final Class<T> theClass)
  {
      return getProxyFactory().getProxy( objectName, theClass );
  }
 

    protected boolean
  shouldOmitObjectNameForDebug()
  {
    return super.shouldOmitObjectNameForDebug() ||
        getObjectName().getKeyProperty( "name" ).equals( AMX.NO_NAME );
  }
 
    protected static boolean
  isSingletonMBean( final Class  mbeanInterface )
  {
    return( Singleton.class.isAssignableFrom( mbeanInterface ) );
  }
 
    protected static boolean
  isUtilityMBean( final Class  mbeanInterface )
  {
    return( Utility.class.isAssignableFrom( mbeanInterface ) );
  }
 
    protected static boolean
  hasElementName( final Class  mbeanInterface )
  {
    return( NamedConfigElement.class.isAssignableFrom( mbeanInterface ) );
  }
 
 
    public Container
  getFactoryContainer()
  {
    return( Container.class.cast( getSelf() ) );
  }
 
    public final ObjectName
  getContainerObjectName( )
  {
    return( getContainerObjectName( getObjectName() ) );
  }
 
    public final Container
  getContainer( )
  {
    final ObjectName  objectName  = getContainerObjectName( getObjectName() );
   
    returngetProxyFactory().getProxy( objectName, Container.class) );
  }
 
      protected ObjectNames
    getObjectNames()
    {
      return ObjectNames.getInstance( getJMXDomain() );
    }
 
    protected synchronized ObjectName
  getContainerObjectName( final ObjectName selfObjectName )
  {
    if ( mCachedContainerObjectName == null &&
      ! getSelfJ2EEType().equals( XTypes.DOMAIN_ROOT ) )
    {
      try
      {
        mCachedContainerObjectName  =
          getObjectNames().getContainerObjectName( getMBeanServer(), selfObjectName );
      }
      catch( InstanceNotFoundException e )
      {
          debug( ExceptionUtil.getStackTrace( e ) );
        throw new RuntimeException( e );
      }
    }

    return( mCachedContainerObjectName );
  }

  /**
    Use the ObjectName with which this MBean was registered in combination with
    its j2eeType and its parent keys to determine the ObjectName <i>pattern</i>
    that uniquely identifies it.
  */
    public final ObjectName
  getObjectNamePattern()
  {
    final ObjectName  selfObjectName  = getObjectName();
    final Set<String>  requiredKeys  = Util.getPatternKeys( getFullType() );
   
    final String    requiredProps  = JMXUtil.getProps( selfObjectName, requiredKeys, true );
    final ObjectName  pat  = Util.newObjectNamePattern( selfObjectName.getDomain(), requiredProps );
   
    return( pat );
  }
   
    public final Class
  getInterface()
  {
    return( mInterface );
  }
 
    public final String
  getInterfaceName()
  {
    return( getInterface().getName() );
  }
    public final String[]
  getAttributeNames()
  {
    return( GSetUtil.toStringArray( getAttributeInfos().keySet() ) );
  }
 
  /**
    An operation has not been implemented. Deal with appropriately.
  */
    protected final void
  unimplementedOperation( final String operation )
  {
      final String msg = "UNIMPLEMENTED OPERATION: " + operation + " in " + getObjectName();
   
    logInfo( msg );
   
    throw new UnsupportedOperationException( operation );
  }
 

  /**
    An Attribute has not been implemented.
  */
    protected final Object
  unimplementedAttribute( final String attrName )
  {
      final String msg = "UNIMPLEMENTED ATTRIBUTE: " + attrName + " in " + getObjectName();
    logInfo( msg );
       
    return( null );
  }
 
  /**
    The impossible has happened.
  */
    protected final void
  impossible( final Throwable t )
  {
    logSevere( "AMXImplBase.impossible: " + t.getMessage() );
    assert( false );
    throw new RuntimeException( t );
  }
 
 
    private Object
  convertToClass(
    final Object  value,
    final Class    theClass )
    throws Exception
  {
    Object  result  = value;
   
    if ( value instanceof String )
    {
      result  = ClassUtil.InstantiateFromString( theClass, (String)value );
    }
    else
    {
      getMBeanLogger().info( "convertToClass: don't know how to convert: " +
        value.getClass().getName() );
    }
   
    return( result );
  }
 
    /**
        Called every time an Attribute is obtained via delegateGetAttribute(), so
        make sure it's reasonably fast.
     */
    private Class<?>
  getAttributeClass( final String attributeName )
    throws ClassNotFoundException
  {
        final Map<String,Class> mappings    = ATTRIBUTE_CLASSES.get( getJ2EEType() );
       
        Class theClass = mappings.get( attributeName );
        // initialize only if the class is null and there isn't a mapping for to null
        if ( theClass == null && ! mappings.containsKey( attributeName ) )
        {
            // no need to synchronize; the Map is already so.
            // And if mappings were somehow 'put' twice, that's rare and of no importance
            final MBeanAttributeInfo[]  infos  = getMBeanInfo().getAttributes();
           
            // Map each Attribute to a Class
            for( int i = 0; i < infos.length; ++i )
            {
                final String attrName   = infos[ i ].getName();
                final Class c = ClassUtil.getClassFromName( infos[ i ].getType() );
                mappings.put( attrName, c );
            }
           
            theClass    = mappings.get( attributeName );
    }
       
    return( theClass );
  }
 
  /**
  */
    protected  Object
  delegateGetAttribute( final String name )
    throws Exception
  {
      assert( name != null );
      final Delegate  delegate    = getDelegate();
      assert( delegate != null );
     
    final Object  value  = delegate.getAttribute( name );
   
    Object result  = value;
   
    if ( value != null )
    {
      Class<?>  attrClass  = getAttributeClass( name );
     
      if ( attrClass != null )
      {
        if ( ClassUtil.IsPrimitiveClass( attrClass ) )
        {
          attrClass  = ClassUtil.PrimitiveClassToObjectClass( attrClass );
        }
         
        if ( ! attrClass.isAssignableFrom( value.getClass() ) )
        {
            try
            {
              result  = convertToClass( value, attrClass );
          }
          catch( Exception e )
          {
              // OK, there are a few exceptions
              result  = value;
          }
        }
      }
      else
      {
        getMBeanLogger().warning( "AMXImplBase.delegateGetAttribute: " +
          "Can't find class for attribute: " + name + "=" + value +
          " in object " + getObjectName() );
               
                // add a null mapping
                ATTRIBUTE_CLASSES.get( getJ2EEType() ).put( name, null );
      }
    }
   
    return( result );
  }
 
    protected  Object
  delegateGetAttributeNoThrow( String name )
  {
    try
    {
      final Object  value  = delegateGetAttribute( name );
     
      return( value );
    }
    catch( Exception e )
    {
      throw new RuntimeException( e );
    }
  }
 
    protected void
  delegateSetAttribute(
    final String  name,
    final Object  value  )
    throws AttributeNotFoundException, InvalidAttributeValueException
  {
    getDelegate().setAttribute( new Attribute( name, value ) );
  }
 
    protected void
  delegateSetAttributeNoThrow( String name, Object value  )
  {
    try
    {
      delegateSetAttribute( name, value );
    }
    catch( JMException e )
    {
        debug( ExceptionUtil.toString( e ) );
      throw new RuntimeException( e );
    }
    catch( RuntimeException ee )
    {
        debug( ExceptionUtil.toString( ee ) );
      throw ee;
    }
  }
 
 
 
    protected Object
  getAttributeNoThrow( String name )
  {
    Object  result  = null;
   
    try
    {
      result  = getAttribute( name );
    }
    catch( Exception e )
    {
      throw new RuntimeException( new ThrowableMapper( e ).map() );
    }
    return( result );
  }
 
    protected synchronized Map<String,MBeanAttributeInfo>
  getAttributeInfos()
  {
    if ( mAttributeInfos == null || ! getMBeanInfoIsInvariant() )
    {
      mAttributeInfos  = JMXUtil.attributeInfosToMap( getMBeanInfo().getAttributes() );
    }
   
    return( mAttributeInfos );
  }
 
  /**
    Subclasses may need to force a refresh.
   */
    protected void
  clearAttributeInfos()
  {
    mAttributeInfos  = null;
  }
 
    protected boolean
  isLegalAttribute( final String name )
  {
    return( getAttributeInfos().keySet().contains( name ) );
  }
 
    protected MBeanAttributeInfo
  getAttributeInfo( final String name )
  {
    return( (MBeanAttributeInfo)getAttributeInfos().get( name ) );
  }
 
    protected boolean
  isReadOnlyAttribute( final String name )
  {
    return( ! getAttributeInfo( name ).isWritable() );
  }
 
 
    public Logger
  getLogger()
  {
    return( getMBeanLogger() );
  }
 
 
        protected void
    checkAttributeSupportedInBuild( final String attributeName )
    {
    }
   
        protected void
    checkOperationSupportedInBuild(
        final String operationName,
    Object[]   args,
    String[]   types)
    {
    }

  /**
    Get an Attribute value, first by looking for a getter method
    of the correct name and signature, then by looking for a delegate,
    and finally by calling getAttributeManually(), which a subclass
    is expected to override.
   
    @param name  name of the Attribute
    @return value of the Attribute
  */
    public Object
  getAttribute( final String name )
    throws AttributeNotFoundException
  {
    mCoverage.attributeWasRead( name );
   
    Object  result  = null;
   
    checkAttributeSupportedInBuild( name );
   
    if ( ! isLegalAttribute( name ) )
    {
        mCoverage.attributeGetFailure( name );
       
      debug( "getAttribute: unknown Attribute " + name + ", legal Attributes are: " +
        toString( getAttributeInfos().keySet() ) );
      throw new AttributeNotFoundException( name );
    }
   
    try
    {
      result  = getAttributeInternal( name );
    }
    catch( AttributeNotFoundException e)
    {
        mCoverage.attributeGetFailure( name );
      throw e;
    }
    catch( Exception e )
    {
        mCoverage.attributeGetFailure( name );
      throw new AttributeNotFoundException( name );
    }
   
    return( result );
  }
 
    protected Object
  getAttributeInternal( String name )
    throws AttributeNotFoundException,
        ReflectionException, MBeanException
  {
    Object  result  = null;
    boolean  handleManually  = false;
   
    // see if a getter exists
    final Method m  = findGetter( name );
    if ( m != null )
    {
      result  = getAttributeByMethod( name, m );
      debug( "getAttribute: " + name + " CALLED GETTER: " + m + " = " + result);
      handleManually  = false;
    }
    else if ( haveDelegate() )
    {
      trace( "getAttribute: " + name + " HAVE DELEGATE " );
       
      if ( getDelegate().supportsAttribute( name ) )
      {
        trace( "getAttribute: " + name + " CALLING DELEGATE " );
        try
        {
          result  = delegateGetAttribute( name );
        }
        catch( Exception e )
        {
          trace( "getAttribute: DELEGATE claims support, but fails: " + name  );
          handleManually  = true;
        }
      }
      else
      {
        trace( "getAttribute: " + name + " DELEGATE DOES NOT SUPPORT " );
        handleManually  = true;
      }
    }
    else
    {
      handleManually  = true;
    }
   
    if ( handleManually )
    {
      trace( "getAttribute: handle manually: " + name );
      try
      {
        result  = getAttributeManually( name );
      }
      catch( AttributeNotFoundException e )
      {
        trace( "getAttribute: " + name + " NOT FOUND " );
        throw e;
      }
    }
   
    return( result );
  }
 
  /**
    Bulk get.  Note that is is important for this implementation to
    call getAttribute() for each name so that each may be processed
    appropriately; some Attributes may be in this MBean itself, and some
    may reside in a {@link Delegate}.
   
    @param names  array of Attribute names
    @return AttributeList of Attributes successfully fetched
  */
    public AttributeList
  getAttributes( String[] names )
  {
    trace( "AMXImplBase.getAttributes: " + SmartStringifier.toString( names ) );
    //trace( "AMXImplBase.getAttributes: delegate class = " + getDelegate().getClass().getName() );
   
    final AttributeList  attrs  = new AttributeList();
   
    for( int i = 0; i < names.length; ++i )
    {
      try
      {
        trace( "%%% calling getAttribute: " + names[ i ] + " on " + getObjectName() );
        final Object value  = getAttribute( names[ i ] );
        attrs.add( new Attribute( names[ i ], value ) );
      }
      catch( Exception e )
      {
        trace( "### AttributeNotFoundException: " + names[ i ] );
        // ignore, as per spec
      }
    }
    return( attrs );
  }
 
 
    private final void
  rethrowAttributeNotFound(
    final Throwable t,
    final String  attrName )
    throws AttributeNotFoundException
  {
    final Throwable rootCause  = ExceptionUtil.getRootCause( t );
    if ( rootCause instanceof AttributeNotFoundException )
    {
      throw (AttributeNotFoundException)rootCause;
    }
   
    final String msg = "Attribute not found: " + StringUtil.quote(attrName) + " [" + rootCause.getMessage() + "]";;
    throw new AttributeNotFoundException( msg );
  }
   
 
  /**
    Set an Attribute by invoking the supplied method.
  */
    protected Object
  getAttributeByMethod( final String attrName, final Method m)
    throws AttributeNotFoundException
  {
    Object  result  = null;
   
    try
    {
      //trace( "getAttributeByMethod: " + attrName  );
      result  = m.invoke( this, (Object[])null );
    }
    catch( InvocationTargetException e )
    {
      trace( "InvocationTargetException: " + attrName + " by " + m );
      rethrowAttributeNotFound( e, attrName );
    }
    catch( IllegalAccessException e )
    {
      trace( "ILLEGAL ACCESS TO: " + attrName + " by " + m );
      rethrowAttributeNotFound( e, attrName );
    }
    catch( Exception e )
    {
      trace( "Exception: " + attrName + " by " + m );
      rethrowAttributeNotFound( e, attrName );
    }
   
    return( result );
  }
 
    protected void
  setAttributeByMethod( final Attribute attr, final Method m)
    throws AttributeNotFoundException, InvalidAttributeValueException
  {
    try
    {
      // trace( "setAttributeByMethod: " + m );
      m.invoke( this, new Object[] { attr.getValue() } );
    }
    catch( InvocationTargetException e )
    {
      trace( "setAttributeByMethod: InvocationTargetException: " + e );
   
      final Throwable t  = ExceptionUtil.getRootCause( e );
      if ( t instanceof InvalidAttributeValueException)
      {
        throw (InvalidAttributeValueException)t;
      }

      rethrowAttributeNotFound( e, attr.getName() );
    }
    catch( IllegalAccessException e )
    {
      trace( "setAttributeByMethod: IllegalAccessException: " + e );
      rethrowAttributeNotFound( e, attr.getName()  );
    }
    catch( Exception e )
    {
      trace( "setAttributeByMethod: Exception: " + e );
      rethrowAttributeNotFound( e, attr.getName()  );
    }
  }
 
  /**
    Subclasses should override this to handle getAttribute( attrName ). It will
    be called if no appropriate getter is found.
    <p>
    It generically handles all <Abc>ObjectName() and <Abc>ObjectNameMap
    Attributes.
  */
    protected Object
  getAttributeManually( final String attributeName )
    throws AttributeNotFoundException
  {
      Object  result  = null;
     
      AMXDebug.getInstance().getOutput( "getAttributeManually" ).println(
          attributeName + " on " + getObjectName() );
         
      if ( isObjectNameAttribute( attributeName ) )
      {
          final String    j2eeType    = attributeNameToJ2EEType( attributeName );
          debug( "getAttributeManually: attributeName " + attributeName + " => j2eeType " + j2eeType );
          result  = getContaineeObjectName( j2eeType );
      }
      else if ( isObjectNameMapAttribute( attributeName  ) )
      {
          final String    j2eeType    = attributeNameToJ2EEType( attributeName );
          debug( "invokeManually:  attributeName " + attributeName + " => j2eeType " + j2eeType );
          result  = getContaineeObjectNameMap( j2eeType );
      }
    else
    {
        throw new AttributeNotFoundException( attributeName );
    }
    return result;
  }


  /**
    Subclasses should override this to handle setAttribute( attr ). It will
    be called if no appropriate setter is found.
  */
    protected void
  setAttributeManually( final Attribute attr )
    throws AttributeNotFoundException, InvalidAttributeValueException
  {
    throw new AttributeNotFoundException( attr.getName() );
  }

    public void
  setAttribute( final Attribute attr )
    throws AttributeNotFoundException, InvalidAttributeValueException
  {
      final String    name    = attr.getName();
     
    mCoverage.attributeWasWritten( name );
       
    if ( isReadOnlyAttribute( name ) )
    {
        mCoverage.attributeSetFailure( name );
      throw new IllegalArgumentException( "Attribute is read-only: " + attr.getName() );
    }
   
    boolean failure = true;
   
    try
    {
      setAttributeInternal( attr );
      failure = false;
    }
    catch( AttributeNotFoundException e )
    {
      throw e;
    }
    catch( InvalidAttributeValueException e )
    {
      throw e;
    }
    catch( RuntimeException e )
    {
      throw (RuntimeException)e;
    }
    catch( Exception e )
    {
      throw new RuntimeException( e );
    }
    finally
    {
        if ( failure )
        {
            mCoverage.attributeSetFailure( name );
        }
    }
  }
 
 
  /**
    Set an Attribute value, first by looking for a setter method
    of the correct name and signature, then by looking for a delegate,
    and finally by calling setAttributeManually(), which a subclass
    is expected to override.
   
    @param attr  the Attribute
  */
    protected void
  setAttributeInternal( final Attribute attr )
    throws AttributeNotFoundException, InvalidAttributeValueException,
        ReflectionException, MBeanException
  {
    trace( "setAttribute: " + attr.getName() + " = " + attr.getValue() );
   
    boolean      handleManually  = false;
    final Method  m  = findSetter( attr );
   
    final boolean  shouldEmitNotifications  = shouldEmitNotifications();
    // note that this will fail if an Attribute is write-only
    final Object  oldValue  = shouldEmitNotifications ?
            getAttribute( attr.getName() ) : null;
   
    if ( m != null )
    {
      setAttributeByMethod( attr, m );
    }
    else if ( haveDelegate() )
    {
      if ( getDelegate().supportsAttribute( attr.getName() ) )
      {
        try
        {
          getDelegate().setAttribute( attr );
        }
        catch( JMException e )
        {
          handleManually  = true;
        }
      }
      else
      {
        handleManually  = true;
      }
    }
    else
    {
      handleManually  = true;
    }
   
    if ( handleManually )
    {
      setAttributeManually( attr );
    }
   
    if ( shouldEmitNotifications )
    {
      final String  attrType  = getAttributeType( attr.getName() );
     
      sendAttributeChangeNotification( "", attrType, oldValue, attr );
    }
  }
 
    protected String
  getAttributeType( final String attrName )
  {
    final MBeanAttributeInfo  info  =
      JMXUtil.getMBeanAttributeInfo( getMBeanInfo(), attrName );
   
    return( info.getType() );
  }
 
    protected synchronized void
  sendAttributeChangeNotification(
    final String  msg,
    final String  attrType,
    final Object  oldValue,
    final Attribute  newAttr)
  {
    final AttributeChangeNotificationBuilder builder  =
    (AttributeChangeNotificationBuilder)
      getNotificationBuilder( AttributeChangeNotification.ATTRIBUTE_CHANGE );
   
    final AttributeChangeNotification  n  =
      builder.buildAttributeChange( msg, newAttr.getName(), attrType, oldValue, newAttr.getValue() );
     
    sendNotification( n );
  }
 
  /**
    Bulk get.  Note that is is important for this implementation to
    call setAttribute() for each name so that each may be processed
    appropriately; some Attributes may be in this MBean itself, and some
    may reside in a {@link Delegate}.
   
    @param attrs  attributes to be set
    @return AttributeList containing Attributes successfully set
  */
    public AttributeList
  setAttributes( final AttributeList attrs )
  {
    trace( "AMXImplBase.setAttributes = " + SmartStringifier.toString( attrs ) );
   
    final int      numAttrs  = attrs.size();
    final AttributeList  successList  = new AttributeList();
   
    for( int i = 0; i < numAttrs; ++i )
    {
      final Attribute attr  = (Attribute)attrs.get( i );
      trace( "setAttributes: " + attr.getName() );
      try
      {
        setAttribute( attr );
       
        successList.add( attr );
      }
      catch( Exception e )
      {
        // ignore, as per spec
      }
    }
    return( successList );
  }
 
 
  /**
    Find a method.
   
    @param methodName
    @param sig
    @return a Method or null if not found
  */
    protected final Method
  findMethod( String methodName, final Class[] sig )
  {
    return( ClassUtil.findMethod( this.getClass(), methodName, sig ) );
  }
 
  /**
    Find a getXXX() method that matches the Attribute
   
    @param name the name to which "get" will be prepended
    @return a Method or null if not found
  */
  static private final Class[]  GETTER_SIG  = new Class[0];
    protected final Method
  findGetter( String name )
  {
    final String  methodName  = GET + name;
   
    Method  m  = findMethod( methodName, GETTER_SIG );
    if ( m == null )
    {
      m  = findMethod( "is" + name, GETTER_SIG );
    }
   
    return( m );
  }
 
  /**
    Find a setXXX() method that matches the Attribute.
   
    @param attr  an Attribute for which a matching setter should be located
    @return a Method or null if not found
  */
    protected final Method
  findSetter( final Attribute attr )
  {
    final Object  value    = attr.getValue();
    Class    valueClass  = null;
    if ( value == null )
    {
        final MBeanAttributeInfo    info    = getAttributeInfos().get( attr.getName() );
        if ( info != null )
        {
            try
            {
                valueClass  = ClassUtil.getClassFromName( info.getType() );
            }
            catch( Exception e )
            {
            }
        }
    }
    else
    {
        valueClass  = value.getClass();
    }
   
    if ( valueClass == null )
    {
        return null;
    }
   
    final String  methodName  = SET + attr.getName();
    Class[]      sig      = new Class[]  { valueClass };
    Method      setter    = findMethod( methodName, sig );
   
    final Class  primitiveClass  = ClassUtil.ObjectClassToPrimitiveClass( valueClass );
    if ( setter == null && primitiveClass != valueClass )
    {
      //trace( "findSetter: retrying for primitive class: " + primitiveClass );
      // the Attribute value is always an object.  But it may be
      // that the setter takes a primitive type.  So for example,
      // the Attribute may contain a value of type Boolean, but the setter
      // may required type boolean
      sig[ 0 = primitiveClass;
      setter    = findMethod( methodName, sig );
    }
   
    return( setter );
  }

    protected static final String GET_PREFIX    = "get";
    protected static final String OBJECT_NAME_SUFFIX    = "ObjectName";
    protected static final String OBJECT_NAME_MAP_SUFFIX    = "ObjectNameMap";
   
        protected boolean
    operationNameMatches(
        final String operationName,
        final String prefix,
        final String suffix )
    {
        return operationName.startsWith( prefix ) &&
          operationName.endsWith( suffix );
    }
   
        protected boolean
    getterNameMatches(
        final String operationName,
        final String suffix )
    {
        return operationNameMatches( operationName, GET_PREFIX, suffix );
    }
   
        protected boolean
    isObjectNameGetter(
    final String   operationName,
    final Object[]  args,
    final String[]  types )
    {
        final int   numArgs = args == null ? 0 : args.length;
        return numArgs == 0 && isObjectNameGetter( operationName );
    }
   
       protected boolean
    isObjectNameGetter( final String operationName)
    {
        return getterNameMatches( operationName, OBJECT_NAME_SUFFIX );
    }
   
    private static final Set<String> NO_AUTO_GET = GSetUtil.newUnmodifiableStringSet(
            "ContainerObjectName",
            "MonitoringPeerObjectName",
            "ObjectName",
            "ConfigPeerObjectName",
            "ServerObjectName" );
          
       protected boolean
    isObjectNameAttribute(final String attributeName)
    {
        return attributeName.endsWith( OBJECT_NAME_SUFFIX ) &&
            ! NO_AUTO_GET.contains( attributeName );
    }
   
        protected boolean
    isObjectNameMapAttribute(final String attributeName)
    {
        return attributeName.endsWith( OBJECT_NAME_MAP_SUFFIX ) &&
            ! NO_AUTO_GET.contains( attributeName );
    }
   
      protected String
  attributeNameToJ2EEType( final String attributeName )
    {
        String  j2eeType   = null;
       
        if ( isObjectNameAttribute( attributeName ) )
        {
            j2eeType   = StringUtil.stripSuffix( attributeName, OBJECT_NAME_SUFFIX);
        }
        else if ( isObjectNameMapAttribute( attributeName ) )
        {
            j2eeType   = StringUtil.stripSuffix( attributeName, OBJECT_NAME_MAP_SUFFIX);
        }
       
        if ( ! J2EETypes.ALL_STD.contains( j2eeType ) )
        {
            j2eeType    = XTypes.PREFIX + j2eeType;
        }
           
        return j2eeType;
    }

        protected boolean
    isObjectNameMapGetter(
    final String     operationName,
    final Object[]  args,
    final String[]  types )
    {
        final int   numArgs = args == null ? 0 : args.length;
        return numArgs == 0 && isObjectNameMapGetter( operationName );
    }
   
        protected boolean
    isObjectNameMapGetter( final String operationName)
    {
        return getterNameMatches( operationName, OBJECT_NAME_MAP_SUFFIX );
    }
   
      protected String
  j2eeTypeToSimpleClassname( final String j2eeType )
    {
        return StringUtil.stripPrefix( j2eeType, XTypes.PREFIX );
    }
   
   
      protected String
  operationNameToJ2EEType( final String operationName )
    {
        String  j2eeType   = null;
       
        if ( isObjectNameGetter( operationName ) )
        {
            j2eeType   =
                StringUtil.stripPrefixAndSuffix( operationName, GET_PREFIX, OBJECT_NAME_SUFFIX);
        }
        else if ( isObjectNameMapGetter( operationName ) )
        {
            j2eeType   =
                StringUtil.stripPrefixAndSuffix( operationName, GET_PREFIX, OBJECT_NAME_MAP_SUFFIX);
        }
       
        if ( ! J2EETypes.ALL_STD.contains( j2eeType ) )
        {
            j2eeType    = XTypes.PREFIX + j2eeType;
        }
           
        return j2eeType;
    }
   
     /**
        An operation is being invoked manually, meaning that it is missing as a method.
        invokeManually() will be called only if no appropriate Method is found.
        <p>
    Subclasses may override this to handle invoke(), though usually it's just
    easier to write the appropriate method directly, which will be found and called
    if present.
     */
      protected Object
  invokeManually(
    String     operationName,
    Object[]  args,
    String[]  types )
    throws MBeanException, ReflectionException, NoSuchMethodException, AttributeNotFoundException
  {
      final int   numArgs = args == null ? 0 : args.length;
     
      Object  result  = null;
     
      boolean handled = false;
     
      final boolean   ALLOW_GETTERS   = true;
     
      if ( ALLOW_GETTERS &&
          numArgs == 0 &&
          operationName.startsWith( GET )  )
      {
          final String    attributeName   = StringUtil.stripPrefix( operationName, GET );
         
          if ( getAttributeInfos().get( attributeName ) != null )
          {
              result  = getAttribute( attributeName );
              handled = true;
          }
      }
      else if ( operationName.equals( "toString" ) && numArgs == 0 )
      {
          result  = toString();
      }
     
      if ( ! handled )
      {
          debugMethod( operationName, args );
        throw new NoSuchMethodException( "no operation " + operationName +
            toString( types ) + " in " + getObjectName() );
    }
   
    return result;
  }

 
    protected void
  handleException( final Exception e )
    throws MBeanException, ReflectionException
  {
    final ThrowableMapper  mapper  = new ThrowableMapper( e );
    final Throwable      mapped  = mapper.map();
   
    if ( mapped instanceof ReflectionException )
    {
      throw (ReflectionException)mapped;
    }
    else if ( mapped instanceof MBeanException )
    {
      throw (MBeanException)mapped;
    }
    else if ( ! (mapped instanceof Exception) )
    {
      // wrap the Throwable in an Exception
      final Exception  wrapper  = new Exception( mapped );
      throw new MBeanException( wrapper );
    }
    else
    {
      throw new MBeanException( (Exception)mapped );
    }
  }
 
    protected void
  handleGetAttributeException( final Exception e )
    throws MBeanException, ReflectionException, AttributeNotFoundException
  {
    if ( e instanceof AttributeNotFoundException )
    {
      // AttributeNotFoundException can never contain anything non-standard
      throw (AttributeNotFoundException)e;
    }
    else
    {
      handleException( e );
    }
  }
 
    protected void
  handleInvokeThrowable( final Exception e )
    throws MBeanException, ReflectionException
  {
    handleException( e );
  }
 

  /**
    Generic handling of invoke(). Converts the types[] to a Class[], then attempts
    to locate a suitable Method.  If a suitable Method is found, it is invoked.
    If not found the subclass is expected to handle it in invokeManually();
  */
    public final Object
  invoke(
    String     operationName,
    Object[]  args,
    String[]  types )
    throws MBeanException, ReflectionException
  {
      mCoverage.operationWasInvoked( operationName, types );
     
    Object  result  = null;
    boolean  unimplemented  = false;
   
    try
    {
        checkOperationSupportedInBuild( operationName, args, types );
   
      final Class[]  signature  = ClassUtil.signatureFromClassnames( types );
      final Method  m  = findMethod( operationName, signature );
      if ( m != null )
      {
        debugMethod( "invoking method: " + operationName, args );
        result  = m.invoke( this, args );
      }
      else if ( haveDelegate() &&
        getDelegate().supportsOperation( operationName, args, types ) )
      {
        debug( "AMXImplBase.invoke: calling delegate for ", operationName );
        result  = getDelegate().invoke( operationName, args, types );

      }
      else
      {
        result  = invokeManually( operationName, args, types );
      }
    }
    catch( Exception e )
    {
          mCoverage.operationFailed( operationName, types );
        debug( ExceptionUtil.toString( e ) );
      handleInvokeThrowable( e );
    }
   
    return( result );
  }
 
    protected TypeInfo
  getTypeInfo( final String j2eeType )
  {
    return( TypeInfos.getInstance().getInfo( j2eeType ) );
  }
 
    protected String
  getSelfJ2EEType()
  {
    return( mJ2EEType );
  }
 
    protected String
  getSelfName()
  {
    return( Util.getName( getObjectName() ) );
  }
 
    protected TypeInfo
  getSelfTypeInfo()
  {
    return( getTypeInfo( getSelfJ2EEType() ) );
  }
 
    private boolean
  isContainer()
  {
    return( Container.class.isAssignableFrom( getInterface() ) );
  }
 
    protected Set<String>
  getChildJ2EETypes()
  {
    return( getSelfTypeInfo().getChildJ2EETypes() );
  }
 
  protected final static Set<String>  EMPTY_STRING_SET    = Collections.emptySet();

  /**
    Certain special cases are present (eg standalone ejb/web modules) where
    a parent as described by the FullType (TypeInfos) does not exist.
    In this case, the actual parent must contain these items.
   */
    protected Set<String>
  getFauxChildTypes()
  {
    return( EMPTY_STRING_SET );
  }
 
    public Set<String>
  getContaineeJ2EETypes()
  {
    if ( ! isContainer() )
    {
      final Exception  e  =
        new AttributeNotFoundException( "ContaineeJ2EETypes" );
     
      throw new RuntimeException( e );
    }
   
    final Set<String>  fauxTypes    = getFauxChildTypes();
    final Set<String>  officialTypes  = getSelfTypeInfo().getContaineeJ2EETypes();

    return( fauxTypes.size() == 0 ? officialTypes : GSetUtil.newSet( fauxTypes, officialTypes ) );
  }
 
 
    protected String
  getChildJ2EEType()
  {
    final Set<String>  types  = getChildJ2EETypes();
    if ( types.size() != 1 )
    {
      debug( "getChildJ2EEType failing on: ", getObjectName(),
        ", got this many children: ", types.size() );
      throw new IllegalArgumentException(
            SmartStringifier.toString( types ) );
    }
   
    return( GSetUtil.getSingleton( types ) );
  }
 
 
  /**
    Our container is the one that actually holds the MBeans we
    created. Ask it for the ObjectName.
   */
    protected ObjectName
  getProgenyObjectName(
    final String  j2eeType,
    final String  name )
  {
    final Container  container  = getContainer();
   
    final AMX  containee  = container.getContainee( j2eeType, name );
    if ( containee == null )
    {
      throw new IllegalArgumentException( "Not containee found: " + j2eeType + "=" + name );
    }
   
    return( Util.getObjectName( containee ) );
  }
 
    protected boolean
  isOfflineCapable( final TypeInfo childInfo )
  {
      final Class c   = childInfo.getInterface();
     
      return  AMXConfig.class.isAssignableFrom( c ) ||
              Utility.class.isAssignableFrom( c ) ||
              c == DomainRoot.class;
  }
 
      protected boolean
  getOffline()
  {
      return BootUtil.getInstance().getOffline();
  }
 
  /**
    Register a child MBean which is a manager.
  */
    protected void
  registerSelfMgrChild( final TypeInfo  childInfo )
    throws JMException, InstantiationException, IllegalAccessException
  {
    final String  childJ2EEType  = childInfo.getJ2EEType( );
   
      if ( ( ! getOffline() ) || isOfflineCapable( childInfo ) )
      {
        final Class    implClass  = childInfo.getImplClass();
       
        final ObjectName  childObjectName  =
          getObjectNames().buildContaineeObjectName( getObjectName(), getFullType(), childJ2EEType );
        if ( ! getMBeanServer().isRegistered ( childObjectName ) )
        {
            final Object  impl  = implClass.newInstance();
       
            registerMBean( impl, childObjectName );
        }
      }
      else
      {
          debug( "Not loading child in offline mode: " + childJ2EEType );
      }
  }

    protected void
  unregisterSelfMgrChildren()
  {
    final TypeInfo    selfInfo    =  getSelfTypeInfo();
    final Set<String>  childTypesSet  =  selfInfo.getContaineeJ2EETypes();
    final String[]    childTypes    =  GSetUtil.toStringArray( childTypesSet );
    final MBeanServer  mbeanServer    =  getMBeanServer();
    for( int i = 0; i < childTypes.length; ++i )
    {
      final String    childType  = childTypes[ i ];
      debug( "unregisterSelfMgrChildren: processing type: ", childType);

      final TypeInfo  childInfo  = getTypeInfo( childType );
 
      final Class  childInterface  = childInfo.getInterface();

      if (   //isConfigMgrMBean( childInterface ) ||
          isSingletonMBean( childInterface ) ||
          isUtilityMBean( childInterface )
        )
      {
        final ObjectName containeeObjectName =
          getContaineeObjectName( childType );
          if ( containeeObjectName != null )
          {
            try
            {
              mbeanServer.unregisterMBean( containeeObjectName );
              debug( "unregisterSelfMgrChildren: ", containeeObjectName,
                " is unregistered" );
            }
            catch ( InstanceNotFoundException infe )
            {
              logWarning( "unregisterSelfMgrChildren: " + infe.getMessage() );
            }
            catch ( Exception e )
            {
              logSevere( "unregisterSelfMgrChildren: " +
                ExceptionUtil.getRootCause(e).getMessage() );
            }
            }
      }
      else
      {
        debug( "unregisterSelfMgrChildren: skipping: ", childInterface.getName() );
      }
    }
  }
 
    protected void
  registerSelfMgrChildren( )
  {
    final TypeInfo    selfInfo    = getSelfTypeInfo();
    final Set<String> childTypesSet  =  selfInfo.getContaineeJ2EETypes();

    debug( "registerSelfMgrChildren for ", getSelfJ2EEType(), ": ", toString( childTypesSet ) );
   
    if ( childTypesSet.size() != 0 )
    {
      debug( "registerSelfMgrChildren: child types = ", toString( childTypesSet ) );
    }
    else
    {
      debug( "no child types for: ", quote( getObjectName() ) );
    }
   
    final String[]  childTypes  = GSetUtil.toStringArray( childTypesSet );
    for( int i = 0; i < childTypes.length; ++i )
    {
      final String    childType  = childTypes[ i ];
      debug( "registerSelfMgrChildren: processing type: ", childType);
     
      final TypeInfo  childInfo  = getTypeInfo( childType );
 
      final Class  childInterface  = childInfo.getInterface();
   
      if (   isSingletonMBean( childInterface ) ||
          isUtilityMBean( childInterface )
          )
      {
        try
        {
          registerSelfMgrChild( childInfo );
        }
        catch( InstantiationException e )
        {
          trace( "InstantiationException for child of type: " + childInfo.getJ2EEType() +
            " = " + e.getMessage() );
          e.printStackTrace();
         
          final Throwable  t  = ExceptionUtil.getRootCause( e );
          if ( t != e && t != null )
          {
            trace( "InstantiationException: root cause msg =" + t.getMessage() );
            trace( ExceptionUtil.getStackTrace( t ) );
          }
          else
          {
            trace( ExceptionUtil.getStackTraceExceptionUtil.getRootCause( e ) ));
          }
        }
        catch( Exception e )
        {
          trace( "Can't create child, info = " + childInfo + "\n" + e + "\n\n" );
          debug( ExceptionUtil.getStackTrace( e ) );
        }
      }
      else
      {
        trace( "registerSelfMgrChildren: skipping: " + childInterface.getName() );
      }
    }
  }
 
  /**
    Register special containee MBeans.
    Usually this should only be done for child MBeans
    that otherwise would not come into existence.
  */
    protected final void
  registerSpecialContainees()
  {
    registerSelfMgrChildren( );
    registerMisc();
  }
 
    protected void
  registerMisc()
  {
    // nothing by default
  }
 
    protected void
  preDeregisterHook()
  {
      unregisterMisc();
    unregisterSelfMgrChildren( );
  }
 
    protected void
  postDeregisterHook()
  {
  }
 
    protected void
  unregisterMisc()
  {
    // nothing by default
  }
 
 
 
  /**
    Classes of MBeans should override this.
  */
    public String
  getGroup()
  {
    return( GROUP_OTHER );
  }
 
    public String
  getName()
  {
    return( Util.getName( getObjectName() ) );
  }
 
    public String
  getJ2EEType()
  {
    return( Util.getJ2EEType( getObjectName() ) );
  }
 
  /**
    @param partialSelfObjectName the ObjectName, lacking the type property
    @return the fully qualified type as required by AMX.FULL_TYPE
   */
    protected static String
  getFullType( final ObjectName partialSelfObjectName )
  {
    final String  selfJ2EEType  = Util.getJ2EEType( partialSelfObjectName );
   
    final TypeInfos  typeInfos  = TypeInfos.getInstance();
    final TypeInfo  info  = typeInfos.getInfo( selfJ2EEType );
   
    final String[]  chain  = typeInfos.getJ2EETypeChain( partialSelfObjectName );
   
    final String  fullType  = ArrayStringifier.stringify( chain, "." );
   
    return( fullType );
  }
 
    public final String
  getFullType( )
  {
    assert( mFullType != null ) : "******************************************************";
    return( mFullType );
  }
 
 
  /**
    O the ObjectName by adding to it:
    <ul>
    <li>adding AMX.FULL_TYPE_KEY property</li>
    <li></li>
    </ul>
  */
    protected  ObjectName
  preRegisterModifyName(
    final MBeanServer  server,
    final ObjectName  nameIn )
  {
    mFullType    = getFullType( nameIn );
   
    // now ensure that certain singleton ancestors have a name
    String  ancestorProps  = "";
    final String[]  fullTypeArray  = Util.getTypeArray( mFullType );
    for( int i = 0; i < fullTypeArray.length - 1; ++i )
    {
      final String  key  = fullTypeArray[ i ];
     
      if ( nameIn.getKeyProperty( key ) == null )
      {
        final String  name  = ObjectNames.getSingletonName( key );
        final String  prop  = Util.makeProp( key, name );
       
        ancestorProps  = Util.concatenateProps( ancestorProps, prop );
      }
    }
   
    final String  props  =  ancestorProps;
   
    final String  newName  =
      Util.concatenateProps( nameIn.toString(), props );
   
    final ObjectName  nameOut  = Util.newObjectName( newName );

    return( nameOut );
  }
 
    /*
        Note that this method is 'synchronized'--to force visibility of all fields it affects.
        Since it's called only once (per instance) for an MBean Registration, it has no performance
        impact on later use, but guarantees visibility of all non-final instance variables.
    */
    public final synchronized ObjectName
  preRegister(
    final MBeanServer  server,
    final ObjectName  nameIn)
    throws Exception
  {
    final ObjectName  nameFromSuper  = super.preRegister( server, nameIn );

    mConnectionSource  = new MBeanServerConnectionSource( server );
   
    if ( mSuppliedDelegate != null )
    {
      mDelegate  = wrapSuppliedDelegate( mSuppliedDelegate );
    }
       
    mSelfObjectName  = preRegisterModifyName( server, nameFromSuper );
   
    if ( getAMXDebug() )
    {
        implCheck();
    }
   
    mSelfObjectName = preRegisterHook( mSelfObjectName );
   
    registerSpecialContainees();
   
    preRegisterDone();
    return( mSelfObjectName );
  }
   
    /**
        This is an opportunity for a subclass to do initialization
        and optionally to modify the ObjectName one last time.
     */
        protected ObjectName
    preRegisterHook( final ObjectName selfObjectName)
      throws Exception
    {
        // subclass may do something
        return selfObjectName;
    }
   
        protected void
    preRegisterDone()
        throws Exception
    {
    debug( "AMXImplBase.preRegister() done for: ", getObjectName() );
   
    mCoverage.setMBeanInfo( getMBeanInfo() );
    }
 
 
  static private final Set<String>  AMX_NATIVE_ATTRIBUTES    =
      Collections.unmodifiableSet( GSetUtil.newSet(
          new String[]
          {
              "Name",
              "ObjectName", "FullType", "Group", "J2EEType", "InterfaceName",
              "MBeanEmitLogNotifications", "MBeanInfoIsInvariant", "MBeanLoggerName",
              "AttributeNames", "MBeanLogLevel",
              "WhatsNotDone",
              "DomainRootObjectName",
              "ContainerObjectName", "ContaineeJ2EETypes", "ContaineeObjectNameSet",
              "NotificationInfo",
              "Properties", "PropertyNames",
              "SystemProperties", "SystemPropertyNames",
              "OpenStats", "StatsInterfaceName", "StatisticNames", "Stats",
              "ConfigProvider",
          }));
     
 
  /**
    An optimization to not bother with all the names that are
    native to AMX and not mapped to a Delegate Attribute.
   */
      private Set<String>
    getMyAttributeMappingCandidates()
    {
    final Set<String>    candidates    = GSetUtil.newSet( getAttributeNames() );
   
    candidates.removeAll( AMX_NATIVE_ATTRIBUTES );
   
    // now remove all Attributes that end appropriately
    final Set<String>   toRemove    = new HashSet<String>();
    for( final String name : candidates )
    {
        if ( name.endsWith( "ObjectNameMap" ) ||
             name.endsWith( "ObjectNameSet" ) ||
             name.endsWith( "ObjectName" ) ||
             name.endsWith( "Stats" )
            )
        {
            toRemove.add( name );
        }
    }
   
    candidates.removeAll( toRemove );
   
    return candidates;
    }

      protected final AMXAttributeNameMapper
  createAttributeNameMapper()
  {
    final AMXAttributeNameMapper   mapper  = new AMXAttributeNameMapperImpl();
    //mapper.setDebugOutput( getDebugOutput() );
   
    final Set<String>    myAttributeNames    = getMyAttributeMappingCandidates();
   
    final String[]    delegateAttributeNames  =
        JMXUtil.getAttributeNames( mSuppliedDelegate.getMBeanInfo().getAttributes() );
   
      mapper.matchNames(
          GSetUtil.toStringArray( myAttributeNames ), delegateAttributeNames );
    addCustomMappings( mapper );
   
    if ( getAMXDebug() || false )
    {
        // this is stuff helpful when implementing; leave here
        // so it can be enabled
       
        final Set<String>   missingAttributeNames =
            GSetUtil.removeSet( myAttributeNames, mapper.getDerivedNames() );
        if ( missingAttributeNames.size() != 0 )
        {
            //handleMissingAttributeMappings( missingAttributeNames );
        }
   
        final Set<String>   missingOriginals  = mapper.getUnmappedOriginals();
        missingOriginals.remove( "name" )// special case, getName() always overides
        missingOriginals.remove( "Name" );
        if ( missingOriginals.size() != 0 )
        {
            handleMissingOriginals( missingOriginals );
        }
    }
   
    return mapper;
  }
 
  /**
      Mapping of Attributes names is done.  But some of our Attributes
      don't map to anything in the Delegate.
   */
      protected void
  handleMissingAttributeMappings( final Set<String> missing )
  {
    if ( missing.size() != 0 )
    {
        final String msg    = getJ2EEType() +
            ": AMX Attributes have no corresponding delegate Attribute: " +
            CollectionUtil.toString( missing, ", " );
           
          AMXDebug.getInstance().getOutput( "AMXImplBase.handleMissingAttributeMappings" ).println( msg );
        logInfo( msg );
        }
  }
 
  /**
      Mapping of Attributes names is done.  But there are still names in the
      Delegate which don't map to anything in this AMX MBean.  This may be OK;
      some delegates contain a bunch of extra stuff not used by AMX.
   */
      protected void
  handleMissingOriginals( final Set<String> missingOriginals )
  {
    if ( missingOriginals.size() != 0 )
    {
        final String msg    = getJ2EEType() +
            ": Delegate Attributes have no matching AMX Attribute: " +
            CollectionUtil.toString( missingOriginals, ", " ) +
            "--(this may or may not be an error; if necessary override handleMissingOriginals()";
       
          AMXDebug.getInstance().getOutput( "AMXImplBase.handleMissingOriginals" ).println( msg );
        logFine( msg );
        }
  }
 
 
  /**
    Subclasses may choose to override any Attribute names by adding custom mappings
    that can't be handled algorithmically.
    <p>
    <b>IMPORTANT: mappings for config delegates should use the same
    name as found in domain.xml, not the name found in the com.sun.appserv MBean.</b>
    This is because a switchover to using ConfigAPI directly will only know
    the names found in domain.xml; we don't want to maintain two sets of custom
    mappings.  The requisite mapping is handled internally, so even though the
    com.sun.appserv MBean might advertise "Id", using the domain.xml form "id"
    will work correctly.
    <p>
    Example:
    </pre>
    super.addCustomMappings( mapper );
    mapper.matchName( "MyName", "YourName", "your-name" );
    </pre>
   */
    protected void
  addCustomMappings( final AMXAttributeNameMapper mapper )
  {
  }
 
  /**
    Wrap the supplied delegate (if one was supplied) with a MappedDelegate
    which will be created by calling createAttributeNameMapper()
   */
    protected final Delegate
  wrapSuppliedDelegate( final Delegate delegate )
  {
    mAttributeNameMapper  = createAttributeNameMapper();
   
    final MappedDelegate result  = new MappedDelegate( mSuppliedDelegate, mAttributeNameMapper );
    result.setDebugOutput( getDebugOutput() );
   
    return( result );
  }
 
    protected void
  implCheck()
  {
    final boolean  isContainer  = isContainer();
    final String  j2eeType  = getSelfJ2EEType();
    final TypeInfo  selfInfo  = TypeInfos.getInstance().getInfo( j2eeType );
   
    final Set<String>  nonChildren  = selfInfo.getNonChildJ2EETypes();
    final Set<String>  children  = selfInfo.getChildJ2EETypes();
   
    if ( isContainer )
    {
      assert( nonChildren.size() != 0 || children.size() != 0 ) :
        "ERROR: is Container but contains no children or containees " + j2eeType;
    }
    else
    {
      assert( nonChildren.size() == 0 ) :
        "ERROR: not a Container: " + j2eeType + " but contains types: " + toString( nonChildren );
       
      assert( children.size() == 0 ) :
        "ERROR: not a Container: " + j2eeType + " but contains children: " + toString( children );
    }
   
      checkSuperfluousMethods();
  }
 
 
  private static final Set<String> NOT_SUPERFLUOUS =
      GSetUtil.newUnmodifiableStringSet(
          "getProxyFactory",
            "getDomainRootObjectName",
            "getQueryMgrObjectName",
            "getServerRootMonitorObjectName"
            );
           
   
    /**
        @return any non-superflous methods that are the exception to the default assumptions
     */
    protected Set<String>
  getNotSuperfluousMethods()
  {
      return NOT_SUPERFLUOUS;
  }
 
    /**
        @return all method names that appear superfluous
     */
    protected Set<String>
  getSuperfluousMethods()
  {
      final Set<String>   items   = new HashSet<String>();
     
      final Method[]  methods = this.getClass().getMethods();
      for( final Method m : methods )
      {
            if ( JMXUtil.isGetter( m ) )
            {
              final String    name    = m.getName();
         
                final String attributeName  = StringUtil.stripPrefix( name, GET );
                if ( isObjectNameAttribute( attributeName ) ||
                    isObjectNameMapAttribute( attributeName ) )
                {
                    items.add( name );
                }
            }
      }
     
      items.removeAll( NOT_SUPERFLUOUS );
     
      return items;
  }

    protected final void
  checkSuperfluousMethods()
  {
      final Set<String>   items = getSuperfluousMethods();
     
      items.removeAll( getNotSuperfluousMethods() );
     
      if ( items.size() != 0 )
      {
          final String    LINE_SEP    = System.getProperty( "line.separator" );
         
            final String msg    =
            "The following methods in " + getJ2EEType() +
            " are probably superfluous:" + LINE_SEP +
            CollectionUtil.toString( items, LINE_SEP ) + LINE_SEP;
         
          AMXDebug.getInstance().getOutput( "AMXImplBase.checkSuperfluousMethods" ).println( msg );
          logFine( msg );
      }
  }
 
    /*
        Note that this method is 'synchronized'--to force visibility of all fields it affects.
        Since it's called only once (per instance) for an MBean Registration, it has no performance
        impact on later use, but guarantees visibility of all non-final instance variables, both
        on this class and all subclasses, since they can only modify things via postRegisterHook().
    */
    public final synchronized void
  postRegister( Boolean registrationSucceeded )
  {
    super.postRegister( registrationSucceeded );
   
    postRegisterHook( registrationSucceeded );
  }
 
 
    public void
  postRegisterHook( Boolean registrationSucceeded )
  {
      if ( registrationSucceeded.booleanValue() )
    {
        enableCoverageInfo( getAMXDebug() );
    }
  }

    public final void
  preDeregister()
    throws Exception
  {
      super.preDeregister();
     
      preDeregisterHook();
  }
 
    public void
  postDeregister()
  {
      super.postDeregister();
     
      postDeregisterHook();
  }

    public final ObjectName
  getDomainRootObjectName()
  {
    return( Util.getObjectName( getDomainRoot() ) );
  }

  /**
    The QueryMgr is a special-case; all the other types rely on it.
  */
    public ObjectName
  getQueryMgrObjectName()
  {
    ObjectName  objectName  = null;
   
    if ( mQueryMgr != null )
    {
      // do it the fast way if we already have the proxy
      objectName  = Util.getObjectName( mQueryMgr );
    }
    else
    {
      final MBeanServer  server    = getMBeanServer();
      final String    domainName  = getObjectName().getDomain();
     
      objectName  = QueryMgrImpl.querySingletonJ2EETypeObjectName( server,
              domainName, QueryMgr.J2EE_TYPE );
    }
 
    assert( objectName != null ) : "getQueryMgrObjectName failed";
    return( objectName );
  }
 
 
    protected ConnectionSource
  getMBeanServerConnectionSource()
  {
    return( mConnectionSource );
  }
 
    public final LoaderMBean
  getLoader()
  {
    return( Loader.getLoader( getMBeanServer() ) );
  }
 
      public boolean
  isDAS()
  {
      return getLoader().isDAS();
  }
 
 
    protected final synchronized AMX
  getSelf()
  {
    if ( mSelfProxy == null )
    {
      final ObjectName  selfObjectName  = getObjectName();
      assert( selfObjectName != null );
     
      mSelfProxy  = getProxyFactory().getProxy( selfObjectName, AMX.class );
      assert( mSelfProxy != null );
    }
    return( mSelfProxy );
  }
 
 
 
    public final DomainRoot
  getDomainRoot()
  {
    return( getProxyFactory().getDomainRoot() );
  }
 
 
    protected final QueryMgr
  getQueryMgr()
  {
        // this relies on mQueryMgr being 'volatile'
    if ( mQueryMgr != null )
            return mQueryMgr;
       
        final ObjectName  objectName  = getQueryMgrObjectName();
        if ( objectName != null )
        {
            // it doesn't matter if two thread do this; the same proxy will be returned.
            mQueryMgr  = getProxyFactory().getProxy( objectName, QueryMgr.class);
        }
   
    return( mQueryMgr );
  }
 
  /**
    Extract the value of the "name" key for each ObjectName and place
    it into an array.
   
    @return String[] containing values of "name" property, one for each ObjectName
  */
    protected final String[]
  getNamePropertyValues( final Set<ObjectName> objectNameSet )
  {
    return( JMXUtil.getKeyProperty( NAME_KEY, objectNameSet ) );
  }
 
 
  /**
    @return String[] containing names of all children of specified type
  */
    protected final String[]
  getChildNames()
  {
    return( getContaineeNamesOfType( getChildJ2EEType() ) );
  }
 
  /**
    @return String[] containing names of all children of specified type
  */
    protected final String[]
  getContaineeNamesOfType( final String j2eeType )
  {
    final Set<ObjectName> objectNames  = getContaineeObjectNameSet( j2eeType );
       
    return( getNamePropertyValues( objectNames ) );
  }
 
  /**
    Get the names of all child objects, which may be of more
    than one type.
   
    @return Set containing all child ObjectNames
  */
    public final Set<ObjectName>
  getContaineeObjectNameSet()
  {
    final String    selfType  = getSelfJ2EEType();
   
    final Set<ObjectName>  allChildren  = new HashSet<ObjectName>();
   
    final Set<String>  containedTypes  =
      GSetUtil.newSet( getChildJ2EETypes(), getContaineeJ2EETypes() );
   
    for( final String  childJ2eeType : containedTypes )
    {
      final Set<ObjectName>  childrenOfType  = getContaineeObjectNameSet( childJ2eeType );
     
      allChildren.addAll( childrenOfType );
    }
   
    return( allChildren );
  }
 
  /**
    Get the name of a child MBean, assuming there is only one kind,
    and there is never more than one.
   
    @return ObjectName of child, or null if not found
  */
    protected ObjectName
  getOnlyChildObjectName()
  {
    return( getContaineeObjectName( getChildJ2EEType() ) );
  }
 

  /**
    @param parentType
    @param subType
   */
    private static String
  makeType( final String parentType, final String subType )
  {
    String  result  = null;
   
    if ( parentType == null || parentType.length() == 0 )
    {
      result  = subType;
    }
    else
    {
      result  = parentType + AMX.FULL_TYPE_DELIM + subType;
    }

    return( result  );
  }
 
   
    protected Set<ObjectName>
  getFauxContaineeObjectNameSet(
    final String  childJ2EEType,
    final String  nullProps )
  {
    assert getFauxChildTypes().contains( childJ2EEType );
   
    final String selfProp  = Util.makeProp( getJ2EEType(), getSelfName() );
   
    final String  childJ2EETypeProp  = Util.makeJ2EETypeProp( childJ2EEType );
    final String  props  = Util.concatenateProps( selfProp, nullProps, childJ2EETypeProp );
   
    final Set<AMX>  candidates  = getQueryMgr().queryPropsSet( props );
    final Set<ObjectName>  objectNames  = Util.toObjectNames( candidates );
   
    return( objectNames );
  }
 
    public Set<ObjectName>
  getContaineeObjectNameSet( final String childJ2EEType )
  {
    final TypeInfos  infos  = TypeInfos.getInstance();
    final TypeInfo  info  = infos.getInfo( childJ2EEType );
   
    String  props  = Util.makeJ2EETypeProp( childJ2EEType );
   
    QueryExp expr  = null;
    if ( info.isSubType() )
    {
      final String  selfFullType  = getFullType();
      final String  childFullType  = makeType( selfFullType, childJ2EEType );
     
      final String  selfProps  = Util.getFullTypeProps( getObjectName(), getFullType() );
     
      props  = Util.concatenateProps( props, selfProps );
      expr  = Query.eq(Query.attr( AMXAttributes.ATTR_FULL_TYPE ), Query.value( childFullType ));
    }
    else
    {
      // not a sub-type; nothing else to add
      expr  = null;
    }
   
        final ObjectName  pattern  =
           JMXUtil.newObjectNamePattern( getObjectName().getDomain(), props );
    final Set<ObjectName>  candidates  = JMXUtil.queryNames( getMBeanServer(), pattern, expr);
   
    return( candidates );
  }
 
 
    public final Set<ObjectName>
  getContaineeObjectNameSet( final Set<String> j2eeTypes )
  {
    final Set<ObjectName>  all  = new HashSet<ObjectName>();

        final Set<String>   actualTypes =
            j2eeTypes == null ? getContaineeJ2EETypes() : j2eeTypes;
           
    for( final String j2eeType : actualTypes )
    {
      final Set<ObjectName>  objectNames  = getContaineeObjectNameSet( j2eeType );
     
      all.addAll( objectNames );
    }
       
    return( all );
  }
 


  /**
    There must be 0 or 1 children of the specified type or an exception
    will be thrown.
   
    @return ObjectName for child of specified type
  */
    public final ObjectName
  getContaineeObjectName( final String j2eeType )
  {
    final Set<ObjectName>  children  = getContaineeObjectNameSet( j2eeType );
   
    ObjectName  result  = null;
   
    if ( children.size() == 1 )
    {
      result  = GSetUtil.getSingleton( children );
    }
    else if ( children.size() == 0 )
    {
      trace( "AMXImplBase.getContaineeObjectName: no children of type " + j2eeType );
      result  = null;
    }
    else
    {
      trace( "AMXImplBase.getContaineeObjectName: " + j2eeType + " impossible");
      impossible( new UnsupportedOperationException( "getContaineeObjectName" ) );
    }
       
    return( result );
  }
 
    protected final ObjectName
  getNamedChildObjectName( final String  name)
  {
    trace( "\nAMXImplBase.getNamedContaineeObjectName: " +
      "Looking for " + name + " in " + quote( getObjectName() ) );
   
    return( getContaineeObjectName( getChildJ2EEType(), name ) );
  }
 
    public final ObjectName
  getContaineeObjectName(
    final String  j2eeType,
    final String  name)
  {
    final Set<ObjectName>  candidates  = getContaineeObjectNameSet( j2eeType );
   
    final Set<ObjectName> matching  =
        JMXUtil.findByProperty( candidates, NAME_KEY, name );
   
    final ObjectName  result  = (matching.size() == 0) ?
      null : GSetUtil.getSingleton( matching );
   
    return( result );
  }
 
    public Map<String,Map<String,ObjectName>>
  getMultiContaineeObjectNameMap( final Set<String> j2eeTypesIn )
  {
    // if Set is null, it means all types
    final Set<String>  j2eeTypes  = j2eeTypesIn == null ?
      getContaineeJ2EETypes() : j2eeTypesIn;
     
    final Map<String,Map<String,ObjectName>>  m  =
        new HashMap<String,Map<String,ObjectName>>();
   
    for( final String j2eeType : j2eeTypes )
    {
      final Map<String,ObjectName>  nameMap  = getContaineeObjectNameMap( j2eeType );
      if ( nameMap.keySet().size() != 0 )
      {
        m.put( j2eeType, nameMap );
      }
    }
   
    return( m );
  }
 
    public final Map<String,ObjectName>
  getContaineeObjectNameMap( final String j2eeType )
  {
    if ( ! getContaineeJ2EETypes().contains( j2eeType ) )
    {
      throw new IllegalArgumentException( getObjectName() +
        " does not contain j2eeType: " + j2eeType );
    }

    final Set<ObjectName>  objectNames  = getContaineeObjectNameSet( j2eeType );
   
    Map<String,ObjectName>  result  = Collections.emptyMap();
   
    if ( objectNames.size() != 0 )
    {
      result  = Util.createObjectNameMap( objectNames );
    }
    assert( result.keySet().size() == objectNames.size() );
   
    return( result );
  }


    public Set<ObjectName>
  getByNameContaineeObjectNameSet(
    final Set<String>    j2eeTypes,
    final String  name )
  {
    final Iterator  iter  = getContaineeObjectNameSet( j2eeTypes ).iterator();
    final Set<ObjectName>    result  = new HashSet<ObjectName>();
   
    while ( iter.hasNext() )
    {
      final ObjectName  objectName  = (ObjectName)iter.next();
     
      if ( Util.getName( objectName ).equals( name ) )
      {
        result.add( objectName );
      }
    }
    return( result );
  }
 
  //------------------------ Access to other MBeans --------------------------------
 
 
    protected Object
  getAttribute(
    final ObjectName  objectName,
    String        name )
    throws AttributeNotFoundException, InstanceNotFoundException,
        ReflectionException, MBeanException
  {
    return( getMBeanServer().getAttribute( objectName, name ) );
  }
 
    protected AttributeList
  getAttributes(
    final ObjectName  objectName,
    String[]       names )
    throws AttributeNotFoundException, InstanceNotFoundException,
        ReflectionException, MBeanException
  {
    return( getMBeanServer().getAttributes( objectName, names ) );
  }
 
    protected void
  setAttribute(
    final ObjectName  objectName,
    Attribute      attr )
    throws AttributeNotFoundException, InvalidAttributeValueException,
        InstanceNotFoundException,
        ReflectionException, MBeanException
  {
    getMBeanServer().setAttribute( objectName, attr );
  }
 
    protected AttributeList
  setAttributes(
    final ObjectName  objectName,
    AttributeList    attrs )
    throws AttributeNotFoundException, InvalidAttributeValueException,
        InstanceNotFoundException,
        ReflectionException, MBeanException
  {
    return( getMBeanServer().setAttributes( objectName, attrs ) );
  }
 
  //-------------------------------------------------------------------------------
 
    protected ObjectName
  registerMBean( Object mbean, ObjectName name )
    throws MalformedObjectNameException, InstanceAlreadyExistsException,
    NotCompliantMBeanException, MBeanRegistrationException
  {
    return getMBeanServer().registerMBean( mbean, name ).getObjectName();
  }
 
 
    protected String
  stringify( Object o )
  {
    return( SmartStringifier.toString( o ) );
  }
 
 
      public String
  toString()
  {
      return getImplString( false );
  }
 
      public String
  getImplString( final boolean verbose )
  {
      final String NEWLINE    = System.getProperty( "line.separator" );
     
      String s = this.getClass().getName() + NEWLINE +
          MBeanInfoStringifier.DEFAULT.stringify( getMBeanInfo() ) + NEWLINE;
     
      if ( verbose )
      {
          final AttributeList attrs   = getAttributes( getAttributeNames() );
          final Map<String,Object>    m   = JMXUtil.attributeListToValueMap( attrs );
          s   = NEWLINE + s + MapUtil.toString( m, NEWLINE + NEWLINE ) + NEWLINE;
      }
     
      return s;
  }

}







TOP

Related Classes of com.sun.enterprise.management.support.AMXImplBase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.