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-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.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)) {
            // do nothing
        } 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();

        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>();

        for (final Map.Entry<String, ObjectName> me : objectNameMap.entrySet()) {
            final ObjectName objectName = me.getValue();

            try {
                final AMXProxy proxy = getProxy(objectName);
                if (proxy != null) {
                    resultMap.put(me.getKey(), 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.