From 78dbf2bef55c20ee9fd2f5d48cfad8ac82287fe7 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Mon, 23 Aug 2010 17:09:32 +0000 Subject: [PATCH] INT-1338, Added namespace support for 'event-types' attribute --- .../config/xml/IntegrationNamespaceUtils.java | 18 ++++++++++++ ...ApplicationEventInboundChannelAdapter.java | 8 ++--- .../EventInboundChannelAdapterParser.java | 26 ++++++++++++++++- .../config/spring-integration-event-2.0.xsd | 9 ++++++ ...cationEventInboundChannelAdapterTests.java | 15 ++++++---- ...boundChannelAdapterParserTests-context.xml | 9 +++++- ...EventInboundChannelAdapterParserTests.java | 29 +++++++++++++++++-- 7 files changed, 99 insertions(+), 15 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java index 2a7c0c3d13..8ab8a40d74 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.Conventions; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; @@ -262,4 +263,21 @@ public abstract class IntegrationNamespaceUtils { return innerComponentDefinition; } + public static Class convertFqClassNameToClassObject(String fullyQualifiedClassname, ParserContext parserContext){ + Assert.isTrue(StringUtils.hasText(fullyQualifiedClassname), "'fullyQualifiedClassname' must be provided"); + Assert.notNull(parserContext, "'parserContext' must be provided"); + ClassLoader classLoader = parserContext.getReaderContext().getBeanClassLoader(); + if (classLoader == null) { + classLoader = ClassUtils.getDefaultClassLoader(); + } + if (classLoader != null){ + try { + return classLoader.loadClass(fullyQualifiedClassname); + } catch (Exception e) { + // no handling required, method may return null + } + + } + return null; + } } diff --git a/spring-integration-event/src/main/java/org/springframework/integration/event/ApplicationEventInboundChannelAdapter.java b/spring-integration-event/src/main/java/org/springframework/integration/event/ApplicationEventInboundChannelAdapter.java index efc0fef211..bc5d57b60f 100644 --- a/spring-integration-event/src/main/java/org/springframework/integration/event/ApplicationEventInboundChannelAdapter.java +++ b/spring-integration-event/src/main/java/org/springframework/integration/event/ApplicationEventInboundChannelAdapter.java @@ -16,8 +16,8 @@ package org.springframework.integration.event; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; @@ -34,7 +34,7 @@ import org.springframework.util.CollectionUtils; */ public class ApplicationEventInboundChannelAdapter extends MessageProducerSupport implements ApplicationListener { - private final List> eventTypes = new CopyOnWriteArrayList>(); + private final Set> eventTypes = new CopyOnWriteArraySet>(); /** @@ -42,7 +42,7 @@ public class ApplicationEventInboundChannelAdapter extends MessageProducerSuppor * this adapter should send to the message channel. By default, all event * types will be sent. */ - public void setEventTypes(List> eventTypes) { + public void setEventTypes(Set> eventTypes) { Assert.notEmpty(eventTypes, "at least one event type is required"); synchronized (this.eventTypes) { this.eventTypes.clear(); diff --git a/spring-integration-event/src/main/java/org/springframework/integration/event/config/EventInboundChannelAdapterParser.java b/spring-integration-event/src/main/java/org/springframework/integration/event/config/EventInboundChannelAdapterParser.java index c8cad719ef..11f5be9d87 100644 --- a/spring-integration-event/src/main/java/org/springframework/integration/event/config/EventInboundChannelAdapterParser.java +++ b/spring-integration-event/src/main/java/org/springframework/integration/event/config/EventInboundChannelAdapterParser.java @@ -15,25 +15,49 @@ */ package org.springframework.integration.event.config; +import java.util.HashSet; +import java.util.Set; +import java.util.StringTokenizer; + import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.context.ApplicationEvent; import org.springframework.integration.config.xml.AbstractChannelAdapterParser; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; import org.springframework.integration.event.ApplicationEventInboundChannelAdapter; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; import org.w3c.dom.Element; /** * @author Oleg Zhurakousky - * + * @since 2.0 */ public class EventInboundChannelAdapterParser extends AbstractChannelAdapterParser{ + @SuppressWarnings("unchecked") @Override protected AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName) { BeanDefinitionBuilder adapterBuilder = BeanDefinitionBuilder.rootBeanDefinition(ApplicationEventInboundChannelAdapter.class); IntegrationNamespaceUtils.setReferenceIfAttributeDefined(adapterBuilder, element, "channel", "outputChannel"); + String stringEventTypes = element.getAttribute("event-types"); + if (StringUtils.hasText(stringEventTypes)){ + //Set eventTypes = StringUtils.commaDelimitedListToSet(stringEventTypes); + StringTokenizer tokenizer = new StringTokenizer(stringEventTypes, " ,"); + Set> applicationEvents = new HashSet>(); + while (tokenizer.hasMoreTokens()) { + String fullyQualifiedClassname = tokenizer.nextToken(); + Class clazz = + (Class) IntegrationNamespaceUtils.convertFqClassNameToClassObject(fullyQualifiedClassname, parserContext); + Assert.notNull(clazz, "Class for the event type '" + fullyQualifiedClassname + "' can not be located"); + applicationEvents.add(clazz); + } + adapterBuilder.addPropertyValue("eventTypes", applicationEvents); + } + //IntegrationNamespaceUtils.setReferenceIfAttributeDefined(adapterBuilder, element, "event", "eventTypes"); return adapterBuilder.getBeanDefinition(); } diff --git a/spring-integration-event/src/main/resources/org/springframework/integration/event/config/spring-integration-event-2.0.xsd b/spring-integration-event/src/main/resources/org/springframework/integration/event/config/spring-integration-event-2.0.xsd index 95204a8f5f..407511a771 100644 --- a/spring-integration-event/src/main/resources/org/springframework/integration/event/config/spring-integration-event-2.0.xsd +++ b/spring-integration-event/src/main/resources/org/springframework/integration/event/config/spring-integration-event-2.0.xsd @@ -38,6 +38,15 @@ Identifies inbound 'channel' which accepts Messages generated from Application Context events. + + + + + Comma delimited list of event types (classes that extend ApplicationEvent) that + this adapter should send to the message channel. By default, all event + types will be sent [OPTIONAL] + + diff --git a/spring-integration-event/src/test/java/org/springframework/integration/event/ApplicationEventInboundChannelAdapterTests.java b/spring-integration-event/src/test/java/org/springframework/integration/event/ApplicationEventInboundChannelAdapterTests.java index 818331ec83..139c8f9641 100644 --- a/spring-integration-event/src/test/java/org/springframework/integration/event/ApplicationEventInboundChannelAdapterTests.java +++ b/spring-integration-event/src/test/java/org/springframework/integration/event/ApplicationEventInboundChannelAdapterTests.java @@ -16,14 +16,11 @@ package org.springframework.integration.event; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import org.junit.Test; - import org.springframework.context.ApplicationEvent; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextRefreshedEvent; @@ -34,6 +31,10 @@ import org.springframework.integration.Message; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.core.PollableChannel; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + /** * @author Mark Fisher */ @@ -61,7 +62,9 @@ public class ApplicationEventInboundChannelAdapterTests { QueueChannel channel = new QueueChannel(); ApplicationEventInboundChannelAdapter adapter = new ApplicationEventInboundChannelAdapter(); adapter.setOutputChannel(channel); - adapter.setEventTypes(Collections.>singletonList(TestApplicationEvent1.class)); + Set> events = new HashSet>(); + events.add(TestApplicationEvent1.class); + adapter.setEventTypes(events); Message message1 = channel.receive(0); assertNull(message1); adapter.onApplicationEvent(new TestApplicationEvent1()); diff --git a/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventInboundChannelAdapterParserTests-context.xml b/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventInboundChannelAdapterParserTests-context.xml index e5edd8abcd..2cce1fb3ea 100644 --- a/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventInboundChannelAdapterParserTests-context.xml +++ b/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventInboundChannelAdapterParserTests-context.xml @@ -7,10 +7,17 @@ http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd http://www.springframework.org/schema/integration/event http://www.springframework.org/schema/integration/event/spring-integration-event-2.0.xsd"> - + + + + + + + diff --git a/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventInboundChannelAdapterParserTests.java b/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventInboundChannelAdapterParserTests.java index 4e310b95fa..81f22664bf 100644 --- a/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventInboundChannelAdapterParserTests.java +++ b/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventInboundChannelAdapterParserTests.java @@ -18,6 +18,10 @@ package org.springframework.integration.event.config; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Set; + import junit.framework.Assert; import org.junit.Test; @@ -49,12 +53,27 @@ public class EventInboundChannelAdapterParserTests { @Test public void validateEventParser() { - Object adapter = context.getBean("eventAdapter"); + Object adapter = context.getBean("eventAdapterSimple"); Assert.assertNotNull(adapter); Assert.assertTrue(adapter instanceof ApplicationEventInboundChannelAdapter); DirectFieldAccessor adapterAccessor = new DirectFieldAccessor(adapter); Assert.assertEquals(context.getBean("input"), adapterAccessor.getPropertyValue("outputChannel")); } + + @SuppressWarnings("unchecked") + @Test + public void validateEventParserWithEventTypes() { + Object adapter = context.getBean("eventAdapterFiltered"); + Assert.assertNotNull(adapter); + Assert.assertTrue(adapter instanceof ApplicationEventInboundChannelAdapter); + DirectFieldAccessor adapterAccessor = new DirectFieldAccessor(adapter); + Assert.assertEquals(context.getBean("inputFiltered"), adapterAccessor.getPropertyValue("outputChannel")); + Set> eventTypes = (Set>) adapterAccessor.getPropertyValue("eventTypes"); + assertNotNull(eventTypes); + assertTrue(eventTypes.size() == 2); + assertTrue(eventTypes.contains(SampleEvent.class)); + assertTrue(eventTypes.contains(AnotherSampleEvent.class)); + } @Test public void validateUsage() { @@ -69,11 +88,15 @@ public class EventInboundChannelAdapterParserTests { @SuppressWarnings("serial") public static class SampleEvent extends ApplicationEvent { - public SampleEvent(Object source) { super(source); } - } + @SuppressWarnings("serial") + public static class AnotherSampleEvent extends ApplicationEvent { + public AnotherSampleEvent(Object source) { + super(source); + } + } }