/*
*
* 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.management.wsdm.capabilities;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javassist.CtClass;
import javassist.CtMethod;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.xml.namespace.QName;
import junit.framework.TestCase;
import org.apache.qpid.management.domain.handler.impl.QpidDomainObject;
import org.apache.qpid.management.wsdm.common.EntityInstanceNotFoundFault;
import org.apache.qpid.management.wsdm.common.MethodInvocationFault;
import org.apache.qpid.management.wsdm.common.NoSuchAttributeFault;
import org.apache.qpid.management.wsdm.common.QManFault;
/**
* Test case for MBean capability builder.
*
* @author Andrea Gazzarini
*/
public class MBeanCapabilityBuilderTest extends TestCase
{
/**
* Management interface for an mbean that has no properties and no
* methods.
*
* @author Andrea Gazzarini
*/
public interface NoPropertiesNoMethodsMBean
{
}
/**
* Implementation of the managenent interface described above.
*
* @author Andrea Gazzarini
*/
public class NoPropertiesNoMethods implements NoPropertiesNoMethodsMBean
{
}
private MBeanCapabilityBuilder _builder;
private ObjectName _objectName;
/**
* Set up fixture for this test case.
*/
protected void setUp() throws Exception
{
_builder = new MBeanCapabilityBuilder();
_objectName = new ObjectName("Test:Name=aName,class=DomainObject");
}
/**
* Tests that state change that occcurs on the begin() method when the requested
* class has not been defined.
*/
public void testBegin_withClassNotYetDefined() throws Exception
{
_builder.begin(_objectName);
assertEquals(_builder._state,_builder._classNotAvailable);
}
/**
* Tests that state change that occcurs on the begin() method when the requested
* class has not been defined.
*/
public void testBegin_withClassAlreadyDefined() throws Exception
{
_objectName = new ObjectName("Test:Name=aString,class=MBeanCapabilityBuilder");
_builder.begin(_objectName);
assertTrue(_builder._state instanceof DummyCapabilityBuilder);
assertSame(_builder._endAttributeHandler, _builder._noPropertyHasBeenDefined);
}
/**
* Tests the generateGetter method().
*/
public void testGenerateGetter()
{
String name ="MyProperty";
String type = Long.class.getName();
String expected =
"public "+
type+
" get"+
name+
"() throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault { return ("+
type+
") getAttribute(\""+
name+
"\"); }";
String result = _builder.generateGetter(type, name,name);
assertEquals(expected,result);
}
/**
* Tests the generateGetter method().
*/
public void testGenerateSetter()
{
String name ="MyProperty";
String type = Long.class.getName();
String expected =
"public void setMyProperty("+
type+
" newValue) throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault { setAttribute(\""+
name+
"\", newValue); }";
String result = _builder.generateSetter(type, name,name);
assertEquals(expected,result);
}
/**
* Tests buils of a capability that has no properties and methods
*
* <br>precondition : the incoming entity definition is empty (no properties and no methods)
* <br>postcondition : the capability class is built successfully and has no props and methods.
* The getPropertyNames returns an empty QName array.
*/
public void testOK_WithNoPropertiesNoMethods() throws Exception {
ObjectName name = new ObjectName("Test:Name=NoPropertiesNoMethods");
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
server.registerMBean(new NoPropertiesNoMethods(), name);
_builder.begin(name);
_builder.endAttributes();
_builder.endOperations();
Class<MBeanCapability> capabilityClass = _builder.getCapabilityClass();
Field[] fields = capabilityClass.getDeclaredFields();
Method [] methods = capabilityClass.getDeclaredMethods();
assertEquals(Arrays.toString(fields),0,fields.length);
assertEquals(Arrays.toString(methods),1,methods.length);
Method getPropertyNames = methods[0];
assertEquals("getPropertyNames",getPropertyNames.getName());
MBeanCapability capability = capabilityClass.newInstance();
QName [] properties = (QName[]) getPropertyNames.invoke(capability);
assertEquals(0,properties.length);
}
/**
* Tests the whole execution of the builder.
*/
@SuppressWarnings("unchecked")
public void testBuildOK() throws Exception
{
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
QpidDomainObject mbean = new QpidDomainObject();
server.registerMBean(mbean, _objectName);
_builder.begin(_objectName);
CtClass definition = _builder._capabilityClassDefinition;
assertEquals(
MBeanCapability.class.getName(),
definition.getSuperclass().getName());
MBeanInfo metadata = server.getMBeanInfo(_objectName);
for (MBeanAttributeInfo attribute : metadata.getAttributes())
{
_builder.onAttribute(attribute);
checkAttribute(attribute, definition);
assertSame(
_builder._endAttributeHandler,
_builder._atLeastThereIsOneProperty);
}
for (MBeanOperationInfo operation : metadata.getOperations())
{
_builder.onOperation(operation);
checkOperation(operation,definition);
}
_builder.endAttributes();
_builder.endOperations();
assertNotNull(_builder.getCapabilityClass());
}
/**
* Checks an operation / method after that it has been declared on
* capability definition.
*
* @param operation the (JMX) operation metadata.
* @param definition the capability class definition.
* @throws Exception when something goes wrong during introspection.
*/
private void checkOperation(MBeanOperationInfo operation, CtClass definition) throws Exception
{
CtMethod method = definition.getDeclaredMethod(operation.getName());
assertNotNull(method);
checkExceptionTypes(
method.getExceptionTypes(),
new String[]{
QManFault.class.getName(),
EntityInstanceNotFoundFault.class.getName(),
MethodInvocationFault.class.getName()});
assertEquals(Result.class.getName(),method.getReturnType().getName());
CtClass [] parameterTypes = method.getParameterTypes();
MBeanParameterInfo [] parameterMetadata = operation.getSignature();
assertEquals(parameterTypes.length, parameterMetadata.length);
for (int i = 0; i < parameterMetadata.length; i++)
{
assertEquals(
parameterTypes[i].getName(),
Class.forName(parameterMetadata[i].getType()).getCanonicalName());
}
}
/**
* Checks the exception types associated with a method.
*
* @param exceptionTypes the exception types actually thrown.
* @param expectedExceptionNames the expected exception types (as strings).
*/
private void checkExceptionTypes(CtClass [] exceptionTypes, String [] expectedExceptionNames)
{
List<String> exceptionNames = new ArrayList<String>(exceptionTypes.length);
for (CtClass exception : exceptionTypes)
{
exceptionNames.add(exception.getName());
}
for (String expectedExceptionName : expectedExceptionNames)
{
exceptionNames.remove(expectedExceptionName);
}
assertTrue(exceptionNames.isEmpty());
}
/**
* Checks an attribute after that it has been declared on capability definition.
*
* @param attribute the (JMX) attribute metadata.
* @param definition the capability class definition.
* @throws Exception when something goes wrong during introspection.
*/
private void checkAttribute(MBeanAttributeInfo attribute, CtClass definition) throws Exception
{
String name = _builder.getNameForAccessors(attribute.getName());
String newPropertyDeclaration =
new StringBuilder("new QName(Names.NAMESPACE_URI, \"")
.append(attribute.getName())
.append("\", Names.PREFIX),")
.toString();
assertTrue(_builder._properties.indexOf(newPropertyDeclaration) != -1);
if (attribute.isReadable())
{
CtMethod getter = definition.getDeclaredMethod("get"+name);
assertNotNull(getter);
checkExceptionTypes(
getter.getExceptionTypes(),
new String[]{
QManFault.class.getName(),
NoSuchAttributeFault.class.getName(),
EntityInstanceNotFoundFault.class.getName()});
assertEquals(0,getter.getParameterTypes().length);
assertEquals(attribute.getType(),getter.getReturnType().getName());
}
if (attribute.isWritable())
{
CtMethod setter = definition.getDeclaredMethod("set"+name);
assertNotNull(setter);
checkExceptionTypes(
setter.getExceptionTypes(),
new String[]{
QManFault.class.getName(),
NoSuchAttributeFault.class.getName(),
EntityInstanceNotFoundFault.class.getName()});
CtClass [] parameterTypes = setter.getParameterTypes();
assertEquals(1,parameterTypes.length);
assertEquals(attribute.getType(),parameterTypes[0].getName());
assertEquals(void.class.getName(),setter.getReturnType().getName());
}
}
}