All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.admin.amx.core.proxy.ProxyFactory Maven / Gradle / Ivy

/*
 * 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.
 */
// Portions Copyright [2019] Payara Foundation and/or affiliates

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.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;

/**
 * @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. 

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 mMBeanInfoCache = new ConcurrentHashMap(); private static final AMXDebugHelper mDebug = new AMXDebugHelper(ProxyFactory.class.getName()); private static void debug(final Object... args) { mDebug.println( args ); } private static final Map INSTANCES = Collections.synchronizedMap(new HashMap()); /** * 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 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()); return true; } catch (Exception e) { connectionBad(); return false; } } 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.
Used * internally as callback for {@link javax.management.NotificationListener}. * DO NOT CALL THIS METHOD. */ @Override 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); } } public DomainRoot createDomainRoot() { return (mDomainRoot); } public DomainRoot initDomainRoot() throws IOException { final ObjectName domainRootObjectName = getDomainRootObjectName(); return getProxy(domainRootObjectName, DomainRoot.class); } /** * 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) { 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 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 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.parseBoolean(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 getProxy( final ObjectName objectName, Class intf) { final MBeanInfo info = getMBeanInfo(objectName); if (info == null) { return null; } return getProxy(objectName, info, intf); } /** * Call getProxy(objectName, getGenericAMXInterface() */ public AMXProxy getProxy(final ObjectName objectName) { final MBeanInfo info = getMBeanInfo(objectName); if (info == null) { return null; } final Class intf = genericInterface(info); return getProxy(objectName, info, intf); } public static Class genericInterface(final MBeanInfo info) { final String intfName = AMXProxyHandler.genericInterfaceName(info); Class 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 getProxy(final ObjectName objectName, final MBeanInfo mbeanInfoIn, final Class intfIn) { 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 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); } catch (IllegalArgumentException e) { throw e; } catch (Exception e) { final Throwable rootCause = ExceptionUtil.getRootCause(e); if (!(rootCause instanceof InstanceNotFoundException)) { 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)); } /** * 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 toProxySet(final Set objectNames) { final Set 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 toProxySet(final ObjectName[] objectNames, final Class intf) { final Set 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 toProxyList(final Collection objectNames) { final List 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 toProxyMap( final Map objectNameMap) { final Map resultMap = new HashMap(); for (final Map.Entry 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 toProxyMap(final ObjectName[] objectNames, final Class intf) { final Map 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 toProxyList(final ObjectName[] objectNames, final Class intf) { final List result = new ArrayList(); for (final ObjectName objectName : objectNames) { final AMXProxy proxy = getProxy(objectName, intf); if (proxy != null) { result.add(proxy); } } return (result); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy