INT-881, Added initial namespace support for auto-exporting SI components as OSGi services.

This commit is contained in:
Oleg Zhurakousky
2009-11-05 16:24:06 +00:00
parent 5ebd3e6d06
commit eb13d55218
17 changed files with 480 additions and 80 deletions

View File

@@ -16,11 +16,16 @@
package org.springframework.integration.osgi.config.xml;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.integration.controlbus.ControlBus;
import org.springframework.intergration.osgi.IntegrationOSGiConstants;
import org.springframework.osgi.service.exporter.support.AutoExport;
import org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean;
import org.springframework.osgi.service.importer.support.Cardinality;
import org.springframework.osgi.service.importer.support.OsgiServiceProxyFactoryBean;
import org.springframework.osgi.util.OsgiBundleUtils;
import org.springframework.osgi.util.OsgiServiceUtils;
import org.springframework.util.StringUtils;
/**
@@ -39,17 +44,36 @@ public class AbstractOSGiServiceManagingParserUtil {
* @param registry
*/
@SuppressWarnings("unchecked")
public static void registerServiceExporterFor(String beanName, BeanDefinitionRegistry registry, Class... publishedIntefaces){
public static BeanDefinitionBuilder defineServiceExporterFor(String beanName, BeanDefinitionRegistry registry, Class... publishedIntefaces){
BeanDefinitionBuilder serviceBuilder = BeanDefinitionBuilder.genericBeanDefinition(OsgiServiceFactoryBean.class);
serviceBuilder.addPropertyValue("targetBeanName", beanName);
serviceBuilder.addPropertyValue("interfaces", new Class[]{ControlBus.class});
if (publishedIntefaces != null && publishedIntefaces.length > 0){
serviceBuilder.addPropertyValue("interfaces", publishedIntefaces);
} else {
serviceBuilder.addPropertyValue("autoExport", AutoExport.INTERFACES);
}
serviceBuilder.addPropertyValue("registerService", true);
BeanDefinitionReaderUtils.registerWithGeneratedName(serviceBuilder.getBeanDefinition(), registry);
return serviceBuilder;
}
@SuppressWarnings("unchecked")
public static BeanDefinitionBuilder defineServiceImporterFor(String beanName, String filter,
BeanDefinitionRegistry registry, Class... publishedIntefaces){
BeanDefinitionBuilder serviceBuilder = BeanDefinitionBuilder.genericBeanDefinition(OsgiServiceProxyFactoryBean.class);
serviceBuilder.addPropertyValue("cardinality", Cardinality.C_0__1);
if (StringUtils.hasText(filter)){
serviceBuilder.addPropertyValue("filter", filter);
}
if (publishedIntefaces != null && publishedIntefaces.length > 0){
serviceBuilder.addPropertyValue("interfaces", publishedIntefaces);
} else {
serviceBuilder.addPropertyValue("autoExport", AutoExport.INTERFACES);
}
serviceBuilder.addPropertyValue("serviceBeanName", beanName);
//TODO: pf.setTimeout(timeoutInMillis)
return serviceBuilder;
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.integration.osgi.config.xml;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanDefinitionStoreException;
@@ -25,10 +23,8 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.controlbus.ControlBus;
import org.springframework.intergration.osgi.OSGiIntegrationControlBus;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -56,53 +52,22 @@ public class BusConfigParser extends AbstractBeanDefinitionParser {
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
String busGroupName = element.getAttribute("group-name");
Assert.isTrue(StringUtils.hasText(busGroupName), "bus-config 'group-name' attribute must be provided");
beanName = "controlBus-" + busGroupName;
beanName = busGroupName;
if (parserContext.getRegistry().containsBeanDefinition(beanName)){
throw new BeanDefinitionStoreException("You atempted to register a second instance of the Control Bus with the same 'group-name' " +
"in the single Application Context which is not allowed.");
}
BeanDefinitionBuilder rootBuilder = BeanDefinitionBuilder.rootBeanDefinition(OSGiIntegrationControlBus.class);
//String busChannelName = "controlMessagesDistributionChannel";
//this.registerPubSubChannelDefinition(element.getAttribute("task-executor"), element, parserContext);
rootBuilder.addConstructorArgReference("controlMessagesDistributionChannel");
rootBuilder.addConstructorArgValue(beanName);
AbstractOSGiServiceManagingParserUtil.registerServiceExporterFor(beanName, parserContext.getRegistry());
BeanDefinitionBuilder osgiServiceDefinition =
AbstractOSGiServiceManagingParserUtil.defineServiceExporterFor(beanName, parserContext.getRegistry(), ControlBus.class);
BeanDefinitionReaderUtils.registerWithGeneratedName(osgiServiceDefinition.getBeanDefinition(), parserContext.getRegistry());
// NOTE add listeners
log.trace("Control Bus " + beanName + " was parsed successfully");
return rootBuilder.getBeanDefinition();
}
/**
*
* @param taskExecutorName
* @param element
* @param parserContext
* @return
*/
private String registerPubSubChannelDefinition(String taskExecutorName, Element element, ParserContext parserContext){
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PublishSubscribeChannel.class.getName());
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-handler");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "ignore-failures");
if (!StringUtils.hasText(taskExecutorName)) {
taskExecutorName = this.createTaskExecutorDefinition(element, parserContext);
}
builder.addConstructorArgReference(taskExecutorName);
String beanName = BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
return beanName;
}
/**
*
* @param element
* @param parserContext
* @return
*/
private String createTaskExecutorDefinition(Element element, ParserContext parserContext){
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ThreadPoolTaskExecutor.class.getName());
builder.addPropertyValue("corePoolSize", 5);
builder.addPropertyValue("maxPoolSize", 10);
builder.addPropertyValue("rejectedExecutionHandler", new ThreadPoolExecutor.DiscardPolicy());
String beanName = BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
return beanName;
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed 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.springframework.integration.osgi.config.xml;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.controlbus.ControlBus;
import org.springframework.integration.osgi.extender.IntegrationServiceRegistrationListener;
import org.springframework.intergration.osgi.ControlBusAwarePostProcessor;
import org.springframework.intergration.osgi.IntegrationOSGiConstants;
import org.springframework.osgi.config.internal.adapter.OsgiServiceRegistrationListenerAdapter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Parser to process 'bus' element
*
* @author Oleg Zhurakousky
* @since 2.0
*/
public class BusParser extends AbstractBeanDefinitionParser {
private static final Log log = LogFactory.getLog(BusConfigParser.class);
private String busGroupName;
/**
*
*/
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
return "controlBusPostProcessor-" + busGroupName;
}
/**
* Will parse 'bus' element and its sub elements
*/
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
this.setBusGroupName(element);
BeanDefinitionRegistry registry = parserContext.getRegistry();
BeanDefinitionBuilder rootDefinition = BeanDefinitionBuilder.rootBeanDefinition(ControlBusAwarePostProcessor.class);
List<Element> producerList = DomUtils.getChildElementsByTagName(element, "manage-producer");
//List<Element> consumerList = DomUtils.getChildElementsByTagName(element, "manage-consumer");
for (Element producerElement : producerList) {
String producerName = producerElement.getAttribute("ref");
Assert.isTrue(StringUtils.hasText(producerName), "'manage-producer' must define 'ref' attribute");
// define service exporter
BeanDefinitionBuilder serviceExportBuilder =
AbstractOSGiServiceManagingParserUtil.defineServiceExporterFor(producerName, registry);
String registrationListenerName = this.defineRegistrationListener(registry);
// add listener(s) to the service exporter
serviceExportBuilder.addPropertyReference("listeners", registrationListenerName);
// register service exporter
BeanDefinitionReaderUtils.registerWithGeneratedName(serviceExportBuilder.getBeanDefinition(), registry);
}
log.trace("Managed configuration for " + busGroupName + " was parsed successfully");
return rootDefinition.getBeanDefinition();
}
/**
* Defines and registers OSGi Service Registration listener for the exported service (e.g., channel), which
* will communicate life-cycle events of this service to the Control Bus
*/
private String defineRegistrationListener(BeanDefinitionRegistry registry){
// define POJO listener
BeanDefinitionBuilder listenerBuilder = BeanDefinitionBuilder.genericBeanDefinition(IntegrationServiceRegistrationListener.class);
// inject Control Bus service instance into the listener
BeanDefinition controlBusDefinition = this.registerImportedControlBusServiceDefinition(registry);
listenerBuilder.addPropertyValue("controlBus", controlBusDefinition);
String listenerName =
BeanDefinitionReaderUtils.registerWithGeneratedName(listenerBuilder.getBeanDefinition(), registry);
// define listener adapter for the above listener
BeanDefinitionBuilder listenerAdapterBuilder =
BeanDefinitionBuilder.genericBeanDefinition(OsgiServiceRegistrationListenerAdapter.class);
listenerAdapterBuilder.addPropertyValue("targetBeanName", listenerName);
listenerAdapterBuilder.addPropertyValue("registrationMethod", "register");
listenerAdapterBuilder.addPropertyValue("unregistrationMethod", "unRegister");
String registrationListenerName =
BeanDefinitionReaderUtils.registerWithGeneratedName(listenerAdapterBuilder.getBeanDefinition(), registry);
return registrationListenerName;
}
/**
* Will define a service importer (equivalent to <osgi:reference>) for the ControlBus service.
*/
private BeanDefinition registerImportedControlBusServiceDefinition(BeanDefinitionRegistry registry){
String filter = "(&(" + IntegrationOSGiConstants.OSGI_BEAN_NAME + "=" + busGroupName + "))";
BeanDefinitionBuilder controlBusImporterBuilder =
AbstractOSGiServiceManagingParserUtil.defineServiceImporterFor(busGroupName, filter, registry, ControlBus.class);
BeanDefinition controlBusImporterDefinition = controlBusImporterBuilder.getBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(controlBusImporterBuilder.getBeanDefinition(), registry);
return controlBusImporterDefinition;
}
/**
* Determines and sets the 'group-name' for the ControlBus group which will be managing this deployment
*/
private void setBusGroupName(Element element){
busGroupName = element.getAttribute("group-name");
Assert.isTrue(StringUtils.hasText(busGroupName), "bus-config 'group-name' attribute must be provided");
log.debug("Control Bus group name: " + busGroupName);
}
}

View File

@@ -28,6 +28,7 @@ public class IntegrationOSGiControlBusNamespaceHandler extends AbstractIntegrati
*/
public void init() {
registerBeanDefinitionParser("bus-config", new BusConfigParser());
registerBeanDefinitionParser("bus", new BusParser());
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed 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.springframework.integration.osgi.extender;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.controlbus.ControlBus;
import org.springframework.integration.message.StringMessage;
/**
* Service Registration listener which publishes registration life-cycle Messages
* to the {@link ControlBus}
*
* @author Oleg Zhurakousky
* @since 2.0
*/
public class IntegrationServiceRegistrationListener {
private static final Log log = LogFactory.getLog(IntegrationServiceRegistrationListener.class);
private ControlBus controlBus;
@SuppressWarnings("unchecked")
public void register(Object service, Map properties){
if (controlBus != null){
log.info("Dispatching REGISTRATION Message for: " + service + "- " + properties + " to: " + controlBus.getName());
//TODO: change to structural message
controlBus.send(new StringMessage("Dispatching REGISTRATION Message for: " + service + "- " + properties));
}
}
@SuppressWarnings("unchecked")
public void unRegister(Object service, Map properties){
if (controlBus != null){
log.info("Dispatching UN-REGISTRATION Message for: " + service + "- " + properties + " to: " + controlBus.getName());
//TODO: change to structural message
controlBus.send(new StringMessage("Dispatching UN-REGISTRATION Message for: " + service + "- " + properties));
}
}
//
public ControlBus getControlBus() {
return controlBus;
}
//
public void setControlBus(ControlBus controlBus) {
this.controlBus = controlBus;
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed 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.springframework.intergration.osgi;
/**
* TODO - insert COMMENT
* @author Oleg Zhurakousky
* @since 2.0
*/
public interface ControlBusAware {
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed 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.springframework.intergration.osgi;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* TODO - insert COMMENT
* @author Oleg Zhurakousky
* @since 2.0
*/
public class ControlBusAwarePostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed 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.springframework.intergration.osgi;
/**
* TODO - insert COMMENT
* @author Oleg Zhurakousky
* @since 2.0
*/
public interface IntegrationOSGiConstants {
//(&(org.springframework.osgi.bean.name=controlBus-DEFAULT_CONTROL_GROUP))
public final String DEFAULT_BUS_GROUP_NAME = "DEFAULT_CONTROL_GROUP";
public final String OSGI_BEAN_NAME = "org.springframework.osgi.bean.name";
}

View File

@@ -23,16 +23,18 @@ import org.springframework.integration.message.MessageHandler;
/**
* Implementation of the {@link ControlBus} interface.
* Control Bus itself wrapper over {@link SubscribableChannel},
* which represents the entry point to Control BUs infrastructure.
* which represents the entry point to Control Bus infrastructure.
*
* @author Oleg Zhurakousky
* @since 2.0
*/
public class OSGiIntegrationControlBus implements ControlBus {
private SubscribableChannel channel;
private String busName;
public OSGiIntegrationControlBus(SubscribableChannel channel){
public OSGiIntegrationControlBus(SubscribableChannel channel, String busName){
this.channel = channel;
this.busName = busName;
}
public boolean subscribe(MessageHandler handler) {
@@ -58,5 +60,8 @@ public class OSGiIntegrationControlBus implements ControlBus {
return channel.send(message, timeout);
}
//
public String getBusName() {
return busName;
}
}

View File

@@ -30,4 +30,32 @@
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="bus">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Configures all required interactions with the named Control Bus configuration
</xsd:documentation>
</xsd:annotation>
<xsd:choice>
<xsd:element name="manage-subscriber" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="ref" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="manage-producer" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="ref" type="xsd:string" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
<xsd:attribute name="group-name" type="xsd:string" default="DEFAULT_CONTROL_GROUP">
<xsd:annotation>
<xsd:documentation>
Identifies group-name of a Control Bus this configuration defines
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -15,21 +15,17 @@
*/
package org.springframework.integration.osgi.config.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.context.ApplicationContext;
import org.springframework.core.task.TaskExecutor;
import org.springframework.integration.channel.SubscribableChannel;
import org.springframework.integration.controlbus.ControlBus;
import org.springframework.integration.osgi.AbstractSIConfigBundleTestDeployer;
import org.springframework.integration.osgi.stubs.SIBundleContextStub;
import org.springframework.integration.util.ErrorHandlingTaskExecutor;
import org.springframework.intergration.osgi.IntegrationOSGiConstants;
/**
@@ -44,10 +40,12 @@ public class BusConfigParserTests extends AbstractSIConfigBundleTestDeployer {
ApplicationContext ac = this.deploySIConfig(bundleContext,
"org/springframework/integration/osgi/config/xml/",
"BusConfigParserTests-default.xml");
ControlBus controlBus = (ControlBus) ac.getBean("controlBus-DEFAULT_CONTROL_GROUP");
ControlBus controlBus = (ControlBus) ac.getBean(IntegrationOSGiConstants.DEFAULT_BUS_GROUP_NAME);
assertNotNull(controlBus);
assertTrue(controlBus.getBusName().equals(IntegrationOSGiConstants.DEFAULT_BUS_GROUP_NAME));
ServiceReference[] sr = bundleContext.getServiceReferences(ControlBus.class.getName(),
"(&(org.springframework.osgi.bean.name=controlBus-DEFAULT_CONTROL_GROUP))");
"(&(" + IntegrationOSGiConstants.OSGI_BEAN_NAME + "=" +
IntegrationOSGiConstants.DEFAULT_BUS_GROUP_NAME + "))");
assertNotNull(sr);
assertTrue(sr.length == 1);
controlBus = (ControlBus) bundleContext.getService(sr[0]);
@@ -59,7 +57,7 @@ public class BusConfigParserTests extends AbstractSIConfigBundleTestDeployer {
ApplicationContext ac = this.deploySIConfig(bundleContext,
"org/springframework/integration/osgi/config/xml/",
"BusConfigParserTests-overrideGroupName.xml");
ControlBus controlBus = (ControlBus) ac.getBean("controlBus-FOO");
ControlBus controlBus = (ControlBus) ac.getBean("FOO");
assertNotNull(controlBus);
ServiceReference sr = bundleContext.getServiceReference(ControlBus.class.getName());
assertNotNull(sr);

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed 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.springframework.integration.osgi.extender;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Map;
import org.junit.Test;
import org.mockito.Mockito;
import org.omg.CORBA.MARSHAL;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.context.ApplicationContext;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.controlbus.ControlBus;
import org.springframework.integration.osgi.AbstractSIConfigBundleTestDeployer;
import org.springframework.integration.osgi.stubs.SIBundleContextStub;
import org.springframework.osgi.config.internal.adapter.OsgiServiceRegistrationListenerAdapter;
import org.springframework.osgi.mock.MockServiceReference;
import org.springframework.osgi.service.exporter.OsgiServiceRegistrationListener;
import org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean;
import org.springframework.osgi.util.OsgiServiceUtils;
/**
* TODO - insert COMMENT
* @author Oleg Zhurakousky
* @since 2.0
*/
public class BusParserProducersTests extends AbstractSIConfigBundleTestDeployer {
@SuppressWarnings("unchecked")
@Test
public void testBusWithSubscribersBusPresent() throws Exception {
SIBundleContextStub bundleContext = SIBundleContextStub.getInstance();
this.deploySIConfig(bundleContext,
"org/springframework/integration/osgi/config/xml/",
"BusConfigParserTests-default.xml");
ApplicationContext ac = this.deploySIConfig(bundleContext,
"org/springframework/integration/osgi/extender/",
"BusParserProducersTests.xml");
Map beans = ac.getBeansOfType(OsgiServiceFactoryBean.class);
assertTrue(beans.size() == 1);
OsgiServiceFactoryBean serviceExporter = (OsgiServiceFactoryBean) beans.values().toArray()[0];
assertTrue(serviceExporter.getTargetBeanName().equals("exportedChannel"));
DirectFieldAccessor serviceExporterAccessor = new DirectFieldAccessor(serviceExporter);
OsgiServiceRegistrationListener[] listeners =
(OsgiServiceRegistrationListener[]) serviceExporterAccessor.getPropertyValue("listeners");
assertTrue(listeners.length == 1);
ServiceReference sr =
bundleContext.getServiceReferences(null, "(&(org.springframework.osgi.bean.name=exportedChannel))")[0];
assertNotNull(sr);
}
@Test
public void testBusWithSubscribersBusNotPresent() throws Exception {
SIBundleContextStub bundleContext = SIBundleContextStub.getInstance();
this.deploySIConfig(bundleContext,
"org/springframework/integration/osgi/extender/",
"BusParserProducersTests.xml");
assertTrue(true); // if exception was not thrown we are ok
}
}

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:si-control="http://www.springframework.org/schema/integration/integration-control-bus"
xmlns:si="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration/integration-control-bus http://www.springframework.org/schema/integration/integration-control-bus/spring-integration-bus-1.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd">
<si-control:bus group-name="DEFAULT_CONTROL_GROUP" >
<si-control:manage-producer ref="exportedChannel"/>
</si-control:bus>
<si:publish-subscribe-channel id="exportedChannel"/>
</beans>

View File

@@ -25,6 +25,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mockito.Mockito;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceFactory;
@@ -46,10 +47,13 @@ public class SIBundleContextStub extends MockBundleContext {
private static SIBundleContextStub bundleContext = new SIBundleContextStub();
private Map<ServiceReference, Object> services = new HashMap<ServiceReference, Object>();
private Set<ServiceReference> serviceReferences = new HashSet<ServiceReference>();
private Map<MapBasedDictionary, ServiceListener> serviceListenerMap =
new HashMap<MapBasedDictionary, ServiceListener>();
/**
*
* @return
@@ -97,7 +101,7 @@ public class SIBundleContextStub extends MockBundleContext {
// });
// t.start();
}
log.debug("Service: " + ref + " is registered");
log.info("Registered SERVICE: " + ref);
return reg;
}
/**
@@ -128,7 +132,6 @@ public class SIBundleContextStub extends MockBundleContext {
/**
*
*/
@SuppressWarnings("unchecked")
public void addServiceListener(ServiceListener listener) {
MapBasedDictionary properties = new MapBasedDictionary();
serviceListenerMap.put(properties, listener);
@@ -147,9 +150,9 @@ public class SIBundleContextStub extends MockBundleContext {
for (Dictionary filter : serviceListenerMap.keySet()) {
MapBasedDictionary listenerFilter = new MapBasedDictionary(filter);
log.debug("Trying to match filter properties: " + listenerFilter);
log.trace("Trying to match filter properties: " + listenerFilter);
MapBasedDictionary inFilter = new MapBasedDictionary(properties);
log.debug("Current filter entry: " + inFilter);
log.trace("Current filter entry: " + inFilter);
boolean objecClassMatch = true;
if (listenerFilter.containsKey("objectClass")){
objecClassMatch = this.matchObjectClass(listenerFilter, inFilter);
@@ -172,9 +175,10 @@ public class SIBundleContextStub extends MockBundleContext {
return Arrays.binarySearch(interfaces, interfaze) >=0;
}
public void removeService(ServiceReference sr){
services.remove(sr);
serviceReferences.remove(sr);
public Map<MapBasedDictionary, ServiceListener> getServiceListenerMap() {
return serviceListenerMap;
}
public Map<ServiceReference, Object> getServices() {
return services;
}
}

View File

@@ -38,15 +38,15 @@ public class SIServiceRegistrationStub extends MockServiceRegistration {
public void setBundleContext(SIBundleContextStub context){
this.context = context;
}
public void unregister() {
ServiceReference ref = this.getReference();
DirectFieldAccessor refAccessor = new DirectFieldAccessor(ref);
Dictionary properties = (Dictionary) refAccessor.getPropertyValue("properties");
context.removeService(this.getReference());
Set<ServiceListener> listeners = context.getFilteredListeners(properties);
for (ServiceListener serviceListener : listeners) {
serviceListener.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, ref));
}
}
// public void unregister() {
// ServiceReference ref = this.getReference();
// DirectFieldAccessor refAccessor = new DirectFieldAccessor(ref);
// Dictionary properties = (Dictionary) refAccessor.getPropertyValue("properties");
//
// context.removeService(this.getReference());
// Set<ServiceListener> listeners = context.getFilteredListeners(properties);
// for (ServiceListener serviceListener : listeners) {
// serviceListener.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, ref));
// }
// }
}

View File

@@ -9,13 +9,16 @@
<param name="ConversionPattern" value="%-5p: %c - %m%n" />
</layout>
</appender>
<logger name="org.springframework.osgi">
<level value="trace" />
<level value="info" />
</logger>
<logger name="org.springframework.integration">
<level value="info" />
</logger>
<logger name="org.springframework.integration.osgi">
<level value="debug" />
</logger>