/****************************************************************************** | |
* Copyright (c) 2006, 2010 VMware Inc. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v1.0 | |
* and Apache License v2.0 which accompanies this distribution. | |
* The Eclipse Public License is available at | |
* http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0 | |
* is available at http://www.opensource.org/licenses/apache2.0.php. | |
* You may elect to redistribute this code under either of these licenses. | |
* | |
* Contributors: | |
* VMware Inc. | |
*****************************************************************************/ | |
package org.eclipse.gemini.blueprint.config.internal; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.Date; | |
import java.util.Dictionary; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import junit.framework.TestCase; | |
import static org.easymock.EasyMock.*; | |
import org.eclipse.gemini.blueprint.config.internal.adapter.OsgiServiceLifecycleListenerAdapter; | |
import org.eclipse.gemini.blueprint.service.importer.ImportedOsgiServiceProxy; | |
import org.eclipse.gemini.blueprint.service.importer.OsgiServiceLifecycleListener; | |
import org.eclipse.gemini.blueprint.service.importer.ServiceReferenceProxy; | |
import org.eclipse.gemini.blueprint.service.importer.support.internal.aop.StaticServiceReferenceProxy; | |
import org.eclipse.gemini.blueprint.util.internal.MapBasedDictionary; | |
import org.osgi.framework.ServiceReference; | |
import org.springframework.beans.factory.config.ConfigurableBeanFactory; | |
import org.eclipse.gemini.blueprint.mock.MockServiceReference; | |
/** | |
* @author Costin Leau | |
*/ | |
public class OsgiServiceLifecycleListenerAdapterTest extends TestCase { | |
protected static class JustListener implements OsgiServiceLifecycleListener { | |
public static int BIND_CALLS = 0; | |
public static int UNBIND_CALLS = 0; | |
public void bind(Object service, Map properties) throws Exception { | |
BIND_CALLS++; | |
} | |
public void unbind(Object service, Map properties) throws Exception { | |
UNBIND_CALLS++; | |
} | |
} | |
protected static class CustomListener { | |
public static int BIND_CALLS = 0; | |
public static int UNBIND_CALLS = 0; | |
public static List BIND_SERVICES = new ArrayList(); | |
public static List UNBIND_SERVICES = new ArrayList(); | |
public void myBind(Object service, Map properties) { | |
BIND_CALLS++; | |
BIND_SERVICES.add(service); | |
} | |
public void myUnbind(Object service, Map properties) { | |
UNBIND_CALLS++; | |
UNBIND_SERVICES.add(service); | |
} | |
public void wrongBind() { | |
BIND_CALLS++; | |
} | |
public void wrongUnbind() { | |
UNBIND_CALLS--; | |
} | |
} | |
protected static class CustomAndListener extends JustListener { | |
public Integer aBind(Object service, Map props) throws Exception { | |
super.bind(service, props); | |
return null; | |
} | |
public void aUnbind(Object service, Map props) throws Exception { | |
super.unbind(service, props); | |
} | |
} | |
protected static class OverloadedCustomMethods extends CustomListener { | |
public void myBind(Date service, Map properties) { | |
super.myBind(service, properties); | |
} | |
public void myUnbind(String service, Map properties) { | |
super.myUnbind(service, properties); | |
} | |
} | |
/** | |
* Override standard methods with ones that throw exceptions. | |
* | |
* @author Costin Leau | |
*/ | |
protected static class ExceptionListener extends CustomAndListener { | |
public void bind(Object service, Map properties) throws Exception { | |
throw new Exception("expected!") { | |
public synchronized Throwable fillInStackTrace() { | |
return null; | |
} | |
}; | |
} | |
public void unbind(Object service, Map properties) throws Exception { | |
throw new IOException("expected!") { | |
public synchronized Throwable fillInStackTrace() { | |
return null; | |
} | |
}; | |
} | |
} | |
protected static class ExceptionCustomListener extends CustomListener { | |
public void myBind(Date service, Map properties) { | |
throw (RuntimeException) new RuntimeException("expected!") { | |
public synchronized Throwable fillInStackTrace() { | |
return null; | |
} | |
}; | |
} | |
public void myUnbind(String service, Map properties) throws IOException { | |
throw new IOException("expected!") { | |
public synchronized Throwable fillInStackTrace() { | |
return null; | |
} | |
}; | |
} | |
} | |
// piggy backs on JustListener static fields | |
protected static class DictionaryAndMapCustomListener { | |
public void bind(Object service, Dictionary properties) { | |
JustListener.BIND_CALLS++; | |
} | |
public void unbind(Object service, Map props) { | |
JustListener.UNBIND_CALLS++; | |
} | |
public void unbind(Object service, Dictionary props) throws Exception { | |
JustListener.UNBIND_CALLS++; | |
} | |
} | |
protected static class OverridingMethodListener extends CustomListener { | |
public void myBind(Object service, Map properties) { | |
BIND_CALLS++; | |
} | |
public void myUnbind(Object service, Map properties) { | |
UNBIND_CALLS++; | |
} | |
} | |
protected static class JustBind { | |
public void myBind(Object service, Map properties) { | |
JustListener.BIND_CALLS++; | |
} | |
} | |
protected static class JustUnbind { | |
public void myUnbind(Object service, Map properties) { | |
JustListener.UNBIND_CALLS++; | |
} | |
} | |
protected static class CustomServiceRefListener { | |
private void myUnbind(ServiceReference ref) { | |
JustListener.UNBIND_CALLS++; | |
} | |
private void myBind(ServiceReference ref) { | |
JustListener.BIND_CALLS++; | |
} | |
} | |
protected static class CustomServiceRefAndObjectWOMapListener { | |
private void myUnbind(ServiceReference ref) { | |
JustListener.UNBIND_CALLS++; | |
} | |
private void myBind(ServiceReference ref) { | |
JustListener.BIND_CALLS++; | |
} | |
private void myBind(Object obj) { | |
JustListener.BIND_CALLS++; | |
} | |
} | |
private OsgiServiceLifecycleListenerAdapter listener; | |
private static final String BEAN_NAME = "bla"; | |
protected void setUp() throws Exception { | |
JustListener.BIND_CALLS = 0; | |
JustListener.UNBIND_CALLS = 0; | |
OverloadedCustomMethods.BIND_SERVICES = new ArrayList(); | |
OverloadedCustomMethods.UNBIND_SERVICES = new ArrayList(); | |
CustomListener.BIND_CALLS = 0; | |
CustomListener.UNBIND_CALLS = 0; | |
} | |
protected void tearDown() throws Exception { | |
listener = null; | |
OverloadedCustomMethods.BIND_SERVICES = null; | |
OverloadedCustomMethods.UNBIND_SERVICES = null; | |
} | |
public void testWrapperOverListener() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new JustListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.afterPropertiesSet(); | |
assertEquals(0, JustListener.BIND_CALLS); | |
listener.bind(null, null); | |
assertEquals(1, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.bind(null, null); | |
assertEquals(2, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.unbind(null, null); | |
assertEquals(1, JustListener.UNBIND_CALLS); | |
assertEquals(2, JustListener.BIND_CALLS); | |
listener.unbind(null, null); | |
assertEquals(2, JustListener.UNBIND_CALLS); | |
assertEquals(2, JustListener.BIND_CALLS); | |
} | |
public void testWrapperOverNoInvalidClass() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setTarget(new Object()); | |
listener.setBeanFactory(createMockBF(new Object())); | |
try { | |
listener.afterPropertiesSet(); | |
fail("should have thrown exception"); | |
} catch (IllegalArgumentException ex) { | |
// expected | |
} | |
} | |
public void testWrapperWithIncorrectCustomMethodNames() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setTarget(new Object()); | |
listener.setBindMethod("pop"); | |
listener.setUnbindMethod("corn"); | |
try { | |
listener.afterPropertiesSet(); | |
fail("should have thrown exception"); | |
} catch (IllegalArgumentException ex) { | |
// expected | |
} | |
} | |
public void testWrapperWithCorrectCustomMethodNamesButIncorrectArgumentTypes() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setTarget(new CustomListener()); | |
listener.setBindMethod("wrongBind"); | |
listener.setUnbindMethod("wrongUnbind"); | |
assertEquals(0, CustomListener.BIND_CALLS); | |
assertEquals(0, CustomListener.UNBIND_CALLS); | |
try { | |
listener.afterPropertiesSet(); | |
fail("should have thrown exception"); | |
} catch (IllegalArgumentException ex) { | |
// expected | |
} | |
assertEquals(0, CustomListener.BIND_CALLS); | |
assertEquals(0, CustomListener.UNBIND_CALLS); | |
} | |
public void testWrapperWithCustomMethods() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new CustomListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("myBind"); | |
listener.setUnbindMethod("myUnbind"); | |
listener.afterPropertiesSet(); | |
Object service = new Object(); | |
assertEquals(0, CustomListener.BIND_CALLS); | |
assertEquals(0, CustomListener.UNBIND_CALLS); | |
listener.bind(new Object(), null); | |
assertEquals(1, CustomListener.BIND_CALLS); | |
assertEquals(0, CustomListener.UNBIND_CALLS); | |
listener.bind(service, null); | |
assertEquals(2, CustomListener.BIND_CALLS); | |
assertEquals(0, CustomListener.UNBIND_CALLS); | |
listener.unbind(service, null); | |
assertEquals(2, CustomListener.BIND_CALLS); | |
assertEquals(1, CustomListener.UNBIND_CALLS); | |
listener.unbind(service, null); | |
assertEquals(2, CustomListener.BIND_CALLS); | |
assertEquals(2, CustomListener.UNBIND_CALLS); | |
} | |
public void testWrapperWithCustomMethodsAndNullParameters() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new CustomListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("myBind"); | |
listener.setUnbindMethod("myUnbind"); | |
listener.afterPropertiesSet(); | |
assertEquals(0, CustomListener.BIND_CALLS); | |
assertEquals(0, CustomListener.UNBIND_CALLS); | |
listener.bind(null, null); | |
assertEquals("null services allowed", 1, CustomListener.BIND_CALLS); | |
listener.unbind(null, null); | |
assertEquals("null services allowed", 1, CustomListener.UNBIND_CALLS); | |
} | |
public void testWrapperWithBothCustomAndInterfaceMethods() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new CustomAndListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("aBind"); | |
listener.setUnbindMethod("aUnbind"); | |
listener.afterPropertiesSet(); | |
Object service = new Object(); | |
assertEquals(0, CustomAndListener.BIND_CALLS); | |
assertEquals(0, CustomAndListener.UNBIND_CALLS); | |
listener.bind(service, null); | |
assertEquals(2, CustomAndListener.BIND_CALLS); | |
assertEquals(0, CustomAndListener.UNBIND_CALLS); | |
listener.unbind(service, null); | |
assertEquals(2, CustomAndListener.BIND_CALLS); | |
assertEquals(2, CustomAndListener.UNBIND_CALLS); | |
} | |
public void testWrapperWithCustomOverloadedMethodsAndDifferentServiceTypes() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new OverloadedCustomMethods())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("myBind"); | |
listener.setUnbindMethod("myUnbind"); | |
listener.afterPropertiesSet(); | |
Object objService = new Object(); | |
Date dateService = new Date(); | |
String stringService = "token"; | |
assertEquals(0, OverloadedCustomMethods.BIND_CALLS); | |
assertEquals(0, OverloadedCustomMethods.UNBIND_CALLS); | |
listener.bind(objService, null); | |
assertEquals("only one method accepts Object(s)", 1, OverloadedCustomMethods.BIND_CALLS); | |
assertEquals(0, OverloadedCustomMethods.UNBIND_CALLS); | |
listener.bind(dateService, null); | |
assertEquals("two method accept Date(s)", 3, OverloadedCustomMethods.BIND_CALLS); | |
assertEquals(0, OverloadedCustomMethods.UNBIND_CALLS); | |
listener.unbind(stringService, null); | |
assertEquals("two method accept Date(s)", 3, OverloadedCustomMethods.BIND_CALLS); | |
assertEquals("two method accept String(s)", 2, OverloadedCustomMethods.UNBIND_CALLS); | |
listener.unbind(objService, null); | |
assertEquals("two method accept Date(s)", 3, OverloadedCustomMethods.BIND_CALLS); | |
assertEquals("only one method accepts Object(s)", 3, OverloadedCustomMethods.UNBIND_CALLS); | |
assertEquals(3, OverloadedCustomMethods.BIND_SERVICES.size()); | |
assertSame("incorrect call order", objService, OverloadedCustomMethods.BIND_SERVICES.get(0)); | |
assertSame("incorrect call order", dateService, OverloadedCustomMethods.BIND_SERVICES.get(1)); | |
assertSame("incorrect call order", dateService, OverloadedCustomMethods.BIND_SERVICES.get(2)); | |
assertEquals(3, OverloadedCustomMethods.UNBIND_SERVICES.size()); | |
assertSame("incorrect call order", stringService, OverloadedCustomMethods.UNBIND_SERVICES.get(0)); | |
assertSame("incorrect call order", stringService, OverloadedCustomMethods.UNBIND_SERVICES.get(1)); | |
assertSame("incorrect call order", objService, OverloadedCustomMethods.UNBIND_SERVICES.get(2)); | |
} | |
public void testExceptionOnListenerMethod() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new ExceptionListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("aBind"); | |
listener.setUnbindMethod("aUnbind"); | |
listener.afterPropertiesSet(); | |
Object service = new Object(); | |
assertEquals(0, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.bind(service, null); | |
assertEquals(1, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.unbind(service, null); | |
assertEquals(1, JustListener.BIND_CALLS); | |
assertEquals(1, JustListener.UNBIND_CALLS); | |
} | |
public void testExceptionOnCustomMethods() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new ExceptionCustomListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("myBind"); | |
listener.setUnbindMethod("myUnbind"); | |
listener.afterPropertiesSet(); | |
Date service = new Date(); | |
assertEquals(0, ExceptionCustomListener.BIND_CALLS); | |
assertEquals(0, ExceptionCustomListener.UNBIND_CALLS); | |
listener.bind(service, null); | |
assertEquals("should have called overloaded method with type Object", 1, ExceptionCustomListener.BIND_CALLS); | |
assertEquals(0, ExceptionCustomListener.UNBIND_CALLS); | |
listener.unbind(service, null); | |
assertEquals(1, ExceptionCustomListener.BIND_CALLS); | |
assertEquals("should have called overloaded method with type Object", 1, ExceptionCustomListener.UNBIND_CALLS); | |
} | |
public void testStandardListenerWithListeningMethodsSpecifiedAsCustomOnes() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new JustListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("bind"); | |
listener.setUnbindMethod("unbind"); | |
listener.afterPropertiesSet(); | |
Object service = null; | |
assertEquals(0, JustListener.BIND_CALLS); | |
listener.bind(service, null); | |
// only the interface is being called since the service is null | |
assertEquals(2, JustListener.BIND_CALLS); | |
service = new Object(); | |
listener.bind(service, null); | |
assertEquals(4, JustListener.BIND_CALLS); | |
} | |
public void testListenerWithOverloadedTypesAndMultipleParameterTypes() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new DictionaryAndMapCustomListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("bind"); | |
listener.setUnbindMethod("unbind"); | |
listener.afterPropertiesSet(); | |
Object service = new Date(); | |
MapBasedDictionary props = new MapBasedDictionary(); | |
assertEquals(0, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.bind(service, props); | |
assertEquals(1, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.unbind(service, props); | |
assertEquals(1, JustListener.BIND_CALLS); | |
assertEquals("only one unbind method should be called", 1, JustListener.UNBIND_CALLS); | |
} | |
public void testOverridingMethodsDiscovery() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new OverridingMethodListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("myBind"); | |
listener.setUnbindMethod("myUnbind"); | |
listener.afterPropertiesSet(); | |
assertEquals(0, CustomListener.BIND_CALLS); | |
assertEquals(0, CustomListener.UNBIND_CALLS); | |
listener.bind(new Object(), null); | |
assertEquals(1, CustomListener.BIND_CALLS); | |
assertEquals(0, CustomListener.UNBIND_CALLS); | |
listener.unbind(new Object(), null); | |
assertEquals(1, CustomListener.BIND_CALLS); | |
assertEquals(1, CustomListener.UNBIND_CALLS); | |
} | |
public void testJustCustomBindMethod() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new JustBind())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("myBind"); | |
listener.afterPropertiesSet(); | |
assertEquals(0, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.bind(new Object(), null); | |
assertEquals(1, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
} | |
public void testJustCustomUnbindMethod() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new JustUnbind())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setUnbindMethod("myUnbind"); | |
listener.afterPropertiesSet(); | |
assertEquals(0, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.unbind(new Object(), null); | |
assertEquals(0, JustListener.BIND_CALLS); | |
assertEquals(1, JustListener.UNBIND_CALLS); | |
} | |
public void testCustomServiceRefBind() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new CustomServiceRefListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("myBind"); | |
listener.afterPropertiesSet(); | |
assertEquals(0, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.bind(new ImportedOsgiServiceProxyMock(), null); | |
assertEquals(1, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
} | |
public void testCustomServiceRefUnbind() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new CustomServiceRefListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setUnbindMethod("myUnbind"); | |
listener.afterPropertiesSet(); | |
assertEquals(0, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.unbind(new ImportedOsgiServiceProxyMock(), null); | |
assertEquals(0, JustListener.BIND_CALLS); | |
assertEquals(1, JustListener.UNBIND_CALLS); | |
} | |
public void testCustomServiceRefAndObjectWOMapBind() throws Exception { | |
listener = new OsgiServiceLifecycleListenerAdapter(); | |
listener.setBeanFactory(createMockBF(new CustomServiceRefAndObjectWOMapListener())); | |
listener.setTargetBeanName(BEAN_NAME); | |
listener.setBindMethod("myBind"); | |
listener.afterPropertiesSet(); | |
assertEquals(0, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
listener.bind(new ImportedOsgiServiceProxyMock(), null); | |
assertEquals(2, JustListener.BIND_CALLS); | |
assertEquals(0, JustListener.UNBIND_CALLS); | |
} | |
private class ImportedOsgiServiceProxyMock implements ImportedOsgiServiceProxy { | |
public Map getServiceProperties() { | |
return new HashMap(); | |
} | |
public ServiceReferenceProxy getServiceReference() { | |
return new StaticServiceReferenceProxy(new MockServiceReference()); | |
} | |
} | |
private ConfigurableBeanFactory createMockBF(Object target) { | |
ConfigurableBeanFactory cbf = createNiceMock(ConfigurableBeanFactory.class); | |
expect(cbf.getBean(BEAN_NAME)).andReturn(target); | |
expect(cbf.getType(BEAN_NAME)).andReturn((Class)target.getClass()); | |
replay(cbf); | |
return cbf; | |
} | |
} |