aoqi@0: /* aoqi@0: * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: aoqi@0: package com.sun.org.glassfish.external.amx; aoqi@0: aoqi@0: import javax.management.ObjectName; aoqi@0: import javax.management.MBeanServer; aoqi@0: import javax.management.MBeanServerConnection; aoqi@0: aoqi@0: import java.io.IOException; aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * AMX behavior specific to Glassfish V3. aoqi@0: */ aoqi@0: public final class AMXGlassfish aoqi@0: { aoqi@0: public static final String DEFAULT_JMX_DOMAIN = "amx"; aoqi@0: aoqi@0: /** Default domain support */ aoqi@0: public static final AMXGlassfish DEFAULT = new AMXGlassfish(DEFAULT_JMX_DOMAIN); aoqi@0: aoqi@0: private final String mJMXDomain; aoqi@0: private final ObjectName mDomainRoot; aoqi@0: aoqi@0: /** Anything other than {@link #DEFAULT} is not supported in Glassfish V3 */ aoqi@0: public AMXGlassfish(final String jmxDomain) aoqi@0: { aoqi@0: mJMXDomain = jmxDomain; aoqi@0: mDomainRoot = newObjectName("", "domain-root", null); aoqi@0: } aoqi@0: aoqi@0: /** Return a version string, or null if not running in Glassfish */ aoqi@0: public static String getGlassfishVersion() aoqi@0: { aoqi@0: // must all exist as a check to verify that it's Glassfish V3 aoqi@0: final String version = System.getProperty( "glassfish.version" ); aoqi@0: return version; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** JMX domain used by AMX MBeans. aoqi@0: *

aoqi@0: * All MBeans in this domain must be AMX-compliant, see http://tinyurl.com/nryoqp = aoqi@0: https://glassfish.dev.java.net/nonav/v3/admin/planning/V3Changes/V3_AMX_SPI.html aoqi@0: */ aoqi@0: public String amxJMXDomain() aoqi@0: { aoqi@0: return mJMXDomain; aoqi@0: } aoqi@0: aoqi@0: /** JMX domain used by AMX support MBeans. Private use only */ aoqi@0: public String amxSupportDomain() aoqi@0: { aoqi@0: return amxJMXDomain() + "-support"; aoqi@0: } aoqi@0: aoqi@0: /** name of the Domain Admin Server (DAS) as found in an ObjectName */ aoqi@0: public String dasName() aoqi@0: { aoqi@0: return "server"; aoqi@0: } aoqi@0: aoqi@0: /** name of the Domain Admin Server (DAS) <config> */ aoqi@0: public String dasConfig() aoqi@0: { aoqi@0: return dasName() + "-config"; aoqi@0: } aoqi@0: aoqi@0: /** return the ObjectName of the AMX DomainRoot MBean */ aoqi@0: public ObjectName domainRoot() aoqi@0: { aoqi@0: return mDomainRoot; aoqi@0: } aoqi@0: aoqi@0: /** ObjectName for top-level monitoring MBean (parent of those for each server) */ aoqi@0: public ObjectName monitoringRoot() aoqi@0: { aoqi@0: return newObjectName("/", "mon", null); aoqi@0: } aoqi@0: aoqi@0: /** ObjectName for top-level monitoring MBean for specified server */ aoqi@0: public ObjectName serverMon(final String serverName) aoqi@0: { aoqi@0: return newObjectName("/mon", "server-mon", serverName); aoqi@0: } aoqi@0: aoqi@0: /** ObjectName for top-level monitoring MBean for the DAS. */ aoqi@0: public ObjectName serverMonForDAS() { aoqi@0: return serverMon( "server" ) ; aoqi@0: } aoqi@0: aoqi@0: /** Make a new AMX ObjectName with unchecked exception. aoqi@0: * name must be null to create a singleton ObjectName. aoqi@0: * Note that the arguments must not contain the characters aoqi@0: * @param pp The parent part aoqi@0: * @param type The ObjectName type aoqi@0: * @param name The ObjectName name aoqi@0: * @return The objectname with pp, type, and (optionally) name. aoqi@0: */ aoqi@0: public ObjectName newObjectName( aoqi@0: final String pp, aoqi@0: final String type, aoqi@0: final String name) aoqi@0: { aoqi@0: String props = prop(AMX.PARENT_PATH_KEY, pp) + "," + prop(AMX.TYPE_KEY, type); aoqi@0: if (name != null) { aoqi@0: props = props + "," + prop(AMX.NAME_KEY, name); aoqi@0: } aoqi@0: aoqi@0: return newObjectName( props); aoqi@0: } aoqi@0: aoqi@0: /** Make a new ObjectName for AMX domain with unchecked exception */ aoqi@0: public ObjectName newObjectName(final String s) aoqi@0: { aoqi@0: String name = s; aoqi@0: if ( ! name.startsWith( amxJMXDomain() ) ) { aoqi@0: name = amxJMXDomain() + ":" + name; aoqi@0: } aoqi@0: aoqi@0: return AMXUtil.newObjectName( name ); aoqi@0: } aoqi@0: aoqi@0: private static String prop(final String key, final String value) aoqi@0: { aoqi@0: return key + "=" + value; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: ObjectName for {@link BootAMXMBean} aoqi@0: */ aoqi@0: public ObjectName getBootAMXMBeanObjectName() aoqi@0: { aoqi@0: return AMXUtil.newObjectName( amxSupportDomain() + ":type=boot-amx" ); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: Invoke the bootAMX() method on {@link BootAMXMBean}. Upon return, aoqi@0: AMX continues to load. aoqi@0: A cilent should call {@link invokeWaitAMXReady} prior to use. aoqi@0: */ aoqi@0: public void invokeBootAMX(final MBeanServerConnection conn) aoqi@0: { aoqi@0: // start AMX and wait for it to be ready aoqi@0: try aoqi@0: { aoqi@0: conn.invoke( getBootAMXMBeanObjectName(), BootAMXMBean.BOOT_AMX_OPERATION_NAME, null, null); aoqi@0: } aoqi@0: catch (final Exception e) aoqi@0: { aoqi@0: e.printStackTrace(); aoqi@0: throw new RuntimeException(e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: Invoke the waitAMXReady() method on the DomainRoot MBean, which must already be loaded. aoqi@0: */ aoqi@0: private static void invokeWaitAMXReady(final MBeanServerConnection conn, final ObjectName objectName) aoqi@0: { aoqi@0: try aoqi@0: { aoqi@0: conn.invoke( objectName, "waitAMXReady", null, null ); aoqi@0: } aoqi@0: catch( final Exception e ) aoqi@0: { aoqi@0: throw new RuntimeException(e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: Listen for the registration of AMX DomainRoot aoqi@0: Listening starts automatically. aoqi@0: */ aoqi@0: public MBeanListener listenForDomainRoot( aoqi@0: final MBeanServerConnection server, aoqi@0: final T callback) aoqi@0: { aoqi@0: final MBeanListener listener = new MBeanListener( server, domainRoot(), callback); aoqi@0: listener.startListening(); aoqi@0: return listener; aoqi@0: } aoqi@0: aoqi@0: private static final class WaitForDomainRootListenerCallback extends MBeanListener.CallbackImpl { aoqi@0: private final MBeanServerConnection mConn; aoqi@0: aoqi@0: public WaitForDomainRootListenerCallback( final MBeanServerConnection conn ) { aoqi@0: mConn = conn; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void mbeanRegistered(final ObjectName objectName, final MBeanListener listener) { aoqi@0: super.mbeanRegistered(objectName,listener); aoqi@0: invokeWaitAMXReady(mConn, objectName); aoqi@0: mLatch.countDown(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: Wait until AMX has loaded and is ready for use. aoqi@0:

aoqi@0: This will not cause AMX to load; it will block forever until AMX is ready. In other words, aoqi@0: don't call this method unless it's a convenient thread that can wait forever. aoqi@0: */ aoqi@0: public ObjectName waitAMXReady( final MBeanServerConnection server) aoqi@0: { aoqi@0: final WaitForDomainRootListenerCallback callback = new WaitForDomainRootListenerCallback(server); aoqi@0: listenForDomainRoot( server, callback ); aoqi@0: callback.await(); aoqi@0: return callback.getRegistered(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: Listen for the registration of the {@link BootAMXMBean}. aoqi@0: Listening starts automatically. See {@link AMXBooter#BootAMXCallback}. aoqi@0: */ aoqi@0: public MBeanListener listenForBootAMX( aoqi@0: final MBeanServerConnection server, aoqi@0: final T callback) aoqi@0: { aoqi@0: final MBeanListener listener = new MBeanListener( server, getBootAMXMBeanObjectName(), callback); aoqi@0: listener.startListening(); aoqi@0: return listener; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: Callback for {@link MBeanListener} that waits for the BootAMXMBean to appear; aoqi@0: it always will load early in server startup. Once it has loaded, AMX can be booted aoqi@0: via {@link #bootAMX}. A client should normally just call {@link #bootAMX}, but aoqi@0: this callback may be suclassed if desired, and used as a trigger to aoqi@0: boot AMX and then take other dependent actions. aoqi@0: */ aoqi@0: public static class BootAMXCallback extends MBeanListener.CallbackImpl aoqi@0: { aoqi@0: private final MBeanServerConnection mConn; aoqi@0: public BootAMXCallback(final MBeanServerConnection conn) aoqi@0: { aoqi@0: mConn = conn; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void mbeanRegistered(final ObjectName objectName, final MBeanListener listener) aoqi@0: { aoqi@0: super.mbeanRegistered(objectName, listener); aoqi@0: mLatch.countDown(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: Ensure that AMX is loaded and ready to use. This method returns only when all aoqi@0: AMX subsystems have been loaded. aoqi@0: It can be called more than once without ill effect, subsequent calls are ignored. aoqi@0: @param conn connection to the MBeanServer aoqi@0: @return the ObjectName of the domain-root MBean aoqi@0: */ aoqi@0: public ObjectName bootAMX(final MBeanServerConnection conn) aoqi@0: throws IOException aoqi@0: { aoqi@0: final ObjectName domainRoot = domainRoot(); aoqi@0: aoqi@0: if ( !conn.isRegistered( domainRoot ) ) aoqi@0: { aoqi@0: // wait for the BootAMXMBean to be available (loads at startup) aoqi@0: final BootAMXCallback callback = new BootAMXCallback(conn); aoqi@0: listenForBootAMX(conn, callback); aoqi@0: callback.await(); // block until the MBean appears aoqi@0: aoqi@0: invokeBootAMX(conn); aoqi@0: aoqi@0: final WaitForDomainRootListenerCallback drCallback = new WaitForDomainRootListenerCallback(conn); aoqi@0: listenForDomainRoot(conn, drCallback); aoqi@0: drCallback.await(); aoqi@0: aoqi@0: invokeWaitAMXReady(conn, domainRoot); aoqi@0: } aoqi@0: else aoqi@0: { aoqi@0: invokeWaitAMXReady(conn, domainRoot ); aoqi@0: } aoqi@0: return domainRoot; aoqi@0: } aoqi@0: aoqi@0: public ObjectName bootAMX(final MBeanServer server) aoqi@0: { aoqi@0: try aoqi@0: { aoqi@0: return bootAMX( (MBeanServerConnection)server); aoqi@0: } aoqi@0: catch( final IOException e ) aoqi@0: { aoqi@0: throw new RuntimeException(e); aoqi@0: } aoqi@0: } aoqi@0: }