diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ControlBusParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ControlBusParser.java index 0ee1956159..22f7894ad7 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ControlBusParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ControlBusParser.java @@ -14,10 +14,12 @@ package org.springframework.integration.config.xml; import org.springframework.beans.BeanMetadataElement; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.integration.control.ExpressionPayloadMessageProcessor; +import org.springframework.integration.control.ControlBusMessageProcessor; +import org.springframework.util.StringUtils; import org.w3c.dom.Element; /** @@ -30,14 +32,22 @@ public class ControlBusParser extends AbstractConsumerEndpointParser { protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder .genericBeanDefinition(ExpressionControlBusFactoryBean.class); - builder.addConstructorArgValue(getMessageProcessorBeanDefinition(element, parserContext)); + builder.addConstructorArgValue(new RootBeanDefinition(ControlBusMessageProcessor.class)); + BeanMetadataElement beanResolver = getBeanResolver(element, parserContext); + if (beanResolver!=null) { + builder.addPropertyValue("beanResolver", beanResolver); + } IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-timeout"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "order"); return builder; } - protected BeanMetadataElement getMessageProcessorBeanDefinition(Element element, ParserContext parserContext) { - return new RootBeanDefinition(ExpressionPayloadMessageProcessor.class); + protected BeanMetadataElement getBeanResolver(Element element, ParserContext parserContext) { + String ref = element.getAttribute("bean-resolver"); + if (!StringUtils.hasText(ref)) { + return null; + } + return new RuntimeBeanReference(ref); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ExpressionControlBusFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ExpressionControlBusFactoryBean.java index 6b7608da9c..d1e645632c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ExpressionControlBusFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ExpressionControlBusFactoryBean.java @@ -13,13 +13,14 @@ package org.springframework.integration.config.xml; +import org.springframework.expression.BeanResolver; import org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean; -import org.springframework.integration.control.ExpressionPayloadMessageProcessor; +import org.springframework.integration.control.ControlBusMessageProcessor; import org.springframework.integration.core.MessageHandler; import org.springframework.integration.handler.ServiceActivatingHandler; /** - * FactoryBean for creating {@link MessageHandler} instances to handle a message as a Groovy Script. + * FactoryBean for creating {@link MessageHandler} instances to handle a message as a SpEL expression. * * @author Dave Syer * @@ -28,17 +29,26 @@ import org.springframework.integration.handler.ServiceActivatingHandler; public class ExpressionControlBusFactoryBean extends AbstractSimpleMessageHandlerFactoryBean { private volatile Long sendTimeout; - private final ExpressionPayloadMessageProcessor processor; + private volatile BeanResolver beanResolver; + + private final ControlBusMessageProcessor processor; - public ExpressionControlBusFactoryBean(ExpressionPayloadMessageProcessor processor) { + public ExpressionControlBusFactoryBean(ControlBusMessageProcessor processor) { this.processor = processor; } + + public void setBeanResolver(BeanResolver beanResolver) { + this.beanResolver = beanResolver; + } public void setSendTimeout(Long sendTimeout) { this.sendTimeout = sendTimeout; } protected MessageHandler createHandler() { + if (beanResolver!=null) { + processor.setBeanResolver(beanResolver); + } ServiceActivatingHandler handler = new ServiceActivatingHandler(processor); if (this.sendTimeout != null) { handler.setSendTimeout(this.sendTimeout); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/control/ExpressionPayloadMessageProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/control/ControlBusMessageProcessor.java similarity index 92% rename from spring-integration-core/src/main/java/org/springframework/integration/control/ExpressionPayloadMessageProcessor.java rename to spring-integration-core/src/main/java/org/springframework/integration/control/ControlBusMessageProcessor.java index 18c55ac2e5..18babbf19a 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/control/ExpressionPayloadMessageProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/control/ControlBusMessageProcessor.java @@ -25,7 +25,7 @@ import org.springframework.integration.handler.AbstractMessageProcessor; * @author Mark Fisher * @since 2.0 */ -public class ExpressionPayloadMessageProcessor extends AbstractMessageProcessor { +public class ControlBusMessageProcessor extends AbstractMessageProcessor { /** * Evaluates the Message payload expression. diff --git a/spring-integration-core/src/main/java/org/springframework/integration/util/AbstractExpressionEvaluator.java b/spring-integration-core/src/main/java/org/springframework/integration/util/AbstractExpressionEvaluator.java index 1970992af5..c4b3498e99 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/util/AbstractExpressionEvaluator.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/util/AbstractExpressionEvaluator.java @@ -18,6 +18,7 @@ import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.context.expression.MapAccessor; import org.springframework.core.convert.ConversionService; +import org.springframework.expression.BeanResolver; import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; @@ -40,6 +41,8 @@ public abstract class AbstractExpressionEvaluator implements BeanFactoryAware { private final BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(); + private volatile BeanResolver beanResolver; + public AbstractExpressionEvaluator() { this.evaluationContext.setTypeConverter(this.typeConverter); this.evaluationContext.addPropertyAccessor(new MapAccessor()); @@ -51,9 +54,16 @@ public abstract class AbstractExpressionEvaluator implements BeanFactoryAware { public void setBeanFactory(final BeanFactory beanFactory) { if (beanFactory != null) { this.typeConverter.setBeanFactory(beanFactory); - this.evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory)); + if (beanResolver == null) { + this.evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory)); + } } } + + public void setBeanResolver(BeanResolver beanResolver) { + this.beanResolver = beanResolver; + this.evaluationContext.setBeanResolver(beanResolver); + } public void setConversionService(ConversionService conversionService) { if (conversionService != null) { @@ -68,11 +78,13 @@ public abstract class AbstractExpressionEvaluator implements BeanFactoryAware { protected T evaluateExpression(Expression expression, Message message, Class expectedType) { try { return evaluateExpression(expression, (Object) message, expectedType); - } catch (EvaluationException e) { + } + catch (EvaluationException e) { Throwable cause = e.getCause(); throw new MessageHandlingException(message, "Expression evaluation failed: " + expression.getExpressionString(), cause == null ? e : cause); - } catch (Exception e) { + } + catch (Exception e) { throw new MessageHandlingException(message, "Expression evaluation failed: " + expression.getExpressionString(), e); } 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 8c035784a2..612d9359b4 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 @@ -2631,6 +2631,15 @@ The list of component name patterns you want to track (e.g., tracked-components + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusBeanResolverTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusBeanResolverTests-context.xml new file mode 100644 index 0000000000..38dd5ca477 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusBeanResolverTests-context.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusBeanResolverTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusBeanResolverTests.java new file mode 100644 index 0000000000..e3e1573d18 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusBeanResolverTests.java @@ -0,0 +1,68 @@ +/* + * 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 static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.expression.AccessException; +import org.springframework.expression.BeanResolver; +import org.springframework.expression.EvaluationContext; +import org.springframework.integration.Message; +import org.springframework.integration.MessageChannel; +import org.springframework.integration.core.PollableChannel; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Dave Syer + * @since 2.0 + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class ControlBusBeanResolverTests { + + @Autowired + private MessageChannel input; + + @Autowired + private PollableChannel output; + + @Test + public void testDefaultEvaluationContext() { + Message message = MessageBuilder.withPayload("@service.convert('aardvark')+headers.foo").setHeader("foo", "bar").build(); + this.input.send(message); + assertEquals("catbar", output.receive(0).getPayload()); + assertNull(output.receive(0)); + } + + public static class TestBeanResolver implements BeanResolver { + public Object resolve(EvaluationContext context, String beanName) throws AccessException { + return new Service(); + } + } + + public static class Service { + public String convert(String input) { + return "cat"; + } + } +}