From b3c79358e150a6dab59e4700417e525293d07d0b Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 8 Oct 2010 14:42:11 -0400 Subject: [PATCH] INT-1505 added support for a 'payload-expression' attribute on the inbound ApplicationEvent Channel Adapter --- .../com.springsource.sts.config.flow.prefs | 4 +-- ...ApplicationEventInboundChannelAdapter.java | 36 +++++++++++++++---- .../EventInboundChannelAdapterParser.java | 5 +-- .../config/spring-integration-event-2.0.xsd | 10 +++++- ...cationEventInboundChannelAdapterTests.java | 24 +++++++++++-- ...boundChannelAdapterParserTests-context.xml | 8 ++++- ...EventInboundChannelAdapterParserTests.java | 19 +++++++--- 7 files changed, 87 insertions(+), 19 deletions(-) diff --git a/spring-integration-event/.settings/com.springsource.sts.config.flow.prefs b/spring-integration-event/.settings/com.springsource.sts.config.flow.prefs index 920caf3658..73c9299da9 100644 --- a/spring-integration-event/.settings/com.springsource.sts.config.flow.prefs +++ b/spring-integration-event/.settings/com.springsource.sts.config.flow.prefs @@ -1,3 +1,3 @@ -#Wed Sep 22 11:50:06 EDT 2010 -//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/integration\:/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventInboundChannelAdapterParserTests-context.xml=\n\n\n\n\n\n\n\n\n\n\n\n\n\n +#Fri Oct 08 14:30:53 EDT 2010 +//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/integration\:/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventInboundChannelAdapterParserTests-context.xml=\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n eclipse.preferences.version=1 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 709881de0d..41f0b99773 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 @@ -21,14 +21,17 @@ import java.util.concurrent.CopyOnWriteArraySet; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; +import org.springframework.expression.Expression; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.endpoint.MessageProducerSupport; import org.springframework.integration.support.MessageBuilder; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; /** - * An inbound Channel Adapter that passes Spring - * {@link ApplicationEvent ApplicationEvents} within messages. + * An inbound Channel Adapter that passes Spring {@link ApplicationEvent ApplicationEvents} within messages. + * If a {@link #setPayloadExpression(String) payloadExpression} is provided, it will be evaluated against + * the ApplicationEvent instance to create the Message payload. * * @author Mark Fisher */ @@ -36,6 +39,10 @@ public class ApplicationEventInboundChannelAdapter extends MessageProducerSuppor private final Set> eventTypes = new CopyOnWriteArraySet>(); + private volatile Expression payloadExpression; + + private final SpelExpressionParser parser = new SpelExpressionParser(); + /** * Set the list of event types (classes that extend ApplicationEvent) that @@ -51,6 +58,24 @@ public class ApplicationEventInboundChannelAdapter extends MessageProducerSuppor } } + /** + * Provide an expression to be evaluated against the received ApplicationEvent + * instance (the "root object") in order to create the Message payload. If none + * is provided, the ApplicationEvent itself will be used as the payload. + */ + public void setPayloadExpression(String payloadExpression) { + if (payloadExpression == null) { + this.payloadExpression = null; + } + else { + this.payloadExpression = this.parser.parseExpression(payloadExpression); + } + } + + public String getComponentType() { + return "event:inbound-channel-adapter"; + } + public void onApplicationEvent(ApplicationEvent event) { if (CollectionUtils.isEmpty(this.eventTypes)) { this.sendEventAsMessage(event); @@ -65,11 +90,8 @@ public class ApplicationEventInboundChannelAdapter extends MessageProducerSuppor } private void sendEventAsMessage(ApplicationEvent event) { - this.sendMessage(MessageBuilder.withPayload(event).build()); - } - - public String getComponentType(){ - return "event:inbound-channel-adapter"; + Object payload = (this.payloadExpression != null) ? this.payloadExpression.getValue(event) : event; + this.sendMessage(MessageBuilder.withPayload(payload).build()); } @Override 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 3b605e5024..37d924f60c 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 @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.event.config; import org.springframework.beans.factory.support.AbstractBeanDefinition; @@ -30,11 +31,11 @@ import org.w3c.dom.Element; public class EventInboundChannelAdapterParser extends AbstractChannelAdapterParser{ @Override - protected AbstractBeanDefinition doParse(Element element, - ParserContext parserContext, String channelName) { + protected AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName) { BeanDefinitionBuilder adapterBuilder = BeanDefinitionBuilder.rootBeanDefinition(ApplicationEventInboundChannelAdapter.class); IntegrationNamespaceUtils.setReferenceIfAttributeDefined(adapterBuilder, element, "channel", "outputChannel"); IntegrationNamespaceUtils.setValueIfAttributeDefined(adapterBuilder, element, "event-types"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(adapterBuilder, element, "payload-expression"); 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 407511a771..c57993c7fe 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 @@ -47,7 +47,15 @@ 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 b3b27c4fb8..e044983b9e 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2010 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. @@ -53,8 +53,8 @@ public class ApplicationEventInboundChannelAdapterTests { assertEquals("event2", ((ApplicationEvent) message3.getPayload()).getSource()); } - @SuppressWarnings("unchecked") @Test + @SuppressWarnings("unchecked") public void onlyConfiguredEventTypesAreSent() { QueueChannel channel = new QueueChannel(); ApplicationEventInboundChannelAdapter adapter = new ApplicationEventInboundChannelAdapter(); @@ -93,6 +93,24 @@ public class ApplicationEventInboundChannelAdapterTests { assertEquals(ContextClosedEvent.class, closedEventMessage.getPayload().getClass()); } + @Test + public void payloadExpressionEvaluatedAgainstApplicationEvent() { + QueueChannel channel = new QueueChannel(); + ApplicationEventInboundChannelAdapter adapter = new ApplicationEventInboundChannelAdapter(); + adapter.setPayloadExpression("'received: ' + source"); + adapter.setOutputChannel(channel); + Message message1 = channel.receive(0); + assertNull(message1); + adapter.onApplicationEvent(new TestApplicationEvent1()); + adapter.onApplicationEvent(new TestApplicationEvent2()); + Message message2 = channel.receive(20); + assertNotNull(message2); + assertEquals("received: event1", message2.getPayload()); + Message message3 = channel.receive(20); + assertNotNull(message3); + assertEquals("received: event2", message3.getPayload()); + } + @SuppressWarnings("serial") private static class TestApplicationEvent1 extends ApplicationEvent { @@ -100,6 +118,8 @@ public class ApplicationEventInboundChannelAdapterTests { public TestApplicationEvent1() { super("event1"); } + + } 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 bf71e51806..835a4cd39a 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 @@ -30,7 +30,13 @@ - + + + + + + + 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 3e7240d423..d1e5d9eebc 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 @@ -33,6 +33,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.expression.Expression; import org.springframework.integration.Message; import org.springframework.integration.core.PollableChannel; import org.springframework.integration.event.ApplicationEventInboundChannelAdapter; @@ -62,9 +63,9 @@ public class EventInboundChannelAdapterParserTests { DirectFieldAccessor adapterAccessor = new DirectFieldAccessor(adapter); Assert.assertEquals(context.getBean("input"), adapterAccessor.getPropertyValue("outputChannel")); } - - @SuppressWarnings("unchecked") + @Test + @SuppressWarnings("unchecked") public void validateEventParserWithEventTypes() { Object adapter = context.getBean("eventAdapterFiltered"); Assert.assertNotNull(adapter); @@ -77,9 +78,9 @@ public class EventInboundChannelAdapterParserTests { assertTrue(eventTypes.contains(SampleEvent.class)); assertTrue(eventTypes.contains(AnotherSampleEvent.class)); } - - @SuppressWarnings("unchecked") + @Test + @SuppressWarnings("unchecked") public void validateEventParserWithEventTypesAndPlaceholder() { Object adapter = context.getBean("eventAdapterFilteredPlaceHolder"); Assert.assertNotNull(adapter); @@ -108,6 +109,16 @@ public class EventInboundChannelAdapterParserTests { assertEquals(SampleEvent.class, message.getPayload().getClass()); } + @Test + public void validatePayloadExpression() { + Object adapter = context.getBean("eventAdapterSpel"); + Assert.assertNotNull(adapter); + Assert.assertTrue(adapter instanceof ApplicationEventInboundChannelAdapter); + DirectFieldAccessor adapterAccessor = new DirectFieldAccessor(adapter); + Expression expression = (Expression) adapterAccessor.getPropertyValue("payloadExpression"); + Assert.assertEquals("source + '-test'", expression.getExpressionString()); + } + @SuppressWarnings("serial") public static class SampleEvent extends ApplicationEvent {