/****************************************************************************** * 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.service.exporter.support; import java.io.Serializable; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Dictionary; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import junit.framework.TestCase; import org.easymock.MockControl; import org.eclipse.gemini.blueprint.service.exporter.OsgiServiceRegistrationListener; import org.eclipse.gemini.blueprint.service.exporter.TestRegistrationListener; import org.eclipse.gemini.blueprint.service.exporter.support.DefaultInterfaceDetector; import org.eclipse.gemini.blueprint.service.exporter.support.OsgiServiceFactoryBean; import org.eclipse.gemini.blueprint.service.exporter.support.ServicePropertiesChangeEvent; import org.eclipse.gemini.blueprint.service.exporter.support.ServicePropertiesChangeListener; import org.eclipse.gemini.blueprint.service.exporter.support.ServicePropertiesListenerManager; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceRegistration; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.eclipse.gemini.blueprint.mock.MockBundleContext; import org.eclipse.gemini.blueprint.mock.MockServiceRegistration; /** * @author Costin Leau */ public class OsgiServiceFactoryBeanTest extends TestCase { private OsgiServiceFactoryBean exporter; private ConfigurableBeanFactory beanFactory; private MockControl beanFactoryControl; private BundleContext bundleContext; private MockControl ctxCtrl; private BundleContext ctx; class MockServiceFactory implements ServiceFactory { public Object getService(Bundle bundle, ServiceRegistration registration) { return null; } public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { } } class UpdateableProperties extends Properties implements ServicePropertiesListenerManager { public List<ServicePropertiesChangeListener> listeners = new ArrayList<ServicePropertiesChangeListener>(); public void addListener(ServicePropertiesChangeListener listener) { listeners.add(listener); } public void removeListener(ServicePropertiesChangeListener listener) { listeners.remove(listener); } public void update() { ServicePropertiesChangeEvent event = new ServicePropertiesChangeEvent(this); for (ServicePropertiesChangeListener listener : listeners) { listener.propertiesChange(event); } } } protected void setUp() throws Exception { exporter = new OsgiServiceFactoryBean(); beanFactoryControl = MockControl.createControl(ConfigurableBeanFactory.class); beanFactory = (ConfigurableBeanFactory) this.beanFactoryControl.getMock(); bundleContext = new MockBundleContext(); ctxCtrl = MockControl.createControl(BundleContext.class); ctx = (BundleContext) ctxCtrl.getMock(); exporter.setBeanFactory(beanFactory); exporter.setBundleContext(bundleContext); } protected void tearDown() throws Exception { exporter = null; bundleContext = null; ctxCtrl = null; ctx = null; } public void testInitWithoutBundleContext() throws Exception { exporter.setBundleContext(null); exporter.setTarget(new Object()); try { this.exporter.afterPropertiesSet(); fail("Expecting IllegalArgumentException"); } catch (IllegalArgumentException ex) { // expected } } public void testInitWithoutBeanFactory() throws Exception { exporter.setBeanFactory(null); exporter.setTarget(new Object()); try { this.exporter.afterPropertiesSet(); fail("Expecting IllegalArgumentException"); } catch (IllegalArgumentException ex) { // expected } } public void testInitWithoutTargetOrTargetReference() throws Exception { try { this.exporter.afterPropertiesSet(); fail("Expecting IllegalArgumentException"); } catch (IllegalArgumentException ex) { // expected } } public void testInitWithTargetAndTargetRerefence() throws Exception { exporter.setTarget(new Object()); exporter.setTargetBeanName("costin"); beanFactoryControl.expectAndReturn(beanFactory.isSingleton("costin"), false); beanFactoryControl.expectAndReturn(beanFactory.containsBean("costin"), true); beanFactoryControl.expectAndReturn(beanFactory.getType("costin"), Object.class); beanFactoryControl.replay(); try { this.exporter.afterPropertiesSet(); fail("Expecting IllegalArgumentException"); } catch (IllegalArgumentException ex) { // expected } } public void testInitWithOnlyJustTarget() throws Exception { exporter.setTarget(new Object()); exporter.setInterfaces(new Class<?>[] { Object.class }); exporter.afterPropertiesSet(); } public void testAutoDetectClassesForPublishingDisabled() throws Exception { exporter.setInterfaceDetector(DefaultInterfaceDetector.DISABLED); Class<?>[] clazz = DefaultInterfaceDetector.DISABLED.detect(Integer.class); assertNotNull(clazz); assertEquals(0, clazz.length); } public void testAutoDetectClassesForPublishingInterfaces() throws Exception { exporter.setInterfaceDetector(DefaultInterfaceDetector.INTERFACES); Class<?>[] clazz = DefaultInterfaceDetector.INTERFACES.detect(HashMap.class); Class<?>[] expected = new Class<?>[] { Cloneable.class, Serializable.class, Map.class }; assertTrue(compareArrays(expected, clazz)); } public void testAutoDetectClassesForPublishingClassHierarchy() throws Exception { exporter.setInterfaceDetector(DefaultInterfaceDetector.CLASS_HIERARCHY); Class<?>[] clazz = DefaultInterfaceDetector.CLASS_HIERARCHY.detect(HashMap.class); Class<?>[] expected = new Class<?>[] { HashMap.class, AbstractMap.class }; assertTrue(compareArrays(expected, clazz)); } public void testAutoDetectClassesForPublishingAll() throws Exception { exporter.setInterfaceDetector(DefaultInterfaceDetector.ALL_CLASSES); Class<?>[] clazz = DefaultInterfaceDetector.ALL_CLASSES.detect(HashMap.class); Class<?>[] expected = new Class<?>[] { Map.class, Cloneable.class, Serializable.class, HashMap.class, AbstractMap.class }; assertTrue(compareArrays(expected, clazz)); } public void testRegisterServiceWithNullClasses() throws Exception { try { exporter.registerService(null, new Properties()); fail("Expected to throw IllegalArgumentException"); } catch (IllegalArgumentException e) { // expected } } public void testRegisterServiceWOClasses() throws Exception { try { exporter.registerService(new Class[0], new Properties()); fail("Expected to throw IllegalArgumentException"); } catch (IllegalArgumentException e) { // expected } } public void testRegisterService() throws Exception { Class<?>[] clazz = new Class<?>[] { Serializable.class, HashMap.class, Cloneable.class, Map.class, LinkedHashMap.class }; String[] names = new String[clazz.length]; for (int i = 0; i < clazz.length; i++) { names[i] = clazz[i].getName(); } final Properties props = new Properties(); final ServiceRegistration reg = new MockServiceRegistration(); exporter.setBundleContext(new MockBundleContext() { public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) { assertTrue(service instanceof ServiceFactory); return reg; } }); Object proxy = MockControl.createControl(ServiceFactory.class).getMock(); exporter.setTarget(proxy); exporter.setInterfaces(new Class<?>[] { ServiceFactory.class }); String beanName = "boo"; exporter.setTargetBeanName(beanName); beanFactoryControl.expectAndReturn(beanFactory.isSingleton(beanName), true); beanFactoryControl.expectAndReturn(beanFactory.isPrototype(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.containsBean(beanName), true); beanFactoryControl.expectAndReturn(beanFactory.getBean(beanName), proxy); beanFactoryControl.expectAndReturn(beanFactory.getType(beanName), proxy.getClass()); beanFactoryControl.replay(); exporter.afterPropertiesSet(); assertSame(reg, exporter.registerService(clazz, props)); } public void testUnregisterWithNullServiceReg() throws Exception { exporter.unregisterService(null); } public void testUnregisterService() throws Exception { MockControl ctrl = MockControl.createControl(ServiceRegistration.class); ServiceRegistration reg = (ServiceRegistration) ctrl.getMock(); reg.unregister(); ctrl.replay(); exporter.unregisterService(reg); ctrl.verify(); } public void testUnregisterServiceAlreadyUnregistered() throws Exception { MockControl ctrl = MockControl.createControl(ServiceRegistration.class); ServiceRegistration reg = (ServiceRegistration) ctrl.getMock(); reg.unregister(); ctrl.setDefaultThrowable(new IllegalStateException()); ctrl.replay(); exporter.unregisterService(reg); ctrl.verify(); } public void testLazyBeanServiceWithUsualBean() throws Exception { final ServiceRegistration reg = new MockServiceRegistration(); final ServiceFactory[] factory = new ServiceFactory[1]; Object service = new Object(); BundleContext ctx = new MockBundleContext() { public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) { assertTrue(service instanceof ServiceFactory); factory[0] = (ServiceFactory) service; return reg; } }; exporter.setBundleContext(ctx); String beanName = "fooBar"; exporter.setTargetBeanName(beanName); exporter.setInterfaces(new Class<?>[] { service.getClass() }); beanFactoryControl.expectAndReturn(beanFactory.isSingleton(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.containsBean(beanName), true); beanFactoryControl.expectAndReturn(beanFactory.getBean(beanName), service); beanFactoryControl.expectAndReturn(beanFactory.getType(beanName), service.getClass()); beanFactoryControl.replay(); exporter.afterPropertiesSet(); exporter.registerService(new Class<?>[] { service.getClass() }, new Properties()); assertSame(service, factory[0].getService(null, null)); beanFactoryControl.verify(); } public void testLazyBeanServiceWithServiceFactoryBean() throws Exception { final ServiceRegistration reg = new MockServiceRegistration(); final ServiceFactory[] factory = new ServiceFactory[1]; final Object actualService = new Object(); Object service = new MockServiceFactory() { public Object getService(Bundle arg0, ServiceRegistration arg1) { return actualService; } }; BundleContext ctx = new MockBundleContext() { public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) { assertTrue(service instanceof ServiceFactory); factory[0] = (ServiceFactory) service; return reg; } }; String beanName = "fooBar"; beanFactoryControl.expectAndReturn(beanFactory.isSingleton(beanName), false); // beanFactoryControl.expectAndReturn(beanFactory.isPrototype(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.containsBean(beanName), true); beanFactoryControl.expectAndReturn(beanFactory.getBean(beanName), service); beanFactoryControl.expectAndReturn(beanFactory.getType(beanName), service.getClass()); beanFactoryControl.replay(); exporter.setBundleContext(ctx); exporter.setBeanFactory(beanFactory); exporter.setTargetBeanName(beanName); exporter.setInterfaces(new Class<?>[] { service.getClass() }); exporter.afterPropertiesSet(); exporter.registerService(new Class<?>[] { actualService.getClass() }, new Properties()); assertSame(actualService, factory[0].getService(null, null)); beanFactoryControl.verify(); } public void testLazyBeanServiceWithTargetObjectSet() throws Exception { final ServiceRegistration reg = new MockServiceRegistration(); final ServiceFactory[] factory = new ServiceFactory[1]; Object service = new Object(); BundleContext ctx = new MockBundleContext() { public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) { assertTrue(service instanceof ServiceFactory); factory[0] = (ServiceFactory) service; return reg; } }; exporter.setBundleContext(ctx); exporter.setBeanFactory(beanFactory); // give an actual target object not a target reference exporter.setTarget(service); exporter.setInterfaces(new Class<?>[] { service.getClass() }); beanFactoryControl.replay(); exporter.afterPropertiesSet(); exporter.registerService(new Class<?>[] { service.getClass() }, new Properties()); assertSame(service, factory[0].getService(null, null)); beanFactoryControl.verify(); } private boolean compareArrays(Object[] a, Object[] b) { if (a.length != b.length) return false; for (int i = 0; i < a.length; i++) { boolean found = false; for (int j = 0; j < b.length; j++) { if (a[i].equals(b[j])) { found = true; break; } } if (!found) return false; } return true; } public void testServiceFactory() throws Exception { ServiceFactory factory = new MockServiceFactory(); ctx = new MockBundleContext(); exporter.setBundleContext(ctx); exporter.setBeanFactory(beanFactory); exporter.setInterfaces(new Class<?>[] { Serializable.class, Cloneable.class }); exporter.setTarget(factory); beanFactoryControl.replay(); exporter.afterPropertiesSet(); } public void testUpdateableProperties() throws Exception { UpdateableProperties properties = new UpdateableProperties(); properties.setProperty("steve", "vai"); exporter.setServiceProperties(properties); exporter.setTarget("string"); exporter.setBeanName("string"); exporter.setInterfaces(new Class<?>[] { Serializable.class }); beanFactoryControl.replay(); exporter.afterPropertiesSet(); ServiceRegistration reg = exporter.getObject(); assertEquals("vai", reg.getReference().getProperty("steve")); assertNull(reg.getReference().getProperty("updated")); properties.setProperty("steve", "jobs"); properties.setProperty("updated", "true"); properties.update(); assertEquals("jobs", reg.getReference().getProperty("steve")); assertNotNull(reg.getReference().getProperty("updated")); } public void testPrototypeServiceFactory() throws Exception { ServiceFactory factory = new MockServiceFactory(); String beanName = "prototype-sf"; beanFactoryControl.expectAndReturn(beanFactory.isSingleton(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.containsBean(beanName), true); beanFactoryControl.expectAndReturn(beanFactory.isPrototype(beanName), true); beanFactoryControl.expectAndReturn(beanFactory.getBean(beanName), factory); beanFactoryControl.expectAndReturn(beanFactory.getType(beanName), factory.getClass()); exporter.setTargetBeanName(beanName); exporter.setInterfaces(new Class<?>[] { Serializable.class }); beanFactoryControl.replay(); exporter.afterPropertiesSet(); } public void testNonSingletonServiceFactoryRegistration() throws Exception { TestRegistrationListener listener = new TestRegistrationListener(); ServiceFactory factory = new MockServiceFactory(); String beanName = "prototype-sf"; beanFactoryControl.expectAndReturn(beanFactory.isSingleton(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.isSingleton(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.isSingleton(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.containsBean(beanName), true); beanFactoryControl.expectAndReturn(beanFactory.isPrototype(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.getBean(beanName), factory); beanFactoryControl.expectAndReturn(beanFactory.getType(beanName), factory.getClass()); exporter.setTargetBeanName(beanName); exporter.setInterfaces(new Class<?>[] { Serializable.class }); exporter.setListeners(new OsgiServiceRegistrationListener[] { listener }); beanFactoryControl.replay(); assertEquals(0, listener.registered.size()); assertEquals(0, listener.unregistered.size()); exporter.afterPropertiesSet(); assertEquals(1, listener.registered.size()); assertEquals(0, listener.unregistered.size()); assertNull(listener.registered.keySet().iterator().next()); exporter.destroy(); assertEquals(1, listener.unregistered.size()); assertNull(listener.unregistered.keySet().iterator().next()); } public void testNonSingletonNonServiceFactoryRegistration() throws Exception { TestRegistrationListener listener = new TestRegistrationListener(); Object obj = new Object(); String beanName = "prototype-non-sf"; beanFactoryControl.expectAndReturn(beanFactory.isSingleton(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.isSingleton(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.isSingleton(beanName), false); beanFactoryControl.expectAndReturn(beanFactory.containsBean(beanName), true); beanFactoryControl.expectAndReturn(beanFactory.getBean(beanName), obj); beanFactoryControl.expectAndReturn(beanFactory.getType(beanName), obj.getClass()); exporter.setTargetBeanName(beanName); exporter.setInterfaces(new Class<?>[] { Object.class }); exporter.setListeners(new OsgiServiceRegistrationListener[] { listener }); beanFactoryControl.replay(); assertEquals(listener.registered.size(), 0); assertEquals(listener.unregistered.size(), 0); exporter.afterPropertiesSet(); assertEquals(listener.registered.size(), 1); assertEquals(listener.unregistered.size(), 0); assertNull(listener.registered.keySet().iterator().next()); exporter.destroy(); assertEquals(listener.unregistered.size(), 1); assertNull(listener.unregistered.keySet().iterator().next()); } }