Package com.sun.appserv.management.client

Source Code of com.sun.appserv.management.client.ProxyFactory

/*
* 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.
*/
package com.sun.appserv.management.client;

import java.util.Collection;
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.io.IOException;
import java.lang.reflect.Proxy;

import javax.management.MBeanServerConnection;
import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.JMException;
import javax.management.relation.MBeanServerNotificationFilter;
import javax.management.MBeanServerNotification;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectionNotification;

import com.sun.appserv.management.DomainRoot;
import com.sun.appserv.management.base.AMX;
import com.sun.appserv.management.base.AMXAttributes;
import com.sun.appserv.management.base.XTypes;
import com.sun.appserv.management.base.Util;
import com.sun.appserv.management.util.jmx.MBeanProxyHandler;
import com.sun.appserv.management.util.jmx.MBeanServerConnectionSource;
import com.sun.appserv.management.util.jmx.MBeanServerConnectionConnectionSource;
import com.sun.appserv.management.util.misc.ClassUtil;
import com.sun.appserv.management.util.misc.TypeCast;

import com.sun.appserv.management.client.ConnectionSource;
import com.sun.appserv.management.client.handler.ConverterHandlerFactory;
import com.sun.appserv.management.client.handler.ConverterHandlerUtil;
import com.sun.appserv.management.client.handler.ProxyCache;

import com.sun.appserv.management.util.misc.GSetUtil;
import com.sun.appserv.management.util.misc.ExceptionUtil;
import com.sun.appserv.management.util.jmx.JMXUtil;

import com.sun.appserv.management.helper.AMXDebugHelper;

/**
  Factory for {@link AMX} proxies.
  Usually proxies are obtained by starting with the DomainRoot obtained via
  {@link AppserverConnectionSource#getDomainRoot}.
 
  @see com.sun.appserv.management.client.AppserverConnectionSource
*/
public final class ProxyFactory implements NotificationListener
{
  private final ProxyCache    mProxyCache;
  private final ConnectionSource  mConnectionSource;
  private final ObjectName    mDomainRootObjectName;
  private final DomainRoot    mDomainRoot;
  private final String      mMBeanServerID;
   
    private static final AMXDebugHelper mDebug  =
        new AMXDebugHelper( "com.sun.appserv.management.client.ProxyFactory" );
    private static void debug( final Object... args ) { mDebug.println( args ); }
 
  private static final Map<MBeanServerConnection,ProxyFactory> INSTANCES  =
      Collections.synchronizedMap( new HashMap<MBeanServerConnection,ProxyFactory>() );
   
    /**
        Because ProxyFactory is used on both client and server, emitting anything to stdout
        or to the log is unacceptable in some circumstances.  Warnings remain available
        if the AMX-DEBUG system property allows it.
     */
        private static void
    warning( final Object... args )
    {
        debug( args );
    }
 
    private
  ProxyFactory( final ConnectionSource connSource )
  {
        mDebug.setEchoToStdOut( true );
       
    assert( connSource != null );
   
    mConnectionSource  = connSource;
    mProxyCache      = new ProxyCache();
   
    try
    {
      final MBeanServerConnection  conn  = getConnection();
     
      mMBeanServerID    = JMXUtil.getMBeanServerID( conn );
       
      mDomainRootObjectName  = initDomainRootObjectName();
      mDomainRoot        = initDomainRoot();
     
      // we should always be able to listen to MBeans--
      // but the http connector does not support listeners
      try
      {
        final MBeanServerNotificationFilter  filter  =
          new MBeanServerNotificationFilter();
        filter.enableAllObjectNames();
        filter.disableAllTypes();
        filter.enableType( MBeanServerNotification.UNREGISTRATION_NOTIFICATION );
       
        JMXUtil.listenToMBeanServerDelegate( conn, this, filter, null );
      }
      catch( Exception e )
      {
        warning( "ProxyFactory: connection does not support notifications: ",
                    mMBeanServerID, connSource);
      }
     
      // same idea as above, this time we want to listen to connection died
      // plus there may not be a JMXConnector involved
      final JMXConnector  connector  = connSource.getJMXConnector( false );
      if ( connector != null )
      {
        try
        {
          connector.addConnectionNotificationListener( this, null, null );
        }
        catch( Exception e )
        {
          warning("addConnectionNotificationListener failed: ",
                        mMBeanServerID, connSource, e);
        }
      }
    }
    catch( Exception e )
    {
      warning( "ProxyFactory.ProxyFactory:\n", e );
      throw new RuntimeException( e );
    }
  }
 
 
  /**
    The connection is bad.  Tell each proxy its gone and remove it.
   */
    private void
  connectionBad()
  {
        final Set<AMX>   proxies  = new HashSet<AMX>();
        proxies.addAll( mProxyCache.values() );
        mProxyCache.clear();
       
        for( final AMX proxy : proxies )
        {
            ConverterHandlerUtil.connectionBad( proxy );
        }
  }
 
  /**
    Verify that the connection is still alive.
   */
    public boolean
  checkConnection()
  {
    boolean  connectionGood  = true;
   
    try
    {
      getConnection().isRegistered( JMXUtil.getMBeanServerDelegateObjectName() );
      connectionGood  = true;
    }
    catch( Exception e )
    {
      connectionBad();
    }
   
    return( connectionGood );
  }
 

    void
  notifsLost()
  {
    // should probably check each proxy for validity, but not clear if it's important...
  }
 
  /**
    Listens for MBeanServerNotification.UNREGISTRATION_NOTIFICATION and
    JMXConnectionNotification and takes appropriate action.
    <br>
      Used internally as callback for {@link javax.management.NotificationListener}.
      <b>DO NOT CALL THIS METHOD</b>.
   */
    public void
  handleNotification(
    final Notification  notifIn,
    final Object    handback)
  {
    final String  type  = notifIn.getType();
   
    if ( type.equals( MBeanServerNotification.UNREGISTRATION_NOTIFICATION)  )
    {
      final MBeanServerNotification  notif  = (MBeanServerNotification)notifIn;
      final ObjectName  objectName  = notif.getMBeanName();
      final AMX proxy  = getProxy( objectName, AMX.class, false );
      mProxyCache.remove( objectName );
      ConverterHandlerUtil.targetUnregistered(proxy);
     
      //debug( "ProxyFactory.handleNotification: UNREGISTERED: ", objectName );
    }
    else if ( notifIn instanceof JMXConnectionNotification )
    {
      if ( type.equals( JMXConnectionNotification.CLOSED ) ||
        type.equals( JMXConnectionNotification.FAILED ) )
      {
                debug( "ProxyFactory.handleNotification: connection closed or failed: ", notifIn);
        connectionBad();
      }
      else if ( type.equals( JMXConnectionNotification.NOTIFS_LOST ) )
      {
                debug( "ProxyFactory.handleNotification: notifications lost: ", notifIn);
        notifsLost();
      }
    }
    else
    {
      debug( "ProxyFactory.handleNotification: UNKNOWN notification: ", notifIn );
    }
  }
 
    private ObjectName
  initDomainRootObjectName()
    throws IOException
  {
    final MBeanServerConnection  conn  = mConnectionSource.getMBeanServerConnection( false );
   
    final String  patternString  = "*:" +
              AMX.J2EE_TYPE_KEY + "=" + XTypes.DOMAIN_ROOT + ",*";
   
    ObjectName  pattern  = null;
    try
    {
      pattern  = new ObjectName( patternString );
    }
    catch ( MalformedObjectNameException e )
    {
            warning( "initDomainRootObjectName: impossible failure", e );
      assert( false )// can't happen
      throw new RuntimeException( e );
    }
   
    final Set<ObjectName>  objectNames  = JMXUtil.queryNames( conn, pattern, null );
    if ( objectNames.size() != 1 )
    {
            warning( "Can't find DomainRoot MBean using pattern: ", pattern);
      throw new IllegalArgumentException( "Can't find DomainRoot MBean using pattern " + pattern );
    }

    final ObjectName  objectName  = GSetUtil.getSingleton( objectNames );
   
    return( objectName );
  }
 
  private final static String  DOMAIN_ROOT_KEY  = "DomainRoot";
 
    public DomainRoot
  createDomainRoot( )
    throws IOException
  {
    return( mDomainRoot );
  }
 
    public DomainRoot
  initDomainRoot( )
    throws IOException
  {
    final ObjectName  domainRootObjectName  = getDomainRootObjectName( );
   
    final DomainRoot  domainRoot  = (DomainRoot)
      newProxyInstance(domainRootObjectName, new Class[] { DomainRoot.class });
   
    return( domainRoot );
  }
 
  /**
      Return the DomainRoot.  AMX may not yet be fully
      initialized; call getDomainRoot( true ) if AMX
      must be initialized upon return.
     
    @return the DomainRoot for this factory.
   */
    public DomainRoot
  getDomainRoot( )
  {
    return getDomainRoot( false );
  }
 
  /**
      If 'waitReady' is true, then upon return AMX
      is guaranteed to be fully loaded.  Otherwise
      AMX MBeans may continue to initialize asynchronously.
     
      @param waitReady
    @return the DomainRoot for this factory.
   */
    public DomainRoot
  getDomainRoot( boolean waitReady )
  {
      if ( waitReady )
      {
          mDomainRoot.waitAMXReady();
      }
     
    return( mDomainRoot );
  }
 
 
  /**
    @return the ConnectionSource used by this factory
   */
    public ConnectionSource
  getConnectionSource()
  {
    return( mConnectionSource );
  }
 
  /**
    @return the JMX MBeanServerID for the MBeanServer in which MBeans reside.
   */
    public String
  getMBeanServerID()
  {
    return( mMBeanServerID );
  }
 
  /**
    Return the ObjectName for the DomainMBean.
   */
    public ObjectName
  getDomainRootObjectName()
    throws IOException
  {
    return( mDomainRootObjectName );
  }
 
  /**
    Get an instance of the ProxyFactory for the MBeanServer.  Generally
    not applicable for remote clients.
   
    @param server
   */
    public static ProxyFactory
  getInstance( final MBeanServer server )
  {
    return( getInstance( new MBeanServerConnectionSource( server ), true ) );
  }
 
  /**
    Get an instance of the ProxyFactory for the MBeanServerConnection.
    Creates a ConnectionSource for it and calls getInstance( connSource, true ).
   */
    public static ProxyFactory
  getInstance( final MBeanServerConnection conn )
  {
    return( getInstance( new MBeanServerConnectionConnectionSource( conn ), true ) );
  }
 
  /**
    Calls getInstance( connSource, true ).
   */
    public static ProxyFactory
  getInstance( final ConnectionSource conn )
  { 
    return( getInstance( conn, true ) );
  }
 
  /**
    Get an instance.  If 'useMBeanServerID' is false, and
    the ConnectionSource is not one that has been passed before, a new ProxyFactory
    is instantiated which will not share its proxies with any previously-instantiated
    ones.  Such usage is discouraged, as it duplicates proxies.  Pass 'true' unless
    there is an excellent reason to pass 'false'.
   
    @param connSource      the ConnectionSource
    @param useMBeanServerID    use the MBeanServerID to determine if it's the same server
   */
    public static synchronized ProxyFactory
  getInstance(
    final ConnectionSource  connSource,
    final boolean      useMBeanServerID )
  {
    ProxyFactory  instance  = findInstance( connSource );
   
    if ( instance == null )
    {
      try
      {
        // match based on the MBeanServerConnection; different
        // ConnectionSource instances could wrap the same connection
        final MBeanServerConnection  conn =
          connSource.getMBeanServerConnection( false );
       
        instance  = findInstance( conn );
       
        // if not found, match based on MBeanServerID as requested, or if this
        // is an in-process MBeanServer
        if ( instance == null &&
          ( useMBeanServerID  || connSource instanceof MBeanServerConnectionSource ) )
        {
          final String  id  = JMXUtil.getMBeanServerID( conn );
          instance  = findInstanceByID( id );
        }
     
        if ( instance == null )
        {
                    debug( "Creating new ProxyFactory for ConnectionSource / conn", connSource, conn );
          instance  = new ProxyFactory( connSource );
          INSTANCES.put( conn, instance );
        }
      }
      catch( Exception e )
      {
        warning( "ProxyFactory.getInstance: failure creating ProxyFactory: ", e );
        throw new RuntimeException( e );
      }
    }
   
    return( instance );
  }
 
  /**
    @return ProxyFactory corresponding to the ConnectionSource
   */
    public static synchronized ProxyFactory
  findInstance( final ConnectionSource conn )
  {
    return( INSTANCES.get( conn ) );
  }
 
  /**
    @return ProxyFactory corresponding to the MBeanServerConnection
   */
    public static synchronized ProxyFactory
  findInstance( final MBeanServerConnection conn )
  {
    ProxyFactory  instance  = null;
   
    final Collection<ProxyFactory> values  = INSTANCES.values();
    for( final ProxyFactory factory : values )
    {
      if ( factory.getConnectionSource().getExistingMBeanServerConnection( ) == conn )
      {
        instance  = factory;
        break;
      }
    }
    return( instance );
  }
 
 
  /**
    @return ProxyFactory corresponding to the MBeanServerID
   */
    public static synchronized ProxyFactory
  findInstanceByID( final String mbeanServerID )
  {
    ProxyFactory  instance  = null;
   
    final Collection<ProxyFactory> values  = INSTANCES.values();
    for( final ProxyFactory factory : values )
    {
      if ( factory.getMBeanServerID().equals( mbeanServerID ) )
      {
        instance  = factory;
        break;
      }
    }
   
    return( instance );
  }
 
   
  /**
    @return an appropriate {@link AMX} interface for the ObjectName
    @deprecated use versions that take a class as a parameter
   */
    public AMX
  getProxy( final ObjectName  objectName )
  {
      return getProxy( objectName, true );
  }
   
  /**
    Get any existing proxy, returning null if none exists and 'create' is false.
   
    @param objectName  ObjectName for which a proxy should be created
    @param create    true to create the proxy, false to return existing value
    @return an appropriate {@link AMX} interface for the ObjectName
    @deprecated use versions that take a class as a parameter
   */
    public AMX
  getProxy( final ObjectName  objectName, boolean create )
  {
      return getProxy( objectName, AMX.class, create );
  }
 
  /**
      The actual interface(s) that the proxy implements are predetermined.
      Specifying the interface ties the return type to the interface at compile-time
      but has no effect on the actual interfaces that are implemented by
      the proxy.
    @return an appropriate {@link AMX} interface for the ObjectName
   */
    public synchronized <T extends AMX> T
  getProxy(
      final ObjectName  objectName,
      final Class<T>      theInterface )
  {
    return getProxy( objectName, theInterface, true );
  }
 
  /**
    Get any existing proxy, returning null if none exists and 'create' is false.
   
    @param objectName  ObjectName for which a proxy should be created
    @param create    true to create the proxy, false to return existing value
    @param theClass     class of returned proxy, avoids casts and compiler warnings
    @return an appropriate {@link AMX} interface for the ObjectName
   */
    public synchronized <T extends AMX> T
  getProxy(
      final ObjectName  objectName,
      Class<T>            theClass,
      boolean             create )
  {
    AMX  proxy  = mProxyCache.getCachedProxy( objectName );
   
    if ( proxy == null && create )
    {
      proxy  = createProxy( objectName );
    }
    return theClass.cast( proxy );
  }
 
  /**
    @return MBeanServerConnection used by this factory
   */
    protected MBeanServerConnection
  getConnection()
    throws IOException
  {
    return( getConnectionSource().getMBeanServerConnection( false ) );
  }
 
  /**
    Create a new proxy.  When a new proxy is created, its parent is
    required, which could cause a chain of proxies to be created.
    @param ObjectName
   */
    private AMX
  createProxy( final ObjectName  objectName  )
  {
    AMX proxy        = null;
   
    try
    {
      String    proxyInterfaceName  = null;
      Class  proxyInterface    = null;
     
      proxyInterfaceName  = (String)
        getConnection().getAttribute( objectName, AMXAttributes.ATTR_INTERFACE_NAME );
     
      proxyInterface  = ClassUtil.getClassFromName( proxyInterfaceName );
         
      proxy  =  newProxyInstance( objectName, new Class[] { proxyInterface } );
    }
    catch( IllegalArgumentException e )
    {
            debug( "createProxy", e );
      throw e;
    }
    catch( Exception e )
    {
            debug( "createProxy", e );
      throw new RuntimeException( e );
    }
       
    return( proxy );
  }
 
      private MBeanProxyHandler
  createProxyHandler( final ObjectName objectName )
      throws IOException
  {
      return ConverterHandlerFactory.createHandler( mConnectionSource, objectName );
  }

   
  /**
    Instantiates a new proxy using the default AttributeNameMangler and with any desired number
    of interfaces.  If you want NotificationBroadcaster as one of the interfaces, you must
    supply it in the list.
    Use of this routine is discouraged in favor of
    {@link #getProxy}
   
    @param objectName      the target MBean which will be invoked by the proxy
    @param interfaceClasses  all interfaces the proxy should implement
   
    @return the new Proxy implementing the specified interface
   */
    public AMX
  newProxyInstance(
    final ObjectName      objectName,
    final Class<?>[]      interfaceClasses )
    throws IOException
  {
    final MBeanProxyHandler  handler  = createProxyHandler( objectName );
   
    final ClassLoader    classLoader  = interfaceClasses[ 0 ].getClassLoader();
   
    final AMX proxy  = Util.asAMX(Proxy.newProxyInstance( classLoader, interfaceClasses, handler));
    if ( proxy != null )
    {
        mProxyCache.remove( objectName );
      mProxyCache.cacheProxy( proxy );
    }
   
    return( proxy );
  }
 
    protected static String
  toString( final Object o )
  {
    return( com.sun.appserv.management.util.stringifier.SmartStringifier.toString( o ) );
  }
   
  /**
    Convert a Set of ObjectName to a Set of AMX.
   
    @return a Set of AMX from a Set of ObjectName.
   */
    public Set<AMX>
  toProxySet( final Set<ObjectName> objectNames )
  {
    final Set<AMX>  s  = new HashSet<AMX>();
   
    for( final ObjectName objectName : objectNames )
    {
      try
      {
        final AMX  proxy  = getProxy( objectName, AMX.class, true );
        assert( ! s.contains( proxy ) );
        s.add( proxy );
      }
      catch( final Exception e )
      {
          debug( "ProxyFactory.toProxySet: exception for MBean ",
                    objectName, " = ", ExceptionUtil.getRootCause( e ) );
      }
    }
   
    return( s );
  }
 
  /**
    Convert a Collection of ObjectName to a List of AMX.
   
    @return a List of AMX from a List of ObjectName.
   */
    public List<AMX>
  toProxyList( final Collection<ObjectName> objectNames )
  {
    final List<AMX>  list  = new ArrayList<AMX>();
   
    for( final ObjectName objectName : objectNames )
    {
      try
      {
        final AMX  proxy  = getProxy( objectName, AMX.class, true );
        list.add( proxy );
      }
      catch( final Exception e )
      {
          debug( "ProxyFactory.toProxySet: exception for MBean ",
                    objectName, " = ", ExceptionUtil.getRootCause( e ) );
      }
    }
   
    return( list );
  }
 
  /**
    Convert a Map of ObjectName, and convert it to a Map
    of AMX, with the same keys.
   
    @return a Map of AMX from a Map of ObjectName.
   */
    public Map<String,AMX>
  toProxyMap(
    final Map<String,ObjectName>  objectNameMap )
  {
    final Map<String,AMX> resultMap  = new HashMap<String,AMX>();
   
    final Set<String>   keys    = objectNameMap.keySet();
   
    for( final String key : keys )
    {
      final ObjectName  objectName  = objectNameMap.get( key );
     
      try
      {
        final AMX  proxy  = getProxy( objectName, AMX.class, true );
        resultMap.put( key, proxy );
      }
      catch( final Exception e )
      {
          debug( "ProxyFactory.toProxySet: exception for MBean ",
                    objectName, " = ", ExceptionUtil.getRootCause( e ) );
      }
    }
   
    return( resultMap );
  }
 
}










TOP

Related Classes of com.sun.appserv.management.client.ProxyFactory

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.