usr/src/java/rad/org/opensolaris/os/rad/jmx/RadJMX.java
author David Powell <david.e.powell@oracle.com>
Thu, 11 Aug 2011 15:41:42 -0700
changeset 764 ebb25c1dac73
parent 677 fbc09f84f958
permissions -rw-r--r--
18812 Support building with alternate java implementations

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
 */

package org.opensolaris.os.rad.jmx;

import java.io.IOException;
import javax.management.*;
import org.opensolaris.os.adr.*;
import org.opensolaris.os.rad.Versions;
import org.opensolaris.os.rad.Version;

public class RadJMX {

    //
    // Static data
    //

    // Descriptor fields
    static final String INTERFACE_NAME = "org.opensolaris.os.rad.interfaceName";
    static final String API_NAME = "org.opensolaris.os.rad.apiName";
    static final String PRIVATE_VER = "org.opensolaris.os.rad.privateVersion";
    static final String UNCOMMITTED_VER =
	"org.opensolaris.os.rad.uncommittedVersion";
    static final String COMMITTED_VER =
	"org.opensolaris.os.rad.commitedVersion";
    static final String STABILITY = "org.opensolaris.os.rad.stability";
    // Pointer to private API data - not for general consumption
    static final String API_PRIVDATA = "org.opensolaris.os.rad.apiPrivate";

    //
    // RadJMXProxy methods
    //

    /**
     * Creates an MXBean proxy after checking that the client and server
     * versions of the specified interface are compatible, for the given
     * stability.
     *
     * @param connection the MBean Server in which the MBean is registered.
     * @param objectName the name of the MBean to forward to.
     * @param interfaceClass the MBean interface that the proxy will implement.
     * @param notificationBroadcaster whether to implement the
     * {@code NotificationBroadcaster} interface in the proxy.
     * @param stab the required stability of the MBean interface.
     *
     * @return a new proxy instance.
     *
     * @throws IOException if there is error while communicating with the
     * MBean server.
     * @throws InstanceNotFoundException if there is no MBean registered for
     * the given object name.
     * @throws IntrospectionException if there an error while introspecting
     * the management interface.
     * @throws ReflectionException if there is an error while invoking methods
     * on the MBean using reflection.
     * @throws IncompatibleVersionException if the client and server versions
     * of the MBean interface are incompatible, for the specified stability.
     */
    public static <T> T newMXBeanProxy(MBeanServerConnection connection,
	ObjectName objectName, Class<T> interfaceClass,
	boolean notificationBroadcaster, Stability stab) throws IOException,
	InstanceNotFoundException, IntrospectionException, ReflectionException,
	IncompatibleVersionException {

	MBeanInfo mbInfo = connection.getMBeanInfo(objectName);

	Versions versions = interfaceClass.getAnnotation(
	    org.opensolaris.os.rad.Versions.class);
	Descriptor descriptor = mbInfo.getDescriptor();

	assertCompatible(interfaceClass, stab, versions, descriptor);

        return JMX.newMXBeanProxy(connection, objectName,
	    interfaceClass, notificationBroadcaster);
    }

    public static <T> T newMXBeanProxy(MBeanServerConnection connection,
	ObjectName objectName, Class<T> interfaceClass,	Stability stab)
	throws IOException, InstanceNotFoundException, IntrospectionException,
	ReflectionException, IncompatibleVersionException {

	return newMXBeanProxy(connection, objectName, interfaceClass,
	    false, stab);
    }

    private static APIVersion getClientVersion(Stability s, Versions versInfo) {
	if (versInfo != null) {
	    for (Version version : versInfo.versions()) {
		if (version.stability() == s) {
		    return new APIVersion(version.stability(), version.major(),
			version.minor());
		}
	    }
	}
	return APIVersion.getNone(s);
    }

    private static void assertCompatible(Class<?> interfaceClass,
	Stability stab, Versions vers, Descriptor desc)
	throws IncompatibleVersionException {

	APIVersion vc = getClientVersion(stab, vers);
	APIVersion vs = APIVersion.getNone(stab);
	if (vers != null && desc != null && vers.interfaceName() != null &&
	    vers.interfaceName().equals(desc.getFieldValue(INTERFACE_NAME))) {
	    String aname = vers.apiName();
	    API api = (API) desc.getFieldValue(API_PRIVDATA);
	    if (aname != null && api != null) {
		if (aname.equals(desc.getFieldValue(API_NAME))) {
		    vs = api.getVersionByStability(stab);
		} else {
		    for (API parent : api.getParents()) {
			if (aname.equals(parent.getName())) {
			    vs = parent.getVersionByStability(stab);
			    break;
			}
		    }
		}
	    }
	}

	if (vs.getMajor() != vc.getMajor() || vs.getMinor() < vc.getMinor())
	    throw new IncompatibleVersionException(interfaceClass, vc, vs);
    }
}