From 0135016d9049b3a240390a01c440ba26b16a0eab Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Tue, 17 Nov 2009 13:49:32 +0000 Subject: [PATCH] INT-881, Decoupled SI Services configuration from service interaction with the Control Bus --- .../osgi/IntegrationOSGiConstants.java | 26 +++ .../osgi/OSGiIntegrationControlBus.java | 69 ++++++++ ...AbstractOSGiServiceManagingParserUtil.java | 60 +++++-- .../osgi/config/xml/BusConfigParser.java | 6 +- .../osgi/config/xml/BusParser.java | 126 -------------- .../osgi/config/xml/ConfigParser.java | 158 ++++++++++++++++++ .../osgi/config/xml/ControlBusOSGiUtils.java | 58 +++++++ ...grationOSGiControlBusNamespaceHandler.java | 1 - ...onOSGiServiceExtenderNamespaceHandler.java | 33 ++++ .../config/xml/SiTypeToJavaTypeMaper.java | 42 +++++ .../ControlBusListeningDecorator.java | 143 ++++++++++++++++ ...ntegrationServiceRegistrationListener.java | 42 +++-- .../main/resources/META-INF/spring.handlers | 3 +- .../main/resources/META-INF/spring.schemas | 2 + .../config/xml/spring-integration-bus-1.0.xsd | 28 ---- ...pring-integration-service-extender-1.0.xsd | 104 ++++++++++++ .../osgi/config/xml/BusConfigParserTests.java | 7 +- .../config/xml/BusUsageFailoverTests.java | 5 +- .../xml/ConfigParserExporterTests-default.xml | 25 +++ ...gParserExporterTests-withbus-attribute.xml | 26 +++ .../config/xml/ConfigParserExporterTests.java | 80 +++++++++ .../ConfigParserImporterTests-default.xml} | 15 +- .../config/xml/ConfigParserImporterTests.java | 44 +++++ .../osgi/config/xml/base-bus-config.xml | 2 +- .../extender/BusParserProducersTests.java | 78 --------- .../osgi/stubs/SIBundleContextStub.java | 5 + .../osgi/stubs/SIServiceRegistrationStub.java | 22 +-- .../src/test/resources/log4j.xml | 2 +- .../template.mf | 6 +- 29 files changed, 921 insertions(+), 297 deletions(-) create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/IntegrationOSGiConstants.java create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/OSGiIntegrationControlBus.java delete 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/config/xml/ConfigParser.java create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/ControlBusOSGiUtils.java create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/IntegrationOSGiServiceExtenderNamespaceHandler.java create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/SiTypeToJavaTypeMaper.java create mode 100644 org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/extender/ControlBusListeningDecorator.java create mode 100644 org.springframework.integration.osgi/src/main/resources/org/springframework/integration/osgi/config/xml/spring-integration-service-extender-1.0.xsd create mode 100644 org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests-default.xml create mode 100644 org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests-withbus-attribute.xml create mode 100644 org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests.java rename org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/{extender/BusParserProducersTests.xml => config/xml/ConfigParserImporterTests-default.xml} (50%) create mode 100644 org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserImporterTests.java delete mode 100644 org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.java diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/IntegrationOSGiConstants.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/IntegrationOSGiConstants.java new file mode 100644 index 0000000000..1bc5fc78fc --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/IntegrationOSGiConstants.java @@ -0,0 +1,26 @@ +/* + * 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; + +/** + * Constants used by OSGi Service Extender + * + * @author Oleg Zhurakousky + * @since 2.0 + */ +public interface IntegrationOSGiConstants { + public final String OSGI_BEAN_NAME = "org.springframework.osgi.bean.name"; +} diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/OSGiIntegrationControlBus.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/OSGiIntegrationControlBus.java new file mode 100644 index 0000000000..26509ab5eb --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/OSGiIntegrationControlBus.java @@ -0,0 +1,69 @@ +/* + * 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; + +import org.springframework.integration.channel.SubscribableChannel; +import org.springframework.integration.controlbus.ControlBus; +import org.springframework.integration.core.Message; +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. + * + * @author Oleg Zhurakousky + * @since 2.0 + */ +public class OSGiIntegrationControlBus implements ControlBus { + private SubscribableChannel channel; + private String busName; + + public OSGiIntegrationControlBus(SubscribableChannel channel, String busName){ + this.channel = channel; + this.busName = busName; + } + + public boolean subscribe(MessageHandler handler) { + return channel.subscribe(handler); + } + + + public boolean unsubscribe(MessageHandler handler) { + return channel.unsubscribe(handler); + } + + public String getName() { + return channel.getName(); + } + + + public boolean send(Message message) { + return channel.send(message); + } + + + public boolean send(Message message, long timeout) { + return channel.send(message, timeout); + } + /* + * (non-Javadoc) + * @see org.springframework.integration.controlbus.ControlBus#isBusAvailable() + */ + public boolean isBusAvailable() { + return true; + } +} 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 46e09aec9f..dee3ad4da7 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 @@ -15,21 +15,21 @@ */ package org.springframework.integration.osgi.config.xml; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.integration.controlbus.ControlBus; -import org.springframework.intergration.osgi.IntegrationOSGiConstants; +import org.springframework.integration.osgi.extender.IntegrationServiceRegistrationListener; 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.Assert; import org.springframework.util.StringUtils; /** - * Will register {@link OsgiServiceFactoryBean} to export {@link ControlBus} as an OSGi service + * Utility class which wraps Spring-DM factory bean creation for exporting and importing SI components as + * OSGi services. * * @author Oleg Zhurakousky * @since 2.0 @@ -37,14 +37,20 @@ import org.springframework.util.StringUtils; public class AbstractOSGiServiceManagingParserUtil { /** - * Will export a bean identified by the 'beanName' as an OSGi Service. It will publish the service under all - * interfaces visible this class represents. + * Will define OSGi Service exporter BeanDefinitionBuilder for a bean identified by the 'beanName' + * parameter as an OSGi Service. If 'publishInterfaces' parameter is not provided this exporter will + * use all interfaces implemented by this service class hierarchy. Otherwise you can provide an array of + * specific interfaces to be published under this service. * * @param beanName * @param registry + * @param publishedIntefaces + * @return */ @SuppressWarnings("unchecked") - public static BeanDefinitionBuilder defineServiceExporterFor(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); if (publishedIntefaces != null && publishedIntefaces.length > 0){ @@ -55,10 +61,18 @@ public class AbstractOSGiServiceManagingParserUtil { serviceBuilder.addPropertyValue("registerService", true); return serviceBuilder; } - + /** + * + * @param beanName + * @param filter + * @param registry + * @param publishedIntefaces + * @return + */ @SuppressWarnings("unchecked") public static BeanDefinitionBuilder defineServiceImporterFor(String beanName, String filter, BeanDefinitionRegistry registry, Class... publishedIntefaces){ + Assert.notEmpty(publishedIntefaces, "At least one interface must be provided"); BeanDefinitionBuilder serviceBuilder = BeanDefinitionBuilder.genericBeanDefinition(OsgiServiceProxyFactoryBean.class); serviceBuilder.addPropertyValue("cardinality", Cardinality.C_0__1); if (StringUtils.hasText(filter)){ @@ -66,14 +80,34 @@ public class AbstractOSGiServiceManagingParserUtil { } 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; } - + /** + * Will define a registration listener bean definition for the exported service adding reference to the + * to the ControlBusListeninigDecorator to it. + * + * @param registry + * @param exporterBuilder + * @param busBeanName + * @return + */ + public static AbstractBeanDefinition defineRegistrationListenerForBus(BeanDefinitionRegistry registry, + BeanDefinitionBuilder exporterBuilder, + String busBeanName){ + BeanDefinitionBuilder listenerBuilder = + BeanDefinitionBuilder.genericBeanDefinition(IntegrationServiceRegistrationListener.class); + String busGroupName = busBeanName; + if (!registry.containsBeanDefinition(busGroupName)){ + ControlBusOSGiUtils.registerImporterForControlBus(registry, busGroupName); + } + listenerBuilder.addConstructorArgReference(busGroupName); + AbstractBeanDefinition listenerDefinition = listenerBuilder.getBeanDefinition(); + exporterBuilder.addPropertyValue("listeners", listenerDefinition); + return listenerDefinition; + } } 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 dfad6e0d06..37540e1a89 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 @@ -24,7 +24,7 @@ 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.controlbus.ControlBus; -import org.springframework.intergration.osgi.OSGiIntegrationControlBus; +import org.springframework.integration.osgi.OSGiIntegrationControlBus; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.w3c.dom.Element; @@ -44,7 +44,7 @@ public class BusConfigParser extends AbstractBeanDefinitionParser { */ protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { - return beanName; + return beanName; } /** * @@ -59,7 +59,7 @@ public class BusConfigParser extends AbstractBeanDefinitionParser { } BeanDefinitionBuilder rootBuilder = BeanDefinitionBuilder.rootBeanDefinition(OSGiIntegrationControlBus.class); - rootBuilder.addConstructorArgReference("controlMessagesDistributionChannel"); + rootBuilder.addConstructorArgReference(ControlBusOSGiUtils.DEFAULT_CONTROL_DIST_CHANNEL); rootBuilder.addConstructorArgValue(beanName); BeanDefinitionBuilder osgiServiceDefinition = 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 deleted file mode 100644 index a28d9231d5..0000000000 --- a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/BusParser.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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/ConfigParser.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/ConfigParser.java new file mode 100644 index 0000000000..714091d027 --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/ConfigParser.java @@ -0,0 +1,158 @@ +/* + * 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.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.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.osgi.extender.IntegrationServiceRegistrationListener; +import org.springframework.util.Assert; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * Parser to process 'config' element of SI Service Extender + * and its sub-elements + * + * @author Oleg Zhurakousky + * @since 2.0 + */ +public class ConfigParser implements BeanDefinitionParser { + private static final Log log = LogFactory.getLog(ConfigParser.class); + private static final String TYPE = "si-type"; + private static final String REF = "ref"; + private static final String NAME = "name"; + private static final String CONTROL_BUS = "control-bus"; + private static final String EXPORTER_SUFFIX = "-Service"; + private static final int EXPORT = 1; + private static final int IMPORT = 2; + /** + * Will parse 'config' element of "integration-service-extender' namespace and its sub-elements + */ + public BeanDefinition parse(Element element, ParserContext parserContext) { + List elements = DomUtils.getChildElementsByTagName(element, "export"); + for (Element exportElements : elements) { + this.processExportElement(exportElements, parserContext, EXPORT); + } + elements = DomUtils.getChildElementsByTagName(element, "import"); + for (Element exportElements : elements) { + this.processImportElement(exportElements, parserContext, IMPORT); + } + return null; + } + /** + */ + private void processExportElement(Element element, ParserContext parserContext, int configType){ + BeanDefinitionRegistry registry = parserContext.getRegistry(); + String includeType = this.getIncludeType(element); + Assert.notNull(includeType, "You must prvide one of the following: 'type' or 'ref' attribute wihin the 'include' element"); + if (includeType.equals(TYPE)){ + this.processTypeAttribute(element, registry, configType); + } else if (includeType.equals(REF)){ + this.processRefAttribute(element, registry, configType); + } + } + /** + */ + private void processImportElement(Element element, ParserContext parserContext, int configType){ + BeanDefinitionRegistry registry = parserContext.getRegistry(); + String serviceName = element.getAttribute(NAME); + Assert.hasText(serviceName, "you must enter a valid value in the " + NAME + " attribute"); + Class[] interfaces = this.discoverInterfaces(serviceName, element); + BeanDefinitionBuilder importerBuilder = + AbstractOSGiServiceManagingParserUtil.defineServiceImporterFor(serviceName, null, registry, interfaces); + registry.registerBeanDefinition(serviceName, importerBuilder.getBeanDefinition()); + } + /** + */ + private void processRefAttribute(Element element, BeanDefinitionRegistry registry, int configType) { + if (configType == EXPORT){ + String beanName = element.getAttribute(REF); + this.generateServiceExorterDefinition(beanName, element, registry); + } else if (configType == IMPORT){ + + } + } + /** + */ + private void processTypeAttribute(Element element, BeanDefinitionRegistry registry, int configType) { + String exportedTypes = element.getAttribute(TYPE); + if (configType == EXPORT){ + Element rootDocumentElement = element.getOwnerDocument().getDocumentElement(); + List elementsToExport = DomUtils.getChildElementsByTagName(rootDocumentElement, exportedTypes); + for (Element elementToExport : elementsToExport) { + String beanName = elementToExport.getAttribute("id"); + this.generateServiceExorterDefinition(beanName, element, registry); + } + } + } + /* + * + */ + private void generateServiceExorterDefinition(String beanName, Element element, BeanDefinitionRegistry registry){ + BeanDefinitionBuilder exportedElementBuilder = + AbstractOSGiServiceManagingParserUtil.defineServiceExporterFor(beanName, registry); + this.connectWithControlBusIfRequired(element, exportedElementBuilder, registry, beanName); + registry.registerBeanDefinition(beanName+EXPORTER_SUFFIX, exportedElementBuilder.getBeanDefinition()); + } + /** + * If element specifies 'control-bus' attribute, this method will register {@link IntegrationServiceRegistrationListener} + * which will send registration messages to the ControlBus + */ + private void connectWithControlBusIfRequired(Element originalElement, + BeanDefinitionBuilder exportedElementBuilder, + BeanDefinitionRegistry registry, + String componentName) { + if (originalElement.hasAttribute(CONTROL_BUS)){ + String controlBusAttributeValue = originalElement.getAttribute(CONTROL_BUS); + Assert.hasText(controlBusAttributeValue, "You must provide control bus name when defining 'control-bus' attribute"); + log.trace("Adding registration listener for exported OSGi service for:" + componentName); + + AbstractBeanDefinition listenerDefinition = + AbstractOSGiServiceManagingParserUtil.defineRegistrationListenerForBus(registry, exportedElementBuilder, controlBusAttributeValue); + BeanDefinitionReaderUtils.registerWithGeneratedName(listenerDefinition, registry); + } + } + /** + */ + private String getIncludeType(Element element){ + if (element.hasAttribute(REF)){ + return REF; + } else if (element.hasAttribute(TYPE)){ + return TYPE; + } + return null; + } + /** + */ + private Class[] discoverInterfaces(String name, Element element){ + if (element.hasAttribute(TYPE)){ + return SiTypeToJavaTypeMaper.mapSiType(element.getAttribute(TYPE)); + } +// Element documentElement = element.getOwnerDocument().getDocumentElement(); +// NodeList children = documentElement.getChildNodes(); + return null; + } +} diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/ControlBusOSGiUtils.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/ControlBusOSGiUtils.java new file mode 100644 index 0000000000..c7beec3655 --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/ControlBusOSGiUtils.java @@ -0,0 +1,58 @@ +/* + * 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 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.integration.controlbus.ControlBus; +import org.springframework.integration.osgi.IntegrationOSGiConstants; +import org.springframework.integration.osgi.extender.ControlBusListeningDecorator; + +/** + * TODO - insert COMMENT + * @author Oleg Zhurakousky + * @since 2.0 + */ +public class ControlBusOSGiUtils { + public final static String DEFAULT_BUS_GROUP_NAME = "DEFAULT_CONTROL_GROUP"; + public final static String DEFAULT_CONTROL_DIST_CHANNEL = "DEFAULT_CONTROL_DIST_CHANNEL"; + /** + * Will define a service importer (equivalent to ) for the ControlBus service. + * It will also register binding listener for this 'controlbus' reference which could be used + * to react to the life-cycle events of this 'controlbus' reference. + * For example: Individual service reference listeners coiuld use it to determine when the bus went away and + * no control events need to be dispatched to the bus. + */ + public static BeanDefinition registerImporterForControlBus(BeanDefinitionRegistry registry, String busGroupName){ + String filter = "(&(" + IntegrationOSGiConstants.OSGI_BEAN_NAME + "=" + busGroupName + "))"; + BeanDefinitionBuilder controlBusImporterBuilder = + AbstractOSGiServiceManagingParserUtil.defineServiceImporterFor(busGroupName, filter, registry, ControlBus.class); + + BeanDefinitionBuilder busListenerBuilder = + BeanDefinitionBuilder.genericBeanDefinition(ControlBusListeningDecorator.class); + AbstractBeanDefinition busListenerDefinition = busListenerBuilder.getBeanDefinition(); + //String listenerName = IntegrationOSGiConstants.BUS_LISTENER_PREFIX + busGroupName; + String listenerName = busGroupName; + registry.registerBeanDefinition(listenerName, busListenerDefinition); + controlBusImporterBuilder.addPropertyReference("listeners", listenerName); + BeanDefinition controlBusImporterDefinition = controlBusImporterBuilder.getBeanDefinition(); + BeanDefinitionReaderUtils.registerWithGeneratedName(controlBusImporterBuilder.getBeanDefinition(), registry); + return controlBusImporterDefinition; + } +} 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 1c4f3500b5..ef91ee98d0 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,7 +28,6 @@ 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/config/xml/IntegrationOSGiServiceExtenderNamespaceHandler.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/IntegrationOSGiServiceExtenderNamespaceHandler.java new file mode 100644 index 0000000000..bd154f027c --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/IntegrationOSGiServiceExtenderNamespaceHandler.java @@ -0,0 +1,33 @@ +/* + * 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 org.springframework.integration.config.xml.AbstractIntegrationNamespaceHandler; + +/** + * @author Oleg Zhurakousky + * @since 2.0 + */ +public class IntegrationOSGiServiceExtenderNamespaceHandler extends AbstractIntegrationNamespaceHandler { + + /** + * Will register the required parsers + */ + public void init() { + registerBeanDefinitionParser("config", new ConfigParser()); + } + +} diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/SiTypeToJavaTypeMaper.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/SiTypeToJavaTypeMaper.java new file mode 100644 index 0000000000..2f579eebd7 --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/config/xml/SiTypeToJavaTypeMaper.java @@ -0,0 +1,42 @@ +/* + * 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.HashMap; +import java.util.Map; + +import org.springframework.integration.channel.PublishSubscribeChannel; +import org.springframework.osgi.util.internal.ClassUtils; +import org.springframework.util.Assert; + +/** + * @author Oleg Zhurakousky + * @since 2.0 + */ +@SuppressWarnings("unchecked") +class SiTypeToJavaTypeMaper { + public static final String PUB_SUB_CHANNEL = "publish-subscribe-channel"; + private static Map siTypeMappings = new HashMap(); + + static { + siTypeMappings.put(PUB_SUB_CHANNEL, ClassUtils.getClassHierarchy(PublishSubscribeChannel.class, ClassUtils.INCLUDE_INTERFACES)); + } + + public static Class[] mapSiType(String siType){ + Assert.isTrue(siTypeMappings.containsKey(siType), "Can not map SI-Type '" + siType + "' to Java Type. Not supported."); + return siTypeMappings.get(siType); + } +} diff --git a/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/extender/ControlBusListeningDecorator.java b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/extender/ControlBusListeningDecorator.java new file mode 100644 index 0000000000..38de5a6e1a --- /dev/null +++ b/org.springframework.integration.osgi/src/main/java/org/springframework/integration/osgi/extender/ControlBusListeningDecorator.java @@ -0,0 +1,143 @@ +/* + * 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.core.Message; +import org.springframework.integration.message.MessageHandler; +import org.springframework.osgi.service.importer.OsgiServiceLifecycleListener; + +/** + * Wraps OSGi Service Reference representing a {@link ControlBus} to provide several simplification + * around life-cycle of the underlying reference. + * + * First, this wrapper implements {@link OsgiServiceLifecycleListener} which will listen for + * bind/unbind events of the service reference representing a particular instance of the {@link ControlBus} service. + * Calls to bind/unbind methods will set busAvailable attribute to 'true'/'false' respectively. + * sparing you from dealing with the internals of the service reference proxy, which might be at the state where + * it is not backed up by a concrete instance of the {@link ControlBus} service (e.g., when such service is unregistered). + * This class also implements {@link ControlBus} interface delegating all method calls to the actual instance of the ControlBus + * with one exception. Call to {@link ControlBus#isBusAvailable()} will return the value of the busAvailable + * attribute which is set by the calls to bind/unbind methods. + * This way you can interact with the ControlBus as if it was a real instance of the ControlBus service when it is + * available, but it also give you a quick and convenient way to know when bus goes away. + * + * @author Oleg Zhurakousky + * @since 2.0 + */ +@SuppressWarnings("unchecked") +public class ControlBusListeningDecorator implements OsgiServiceLifecycleListener, ControlBus { + + private static final Log log = LogFactory.getLog(ControlBusListeningDecorator.class); + private boolean busAvailable; + private ControlBus controlBus; + private String name; + /* + * (non-Javadoc) + * @see org.springframework.osgi.service.importer.OsgiServiceLifecycleListener#bind(java.lang.Object, java.util.Map) + */ + public void bind(Object service, Map properties) throws Exception { + controlBus = (ControlBus) service; + name = controlBus.getName(); + log.debug("Binding to the Control Bus: " + name); + busAvailable = true; + } + /* + * (non-Javadoc) + * @see org.springframework.osgi.service.importer.OsgiServiceLifecycleListener#unbind(java.lang.Object, java.util.Map) + */ + public void unbind(Object service, Map properties) throws Exception { + log.debug("un-Binding from the Control Bus: " + name); + busAvailable = false; + controlBus = null; + } + /* + */ + public void setControlBus(ControlBus controlBus) { + this.controlBus = controlBus; + } + /* + * (non-Javadoc) + * @see org.springframework.integration.controlbus.ControlBus#isBusAvailable() + */ + public boolean isBusAvailable() { + return busAvailable; + } + /* + */ + public void setBusAvailable(boolean busAvailable) { + this.busAvailable = busAvailable; + } + /* + * (non-Javadoc) + * @see org.springframework.integration.channel.SubscribableChannel#subscribe(org.springframework.integration.message.MessageHandler) + */ + public boolean subscribe(MessageHandler handler) { + if (isBusAvailable()){ + return controlBus.subscribe(handler); + } else { + log.debug("Can not subscribe to the Control Bus: " + name + ". Control Bus is not availabel"); + return false; + } + } + /* + * (non-Javadoc) + * @see org.springframework.integration.channel.SubscribableChannel#unsubscribe(org.springframework.integration.message.MessageHandler) + */ + public boolean unsubscribe(MessageHandler handler) { + if (isBusAvailable()){ + return controlBus.unsubscribe(handler); + } else { + log.debug("Can not unsubscribe from the Control Bus: " + name + ". Control Bus is not availabel"); + return false; + } + } + /* + * (non-Javadoc) + * @see org.springframework.integration.core.MessageChannel#getName() + */ + public String getName() { + return name; + } + /* + * (non-Javadoc) + * @see org.springframework.integration.core.MessageChannel#send(org.springframework.integration.core.Message) + */ + public boolean send(Message message) { + if (isBusAvailable()){ + return controlBus.send(message); + } else { + log.debug("Can not send message to the Control Bus: " + name + ". Control Bus is not availabel"); + return false; + } + } + /* + * (non-Javadoc) + * @see org.springframework.integration.core.MessageChannel#send(org.springframework.integration.core.Message, long) + */ + public boolean send(Message message, long timeout) { + if (isBusAvailable()){ + return controlBus.send(message, timeout); + } else { + log.debug("Can not send message to the Control Bus: " + name + ". Control Bus is not availabel"); + return false; + } + } +} 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 index 2913a1165b..9d695a07f5 100644 --- 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 @@ -21,6 +21,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.integration.controlbus.ControlBus; import org.springframework.integration.message.StringMessage; +import org.springframework.osgi.service.exporter.OsgiServiceRegistrationListener; /** * Service Registration listener which publishes registration life-cycle Messages @@ -29,32 +30,37 @@ import org.springframework.integration.message.StringMessage; * @author Oleg Zhurakousky * @since 2.0 */ -public class IntegrationServiceRegistrationListener { +public class IntegrationServiceRegistrationListener implements OsgiServiceRegistrationListener { private static final Log log = LogFactory.getLog(IntegrationServiceRegistrationListener.class); - private ControlBus controlBus; + private ControlBusListeningDecorator controlBusDecorator; + public IntegrationServiceRegistrationListener(ControlBusListeningDecorator controlBusDecorator){ + this.controlBusDecorator = controlBusDecorator; + } + /** + * Will send a notification message to the named {@link ControlBus} notifying that service + * for an SI component was registered and is ready to be used. + */ @SuppressWarnings("unchecked") - public void register(Object service, Map properties){ - if (controlBus != null){ - log.info("Dispatching REGISTRATION Message for: " + service + "- " + properties + " to: " + controlBus.getName()); + public void registered(Object service, Map properties){ + if (controlBusDecorator.isBusAvailable()){ + log.info("Dispatching REGISTRATION Message for: " + service + "- " + properties + " to: " + + controlBusDecorator.getName()); //TODO: change to structural message - controlBus.send(new StringMessage("Dispatching REGISTRATION Message for: " + service + "- " + properties)); + controlBusDecorator.send(new StringMessage("Dispatching REGISTRATION Message for: " + service + "- " + properties)); } } + /** + * Will send a notification message to the named {@link ControlBus} notifying that service + * for an SI component was un-registered and can no longet be used. + */ @SuppressWarnings("unchecked") - public void unRegister(Object service, Map properties){ - if (controlBus != null){ - log.info("Dispatching UN-REGISTRATION Message for: " + service + "- " + properties + " to: " + controlBus.getName()); + public void unregistered(Object service, Map properties){ + if (controlBusDecorator.isBusAvailable()){ + log.info("Dispatching UN-REGISTRATION Message for: " + service + "- " + properties + " to: " + + controlBusDecorator.getName()); //TODO: change to structural message - controlBus.send(new StringMessage("Dispatching UN-REGISTRATION Message for: " + service + "- " + properties)); + controlBusDecorator.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/resources/META-INF/spring.handlers b/org.springframework.integration.osgi/src/main/resources/META-INF/spring.handlers index ced91b7818..1ddd8fe6db 100644 --- a/org.springframework.integration.osgi/src/main/resources/META-INF/spring.handlers +++ b/org.springframework.integration.osgi/src/main/resources/META-INF/spring.handlers @@ -1 +1,2 @@ -http\://www.springframework.org/schema/integration/integration-control-bus=org.springframework.integration.osgi.config.xml.IntegrationOSGiControlBusNamespaceHandler \ No newline at end of file +http\://www.springframework.org/schema/integration/integration-control-bus=org.springframework.integration.osgi.config.xml.IntegrationOSGiControlBusNamespaceHandler +http\://www.springframework.org/schema/integration/integration-service-extender=org.springframework.integration.osgi.config.xml.IntegrationOSGiServiceExtenderNamespaceHandler \ No newline at end of file diff --git a/org.springframework.integration.osgi/src/main/resources/META-INF/spring.schemas b/org.springframework.integration.osgi/src/main/resources/META-INF/spring.schemas index 785dbf4d6f..0475b358bf 100644 --- a/org.springframework.integration.osgi/src/main/resources/META-INF/spring.schemas +++ b/org.springframework.integration.osgi/src/main/resources/META-INF/spring.schemas @@ -1 +1,3 @@ http\://www.springframework.org/schema/integration/integration-control-bus/spring-integration-bus-1.0.xsd=org/springframework/integration/osgi/config/xml/spring-integration-bus-1.0.xsd +http\://www.springframework.org/schema/integration/integration-service-extender/spring-integration-service-extender-1.0.xsd=org/springframework/integration/osgi/config/xml/spring-integration-service-extender-1.0.xsd + 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 7ac896fe77..ed207e7133 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,32 +30,4 @@ - - - - - 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/main/resources/org/springframework/integration/osgi/config/xml/spring-integration-service-extender-1.0.xsd b/org.springframework.integration.osgi/src/main/resources/org/springframework/integration/osgi/config/xml/spring-integration-service-extender-1.0.xsd new file mode 100644 index 0000000000..98945d934c --- /dev/null +++ b/org.springframework.integration.osgi/src/main/resources/org/springframework/integration/osgi/config/xml/spring-integration-service-extender-1.0.xsd @@ -0,0 +1,104 @@ + + + + + + + + + Configures SI Service Extender, which configures + existing beans as SI Services. + + + + + + + + + + + Identifies the name of the 'bean' to be + exported as an SI Service. Framework will find bean matching + this name and export it as an SI Service. + + + + + + + + + + + + + + + Identifies the name of the 'bean' to be + imported as an SI Service. + + + + + + + + + + + + + + + + + Identifies the supported type of Spring + Integration components to be + exported as SI Services. Framework + will find all components of matching type and export them as + SI + Services. + + + + + + + Will export all components of type + <publish-subscribe-channel> as SI Services + + + + + + + Will export all components of type + <channel> as SI Services + s + + + + + + + + Identifies the name of the 'control-bus' + which + will manage this component. This + means that framework will + dispatch + control events to the identified + 'control-bus'. + (OPTIONAL if no + control is necessary) + + + + + \ 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 30b893d98f..7f6c0ec650 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 @@ -24,8 +24,8 @@ import org.osgi.framework.ServiceReference; import org.springframework.context.ApplicationContext; import org.springframework.integration.controlbus.ControlBus; import org.springframework.integration.osgi.AbstractSIConfigBundleTestDeployer; +import org.springframework.integration.osgi.IntegrationOSGiConstants; import org.springframework.integration.osgi.stubs.SIBundleContextStub; -import org.springframework.intergration.osgi.IntegrationOSGiConstants; /** @@ -40,12 +40,11 @@ public class BusConfigParserTests extends AbstractSIConfigBundleTestDeployer { ApplicationContext ac = this.deploySIConfig(bundleContext, "org/springframework/integration/osgi/config/xml/", "BusConfigParserTests-default.xml"); - ControlBus controlBus = (ControlBus) ac.getBean(IntegrationOSGiConstants.DEFAULT_BUS_GROUP_NAME); + ControlBus controlBus = (ControlBus) ac.getBean(ControlBusOSGiUtils.DEFAULT_BUS_GROUP_NAME); assertNotNull(controlBus); - assertTrue(controlBus.getBusName().equals(IntegrationOSGiConstants.DEFAULT_BUS_GROUP_NAME)); ServiceReference[] sr = bundleContext.getServiceReferences(ControlBus.class.getName(), "(&(" + IntegrationOSGiConstants.OSGI_BEAN_NAME + "=" + - IntegrationOSGiConstants.DEFAULT_BUS_GROUP_NAME + "))"); + ControlBusOSGiUtils.DEFAULT_BUS_GROUP_NAME + "))"); assertNotNull(sr); assertTrue(sr.length == 1); controlBus = (ControlBus) bundleContext.getService(sr[0]); diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/BusUsageFailoverTests.java b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/BusUsageFailoverTests.java index 774bffe6a3..b2ca4a7a38 100644 --- a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/BusUsageFailoverTests.java +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/BusUsageFailoverTests.java @@ -29,7 +29,7 @@ import org.springframework.integration.osgi.AbstractSIConfigBundleTestDeployer; import org.springframework.integration.osgi.stubs.SIBundleContextStub; /** - * THis test bootstraps two instances of the Control Bus, then shuts down one demonstrating and testing + * This test bootstraps two instances of the Control Bus, then shuts down one demonstrating and testing * transparent fail-over to another instance of the Control Bus * * @author Oleg Zhurakousky @@ -38,8 +38,9 @@ import org.springframework.integration.osgi.stubs.SIBundleContextStub; public class BusUsageFailoverTests extends AbstractSIConfigBundleTestDeployer { static MessageHandler handler = Mockito.mock(MessageHandler.class); + @Test - public void testDefaultControlBusConfig() throws Exception { + public void testControlBusFailover() throws Exception { BundleContext bundleContext = SIBundleContextStub.getInstance(); ConfigurableApplicationContext primaryAc = this.deploySIConfig(bundleContext, diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests-default.xml b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests-default.xml new file mode 100644 index 0000000000..9309342d35 --- /dev/null +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests-default.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests-withbus-attribute.xml b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests-withbus-attribute.xml new file mode 100644 index 0000000000..7068a5e6c2 --- /dev/null +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests-withbus-attribute.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests.java b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests.java new file mode 100644 index 0000000000..f4875e7d05 --- /dev/null +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserExporterTests.java @@ -0,0 +1,80 @@ +/* + * 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 static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.mockito.Mockito; +import org.osgi.framework.BundleContext; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.integration.channel.SubscribableChannel; +import org.springframework.integration.controlbus.ControlBus; +import org.springframework.integration.core.Message; +import org.springframework.integration.message.MessageHandler; +import org.springframework.integration.message.StringMessage; +import org.springframework.integration.osgi.AbstractSIConfigBundleTestDeployer; +import org.springframework.integration.osgi.stubs.SIBundleContextStub; + +/** + * Tests 'config' element. + * + * @author Oleg Zhurakousky + * @since 2.0 + */ +public class ConfigParserExporterTests extends AbstractSIConfigBundleTestDeployer { + + @Test + public void testBasicSIServiceConfig() throws Exception { + BundleContext bundleContext = SIBundleContextStub.getNewInstance(); + ApplicationContext ac = this.deploySIConfig(bundleContext, + "org/springframework/integration/osgi/config/xml/", + "ConfigParserExporterTests-default.xml"); + assertNotNull(ac.getBean("channelA-Service")); + assertNotNull(ac.getBean("channelB-Service")); + assertNotNull(ac.getBean("channelC-Service")); + + SubscribableChannel channel = (SubscribableChannel) ac.getBean("channelA"); + SubscribableChannel channel_reference = ac.getBean("channelA-reference", SubscribableChannel.class); + // verify that standar OSGi configuration can still bind to this service + MessageHandler handler = Mockito.mock(MessageHandler.class); + channel_reference.subscribe(handler); + Message message = new StringMessage("hello"); + channel.send(message); + Mockito.verify(handler, Mockito.times(1)).handleMessage(message); + } + @Test + public void testControlBusAttributeWithBusPresent() throws Exception { + BundleContext bundleContext = SIBundleContextStub.getNewInstance(); + ConfigurableApplicationContext busAC = this.deploySIConfig(bundleContext, + "org/springframework/integration/osgi/config/xml/", + "BusConfigParserTests-default.xml"); + ConfigurableApplicationContext ac = this.deploySIConfig(bundleContext, + "org/springframework/integration/osgi/config/xml/", + "ConfigParserExporterTests-withbus-attribute.xml"); + assertNotNull(ac.getBean("channelA-Service")); + assertNotNull(ac.getBean("channelB-Service")); + assertNotNull(ac.getBean("channelC-Service")); + ControlBus bus = (ControlBus) ac.getBean("DEFAULT_CONTROL_GROUP"); + assertNotNull(bus); + MessageHandler handler = Mockito.mock(MessageHandler.class); + bus.subscribe(handler); + ac.close(); + // should be 3 notification messages sent to the bus + Mockito.verify(handler, Mockito.times(3)).handleMessage((Message) Mockito.any()); + } +} 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/config/xml/ConfigParserImporterTests-default.xml similarity index 50% rename from org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.xml rename to org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserImporterTests-default.xml index 4db586d632..5b03a81a19 100644 --- 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/config/xml/ConfigParserImporterTests-default.xml @@ -1,15 +1,16 @@ - - - - - + + + + diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserImporterTests.java b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserImporterTests.java new file mode 100644 index 0000000000..98e2b5b4bd --- /dev/null +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/ConfigParserImporterTests.java @@ -0,0 +1,44 @@ +/* + * 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 static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.osgi.framework.BundleContext; +import org.springframework.context.ApplicationContext; +import org.springframework.integration.osgi.AbstractSIConfigBundleTestDeployer; +import org.springframework.integration.osgi.stubs.SIBundleContextStub; + +/** + * Tests 'config' element. + * + * @author Oleg Zhurakousky + * @since 2.0 + */ +public class ConfigParserImporterTests extends AbstractSIConfigBundleTestDeployer { + + @Test + public void testBasicSIServiceConfig() throws Exception { + BundleContext bundleContext = SIBundleContextStub.getNewInstance(); + ApplicationContext ac = this.deploySIConfig(bundleContext, + "org/springframework/integration/osgi/config/xml/", + "ConfigParserImporterTests-default.xml"); + assertNotNull(ac.getBean("channelA")); + + + } +} diff --git a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/base-bus-config.xml b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/base-bus-config.xml index 4cc4ee4722..d0d2495078 100644 --- a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/base-bus-config.xml +++ b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/config/xml/base-bus-config.xml @@ -22,7 +22,7 @@ - + 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 deleted file mode 100644 index a095c295d1..0000000000 --- a/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/extender/BusParserProducersTests.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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/stubs/SIBundleContextStub.java b/org.springframework.integration.osgi/src/test/java/org/springframework/integration/osgi/stubs/SIBundleContextStub.java index 6d08fe7b8c..716d7fe82a 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 @@ -181,4 +181,9 @@ public class SIBundleContextStub extends MockBundleContext { public Map getServices() { return services; } + + public void remove(ServiceReference sr){ + services.remove(sr); + serviceReferences.remove(sr); + } } 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 63f1578a09..0a438fbec2 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.remove(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 6857a52247..d48f36a320 100644 --- a/org.springframework.integration.osgi/src/test/resources/log4j.xml +++ b/org.springframework.integration.osgi/src/test/resources/log4j.xml @@ -19,7 +19,7 @@ - + diff --git a/org.springframework.integration.osgi/template.mf b/org.springframework.integration.osgi/template.mf index 5cb104d33a..05a09d1e68 100644 --- a/org.springframework.integration.osgi/template.mf +++ b/org.springframework.integration.osgi/template.mf @@ -8,8 +8,8 @@ Import-Package: org.springframework.integration.handler;version="[2.0.0, 2.0.1)" org.springframework.integration.endpoint;version="[2.0.0, 2.0.1)" Import-Template: org.springframework.integration.*;version="[2.0.0, 2.0.1)", org.springframework.osgi.*;version="[1.2.0, 2.0.1)", - org.apache.commons.logging.*;version="1.1.1", - org.springframework.*;version="[3.0.0,4.0.0)", - org.w3c.dom.*;version="0" + org.springframework.*;version="[3.0.0, 3.1.0]", + org.apache.commons.logging.*;version="[1.1.1,1.1.1]", + org.w3c.dom;version="0" \ No newline at end of file