|
Glassfish example source code file (ProxyFactory.java)
This example Glassfish source code file (ProxyFactory.java) is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.
The Glassfish ProxyFactory.java source code
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 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.core.AMXProxy;
import org.glassfish.admin.amx.util.AMXDebugHelper;
import org.glassfish.admin.amx.util.jmx.JMXUtil;
import org.glassfish.admin.amx.util.ExceptionUtil;
import org.glassfish.admin.amx.util.StringUtil;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerNotification;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.MBeanInfo;
import javax.management.InstanceNotFoundException;
import javax.management.relation.MBeanServerNotificationFilter;
import javax.management.remote.JMXConnectionNotification;
import javax.management.remote.JMXConnector;
import java.io.IOException;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
import javax.management.Descriptor;
import org.glassfish.external.arc.Stability;
import org.glassfish.external.arc.Taxonomy;
import org.glassfish.admin.amx.config.AMXConfigProxy;
import org.glassfish.admin.amx.core.Util;
import static org.glassfish.external.amx.AMX.*;
import org.glassfish.external.amx.AMXGlassfish;
//import org.glassfish.api.amx.AMXUtil;
/**
Factory for {@link AMXProxy} proxies.
*/
@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();
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();
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.
*/
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();
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();
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();
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();
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();
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();
for( final ObjectName objectName : objectNames )
{
final AMXProxy proxy = getProxy( objectName, intf);
if ( proxy != null )
{
result.add( proxy );
}
}
return( result );
}
}
Other Glassfish examples (source code examples)
Here is a short list of links related to this Glassfish ProxyFactory.java source code file:
|