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

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

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 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.annotation.ChildGetter;
import org.glassfish.admin.amx.base.DomainRoot;
import org.glassfish.admin.amx.base.Tools;
import org.glassfish.admin.amx.core.AMXProxy;
import org.glassfish.admin.amx.core.Extra;
import org.glassfish.admin.amx.core.PathnameParser;
import org.glassfish.admin.amx.core.Util;
import org.glassfish.admin.amx.util.*;
import org.glassfish.admin.amx.util.jmx.JMXUtil;
import org.glassfish.admin.amx.util.jmx.MBeanProxyHandler;
import org.glassfish.external.arc.Stability;
import org.glassfish.external.arc.Taxonomy;

import javax.management.*;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.*;

import static org.glassfish.external.amx.AMX.*;

/**
@deprecated Extends MBeanProxyHandler by also supporting the functionality required of an AMX.
*/
@Deprecated
@Taxonomy(stability = Stability.PRIVATE)
public final class AMXProxyHandler extends MBeanProxyHandler
        implements AMXProxy, Extra
{

    private static void sdebug(final String s)
    {
        System.out.println(s);
    }
    private final ObjectName mParentObjectName;
    private final String mName;

    /** convert to specified class. */
    public <T extends AMXProxy> T as(final Class<T> intf)
    {
        if (this.getClass().isAssignableFrom(intf))
        {
            return intf.cast(this);
        }

        final T result = proxyFactory().getProxy(getObjectName(), getMBeanInfo(), intf);
        if ( result == null )
        {
            throw new IllegalStateException( "Proxy no longer valid for: " + objectName() );
        }
       
        return result;

    //throw new IllegalArgumentException( "Cannot convert " + getObjectName() +
    // " to interface " + intf.getName() + ", interfaceName from Descriptor = " + interfaceName());
    }

    public Extra extra()
    {
        return this;
    }

    public static AMXProxyHandler unwrap(final AMXProxy proxy)
    {
        return (AMXProxyHandler) Proxy.getInvocationHandler(proxy);
    }

    /**
    Create a new AMX proxy.
     */
    protected AMXProxyHandler(
            final MBeanServerConnection conn,
            final ObjectName objectName,
            final MBeanInfo mbeanInfo)
            throws IOException
    {
        super(conn, objectName, mbeanInfo);

        try
        {
            // one call, so one trip to the server
            final AttributeList attrs = conn.getAttributes(objectName, new String[]
                    {
                        ATTR_NAME, ATTR_PARENT
                    });
            final Map<String, Object> m = JMXUtil.attributeListToValueMap(attrs);

            mParentObjectName = (ObjectName) m.get(ATTR_PARENT);
            mName = (String) m.get(ATTR_NAME);
        }
        catch (final Exception e)
        {
            throw new RuntimeException("Can't get Name and/or Parent attributes from " + objectName, e);
        }
    }
    private static final String GET = "get";
    public final static String ADD_NOTIFICATION_LISTENER = "addNotificationListener";
    public final static String REMOVE_NOTIFICATION_LISTENER = "removeNotificationListener";
    private final static String QUERY = "query";


    public final DomainRoot domainRootProxy()
    {
        return proxyFactory().getDomainRootProxy();
    }
   
    private static final String STRING = String.class.getName();
    private static final String[] EMPTY_SIG = new String[0];
    private static final String[] STRING_SIG = new String[]
    {
        STRING
    };

    protected <T extends AMXProxy> T getProxy(final ObjectName objectName, final Class<T> intf)
    {
        return (proxyFactory().getProxy(objectName, intf));
    }

    protected AMXProxy getProxy(final ObjectName objectName)
    {
        return getProxy(objectName, AMXProxy.class);
    }

    private Object invokeTarget(
            final String methodName,
            final Object[] args,
            final String[] sig)
            throws IOException, ReflectionException, InstanceNotFoundException, MBeanException,
                   AttributeNotFoundException
    {
        final int numArgs = args == null ? 0 : args.length;

        Object result = null;

        if (numArgs == 0 &&
            methodName.startsWith(GET))
        {
            final String attributeName = StringUtil.stripPrefix(methodName, GET);
            result = getMBeanServerConnection().getAttribute(getObjectName(), attributeName);
        }
        else
        {
            result = getMBeanServerConnection().invoke(getObjectName(), methodName, args, sig);
        }

        return result;
    }

    /**
    Return true if the method is one that is requesting a single AMX object.
    Such methods are client-side methods and do not operate on the target MBean.
     */
    protected static boolean isSingleProxyGetter(final Method method, final int argCount)
    {
        boolean isProxyGetter = false;

        final String name = method.getName();
        if ((name.startsWith(GET) || name.startsWith(QUERY)) &&
            AMXProxy.class.isAssignableFrom(method.getReturnType()))
        {
            isProxyGetter = true;
        }

        return (isProxyGetter);
    }

    /**
    The method is one that requests a Proxy. The method could retrieve a real attribute,
    but if there is no real Attribute, attempt to find a child of the matching type.
     */
    AMXProxy invokeSingleProxyGetter(
            final Object myProxy,
            final Method method,
            final Object[] args)
            throws IOException, ReflectionException, InstanceNotFoundException, MBeanException,
                   AttributeNotFoundException
    {
        final String methodName = method.getName();
        final int numArgs = (args == null) ? 0 : args.length;

        final Class<? extends AMXProxy> returnClass = method.getReturnType().asSubclass(AMXProxy.class);
        ObjectName objectName = null;

        if (numArgs == 0)
        {
            //System.out.println( "invokeSingleProxyGetter: intf = " + returnClass.getName() );

            // If a real Attribute exists with this name then it takes priority
            final String attrName = JMXUtil.getAttributeName(method);
            if (getAttributeInfo(attrName) != null)
            {
                objectName = (ObjectName) invokeTarget(methodName, null, null);
            }
            else
            {
                final String type = Util.deduceType(returnClass);

                //System.out.println( "invokeSingleProxyGetter: type = " + type );

                final AMXProxy childProxy = child(type);
                objectName = childProxy == null ? null : childProxy.extra().objectName();
            }
        }
        else
        {
            objectName = (ObjectName) invokeTarget(methodName, args, STRING_SIG);
        }

        return objectName == null ? null : getProxy(objectName, returnClass);
    }

    private static String toString(Object o)
    {
        //String result  = o == null ? "null" : SmartStringifier.toString( o );
        String result = "" + o;

        final int MAX_LENGTH = 256;
        if (result.length() > MAX_LENGTH)
        {
            result = result.substring(0, MAX_LENGTH - 1) + "...";
        }

        return result;
    }

    private static final Map<String, AMXProxy> EMPTY_String_AMX = Collections.emptyMap();
    private final static Class[] NOTIFICATION_LISTENER_SIG1 = new Class[]
    {
        NotificationListener.class
    };
    private final static Class[] NOTIFICATION_LISTENER_SIG2 = new Class[]
    {
        NotificationListener.class,
        NotificationFilter.class,
        Object.class
    };
    /** Cached forever, parent ObjectName */
    private static final String GET_PARENT = GET + ATTR_PARENT;
    /** proxy method */
    private static final String METHOD_NAME_PROP = "nameProp";
    private static final String METHOD_TYPE = "type";
    private static final String METHOD_PARENT_PATH = "parentPath";
    /** proxy method */
    private static final String METHOD_CHILDREN = "children";
    /** proxy method */
    private static final String METHOD_CHILDREN_MAP = "childrenMap";
    /** proxy method */
    private static final String METHOD_CHILDREN_MAPS = "childrenMaps";
    /** proxy method */
    private static final String METHOD_CHILDREN_SET = "childrenSet";
    /** proxy method */
    private static final String METHOD_CHILD = "child";
    /** proxy method */
    private static final String METHOD_PARENT = "parent";
    /** proxy method */
    private static final String METHOD_OBJECTNAME = "objectName";
    /** proxy method */
    private static final String METHOD_EXTRA = "extra";
    /** proxy method */
    private static final String METHOD_AS = "as";
    /** proxy method */
    private static final String METHOD_VALID = "valid";
    /** proxy method */
    private static final String METHOD_ATTRIBUTES_MAP = "attributesMap";
    /** proxy method */
    private static final String METHOD_ATTRIBUTE_NAMES = "attributeNames";
    /** proxy method */
    private static final String METHOD_PATHNAME = "path";
   
    private static final String INVOKE_OPERATION = "invokeOp";

    /**
    These Attributes are handled specially.  For example, J2EE_TYPE and
    J2EE_NAME are part of the ObjectName.
     */
    private static final Set<String> SPECIAL_METHOD_NAMES = SetUtil.newUnmodifiableStringSet(
            GET_PARENT,
            METHOD_NAME_PROP,
            METHOD_TYPE,
            METHOD_PARENT,
            METHOD_PARENT_PATH,
            METHOD_CHILDREN_SET,
            METHOD_CHILDREN_MAP,
            METHOD_CHILDREN_MAPS,
            METHOD_CHILD,
            METHOD_OBJECTNAME,
            METHOD_EXTRA,
            METHOD_AS,
            METHOD_VALID,
            METHOD_ATTRIBUTES_MAP,
            METHOD_ATTRIBUTE_NAMES,
            METHOD_PATHNAME,
            ADD_NOTIFICATION_LISTENER,
            REMOVE_NOTIFICATION_LISTENER);

    /**
    Handle a "special" method; one that requires special handling and/or can
    be dealt with on the client side and/or can be handled most efficiently
    by special-casing it.
     */
    private Object handleSpecialMethod(
            final Object myProxy,
            final Method method,
            final Object[] args)
            throws ClassNotFoundException, JMException, IOException
    {
        final String methodName = method.getName();
        final int numArgs = args == null ? 0 : args.length;
        Object result = null;
        boolean handled = false;

        if (numArgs == 0)
        {
            handled = true;
            if (methodName.equals(METHOD_PARENT))
            {
                result = parent();
            }
            else if (methodName.equals(GET_PARENT))
            {
                result = parent() == null ? null : parent().extra().objectName();
            }
            else if (methodName.equals(METHOD_CHILDREN_SET))
            {
                result = childrenSet();
            }
            else if (methodName.equals(METHOD_CHILDREN_MAPS))
            {
                result = childrenMaps();
            }
            else if (methodName.equals(METHOD_EXTRA))
            {
                result = this;
            }
            else if (methodName.equals(METHOD_OBJECTNAME))
            {
                result = getObjectName();
            }
            else if (methodName.equals(METHOD_NAME_PROP))
            {
                result = getObjectName().getKeyProperty(NAME_KEY);
            }
            else if (methodName.equals(METHOD_TYPE))
            {
                result = type();
            }
            else if (methodName.equals(METHOD_PARENT_PATH))
            {
                result = parentPath();
            }
            else if (methodName.equals(METHOD_ATTRIBUTES_MAP))
            {
                result = attributesMap();
            }
            else if (methodName.equals(METHOD_ATTRIBUTE_NAMES))
            {
                result = attributeNames();
            }
            else if (methodName.equals(METHOD_VALID))
            {
                result = valid();
            }
            else if (methodName.equals(METHOD_PATHNAME))
            {
                result = path();
            }
            else
            {
                handled = false;
            }
        }
        else if (numArgs == 1)
        {
            handled = true;
            final Object arg = args[0];

            if (methodName.equals("equals"))
            {
                result = equals(arg);
            }
            else if (methodName.equals(METHOD_ATTRIBUTES_MAP))
            {
                result = attributesMap( TypeCast.checkedStringSet( Set.class.cast(arg) ) );
            }
            else if (methodName.equals(METHOD_CHILDREN_MAP))
            {
                if (arg instanceof String)
                {
                    result = childrenMap((String) arg);
                }
                else if (arg instanceof Class)
                {
                    result = childrenMap((Class) arg);
                }
                else
                {
                    handled = false;
                }
            }
            else if (methodName.equals(METHOD_CHILD))
            {
                if (arg instanceof String)
                {
                    result = child((String) arg);
                }
                else if (arg instanceof Class)
                {
                    result = child((Class) arg);
                }
                else
                {
                    handled = false;
                }
            }
            else if (methodName.equals(METHOD_AS) && (arg instanceof Class))
            {
                result = as((Class) arg);
            }
            else
            {
                handled = false;
            }
        }
        else
        {
            handled = true;
            final Class[] signature = method.getParameterTypes();

            if (methodName.equals(ADD_NOTIFICATION_LISTENER) &&
                (ClassUtil.sigsEqual(NOTIFICATION_LISTENER_SIG1, signature) ||
                 ClassUtil.sigsEqual(NOTIFICATION_LISTENER_SIG2, signature)))
            {
                addNotificationListener(args);
            }
            else if (methodName.equals(REMOVE_NOTIFICATION_LISTENER) &&
                     (ClassUtil.sigsEqual(NOTIFICATION_LISTENER_SIG1, signature) ||
                      ClassUtil.sigsEqual(NOTIFICATION_LISTENER_SIG2, signature)))
            {
                removeNotificationListener(args);
            }
            else
            {
                handled = false;
            }
        }

        if (!handled)
        {
            assert (false);
            throw new RuntimeException("unknown method: " + method);
        }

        return (result);
    }

    public final Object invoke(
            final Object myProxy,
            final Method method,
            final Object[] args)
            throws java.lang.Throwable
    {
        try
        {
            //System.out.println( "invoking: " + method.getName()  );
            final Object result = _invoke(myProxy, method, args);

            // System.out.println( "invoke: " + method.getName() + ", result = " + result );

            assert (result == null ||
                    ClassUtil.isPrimitiveClass(method.getReturnType()) ||
                    method.getReturnType().isAssignableFrom(result.getClass())) :
                    method.getName() + ": result of type " + result.getClass().getName() +
                    " not assignable to " + method.getReturnType().getName() + ", " +
                    "interfaces: " + toString(result.getClass().getInterfaces()) +
                    ", ObjectName = " + getObjectName();

            //System.out.println( "invoke: " + method.getName() + ", return result = " + result );
            return result;
        }
        catch (IOException e)
        {
            proxyFactory().checkConnection();
            throw e;
        }
        catch (InstanceNotFoundException e)
        {
            isValid();
            throw e;
        }
    }
   
    public Object invokeOp( final String operationName)
    {
        try
        {
            return getMBeanServerConnection().invoke(getObjectName(), operationName, null, null);
        }
        catch( final Exception e )
        {
            throw new RuntimeException( "Exception invoking " + operationName, e );
        }
    }
   
    public Object invokeOp( final String operationName, final Object[] args, final String[] signature )
    {
        try
        {
            return getMBeanServerConnection().invoke(getObjectName(), operationName, args, signature);
        }
        catch( final Exception e )
        {
            throw new RuntimeException( "Exception invoking " + operationName, e );
        }
    }
   
    private boolean isChildGetter( final Method m, final Object[] args)
    {
        boolean isChildGetter = false;
        if ( args == null || args.length == 0 )
        {
            final ChildGetter getter = m.getAnnotation(ChildGetter.class);
            isChildGetter = getter != null;
        }
        return isChildGetter;
    }
   
    private String deduceChildType( final Method m )
    {
        String type = null;
        final ChildGetter getter = m.getAnnotation(ChildGetter.class);
        if ( getter != null )
        {
            type = getter.type();
        }
       
        if ( type == null || type.length() == 0 )
        {
            String temp = m.getName();
            final String GET = "get";
            if ( temp.startsWith(GET) )
            {
                temp = temp.substring( GET.length() );
            }
            type = Util.typeFromName(temp);
        }
       
        return type;
    }
   
    private ObjectName[] handleChildGetter(
        final Method method,
        final Object[] args)
    {
        final String type = deduceChildType(method);
       
        final List<ObjectName> childrenList = childrenOfType(type);
       
        final ObjectName[] children = new ObjectName[ childrenList.size() ];
        childrenList.toArray( children );
       
        return children;
    }
   
    /**
        Convert an ObjectName[] to the proxy-based Map/Set/List/[] result type
     */
        Object
    autoConvert(final Method method, final ObjectName[] items )
    {
        //debug( "_invoke: trying to make ObjectName[] into proxies for " + method.getName() );
        final Class<?> returnType = method.getReturnType();       
        Class<? extends AMXProxy> proxyClass = AMXProxy.class;
       
        Object result = items;  // fallback is to return the original ObjectName[]
       
        if ( returnType.isArray() )
        {
            final Class<?> componentType = returnType.getComponentType();
            if ( AMXProxy.class.isAssignableFrom(componentType) )
            {
                proxyClass = componentType.asSubclass(AMXProxy.class);
                final List<AMXProxy> proxyList = proxyFactory().toProxyList(items, proxyClass);
                final AMXProxy[] proxies = (AMXProxy[])Array.newInstance( proxyClass, proxyList.size() );
                proxyList.toArray(proxies);
                result = proxies;
            }
        }
        else
        {
            if (method.getGenericReturnType() instanceof ParameterizedType)
            {
                proxyClass = getProxyClass((ParameterizedType) method.getGenericReturnType());
            }
           
            // Note that specialized sub-types of Set/List/Map, are *not* supported;
            // the method must be declared with Set/List/Map. This is intentional
            // to discourage use of HashMap, LinkedList, ArrayList, TreeMap, etc.
            if (Set.class.isAssignableFrom(returnType))
            {
                result = proxyFactory().toProxySet(items, proxyClass);
            }
            else if (List.class.isAssignableFrom(returnType))
            {
                result = proxyFactory().toProxyList(items, proxyClass);
            }
            else if (Map.class.isAssignableFrom(returnType))
            {
                result = proxyFactory().toProxyMap(items, proxyClass);
            }
        }
       
        return result;
    }
   
        private List<ObjectName>
    tentativeObjectNameList(final Collection<?> items)
    {
        final List<ObjectName> objectNames = new ArrayList<ObjectName>();
        // verify that all items are of type ObjectName
        // do NOT throw an exception, we just want to check, not require it.
        for( final Object item : items )
        {
            if ( ! (item instanceof ObjectName) )
            {
                return null;
            }
            objectNames.add((ObjectName)item);
        }
        return objectNames;
    }
   
    /**
        Convert an Map/Set/List to the proxy-based Map/Set/List/[] result type
     */
        Object
    autoConvertCollection(final Method method, final Object itemsIn)
    {
        Object result = itemsIn;  // fallback is to return the original result
       
        //System.out.println( "autoConvertCollection() for " + method.getName() );
        final Class<?> returnType = method.getReturnType();
        Class<? extends AMXProxy> proxyClass = AMXProxy.class;
        if (method.getGenericReturnType() instanceof ParameterizedType)
        {
            proxyClass = getProxyClass((ParameterizedType) method.getGenericReturnType());
        }
       
        // definitely do not want to auto convert to proxy if it's List<ObjectName> (for example)
        if ( proxyClass == null || ! AMXProxy.class.isAssignableFrom(proxyClass) )
        {
            return itemsIn;
        }
       
        if ( Collection.class.isAssignableFrom(returnType) && (itemsIn instanceof Collection) )
        {
            final List<ObjectName> objectNames = tentativeObjectNameList((Collection)itemsIn);
            if ( objectNames != null )
            {
                final ObjectName[] objectNamesA = new ObjectName[objectNames.size()];
                objectNames.toArray(objectNamesA);
                if (Set.class.isAssignableFrom(returnType))
                {
                    result = proxyFactory().toProxySet(objectNamesA, proxyClass);
                }
                else if (List.class.isAssignableFrom(returnType))
                {
                    result = proxyFactory().toProxyList(objectNamesA, proxyClass);
                }
            }
        }
        else if ( Map.class.isAssignableFrom(returnType) && (itemsIn instanceof Map) )
        {
            final Map m = (Map)itemsIn;
            final Map<String,AMXProxy> proxies = new HashMap<String,AMXProxy>();
            boolean ok = true;
            for( final Object  meo : m.entrySet() )
            {
                Map.Entry me = (Map.Entry)meo;
                if ( ! (me.getKey() instanceof String) )
                {
                    ok = false;
                    break;
                }
                final Object value = me.getValue();
                if ( ! (value instanceof ObjectName) )
                {
                    ok = false;
                    break;
                }
                proxies.put( (String)me.getKey(), proxyFactory().getProxy((ObjectName)value, proxyClass ));
            }
           
            if ( ok )
            {
                result = proxies;
            }
        }
   
        return result;
    }


    protected Object _invoke(
            final Object myProxy,
            final Method method,
            final Object[] argsIn)
            throws java.lang.Throwable
    {
        final int numArgs = argsIn == null ? 0 : argsIn.length;
       
        // auto-convert any AMXProxy to ObjectName (Lists, Maps, etc thereof are caller's design headache)
        final Object[] args = argsIn == null new Object[0] : new Object[ argsIn.length ];
        for( int i = 0; i < numArgs; ++i )
        {
            args[i] = argsIn[i];    // leave alone by default
            if ( args[i] instanceof AMXProxy )
            {
                args[i] = ((AMXProxy)argsIn[i]).objectName();
            }
        }
       
        debugMethod(method.getName(), args);
        Object result = null;
        final String methodName = method.getName();
        //System.out.println( "_invoke: " + methodName + " on " + objectName() );

        if (SPECIAL_METHOD_NAMES.contains(methodName))
        {
            result = handleSpecialMethod(myProxy, method, args);
        }
        else if ( isChildGetter(method, args) )
        {
            result = handleChildGetter(method,args);
        }
        else if ( INVOKE_OPERATION.equals(methodName) )
        {
            if ( args.length == 1 )
            {
                result = invokeOp( (String)args[0] );
            }
            else if ( args.length == 3 )
            {
                result = invokeOp( (String)args[0], (Object[])args[1], (String[])args[2] );
            }
            else
            {
                throw new IllegalArgumentException();
            }
        }
        else
        {
            //System.out.println( "_invoke: (not handled): " + methodName + " on " + objectName() );
            if (isSingleProxyGetter(method, numArgs))
            {
                result = invokeSingleProxyGetter(myProxy, method, args);
            }
            else
            {
                result = super.invoke(myProxy, method, args);
            }
        }

        // AUTO-CONVERT certain return types to proxy from ObjectName, ObjectName[]

        final Class<?> returnType = method.getReturnType();

        if ((result instanceof ObjectName) &&
            AMXProxy.class.isAssignableFrom(returnType))
        {
            result = getProxy((ObjectName) result, returnType.asSubclass(AMXProxy.class));
        }
        else if (result != null &&
                 result instanceof ObjectName[])
        {
            result = autoConvert( method, (ObjectName[]) result );
        }
        else if ( result != null && ( (result instanceof Collection) || (result instanceof Map) ) )
        {
            result = autoConvertCollection( method, result );
        }

        //System.out.println( "_invoke: done:  result class is " + result.getClass().getName() );
        return (result);
    }

    private Class<? extends AMXProxy> getProxyClass(final ParameterizedType pt)
    {
        Class<? extends AMXProxy> intf = null;

        final Type[] argTypes = pt.getActualTypeArguments();
        if (argTypes.length >= 1)
        {
            final Type argType = argTypes[argTypes.length - 1];
            if ((argType instanceof Class) && AMXProxy.class.isAssignableFrom((Class) argType))
            {
                intf = ((Class) argType).asSubclass(AMXProxy.class);
            }
        }
        if (intf == null)
        {
            intf = AMXProxy.class;
        }
        return intf;
    }

    protected void addNotificationListener(final Object[] args)
            throws IOException, InstanceNotFoundException
    {
        final NotificationListener listener = (NotificationListener) args[ 0];
        final NotificationFilter filter = (NotificationFilter) (args.length <= 1 ? null : args[ 1]);
        final Object handback = args.length <= 1 ? null : args[ 2];

        getMBeanServerConnection().addNotificationListener(
                getObjectName(), listener, filter, handback);
    }

    protected void removeNotificationListener(final Object[] args)
            throws IOException, InstanceNotFoundException, ListenerNotFoundException
    {
        final NotificationListener listener = (NotificationListener) args[ 0];

        // important:
        // this form removes the same listener registered with different filters and/or handbacks
        if (args.length == 1)
        {
            getMBeanServerConnection().removeNotificationListener(getObjectName(), listener);
        }
        else
        {
            final NotificationFilter filter = (NotificationFilter) args[ 1];
            final Object handback = args[ 2];

            getMBeanServerConnection().removeNotificationListener(
                    getObjectName(), listener, filter, handback);
        }
    }

//-----------------------------------
    public static String interfaceName(final MBeanInfo info)
    {
        final Object value = info.getDescriptor().getFieldValue(DESC_STD_INTERFACE_NAME);
        return (String) value;
    }

    @Override
    public String interfaceName()
    {
        String name = super.interfaceName();
        if (name == null)
        {
            name = AMXProxy.class.getName();
        }

        return name;
    }

    public static String genericInterfaceName(final MBeanInfo info)
    {
        final Object value = info.getDescriptor().getFieldValue(DESC_GENERIC_INTERFACE_NAME);
        return (String) value;
    }
    public String genericInterfaceName()
    {
        return genericInterfaceName(mbeanInfo());
    }

    public Class<? extends AMXProxy>  genericInterface()
    {
        return ProxyFactory.genericInterface(mbeanInfo());
    }

    public boolean valid()
    {
        return isValid();
    }

    public ProxyFactory proxyFactory()
    {
        return (ProxyFactory.getInstance(getMBeanServerConnection()));
    }

    public MBeanServerConnection mbeanServerConnection()
    {
        return getMBeanServerConnection();
    }

    public ObjectName objectName()
    {
        return getObjectName();
    }

    public String nameProp()
    {
        // name as found in the ObjectName
        return Util.getNameProp(getObjectName());
    }

    public String parentPath()
    {
        return Util.unquoteIfNeeded(getObjectName().getKeyProperty(PARENT_PATH_KEY));
    }

    public String type()
    {
        return Util.getTypeProp(getObjectName());
    }

    public String getName()
    {
        // internal *unquoted* name, but we consider it invariant once fetched
        return mName;
    }

    public ObjectName getParent()
    {
        return mParentObjectName;
    }

    public AMXProxy parent()
    {
        if ( mParentObjectName == null ) return null;
       
        final AMXProxy proxy = proxyFactory().getProxy(mParentObjectName);
       
        return proxy;
    }

    public String path()
    {
        // special case DomainRoot, which has no parent
        if (getParent() == null)
        {
            return DomainRoot.PATH;
        }

        final ObjectName on = getObjectName();
        final String parentPath = Util.unquoteIfNeeded(Util.getParentPathProp(on));

        final String type = Util.getTypeProp(on);
        return PathnameParser.path(parentPath, type, singleton() ? null : Util.getNameProp(on));
    }

    public ObjectName[] getChildren()
    {
        ObjectName[] objectNames = null;
        try
        {
            objectNames = (ObjectName[]) getAttributeNoThrow(ATTR_CHILDREN);
        }
        catch (final Exception e)
        {
            final Throwable t = ExceptionUtil.getRootCause(e);
            if (!(t instanceof AttributeNotFoundException))
            {
                throw new RuntimeException("Could not get Children attribute", e);
            }
        }
        return objectNames;
    }

    /**
    Returns an array of children, including an empty array if there are none, but children
    are possible.  Returns null if children are not possible.
     */
    public Set<AMXProxy> childrenSet()
    {
        return childrenSet(getChildren());
    }

    public Set<AMXProxy> childrenSet(final ObjectName[] objectNames)
    {
        return objectNames == null ? null : SetUtil.newSet(proxyFactory().toProxy(objectNames));
    }

    public Set<String> childrenTypes(final ObjectName[] objectNames)
    {
        final Set<String> types = new HashSet<String>();
        for (final ObjectName o : objectNames)
        {
            final String type = Util.getTypeProp(o);
            types.add(type);
        }
        return types;
    }

    public Map<String, AMXProxy> childrenMap(final String type)
    {
        return childrenMap(type, AMXProxy.class);
    }

    public <T extends AMXProxy> Map<String, T> childrenMap(final Class<T> intf)
    {
        if (!intf.isInterface())
        {
            throw new IllegalArgumentException("" + intf);
        }
        return childrenMap(Util.deduceType(intf), intf);
    }

    private List<ObjectName> childrenOfType(final String type)
    {
        final ObjectName[] objectNames = getChildren();
        if (objectNames == null)
        {
            return Collections.emptyList();
        }
       
        final List<ObjectName> items = new ArrayList<ObjectName>();

        for (final ObjectName objectName : objectNames)
        {
            if (Util.getTypeProp(objectName).equals(type))
            {
                items.add(objectName);
            }
        }
        return items;
    }
   
    public <T extends AMXProxy> Map<String, T> childrenMap(final String type, final Class<T> intf)
    {
        final Map<String, T> m = new HashMap<String, T>();
        for (final ObjectName objectName : childrenOfType(type))
        {
            m.put( Util.unquoteIfNeeded(Util.getNameProp(objectName)), getProxy(objectName, intf));
        }
        return m;
    }

    public Map<String, Map<String, AMXProxy>> childrenMaps()
    {
        final ObjectName[] children = getChildren();
        if (children == null)
        {
            return null;
        }

        final Set<AMXProxy> childrenSet = childrenSet(children);

        final Map<String, Map<String, AMXProxy>> maps = new HashMap<String, Map<String, AMXProxy>>();
        final Set<String> types = childrenTypes(children);
        for (final String type : types)
        {
            maps.put(type, new HashMap<String, AMXProxy>());
        }

        for (final AMXProxy proxy : childrenSet)
        {
            final Map<String, AMXProxy> m = maps.get( proxy.type() );
            m.put(proxy.nameProp(), proxy);
        }
        return maps;
    }

    public <T extends AMXProxy> Set<T> childrenSet(final String type, final Class<T> intf)
    {
        final Map<String, T> m = childrenMap(type, intf);
        return new HashSet<T>(m.values());
    }

    public AMXProxy child(final String type)
    {
        return child(type, AMXProxy.class);
    }

    public <T extends AMXProxy> T child(final Class<T> intf)
    {
        final String type = Util.deduceType(intf);
        //sdebug( "Deduced type of " + intf.getName() + " = " + type );
        return child(type, intf);
    }

    public <T extends AMXProxy> T child(final String type, final Class<T> intf)
    {
        //sdebug( "Child " + type + " has interface " + intf.getName() );
        final Map<String, T> children = childrenMap(type, intf);
        if (children.size() == 0)
        {
            return null;
        }
        if (children.size() > 1)
        {
            throw new IllegalArgumentException("Not a singleton: " + type);
        }

        final T child = children.values().iterator().next();
        if (!child.extra().singleton())
        {
            throw new IllegalArgumentException("Not a singleton: " + type);
        }

        return child;
    }

    public <T extends AMXProxy> T child(final String type, final String name, final Class<T> intf)
    {
        final Set<AMXProxy> children = childrenSet();
        if (children == null)
        {
            return null;
        }

        T child = null;
        for (final AMXProxy c : children)
        {
            final ObjectName objectName = c.extra().objectName();
            if (Util.getTypeProp(objectName).equals(type) && Util.getNameProp(objectName).equals(name))
            {
                child = c.as(intf);
                break;
            }
        }
        return child;
    }

    public final MBeanInfo mbeanInfo()
    {
        return getMBeanInfo();
    }
   
   
    public Map<String, Object> attributesMap( final Set<String> attrNames )
    {
        try
        {
            final String[] namesArray = attrNames.toArray(new String[attrNames.size()]);
            final AttributeList attrs = getAttributes(namesArray);
            return JMXUtil.attributeListToValueMap(attrs);
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }
    public Map<String, Object> attributesMap()
    {
        return attributesMap( attributeNames() );
    }

    public MBeanAttributeInfo getAttributeInfo(final String name)
    {
        for (final MBeanAttributeInfo attrInfo : getMBeanInfo().getAttributes())
        {
            if (attrInfo.getName().equals(name))
            {
                return attrInfo;
            }
        }
        return null;
    }

    public Set<String> attributeNames()
    {
        final String[] names = JMXUtil.getAttributeNames(getMBeanInfo().getAttributes());

        return SetUtil.newStringSet(names);
    }

    public static <T> T getDescriptorField(final MBeanInfo info, final String name, final T defaultValue)
    {
        T value = (T) info.getDescriptor().getFieldValue(name);
        if (value == null)
        {
            value = defaultValue;
        }
        return value;
    }

    public static boolean singleton(final MBeanInfo info)
    {
        return getDescriptorField(info, DESC_IS_SINGLETON, Boolean.FALSE);
    }
   
    public static boolean globalSingleton(final MBeanInfo info)
    {
        return getDescriptorField(info, DESC_IS_GLOBAL_SINGLETON, Boolean.FALSE);
    }

    protected <T> T getDescriptorField(final String name, final T defaultValue)
    {
        return getDescriptorField(getMBeanInfo(), name, defaultValue);
    }

    public boolean singleton()
    {
        return getDescriptorField(DESC_IS_SINGLETON, Boolean.FALSE);
    }

    public boolean globalSingleton()
    {
        return getDescriptorField(DESC_IS_GLOBAL_SINGLETON, Boolean.FALSE);
    }

    public String group()
    {
        return getDescriptorField(DESC_GROUP, GROUP_OTHER);
    }

    public boolean supportsAdoption()
    {
        return getDescriptorField(DESC_SUPPORTS_ADOPTION, Boolean.FALSE);
    }
    private static final String[] EMPTY_STRINGS = new String[0];

    public String[] subTypes()
    {
        return getDescriptorField(DESC_SUB_TYPES, EMPTY_STRINGS);
    }
   
    public String java() {
        final Tools tools  = domainRootProxy().getTools();
        return tools.java( getObjectName() );
    }
   
    public Descriptor descriptor() {
        return getMBeanInfo().getDescriptor();
    }
   
    public MBeanAttributeInfo attributeInfo(final String attrName) {
        for( final MBeanAttributeInfo info: getMBeanInfo().getAttributes() )
        {
            if ( info.getName().equals(attrName) )
            {
                return info;
            }
        }
        return null;
    }
   
    @Override
    public MBeanOperationInfo operationInfo(final String operationName) {
        for( final MBeanOperationInfo info: getMBeanInfo().getOperations() )
        {
            if ( info.getName().equals(operationName) )
            {
                return info;
            }
        }
        return null;
    }
   
    @Override
    public boolean equals(final Object rhs)
    {
        return super.equals(rhs);
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }
}




TOP

Related Classes of org.glassfish.admin.amx.core.proxy.AMXProxyHandler

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.