blob: 89b74f939d07b33f2782c8536c80e3325e20791b [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.qpid.server.management;
import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.NotCompliantMBeanException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* This class is a utility class to introspect the MBean class and the management
* interface class for various purposes.
* @author Bhupendra Bhardwaj
* @version 0.1
*/
class MBeanIntrospector {
private static final String _defaultAttributeDescription = "Management attribute";
private static final String _defaultOerationDescription = "Management operation";
private static final String _defaultConstructorDescription = "MBean constructor";
private static final String _defaultMbeanDescription = "Management interface of the MBean";
private MBeanIntrospector()
{
}
/**
* Introspects the management interface class for MBean attributes.
* @param interfaceClass
* @return MBeanAttributeInfo[]
* @throws NotCompliantMBeanException
*/
static MBeanAttributeInfo[] getMBeanAttributesInfo(Class interfaceClass)
throws NotCompliantMBeanException
{
List<MBeanAttributeInfo> attributesList = new ArrayList<MBeanAttributeInfo>();
/**
* Using reflection, all methods of the managemetn interface will be analysed,
* and MBeanInfo will be created.
*/
for (Method method : interfaceClass.getMethods())
{
String name = method.getName();
Class<?> resultType = method.getReturnType();
MBeanAttributeInfo attributeInfo = null;
if (isAttributeGetterMethod(method))
{
String desc = getAttributeDescription(method);
attributeInfo = new MBeanAttributeInfo(name.substring(3),
resultType.getName(),
desc,
true,
false,
false);
int index = getIndexIfAlreadyExists(attributeInfo, attributesList);
if (index == -1)
{
attributesList.add(attributeInfo);
}
else
{
attributeInfo = new MBeanAttributeInfo(name.substring(3),
resultType.getName(),
desc,
true,
true,
false);
attributesList.set(index, attributeInfo);
}
}
else if (isAttributeSetterMethod(method))
{
String desc = getAttributeDescription(method);
attributeInfo = new MBeanAttributeInfo(name.substring(3),
method.getParameterTypes()[0].getName(),
desc,
false,
true,
false);
int index = getIndexIfAlreadyExists(attributeInfo, attributesList);
if (index == -1)
{
attributesList.add(attributeInfo);
}
else
{
attributeInfo = new MBeanAttributeInfo(name.substring(3),
method.getParameterTypes()[0].getName(),
desc,
true,
true,
false);
attributesList.set(index, attributeInfo);
}
}
else if (isAttributeBoolean(method))
{
attributeInfo = new MBeanAttributeInfo(name.substring(2),
resultType.getName(),
getAttributeDescription(method),
true,
false,
true);
attributesList.add(attributeInfo);
}
}
return attributesList.toArray(new MBeanAttributeInfo[0]);
}
/**
* Introspects the management interface class for management operations.
* @param interfaceClass
* @return MBeanOperationInfo[]
*/
static MBeanOperationInfo[] getMBeanOperationsInfo(Class interfaceClass)
{
List<MBeanOperationInfo> operationsList = new ArrayList<MBeanOperationInfo>();
for (Method method : interfaceClass.getMethods())
{
if (!isAttributeGetterMethod(method) &&
!isAttributeSetterMethod(method) &&
!isAttributeBoolean(method))
{
operationsList.add(getOperationInfo(method));
}
}
return operationsList.toArray(new MBeanOperationInfo[0]);
}
/**
* Checks if the method is an attribute getter method.
* @param method
* @return true if the method is an attribute getter method.
*/
private static boolean isAttributeGetterMethod(Method method)
{
if (!(method.getName().equals("get")) &&
method.getName().startsWith("get") &&
method.getParameterTypes().length == 0 &&
!method.getReturnType().equals(void.class))
{
return true;
}
return false;
}
/**
* Checks if the method is an attribute setter method.
* @param method
* @return true if the method is an attribute setter method.
*/
private static boolean isAttributeSetterMethod(Method method)
{
if (!(method.getName().equals("set")) &&
method.getName().startsWith("set") &&
method.getParameterTypes().length == 1 &&
method.getReturnType().equals(void.class))
{
return true;
}
return false;
}
/**
* Checks if the attribute is a boolean and the method is a isX kind og method.
* @param method
* @return true if the method is an attribute isX type of method
*/
private static boolean isAttributeBoolean(Method method)
{
if (!(method.getName().equals("is")) &&
method.getName().startsWith("is") &&
method.getParameterTypes().length == 0 &&
method.getReturnType().equals(boolean.class))
{
return true;
}
return false;
}
/**
* Helper method to retrieve the attribute index from the list of attributes.
* @param attribute
* @param list
* @return attribute index no. -1 if attribtue doesn't exist
* @throws NotCompliantMBeanException
*/
private static int getIndexIfAlreadyExists(MBeanAttributeInfo attribute,
List<MBeanAttributeInfo> list)
throws NotCompliantMBeanException
{
String exceptionMsg = "Conflicting attribute methods for attribute " + attribute.getName();
for (MBeanAttributeInfo memberAttribute : list)
{
if (attribute.getName().equals(memberAttribute.getName()))
{
if (!attribute.getType().equals(memberAttribute.getType()))
{
throw new NotCompliantMBeanException(exceptionMsg);
}
if (attribute.isReadable() && memberAttribute.isReadable())
{
if (attribute.isIs() != memberAttribute.isIs())
{
throw new NotCompliantMBeanException(exceptionMsg);
}
}
return list.indexOf(memberAttribute);
}
}
return -1;
}
/**
* Retrieves the attribute description from annotation
* @param attributeMethod
* @return attribute description
*/
private static String getAttributeDescription(Method attributeMethod)
{
MBeanAttribute anno = attributeMethod.getAnnotation(MBeanAttribute.class);
if (anno != null)
{
return anno.description();
}
return _defaultAttributeDescription;
}
/**
* Introspects the method to retrieve the operation information.
* @param operation
* @return MBeanOperationInfo
*/
private static MBeanOperationInfo getOperationInfo(Method operation)
{
MBeanOperationInfo operationInfo = null;
Class<?> returnType = operation.getReturnType();
MBeanParameterInfo[] paramsInfo = getParametersInfo(operation.getParameterAnnotations(),
operation.getParameterTypes());
String operationDesc = _defaultOerationDescription;
int impact = MBeanOperationInfo.UNKNOWN;
if (operation.getAnnotation(MBeanOperation.class) != null)
{
operationDesc = operation.getAnnotation(MBeanOperation.class).description();
impact = operation.getAnnotation(MBeanOperation.class).impact();
}
operationInfo = new MBeanOperationInfo(operation.getName(),
operationDesc,
paramsInfo,
returnType.getName(),
impact);
return operationInfo;
}
/**
* Constructs the parameter info.
* @param paramsAnno
* @param paramTypes
* @return MBeanParameterInfo[]
*/
private static MBeanParameterInfo[] getParametersInfo(Annotation[][] paramsAnno,
Class<?>[] paramTypes)
{
int noOfParams = paramsAnno.length;
MBeanParameterInfo[] paramsInfo = new MBeanParameterInfo[noOfParams];
for (int i = 0; i < noOfParams; i++)
{
MBeanParameterInfo paramInfo = null;
String type = paramTypes[i].getName();
for (Annotation anno : paramsAnno[i])
{
String name,desc;
if (MBeanOperationParameter.class.isInstance(anno))
{
name = MBeanOperationParameter.class.cast(anno).name();
desc = MBeanOperationParameter.class.cast(anno).description();
paramInfo = new MBeanParameterInfo(name, type, desc);
}
}
if (paramInfo == null)
{
paramInfo = new MBeanParameterInfo("p " + (i + 1), type, "parameter " + (i + 1));
}
if (paramInfo != null)
{
paramsInfo[i] = paramInfo;
}
}
return paramsInfo;
}
/**
* Introspects the MBean class for constructors
* @param implClass
* @return MBeanConstructorInfo[]
*/
static MBeanConstructorInfo[] getMBeanConstructorsInfo(Class implClass)
{
List<MBeanConstructorInfo> constructors = new ArrayList<MBeanConstructorInfo>();
for (Constructor cons : implClass.getConstructors())
{
MBeanConstructorInfo constructorInfo = getMBeanConstructorInfo(cons);
if (constructorInfo != null)
{
constructors.add(constructorInfo);
}
}
return constructors.toArray(new MBeanConstructorInfo[0]);
}
/**
* Retrieves the constructor info from given constructor.
* @param cons
* @return MBeanConstructorInfo
*/
private static MBeanConstructorInfo getMBeanConstructorInfo(Constructor cons)
{
String desc = _defaultConstructorDescription;
Annotation anno = cons.getAnnotation(MBeanConstructor.class);
if (anno != null && MBeanConstructor.class.isInstance(anno))
{
desc = MBeanConstructor.class.cast(anno).value();
if(desc == null)
{
desc = _defaultConstructorDescription;
}
}
return new MBeanConstructorInfo(cons.getName(), desc, null);
}
/**
* Retrieves the description from the annotations of given class
* @param annotatedClass
* @return class description
*/
static String getMBeanDescription(Class annotatedClass)
{
Annotation anno = annotatedClass.getAnnotation(MBeanDescription.class);
if (anno != null && MBeanDescription.class.isInstance(anno))
{
return MBeanDescription.class.cast(anno).value();
}
return _defaultMbeanDescription;
}
}