FileDocCategorySizeDatePackage
Introspector.javaAPI DocJava SE 5 API18224Fri Aug 26 14:54:58 BST 2005com.sun.jmx.mbeanserver

Introspector

public class Introspector extends Object
This class contains the methods for performing all the tests needed to verify that a class represents a JMX compliant MBean.
since
1.5

Fields Summary
private static final String
attributeDescription
private static final String
operationDescription
private static final String
constructorDescription
private static final String
mbeanInfoDescription
Constructors Summary
private Introspector()

    

     /*
     * ------------------------------------------
     *  PRIVATE CONSTRUCTORS
     * ------------------------------------------
     */

    // private constructor defined to "hide" the default public constructor
      

	// ------------------------------ 
	// ------------------------------
	
    
Methods Summary
private static javax.management.MBeanInfoconstructResult(java.lang.Class baseClass, java.util.List attributes, java.util.List operations)
Constructs the MBeanInfo of the MBean.

	
	final int len = attributes.size();
	final MBeanAttributeInfo[] attrlist = new MBeanAttributeInfo[len];
	attributes.toArray(attrlist);
	final ArrayList mergedAttributes = new ArrayList();
	
	for (int i=0;i<len;i++) {
	    final MBeanAttributeInfo bi = attrlist[i];
	    
	    // bi can be null if it has already been eliminated
	    // by the loop below at an earlier iteration
	    // (cf. attrlist[j]=null;) In this case, just skip it.
	    //
	    if (bi == null) continue;

	    // Placeholder for the final attribute info we're going to
	    // keep.
	    //
	    MBeanAttributeInfo att = bi;

	    // The loop below will try to find whether bi is also present
	    // elsewhere further down the list. 
	    // If it is not, att will be left unchanged.
	    // Otherwise, the found attribute info will be merged with
	    // att and `removed' from the array by setting them to `null'
	    //
            for (int j=i+1;j<len;j++) {
		MBeanAttributeInfo mi = attrlist[j];
		
		// mi can be null if it has already been eliminated
		// by this loop at an earlier iteration.
		// (cf. attrlist[j]=null;) In this case, just skip it.
		//
		if (mi == null) continue;
                if ((mi.getName().compareTo(bi.getName()) == 0)) {
		    // mi and bi have the same name, which means that 
		    // that the attribute has been inserted twice in 
		    // the list, which means that it is a read-write
		    // attribute.
		    // So we're going to replace att with a new 
		    // attribute info with read-write mode.
		    // We also set attrlist[j] to null in order to avoid
		    // duplicates (attrlist[j] and attrlist[i] are now
		    // merged into att).
		    //
		    attrlist[j]=null;
		    att = new MBeanAttributeInfo(bi.getName(), 
						 bi.getType(), 
						 attributeDescription, 
						 true, true, bi.isIs());
		    // I think we could break, but it is probably
		    // safer not to...
		    //
		    // break;
		}
	    }
                
	    // Now all attributes info which had the same name than bi
	    // have been merged together in att. 
	    // Simply add att to the merged list.
	    //
	    mergedAttributes.add(att);	    
        }
 
        final MBeanAttributeInfo[] resultAttributes =
	    new MBeanAttributeInfo[mergedAttributes.size()];
	mergedAttributes.toArray(resultAttributes);

        final MBeanOperationInfo[] resultOperations =
	    new MBeanOperationInfo[operations.size()];
	operations.toArray(resultOperations);

	final MBeanConstructorInfo[] resultConstructors =
	    getConstructors(baseClass);     

        final MBeanInfo resultMBeanInfo =
	    new MBeanInfo(baseClass.getName(), mbeanInfoDescription, 
			  resultAttributes, resultConstructors, 
			  resultOperations, null);
	return resultMBeanInfo;
    
private static voiderror(java.lang.String method, java.lang.Throwable t)

	com.sun.jmx.trace.Trace.send(com.sun.jmx.trace.Trace.LEVEL_ERROR,
				     com.sun.jmx.trace.Trace.INFO_MBEANSERVER,
				     "Introspector",
				     method,
				     t);
				     
    
private static java.lang.ClassfindMBeanInterface(java.lang.Class aClass, java.lang.String aName)
Try to find the MBean interface corresponding to the class aName - i.e. aNameMBean, from within aClass and its superclasses.

	Class current = aClass;
	while (current != null) {
	    final Class[] interfaces = current.getInterfaces();   
	    final int len = interfaces.length;
	    for (int i=0;i<len;i++)  {	     
		final Class inter = 
		    implementsMBean(interfaces[i], aName);
		if (inter != null) return inter;
	    }
	    current = current.getSuperclass();
	}
	return null;     
    
static javax.management.MBeanConstructorInfo[]getConstructors(java.lang.Class baseClass)
Discovers the constructors of the MBean

	Constructor[] consList = baseClass.getConstructors();
	List constructors = new ArrayList();
	
	// Now analyze each Constructor.        
	for (int i = 0; i < consList.length; i++) {
	    Constructor constructor = consList[i];    	    
	    MBeanConstructorInfo mc = null;
	    try {               
		mc = new MBeanConstructorInfo(constructorDescription, constructor);		     		                
	    } catch (Exception ex) {
		mc = null;
	    }
	    if (mc != null) {
		constructors.add(mc);
	    }
	}
	// Allocate and populate the result array.
	MBeanConstructorInfo[] resultConstructors =
	    new MBeanConstructorInfo[constructors.size()];
	constructors.toArray(resultConstructors);
	return resultConstructors;
    
public static java.lang.ClassgetMBeanInterface(java.lang.Class baseClass)
Get the MBean interface implemented by a JMX standard MBean class.

param
baseClass The class to be tested
return
The MBean interface implemented by the MBean. Return null if the MBean is a DynamicMBean, or if no MBean interface is found.


	// ------------------------------ 
	// ------------------------------
	
	// Check if the MBean implements the MBean or the Dynamic 
	// MBean interface
	if (isDynamic(baseClass)) return null;

	return getStandardMBeanInterface(baseClass);     
    
static java.lang.ClassgetStandardMBeanInterface(java.lang.Class baseClass)
Get the MBean interface implemented by a JMX standard MBean class.

param
baseClass The class to be tested
return
The MBean interface implemented by the MBean. Return null if no MBean interface is found. Does not check whether the MBean is a DynamicMBean.


	// ------------------------------ 
	// ------------------------------
	
	Class current = baseClass;
	Class mbeanInterface = null;
	
	while (current != null) {
	    mbeanInterface = 
		findMBeanInterface(current, current.getName());
	    if (mbeanInterface != null) break;
	    current = current.getSuperclass();
	}
	return mbeanInterface;
    
static java.lang.ClassimplementsMBean(java.lang.Class c, java.lang.String clName)
Returns the XXMBean interface or null if no such interface exists

param
c The interface to be tested
param
clName The name of the class implementing this interface

	if (c.getName().compareTo(clName + "MBean") == 0) {
	    return c;
	}   
	Class current = c;
	Class[] interfaces = c.getInterfaces();
	for (int i = 0;i < interfaces.length; i++) {

	    try {
		if (interfaces[i].getName().compareTo(clName + "MBean") == 0) {
		    return interfaces[i];
		}     
	    } catch (Exception e) {
		return null;
	    }  	
	}
	
	return null;
    
private static javax.management.MBeanInfointrospect(java.lang.Class baseClass, java.lang.Class beanClass)
Discovers the getters, setters, operations of the class

param
baseClass The XX base class.
param
beanClass The XXMBean interface implemented by the tested class.
exception
NotCompliantMBeanException The tested class is not a JMX compliant MBean


	// ------------------------------ 
	// ------------------------------

	List/*<MBeanAttributeInfo>*/ attributes =
	    new ArrayList/*<MBeanAttributeInfo>*/();
	List/*<MBeanOperationInfo>*/ operations =
	    new ArrayList/*<MBeanOperationInfo>*/();
	
	Method methodList[] = beanClass.getMethods();
	
	// Now analyze each method.        
	for (int i = 0; i < methodList.length; i++) { 
	    Method method = methodList[i];
	    String name = method.getName();            
	    Class argTypes[] = method.getParameterTypes();
	    Class resultType = method.getReturnType();
	    int argCount = argTypes.length;

	    try {
		final MBeanAttributeInfo attr;

		if (name.startsWith("get") && !name.equals("get")
		    && argCount == 0 && !resultType.equals(void.class)) {
		    // if the method is "T getX()" it is a getter
		    attr = new MBeanAttributeInfo(name.substring(3),
						  attributeDescription,
						  method, null);
		} else if (name.startsWith("set") && !name.equals("set")
			   && argCount == 1 && resultType.equals(void.class)) {
		    // if the method is "void setX(T x)" it is a setter
		    attr = new MBeanAttributeInfo(name.substring(3),
						  attributeDescription,
						  null, method);
		} else if (name.startsWith("is") && !name.equals("is")
			   && argCount == 0
			   && resultType.equals(boolean.class)) {
		    // if the method is "boolean isX()" it is a getter
		    attr = new MBeanAttributeInfo(name.substring(2),
						  attributeDescription,
						  method, null);
		} else {
		    // in all other cases it is an operation
		    attr = null;
		}

		if (attr != null) {
		    if (testConsistency(attributes, attr))
			attributes.add(attr);
		} else {
		    final MBeanOperationInfo oper =
			new MBeanOperationInfo(operationDescription, method);
		    operations.add(oper);
		}
	    } catch (IntrospectionException e) {
		// Should not happen (MBeanAttributeInfo constructor)
		error("introspect", e);
	    }
	}

	return constructResult(baseClass, attributes, operations); 
    
public static final booleanisDynamic(java.lang.Class c)
Tell whether a MBean of the given class is a Dynamic MBean. This method does nothing more than returning
javax.management.DynamicMBean.class.isAssignableFrom(c)
This method does not check for any JMX MBean compliance:
  • If true is returned, then instances of c are DynamicMBean.
  • If false is returned, then no further assumption can be made on instances of c. In particular, instances of c may, or may not be JMX standard MBeans.

param
c The class of the MBean under examination.
return
true if instances of c are Dynamic MBeans, false otherwise.
since.unbundled
JMX RI 1.2

	// Check if the MBean implements the DynamicMBean interface
	return javax.management.DynamicMBean.class.isAssignableFrom(c);
    
public static javax.management.MBeanInfotestCompliance(java.lang.Class baseClass)
Basic method for testing if a given class is a JMX compliant MBean.

param
baseClass The class to be tested
return
null if the MBean is a DynamicMBean, the computed {@link javax.management.MBeanInfo} otherwise.
exception
NotCompliantMBeanException The specified class is not a JMX compliant MBean


	// ------------------------------ 
	// ------------------------------
	
	// Check if the MBean implements the MBean or the Dynamic 
	// MBean interface
	if (isDynamic(baseClass)) 
	    return null;
	
	return testCompliance(baseClass, null);
    
static javax.management.MBeanInfotestCompliance(java.lang.Class baseClass, java.lang.Class mbeanInterface)
Basic method for testing if a given class is a JMX compliant MBean.

param
baseClass The class to be tested
return
null if the MBean is a DynamicMBean, the computed {@link javax.management.MBeanInfo} otherwise.
exception
NotCompliantMBeanException The specified class is not a JMX compliant MBean

	
	if (baseClass.isInterface()) 
	    throw new NotCompliantMBeanException(baseClass.getName() + 
						 " must be a class.");
	// ------------------------------ 
	// ------------------------------
	if (mbeanInterface == null)
	    // No interface specified: look for default MBean interface.
	    mbeanInterface = getStandardMBeanInterface(baseClass);
	else if (! mbeanInterface.isAssignableFrom(baseClass)) {
	    // specified interface not implemented by given class
	    final String msg =
		baseClass.getName() + " does not implement the " + 
		mbeanInterface.getName() + " interface";
	    throw new NotCompliantMBeanException(msg);
	} else if (! mbeanInterface.isInterface()) {
	    // Base class X, but XMBean is not an interface
	    final String msg =
		baseClass.getName() + ": " + mbeanInterface.getName() + 
		" is not an interface";
	    throw new NotCompliantMBeanException(msg);
	}


	if (mbeanInterface == null) {
	    // Error: MBean does not implement javax.management.DynamicMBean 
	    // nor MBean interface
	    final String baseClassName = baseClass.getName();
	    final String msg =
		baseClassName + " does not implement the " + baseClassName +
		"MBean interface or the DynamicMBean interface";
	    throw new NotCompliantMBeanException(msg);
	}
	
	final int mods = mbeanInterface.getModifiers();
	if (!Modifier.isPublic(mods)) 
	    throw new NotCompliantMBeanException(mbeanInterface.getName() + 
						 " implemented by " +
						 baseClass.getName() + 
						 " must be public");

	return (introspect(baseClass, mbeanInterface));
    
private static booleantestConsistency(java.util.List attributes, javax.management.MBeanAttributeInfo attr)
Checks if the types and the signatures of getters/setters/operations are conform to the MBean design patterns. Error cases: - It exposes a method void Y getXX() AND a method void setXX(Z) (parameter type mismatch) - It exposes a method void setXX(Y) AND a method void setXX(Z) (parameter type mismatch) - It exposes a boolean isXX() method AND a YY getXX() or a void setXX(Y). Returns false if the attribute is already in attributes List

	for (Iterator it = attributes.iterator(); it.hasNext(); ) {
	    MBeanAttributeInfo mb = (MBeanAttributeInfo) it.next();
	    if (mb.getName().equals(attr.getName())) {
		if ((attr.isReadable() && mb.isReadable()) && 
		    (attr.isIs() != mb.isIs())) {
		    final String msg =
			"Conflicting getters for attribute " + mb.getName();
		    throw new NotCompliantMBeanException(msg);
		}  
		if (!mb.getType().equals(attr.getType())) {
		    if (mb.isWritable() && attr.isWritable()) {
			final String msg =
			    "Type mismatch between parameters of set" +
			    mb.getName() + " methods";
			throw new NotCompliantMBeanException(msg);
		    } else {
			final String msg =
			    "Type mismatch between parameters of get or is" +
			    mb.getName() + ", set" + mb.getName() + " methods";
			throw new NotCompliantMBeanException(msg);
		    }
		}
		if (attr.isReadable() && mb.isReadable()) {
		    return false;
		}
		if (attr.isWritable() && mb.isWritable()) {
		    return false;
		}
	    }
	}
	return true;
    
public static voidtestCreation(java.lang.Class c)
Basic method for testing that a MBean of a given class can be instantiated by the MBean server.

This method checks that:

  • The given class is a concrete class.
  • The given class exposes at least one public constructor.
If these conditions are not met, throws a NotCompliantMBeanException.

param
c The class of the MBean we want to create.
exception
NotCompliantMBeanException if the MBean class makes it impossible to instantiate the MBean from within the MBeanServer.
since.unbundled
JMX RI 1.2

	// Check if the class is a concrete class
	final int mods = c.getModifiers(); 
	if (Modifier.isAbstract(mods) || Modifier.isInterface(mods)) {
	    throw new NotCompliantMBeanException("MBean class must be concrete");
	}

	// Check if the MBean has a public constructor 
	final Constructor[] consList = c.getConstructors();     
	if (consList.length == 0) {
	    throw new NotCompliantMBeanException("MBean class must have public constructor");
	}