diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/ServiceActivatorFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/ServiceActivatorFactoryBean.java new file mode 100644 index 0000000000..a053dbb745 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/ServiceActivatorFactoryBean.java @@ -0,0 +1,58 @@ +/* + * 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. + * 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.config; + +import org.springframework.integration.handler.ServiceActivatingHandler; +import org.springframework.integration.message.MessageHandler; +import org.springframework.util.StringUtils; + +/** + * FactoryBean for creating {@link ServiceActivatingHandler} instances. + * + * @author Mark Fisher + * @since 2.0 + */ +public class ServiceActivatorFactoryBean extends AbstractMessageHandlerFactoryBean { + + private volatile Long sendTimeout; + + public void setSendTimeout(Long sendTimeout) { + this.sendTimeout = sendTimeout; + } + + @Override + MessageHandler createMethodInvokingHandler(Object targetObject, String targetMethodName) { + ServiceActivatingHandler handler = (StringUtils.hasText(targetMethodName)) + ? new ServiceActivatingHandler(targetObject, targetMethodName) + : new ServiceActivatingHandler(targetObject); + return this.configureHandler(handler); + } + + @Override + MessageHandler createExpressionEvaluatingHandler(String expression) { + Class expectedType = null; + return this.configureHandler(new ServiceActivatingHandler(expression, expectedType)); + } + + private ServiceActivatingHandler configureHandler(ServiceActivatingHandler handler) { + if (this.sendTimeout != null) { + handler.setSendTimeout(sendTimeout); + } + return handler; + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ServiceActivatorParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ServiceActivatorParser.java index e2a04eb519..aa71ea9355 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ServiceActivatorParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ServiceActivatorParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 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. @@ -16,43 +16,22 @@ package org.springframework.integration.config.xml; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - /** * Parser for the <service-activator> element. * * @author Mark Fisher * @author Oleg Zhurakousky */ -public class ServiceActivatorParser extends AbstractConsumerEndpointParser { +public class ServiceActivatorParser extends AbstractDelegatingConsumerEndpointParser { @Override - protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) { - BeanComponentDefinition innerHandlerDefinition = IntegrationNamespaceUtils.parseInnerHandlerDefinition(element, parserContext); - - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( - IntegrationNamespaceUtils.BASE_PACKAGE + ".handler.ServiceActivatingHandler"); - if (innerHandlerDefinition != null){ - builder.addConstructorArgValue(innerHandlerDefinition); - } else { - String ref = element.getAttribute(REF_ATTRIBUTE); - if (!StringUtils.hasText(ref)) { - parserContext.getReaderContext().error("The '" + REF_ATTRIBUTE + "' attribute is required for element " - + IntegrationNamespaceUtils.createElementDescription(element) + ".", element); - } - builder.addConstructorArgReference(ref); - } - - if (StringUtils.hasText(element.getAttribute(METHOD_ATTRIBUTE))) { - String method = element.getAttribute(METHOD_ATTRIBUTE); - builder.getRawBeanDefinition().getConstructorArgumentValues().addGenericArgumentValue(method, "java.lang.String"); - } - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-timeout"); - return builder; + String getFactoryBeanClassName() { + return "org.springframework.integration.config.ServiceActivatorFactoryBean"; + } + + @Override + boolean hasDefaultOption() { + return false; } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java index 2f8f73f035..8331deff9f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java @@ -18,6 +18,7 @@ package org.springframework.integration.handler; import java.lang.reflect.Method; +import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.integration.annotation.ServiceActivator; import org.springframework.integration.core.Message; import org.springframework.integration.message.MessageHandlingException; @@ -27,7 +28,7 @@ import org.springframework.integration.message.MessageHandlingException; */ public class ServiceActivatingHandler extends AbstractReplyProducingMessageHandler { - private final MethodInvokingMessageProcessor processor; + private final AbstractMessageProcessor processor; public ServiceActivatingHandler(final Object object) { @@ -42,6 +43,12 @@ public class ServiceActivatingHandler extends AbstractReplyProducingMessageHandl this.processor = new MethodInvokingMessageProcessor(object, methodName); } + public ServiceActivatingHandler(String expression, Class expectedType) { + ExpressionEvaluatingMessageProcessor eemp = new ExpressionEvaluatingMessageProcessor(expression); + eemp.setExpectedType(expectedType); + this.processor = eemp; + } + @Override public String getComponentType() { @@ -51,6 +58,9 @@ public class ServiceActivatingHandler extends AbstractReplyProducingMessageHandl @Override public final void onInit() { this.processor.setConversionService(this.getConversionService()); + if (this.processor instanceof BeanFactoryAware) { + ((BeanFactoryAware) this.processor).setBeanFactory(this.getBeanFactory()); + } } @Override diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd index 732fa98bec..9f279fb7c7 100644 --- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd +++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd @@ -730,7 +730,7 @@ default="true" /> - + Defines an endpoint for exposing any bean reference as a service that @@ -2125,7 +2125,13 @@ - + + + + A SpEL expression to be evaluated against the input Message as its root object. + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-context.xml new file mode 100644 index 0000000000..99b38387b9 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-context.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests.java new file mode 100644 index 0000000000..c450a23681 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests.java @@ -0,0 +1,100 @@ +/* + * 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. + * 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.config.xml; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.integration.core.MessageChannel; +import org.springframework.integration.gateway.SimpleMessagingGateway; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Mark Fisher + * @since 2.0 + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class ServiceActivatorParserTests { + + @Autowired + private MessageChannel literalExpressionInput; + + @Autowired + private MessageChannel beanAsTargetInput; + + @Autowired + private MessageChannel beanAsArgumentInput; + + @Autowired + private MessageChannel beanInvocationResultInput; + + + @Test + public void literalExpression() { + Object result = this.sendAndReceive(literalExpressionInput, "hello"); + assertEquals("foo", result); + } + + @Test + public void beanAsTarget() { + Object result = this.sendAndReceive(beanAsTargetInput, "hello"); + assertEquals("HELLO", result); + } + + @Test + public void beanAsArgument() { + Object result = this.sendAndReceive(beanAsArgumentInput, new TestPayload()); + assertEquals("TestBean", result); + } + + @Test + public void beanInvocationResult() { + Object result = this.sendAndReceive(beanInvocationResultInput, "hello"); + assertEquals("helloFOO", result); + } + + + private Object sendAndReceive(MessageChannel channel, Object payload) { + SimpleMessagingGateway gateway = new SimpleMessagingGateway(); + gateway.setRequestChannel(channel); + return gateway.sendAndReceive(payload); + } + + + @SuppressWarnings("unused") + private static class TestBean { + + public String caps(String s) { + return s.toUpperCase(); + } + } + + + @SuppressWarnings("unused") + private static class TestPayload { + + public String getSimpleClassName(Object o) { + return o.getClass().getSimpleName(); + } + } + +}