Package org.glassfish.admin.amx.core.proxy

Source Code of org.glassfish.admin.amx.core.proxy.ProxyFactory

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2011 Oracle and/or its affiliates. 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_1_1.html
* or packager/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 packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [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 org.glassfish.admin.amx.core.proxy;

import org.glassfish.admin.amx.base.DomainRoot;
import org.glassfish.admin.amx.config.AMXConfigProxy;
import org.glassfish.admin.amx.core.AMXProxy;
import org.glassfish.admin.amx.core.Util;
import org.glassfish.admin.amx.util.AMXDebugHelper;
import org.glassfish.admin.amx.util.ExceptionUtil;
import org.glassfish.admin.amx.util.StringUtil;
import org.glassfish.admin.amx.util.jmx.JMXUtil;
import org.glassfish.external.amx.AMXGlassfish;
import org.glassfish.external.arc.Stability;
import org.glassfish.external.arc.Taxonomy;

import javax.management.*;
import javax.management.relation.MBeanServerNotificationFilter;
import javax.management.remote.JMXConnectionNotification;
import java.io.IOException;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static org.glassfish.external.amx.AMX.DESC_STD_IMMUTABLE_INFO;
import static org.glassfish.external.amx.AMX.NAME_KEY;

//import org.glassfish.api.amx.AMXUtil;


/**
  @deprecated Factory for {@link AMXProxy} proxies.
*/
@Deprecated
@Taxonomy(stability = Stability.UNCOMMITTED)
public final class ProxyFactory implements NotificationListener
{
  private final MBeanServerConnection  mMBeanServerConnection;
  private final String          mMBeanServerID;
  private final ObjectName        mDomainRootObjectName;
  private final DomainRoot        mDomainRoot;
   
    /**
        For immutable MBeanInfo, we want to pay the cost once and only once of a trip to the server.
        <p>
        Can we assume it's unique per *type* so that we can cache it once per type? If we could so so,
        the size of the cache would stay much smaller.
    */
    private final ConcurrentMap<ObjectName,MBeanInfo> mMBeanInfoCache = new ConcurrentHashMap<ObjectName,MBeanInfo>();
   
    private static final AMXDebugHelper mDebug  =
        new AMXDebugHelper( ProxyFactory.class.getName() );
    private static void debug( final Object... args )
    {
        //mDebug.println( args );
        System.out.println( StringUtil.toString( ", ", 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 MBeanServerConnection conn )
  {
        mDebug.setEchoToStdOut( true );
    assert( conn != null );
   
    mMBeanServerConnection  = conn;
   
    try
    {
      mMBeanServerID    = JMXUtil.getMBeanServerID( conn );
       
      mDomainRootObjectName = AMXGlassfish.DEFAULT.domainRoot();
            if ( mDomainRootObjectName == null )
            {
                throw new IllegalStateException( "ProxyFactory: AMX has not been started" );
            }
            mDomainRoot           = getProxy(mDomainRootObjectName, DomainRoot.class);
     
      // 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, conn);
      }
    }
    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<AMXProxy>   proxies  = new HashSet<AMXProxy>();
       
        for( final AMXProxy amx : proxies )
        {
            final AMXProxyHandler proxy = AMXProxyHandler.unwrap(amx);
            proxy.connectionBad();
        }
  }
 
  /**
    Verify that the connection is still alive.
   */
    public boolean
  checkConnection()
  {
    boolean  connectionGood  = true;
   
    try
    {
      getMBeanServerConnection().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();
      //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 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 dr  = getProxy(domainRootObjectName, DomainRoot.class);
   
    return( dr );
  }

  /**
    Return the ObjectName for the DomainMBean.
   */
    public ObjectName
  getDomainRootObjectName()
  {
    return( mDomainRootObjectName );
  }
 
  /**
      Return the DomainRoot. AMX is guaranteed to be ready after this call returns.
     
    @return the DomainRoot for this factory.
   */
    public DomainRoot
  getDomainRootProxy( )
  {
    return getDomainRootProxy( 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
  getDomainRootProxy( boolean waitReady )
  {
      if ( waitReady )
      {
          mDomainRoot.waitAMXReady();
      }
     
    return( mDomainRoot );
  }
 
   
  /**
    @return the JMX MBeanServerID for the MBeanServer in which MBeans reside.
   */
    public String
  getMBeanServerID()
  {
    return( mMBeanServerID );
  }
 
  /**
    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( 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( 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 MBeanServerConnection  conn,
    final boolean          useMBeanServerID )
  {
    ProxyFactory  instance  = findInstance( conn );
   
    if ( instance == null )
    {
      try
      {
        // if not found, match based on MBeanServerID as requested, or if this
        // is an in-process MBeanServer
        if ( useMBeanServerID )
        {
          final String  id  = JMXUtil.getMBeanServerID( conn );
          instance  = findInstanceByID( id );
        }
     
        if ( instance == null )
        {
                    //debug( "Creating new ProxyFactory for ConnectionSource / conn", connSource, conn );
          instance  = new ProxyFactory( conn );
          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 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.getMBeanServerConnection() == 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 (possibly cached) MBeanInfo.  If the MBean does not exist,
        then null is returned.
     */
    public MBeanInfo getMBeanInfo( final ObjectName objectName )
    {
        try
        {
            MBeanInfo info = mMBeanInfoCache.get(objectName);
            if ( info == null )
            {
                // race condition: doesn't matter if two threads both get it
                info = getMBeanServerConnection().getMBeanInfo(objectName);
                if ( invariantMBeanInfo(info)  )
                {
                    mMBeanInfoCache.put(objectName, info);
                }
            }
            return info;
        }
        catch( final InstanceNotFoundException e )
        {
            // OK, return null
        }
        catch ( Exception e )
        {
            throw new RuntimeException(e);
        }
        return null;
    }
   
    public static boolean invariantMBeanInfo(final MBeanInfo info )
    {
        final Descriptor d = info.getDescriptor();
        if ( d == null ) return false;
       
        final String value =  "" + d.getFieldValue( DESC_STD_IMMUTABLE_INFO);
        return Boolean.valueOf( value );
    }
   
    
  /**
    @return MBeanServerConnection used by this factory
   */
    protected MBeanServerConnection
  getMBeanServerConnection()
  {
    return mMBeanServerConnection;
  }
   
  /**
    Get any existing proxy, returning null if none exists and 'create' is false.
        If an MBean is no longer registered, the proxy returned will be null.
   
    @param objectName  ObjectName for which a proxy should be created
    @param intf         class of returned proxy, avoids casts and compiler warnings
    @return an appropriate {@link AMXProxy} interface for the ObjectName
   */
    public <T extends AMXProxy> T
  getProxy(
      final ObjectName  objectName,
      Class<T>            intf)
  {
        final MBeanInfo info = getMBeanInfo(objectName);
        if ( info == null ) return null;
       
    final T proxy = getProxy( objectName, info, intf);
    return proxy;
  }
   
    /** Call getProxy(objectName, getGenericAMXInterface() */
      public AMXProxy
  getProxy( final ObjectName  objectName)
  {
        final MBeanInfo info = getMBeanInfo(objectName);
        if ( info == null ) return null;
       
        final Class<? extends AMXProxy>  intf = genericInterface(info);
    final AMXProxy proxy = getProxy( objectName, info, intf);
        return proxy;
  }

       
    public static Class<? extends AMXProxy> genericInterface(final MBeanInfo info)
    {
        final String intfName = AMXProxyHandler.genericInterfaceName(info);
        Class<? extends AMXProxy> intf = AMXProxy.class;

        if (intfName == null || AMXProxy.class.getName().equals(intfName))
        {
            intf = AMXProxy.class;
        }
        else if (AMXConfigProxy.class.getName().equals(intfName))
        {
            intf = AMXConfigProxy.class;
        }
        else if (intfName.startsWith(AMXProxy.class.getPackage().getName()))
        {
            try
            {
                intf = Class.forName(intfName, false, ProxyFactory.class.getClassLoader()).asSubclass(AMXProxy.class);
            }
            catch (final Exception e)
            {
                // ok, use generic
                debug("ProxyFactory.getInterfaceClass(): Unable to load interface " + intfName);
            }
        }
        else
        {
            intf = AMXProxy.class;
        }
        return intf;
    }


    /** NOTE: a null proxy may be returned if the MBean is no longer registered */
        <T extends AMXProxy> T
  getProxy(
        final ObjectName objectName,
        final MBeanInfo  mbeanInfoIn,
        final Class<T>   intfIn)
  {
        //debug( "ProxyFactory.createProxy: " + objectName + " of class " + expected.getName() + " with interface " + JMXUtil.interfaceName(mbeanInfo) + ", descriptor = " + mbeanInfo.getDescriptor() );
    AMXProxy proxy = null;
       
        try
        {
            MBeanInfo mbeanInfo = mbeanInfoIn;
            if ( mbeanInfo == null )
            {
                mbeanInfo = getMBeanInfo(objectName);
            }
           
            // if it's a plain AMXProxy, it might have a more generic sub-interface we should use.
            Class<? extends AMXProxy>  intf = intfIn;
            if ( AMXProxy.class == intf )
            {
                intf = genericInterface(mbeanInfoIn);
            }
       
            final AMXProxyHandler handler  = new AMXProxyHandler( getMBeanServerConnection(), objectName, mbeanInfo);
            proxy  = (AMXProxy)Proxy.newProxyInstance( intf.getClassLoader(), new Class[] { intf }, handler);
            //debug( "CREATED proxy of type " + intf.getName() + ", metadata specifies " + AMXProxyHandler.interfaceName(mbeanInfo) );
        }
        catch( IllegalArgumentException e )
        {
            //debug( "createProxy", e );
            throw e;
        }
        catch( Exception e )
        {
            final Throwable rootCause = ExceptionUtil.getRootCause(e);
            if ( ! ( rootCause instanceof InstanceNotFoundException) )
            {
                //debug( "createProxy", e );
                throw new RuntimeException( e );
            }
            proxy = null;
        }
       
    return proxy == null ? null : intfIn.cast( proxy );
  }

 
    protected static String
  toString( final Object o )
  {
    //return( org.glassfish.admin.amx.util.stringifier.SmartStringifier.toString( o ) );
        return "" + o;
  }
   
    /**
        Array entries for MBeans that are no longer registered will contain null values.
     */
        public AMXProxy[]
    toProxy( final ObjectName[] objectNames )
    {
        final AMXProxy[] result = new AMXProxy[objectNames.length];
        for( int i = 0; i < objectNames.length; ++i )
        {
            result[i] = getProxy(objectNames[i]);
        }
        return result;
    }
   
  /**
    Convert a Set of ObjectName to a Set of AMX.
    The resulting Set may be smaller than the original if, for example, some MBeans
        are no longer registered.
   */
    public Set<AMXProxy>
  toProxySet( final Set<ObjectName> objectNames )
  {
    final Set<AMXProxy>  s  = new HashSet<AMXProxy>();
   
    for( final ObjectName objectName : objectNames )
    {
      try
      {
        final AMXProxy  proxy  = getProxy( objectName );
                if ( proxy != null )
                {
                    s.add( proxy );
                }
      }
      catch( final Exception e )
      {
          debug( "ProxyFactory.toProxySet: exception for MBean ",
                    objectName, " = ", ExceptionUtil.getRootCause( e ) );
      }
    }
   
    return( s );
  }
   
  /**
    Convert a Set of ObjectName to a Set of AMX.
    The resulting Set may be smaller than the original if, for example, some MBeans
        are no longer registered.
   */
        public Set<AMXProxy>
  toProxySet( final ObjectName[] objectNames, final Class<? extends AMXProxy> intf)
  {
    final Set<AMXProxy> result = new HashSet<AMXProxy>();
    for( final ObjectName objectName : objectNames )
    {
            final AMXProxy  proxy = getProxy( objectName, intf);
            if ( proxy != null )
            {
                result.add( proxy );
            }
    }
    return( result );
    }
 
  /**
    Convert a Collection of ObjectName to a List of AMX.
        Resulting Map could differ in size if some MBeans are no longer registered.
   
    @return a List of AMX from a List of ObjectName.
   */
    public List<AMXProxy>
  toProxyList( final Collection<ObjectName> objectNames )
  {
    final List<AMXProxy>  list  = new ArrayList<AMXProxy>();
   
    for( final ObjectName objectName : objectNames )
    {
      try
      {
        final AMXProxy  proxy  = getProxy( objectName );
                if ( proxy != null )
                {
                    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.
        Resulting Map could differ in size if some MBeans are no longer registered.
   
    @return a Map of AMX from a Map of ObjectName.
   */
    public Map<String,AMXProxy>
  toProxyMap(
    final Map<String,ObjectName>  objectNameMap )
  {
    final Map<String,AMXProxy> resultMap  = new HashMap<String,AMXProxy>();
   
    final Set<String>   keys    = objectNameMap.keySet();
   
    for( final String key : keys )
    {
      final ObjectName  objectName  = objectNameMap.get( key );
     
      try
      {
        final AMXProxy  proxy  = getProxy( objectName );
                if ( proxy != null )
                {
                    resultMap.put( key, proxy );
                }
      }
      catch( final Exception e )
      {
          debug( "ProxyFactory.toProxySet: exception for MBean ",
                    objectName, " = ", ExceptionUtil.getRootCause( e ) );
      }
    }
   
    return( resultMap );
  }
 
    /** Resulting Map could differ in size if some MBeans are no longer registered */
        public Map<String,AMXProxy>
  toProxyMap( final ObjectName[] objectNames, final Class<? extends AMXProxy> intf)
  {
    final Map<String,AMXProxy> resultMap  = new HashMap<String,AMXProxy>();
   
    for( final ObjectName objectName : objectNames )
    {
            final String key = Util.unquoteIfNeeded(objectName.getKeyProperty(NAME_KEY));

            final AMXProxy  proxy  = getProxy( objectName, intf);
            if ( proxy != null )
            {
                resultMap.put( key, proxy );
            }
    }
   
    return( resultMap );
    }
   
    /** Resulting list could differ in size if some MBeans are no longer registered */
        public List<AMXProxy>
  toProxyList( final ObjectName[] objectNames, final Class<? extends AMXProxy> intf)
  {
    final List<AMXProxy> result = new ArrayList<AMXProxy>();
    for( final ObjectName objectName : objectNames )
    {
            final AMXProxy proxy = getProxy( objectName, intf);
            if ( proxy != null )
            {
                result.add( proxy );
            }
    }
    return( result );
    }
}













TOP

Related Classes of org.glassfish.admin.amx.core.proxy.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.