From eb13d55218246199bcb47bd0113dde5ca123621c Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Thu, 5 Nov 2009 16:24:06 +0000 Subject: [PATCH] INT-881, Added initial namespace support for auto-exporting SI components as OSGi services. --- ...AbstractOSGiServiceManagingParserUtil.java | 32 ++++- .../osgi/config/xml/BusConfigParser.java | 53 ++------ .../osgi/config/xml/BusParser.java | 126 ++++++++++++++++++ ...grationOSGiControlBusNamespaceHandler.java | 1 + ...ntegrationServiceRegistrationListener.java | 60 +++++++++ .../intergration/osgi/ControlBusAware.java | 25 ++++ .../osgi/ControlBusAwarePostProcessor.java | 40 ++++++ .../osgi/IntegrationOSGiConstants.java | 27 ++++ .../osgi/OSGiIntegrationControlBus.java | 11 +- .../config/xml/spring-integration-bus-1.0.xsd | 28 ++++ .../osgi/config/xml/BusConfigParserTests.java | 14 +- .../extender/BusParserProducersTests.java | 78 +++++++++++ .../osgi/extender/BusParserProducersTests.xml | 15 +++ .../osgi/stubs/SIBundleContextStub.java | 20 +-- .../osgi/stubs/SIServiceRegistrationStub.java | 22 +-- .../src/test/resources/log4j.xml | 7 +- .../integration/controlbus/ControlBus.java | 1 + 17 files changed, 480 insertions(+), 80 deletions(-) create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/BusParser.java create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/extender/IntegrationServiceRegistrationListener.java create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/ControlBusAware.java create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/ControlBusAwarePostProcessor.java create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/IntegrationOSGiConstants.java create mode 100644 org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.java create mode 100644 org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.xml diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/AbstractOSGiServiceManagingParserUtil.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/AbstractOSGiServiceManagingParserUtil.java index 54d66684bc..46e09aec9f 100644 --- a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/AbstractOSGiServiceManagingParserUtil.java +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/AbstractOSGiServiceManagingParserUtil.java @@ -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; } } diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/BusConfigParser.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/BusConfigParser.java index bc4cc4297b..dfad6e0d06 100644 --- a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/BusConfigParser.java +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/BusConfigParser.java @@ -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; - } - } diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/BusParser.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/BusParser.java new file mode 100644 index 0000000000..a28d9231d5 --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/BusParser.java @@ -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 producerList = DomUtils.getChildElementsByTagName(element, "manage-producer"); + //List 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 ) 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); + } +} diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/IntegrationOSGiControlBusNamespaceHandler.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/IntegrationOSGiControlBusNamespaceHandler.java index ef91ee98d0..1c4f3500b5 100644 --- a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/IntegrationOSGiControlBusNamespaceHandler.java +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/IntegrationOSGiControlBusNamespaceHandler.java @@ -28,6 +28,7 @@ public class IntegrationOSGiControlBusNamespaceHandler extends AbstractIntegrati */ public void init() { registerBeanDefinitionParser("bus-config", new BusConfigParser()); + registerBeanDefinitionParser("bus", new BusParser()); } } diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/extender/IntegrationServiceRegistrationListener.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/extender/IntegrationServiceRegistrationListener.java new file mode 100644 index 0000000000..2913a1165b --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/extender/IntegrationServiceRegistrationListener.java @@ -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; + } +} diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/ControlBusAware.java b/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/ControlBusAware.java new file mode 100644 index 0000000000..b00e82b7fb --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/ControlBusAware.java @@ -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 { + +} diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/ControlBusAwarePostProcessor.java b/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/ControlBusAwarePostProcessor.java new file mode 100644 index 0000000000..a3f3b877a5 --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/ControlBusAwarePostProcessor.java @@ -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; + } + +} diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/IntegrationOSGiConstants.java b/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/IntegrationOSGiConstants.java new file mode 100644 index 0000000000..8175f146d9 --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/IntegrationOSGiConstants.java @@ -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"; +} diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/OSGiIntegrationControlBus.java b/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/OSGiIntegrationControlBus.java index 8cc9e9e74b..5ffd6af7a2 100644 --- a/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/OSGiIntegrationControlBus.java +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/intergration/osgi/OSGiIntegrationControlBus.java @@ -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; + } } diff --git a/org.springframework.integration.osgi/src/main/resources/org/springframework/integration/osgi/config/xml/spring-integration-bus-1.0.xsd b/org.springframework.integration.osgi/src/main/resources/org/springframework/integration/osgi/config/xml/spring-integration-bus-1.0.xsd index ed207e7133..7ac896fe77 100644 --- a/org.springframework.integration.osgi/src/main/resources/org/springframework/integration/osgi/config/xml/spring-integration-bus-1.0.xsd +++ b/org.springframework.integration.osgi/src/main/resources/org/springframework/integration/osgi/config/xml/spring-integration-bus-1.0.xsd @@ -30,4 +30,32 @@ + + + + + Configures all required interactions with the named Control Bus configuration + + + + + + + + + + + + + + + + + + Identifies group-name of a Control Bus this configuration defines + + + + + \ No newline at end of file diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/BusConfigParserTests.java b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/BusConfigParserTests.java index 9f0fbbd877..30b893d98f 100644 --- a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/BusConfigParserTests.java +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/BusConfigParserTests.java @@ -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); diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.java b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.java new file mode 100644 index 0000000000..a095c295d1 --- /dev/null +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.java @@ -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 + } +} diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.xml b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.xml new file mode 100644 index 0000000000..4db586d632 --- /dev/null +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/stubs/SIBundleContextStub.java b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/stubs/SIBundleContextStub.java index b64657ee28..6d08fe7b8c 100644 --- a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/stubs/SIBundleContextStub.java +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/stubs/SIBundleContextStub.java @@ -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 services = new HashMap(); + + private Set serviceReferences = new HashSet(); private Map serviceListenerMap = new HashMap(); + /** * * @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 getServiceListenerMap() { + return serviceListenerMap; + } + public Map getServices() { + return services; } } diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/stubs/SIServiceRegistrationStub.java b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/stubs/SIServiceRegistrationStub.java index b544240031..63f1578a09 100644 --- a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/stubs/SIServiceRegistrationStub.java +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/stubs/SIServiceRegistrationStub.java @@ -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 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 listeners = context.getFilteredListeners(properties); +// for (ServiceListener serviceListener : listeners) { +// serviceListener.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, ref)); +// } +// } } diff --git a/org.springframework.integration.osgi/src/test/resources/log4j.xml b/org.springframework.integration.osgi/src/test/resources/log4j.xml index d964b5cc46..6857a52247 100644 --- a/org.springframework.integration.osgi/src/test/resources/log4j.xml +++ b/org.springframework.integration.osgi/src/test/resources/log4j.xml @@ -9,13 +9,16 @@ - - + + + + + diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/controlbus/ControlBus.java b/org.springframework.integration/src/main/java/org/springframework/integration/controlbus/ControlBus.java index ce448ead93..ce0e6cc382 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/controlbus/ControlBus.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/controlbus/ControlBus.java @@ -26,4 +26,5 @@ import org.springframework.integration.channel.SubscribableChannel; * @since 2.0 */ public interface ControlBus extends SubscribableChannel { + public String getBusName(); }