/*
* RHQ Management Platform
* Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.enterprise.server.naming;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.event.EventContext;
import javax.naming.ldap.LdapContext;
import org.testng.annotations.Test;
import org.rhq.enterprise.server.naming.util.DecoratorPicker;
import org.rhq.enterprise.server.naming.util.DecoratorSetContext;
/**
* @author Lukas Krejci
*/
@Test
public class DecoratorPickerTest {
private static final InvocationHandler DUMMY_HANDLER = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("hashCode".equals(method.getName())) {
return 0;
} else if ("equals".equals(method.getName())) {
return false;
}
return null;
}
};
private static final Class<?> TEST_OBJECT_CLASS1 = createProxyClass(Context.class);
private static final Class<?> TEST_OBJECT_CLASS2 = createProxyClass(DirContext.class);
private static final Class<?> TEST_OBJECT_CLASS3 = createProxyClass(LdapContext.class);
private static final Class<?> TEST_OBJECT_CLASS4 = createProxyClass(LdapContext.class, EventContext.class);
private static final Class<?> DECORATOR_CLASS1 = createProxyClass(Context.class);
private static final Class<?> DECORATOR_CLASS2 = createProxyClass(EventContext.class);
private static final Class<?> DECORATOR_CLASS3 = createProxyClass(LdapContext.class);
private static final Class<?> DECORATOR_CLASS4 = createProxyClass(DirContext.class);
public void testSimpleDecoratorIdentifiedByClass() throws Exception {
DecoratorPicker<Object, Object> picker = createTestPicker();
Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS1);
assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for Context class");
assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], Context.class);
}
public void testSuperClassDecoratorHasPrecedenceOverSubClassDecorator() throws Exception {
DecoratorPicker<Object, Object> picker = createTestPicker();
//this tests that the LdapContext isn't returned even though it subclasses the DirContext
Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS2);
assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for DirContext class");
assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], DirContext.class);
}
public void testSubClassDecoratorCorrectlyIdentified() throws Exception {
DecoratorPicker<Object, Object> picker = createTestPicker();
Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS3);
assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for LdapContext class");
assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
}
public void testMultipleDecoratorsDetectable() throws Exception {
DecoratorPicker<Object, Object> picker = createTestPicker();
Set<Object> decorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS4);
assertEquals(decorators.size(), 2,
"Exactly 2 decorators should have been found for a class implementing 2 interfaces.");
boolean ldapContextDecoratorFound = false;
boolean eventContextDecoratorFound = false;
for (Object d : decorators) {
if (LdapContext.class.isAssignableFrom(d.getClass())) {
ldapContextDecoratorFound = true;
continue; //just to make sure that somehow the decorator doesn't implement both
}
if (EventContext.class.isAssignableFrom(d.getClass())) {
eventContextDecoratorFound = true;
}
}
assertTrue(ldapContextDecoratorFound && eventContextDecoratorFound,
"The found decorators don't implement the desired interfaces.");
}
public void testDecoratorsIdentifiedByMethod() throws Exception {
DecoratorPicker<Object, Object> picker = createTestPicker();
Set<Object> decorators =
picker.getDecoratorsForMethod(LdapContext.class.getMethod("getConnectControls", (Class<?>[]) null));
assertEquals(decorators.size(), 1,
"Expected exactly one decorator for method 'getConnectControls()' from LdapContext class");
assertEquals(decorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
}
public void testMethodFromSubclassMatchesSubclassDecorator() throws Exception {
DecoratorPicker<Object, Object> picker = createTestPicker();
//this is a method from the DirContext but we're asking for it from a class
//that implements also an LdapContext
//The LdapContext decorator also inherits from the DirContext decorator
//(by the virtue of LdapContext interface inheriting from the DirContext)
//The picker should therefore match the LdapContext decorator because its
//the "closest" one to the actual class.
Set<Object> decorators =
picker.getDecoratorsForMethod(TEST_OBJECT_CLASS3.getMethod("getSchemaClassDefinition",
new Class<?>[] { String.class }));
assertEquals(decorators.size(), 1,
"Expected exactly one decorator for method 'getSchemaClassDefinition(String)' from LdapContext class");
assertEquals(decorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
}
private static Class<?> createProxyClass(Class<?>... ifaces) {
return Proxy.getProxyClass(DecoratorPickerTest.class.getClassLoader(), ifaces);
}
private static DecoratorPicker<Object, Object> createTestPicker() {
DecoratorPicker<Object, Object> picker = new DecoratorPicker<Object, Object>();
DecoratorSetContext<Object, Object> decSet = new DecoratorSetContext<Object, Object>() {
public Object instantiate(Class<? extends Object> decoratorClass) throws Exception {
Constructor<? extends Object> ctor = decoratorClass.getConstructor(InvocationHandler.class);
return ctor.newInstance(DUMMY_HANDLER);
}
public void init(Object decorator, Object object) throws Exception {
}
@SuppressWarnings("unchecked")
public Set<Class<? extends Object>> getSupportedInterfaces() {
return new HashSet<Class<? extends Object>>(Arrays.asList(Context.class, EventContext.class,
LdapContext.class, DirContext.class));
}
@SuppressWarnings("unchecked")
public Set<Class<? extends Object>> getDecoratorClasses() {
return new HashSet<Class<? extends Object>>(Arrays.asList(DECORATOR_CLASS1, DECORATOR_CLASS2, DECORATOR_CLASS3, DECORATOR_CLASS4));
}
};
picker.setContext(decSet);
return picker;
}
}