/******************************************************************************
* 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());
}
}