INT-1639 Externalize SpEL Evaluation Context
Allow modification of context property accessors and functions. Polishing - Fix tests to ensure the EvaluationContextFactoryBean is available when necessary. Polishing - Use Utility for ALL EvaluationContexts Add Test Showing Custom Function See SpelTransformerIntegrationTests-context.xml Polishing Polishing -fix Remote Sync Polishing - Emit WARN if No BeanFactory Polishing - Do Not Override ConversionService Kludge to Prevent Warning When No BeanFactory Expressions for method invoking in the MessagingMethodInvokerHelper don't need a BeanFactory - suppress the warning. Polishing - PR Comments - Invert Boolean
This commit is contained in:
committed by
Mark Fisher
parent
351af6b16b
commit
7f008b58c2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -24,7 +24,9 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
@@ -37,6 +39,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.support.channel.ChannelResolver;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -47,11 +50,11 @@ import org.springframework.util.StringUtils;
|
||||
* payload of the published Message can be derived from arguments or any return
|
||||
* value or exception resulting from the method invocation. That mapping is the
|
||||
* responsibility of the EL expression provided by the {@link PublisherMetadataSource}.
|
||||
*
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MessagePublishingInterceptor implements MethodInterceptor {
|
||||
public class MessagePublishingInterceptor implements MethodInterceptor, BeanFactoryAware {
|
||||
|
||||
private final MessagingTemplate messagingTemplate = new MessagingTemplate();
|
||||
|
||||
@@ -61,6 +64,8 @@ public class MessagePublishingInterceptor implements MethodInterceptor {
|
||||
|
||||
private volatile ChannelResolver channelResolver;
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
|
||||
@@ -83,10 +88,14 @@ public class MessagePublishingInterceptor implements MethodInterceptor {
|
||||
this.channelResolver = channelResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
public final Object invoke(final MethodInvocation invocation) throws Throwable {
|
||||
Assert.notNull(this.metadataSource, "PublisherMetadataSource is required.");
|
||||
final StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
context.addPropertyAccessor(new MapAccessor());
|
||||
final StandardEvaluationContext context = ExpressionUtils.createStandardEvaluationContext(this.beanFactory);
|
||||
Class<?> targetClass = AopUtils.getTargetClass(invocation.getThis());
|
||||
final Method method = AopUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
|
||||
String[] argumentNames = this.resolveArgumentNames(method);
|
||||
|
||||
@@ -74,6 +74,7 @@ public class PublisherAnnotationAdvisor extends AbstractPointcutAdvisor implemen
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.interceptor.setChannelResolver(new BeanFactoryChannelResolver(beanFactory));
|
||||
this.interceptor.setBeanFactory(beanFactory);
|
||||
}
|
||||
|
||||
public Advice getAdvice() {
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2013 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 java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
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.PropertyAccessor;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardTypeConverter;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
* @since 3.0
|
||||
*/
|
||||
public class IntegrationEvaluationContextFactoryBean implements FactoryBean<StandardEvaluationContext>,
|
||||
ApplicationContextAware, BeanFactoryAware, InitializingBean {
|
||||
|
||||
private volatile List<PropertyAccessor> propertyAccessors = new ArrayList<PropertyAccessor>();
|
||||
|
||||
private TypeConverter typeConverter = new StandardTypeConverter();
|
||||
|
||||
private volatile Map<String, Method> functions = new LinkedHashMap<String, Method>();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private BeanResolver beanResolver;
|
||||
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.beanResolver = new BeanFactoryResolver(this.applicationContext != null ? this.applicationContext : this.beanFactory);
|
||||
this.loadDefaultPropertyAccessors(this.propertyAccessors);
|
||||
if (this.applicationContext != null) {
|
||||
ConversionService conversionService = IntegrationContextUtils.getConversionService(this.applicationContext);
|
||||
if (conversionService != null) {
|
||||
this.typeConverter = new StandardTypeConverter(conversionService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setPropertyAccessors(PropertyAccessor... accessors) {
|
||||
Assert.noNullElements(accessors, "Cannot have null elements in accessors");
|
||||
List<PropertyAccessor> propertyAccessors = new ArrayList<PropertyAccessor>();
|
||||
loadDefaultPropertyAccessors(propertyAccessors);
|
||||
for (PropertyAccessor accessor : accessors) {
|
||||
propertyAccessors.add(accessor);
|
||||
}
|
||||
this.propertyAccessors = propertyAccessors;
|
||||
}
|
||||
|
||||
private void loadDefaultPropertyAccessors(List<PropertyAccessor> propertyAccessors) {
|
||||
propertyAccessors.add(new MapAccessor());
|
||||
}
|
||||
|
||||
public void setFunctions(Map<String, Method> functionsArg) {
|
||||
Map<String, Method> functions = new LinkedHashMap<String, Method>();
|
||||
for (Entry<String, Method> function : functionsArg.entrySet()) {
|
||||
Assert.notNull(function.getValue(), "Method cannot be null");
|
||||
functions.put(function.getKey(), function.getValue());
|
||||
}
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StandardEvaluationContext getObject() throws Exception {
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
for (PropertyAccessor propertyAccessor : this.propertyAccessors) {
|
||||
evaluationContext.addPropertyAccessor(propertyAccessor);
|
||||
}
|
||||
evaluationContext.setBeanResolver(this.beanResolver);
|
||||
evaluationContext.setTypeConverter(this.typeConverter);
|
||||
for (Entry<String, Method> functionEntry : this.functions.entrySet()) {
|
||||
evaluationContext.registerFunction(functionEntry.getKey(), functionEntry.getValue());
|
||||
}
|
||||
return evaluationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return StandardEvaluationContext.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -32,15 +32,18 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.integration.channel.NullChannel;
|
||||
import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.expression.IntegrationEvaluationContextAwareBeanPostProcessor;
|
||||
|
||||
/**
|
||||
* A {@link BeanFactoryPostProcessor} implementation that provides default beans for the error handling and task
|
||||
* scheduling if those beans have not already been explicitly defined within the registry. It also registers a single
|
||||
* null channel with the bean name "nullChannel".
|
||||
*
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
|
||||
|
||||
@@ -61,6 +64,10 @@ class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProce
|
||||
this.registerTaskScheduler(registry);
|
||||
}
|
||||
this.registerIdGeneratorConfigurer(registry);
|
||||
if (!beanFactory.containsBean(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME)) {
|
||||
this.registerIntegrationEvaluationContext(registry);
|
||||
beanFactory.addBeanPostProcessor(new IntegrationEvaluationContextAwareBeanPostProcessor(beanFactory));
|
||||
}
|
||||
}
|
||||
else if (logger.isWarnEnabled()) {
|
||||
logger.warn("BeanFactory is not a BeanDefinitionRegistry. The default '"
|
||||
@@ -71,6 +78,16 @@ class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProce
|
||||
}
|
||||
}
|
||||
|
||||
private void registerIntegrationEvaluationContext(BeanDefinitionRegistry registry) {
|
||||
BeanDefinitionBuilder integrationEvaluationContextBuilder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
IntegrationEvaluationContextFactoryBean.class);
|
||||
integrationEvaluationContextBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
BeanDefinitionHolder integrationEvaluationContextHolder = new BeanDefinitionHolder(
|
||||
integrationEvaluationContextBuilder.getBeanDefinition(),
|
||||
IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(integrationEvaluationContextHolder, registry);
|
||||
}
|
||||
|
||||
private void registerIdGeneratorConfigurer(BeanDefinitionRegistry registry) {
|
||||
String listenerClassName = "org.springframework.integration.config.IdGeneratorConfigurer";
|
||||
String[] definitionNames = registry.getBeanDefinitionNames();
|
||||
@@ -113,7 +130,7 @@ class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProce
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an error channel in the given BeanDefinitionRegistry.
|
||||
* Register an error channel in the given BeanDefinitionRegistry.
|
||||
*/
|
||||
private void registerErrorChannel(BeanDefinitionRegistry registry) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
@@ -139,7 +156,7 @@ class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProce
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a TaskScheduler in the given BeanDefinitionRegistry.
|
||||
* Register a TaskScheduler in the given BeanDefinitionRegistry.
|
||||
*/
|
||||
private void registerTaskScheduler(BeanDefinitionRegistry registry) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.context;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.store.metadata.MetadataStore;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
@@ -28,6 +29,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Josh Long
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public abstract class IntegrationContextUtils {
|
||||
|
||||
@@ -41,6 +43,7 @@ public abstract class IntegrationContextUtils {
|
||||
|
||||
public static final String INTEGRATION_CONVERSION_SERVICE_BEAN_NAME = "integrationConversionService";
|
||||
|
||||
public static final String INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME = "integrationEvaluationContext";
|
||||
|
||||
/**
|
||||
* Return the {@link MetadataStore} bean whose name is "metadataStore".
|
||||
@@ -85,6 +88,14 @@ public abstract class IntegrationContextUtils {
|
||||
return getBeanOfType(beanFactory, INTEGRATION_CONVERSION_SERVICE_BEAN_NAME, ConversionService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the instance of {@link StandardEvaluationContext} bean whose name is "integrationEvaluationContext" .
|
||||
* @param beanFactory BeanFactory for lookup, must not be null.
|
||||
*/
|
||||
public static StandardEvaluationContext getEvaluationContext(BeanFactory beanFactory) {
|
||||
return getBeanOfType(beanFactory, INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME, StandardEvaluationContext.class);
|
||||
}
|
||||
|
||||
private static <T> T getBeanOfType(BeanFactory beanFactory, String beanName, Class<T> type) {
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
if (!beanFactory.containsBean(beanName)) {
|
||||
|
||||
@@ -140,7 +140,7 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
|
||||
this.taskScheduler = taskScheduler;
|
||||
}
|
||||
|
||||
protected final ConversionService getConversionService() {
|
||||
public final ConversionService getConversionService() {
|
||||
if (this.conversionService == null && this.beanFactory != null) {
|
||||
synchronized (this) {
|
||||
if (this.conversionService == null) {
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
*/
|
||||
package org.springframework.integration.endpoint;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.integration.endpoint.MessageProducerSupport;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.expression.IntegrationEvaluationContextAware;
|
||||
|
||||
/**
|
||||
* A {@link MessageProducerSupport} sub-class that provides {@linkplain #payloadExpression}
|
||||
@@ -22,15 +24,18 @@ import org.springframework.integration.endpoint.MessageProducerSupport;
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
* @since 2.1
|
||||
*
|
||||
*/
|
||||
public abstract class ExpressionMessageProducerSupport extends MessageProducerSupport {
|
||||
public abstract class ExpressionMessageProducerSupport extends MessageProducerSupport implements IntegrationEvaluationContextAware {
|
||||
|
||||
private final SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
private volatile Expression payloadExpression;
|
||||
|
||||
private volatile EvaluationContext evaluationContext;
|
||||
|
||||
public void setPayloadExpression(String payloadExpression) {
|
||||
if (payloadExpression == null) {
|
||||
this.payloadExpression = null;
|
||||
@@ -40,10 +45,23 @@ public abstract class ExpressionMessageProducerSupport extends MessageProducerSu
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntegrationEvaluationContext(EvaluationContext evaluationContext) {
|
||||
this.evaluationContext = evaluationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() {
|
||||
super.onInit();
|
||||
if (this.evaluationContext == null) {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
}
|
||||
}
|
||||
|
||||
protected Object evaluatePayloadExpression(Object payload){
|
||||
Object evaluationResult = payload;
|
||||
if (payloadExpression != null) {
|
||||
evaluationResult = payloadExpression.getValue(payload);
|
||||
evaluationResult = payloadExpression.getValue(this.evaluationContext, payload);
|
||||
}
|
||||
return evaluationResult;
|
||||
}
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
package org.springframework.integration.expression;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
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.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardTypeConverter;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
@@ -36,26 +37,7 @@ import org.springframework.integration.context.IntegrationContextUtils;
|
||||
*/
|
||||
public abstract class ExpressionUtils {
|
||||
|
||||
/**
|
||||
* Create a {@link StandardEvaluationContext} with a {@link MapAccessor} in its
|
||||
* property accessor property.
|
||||
* @return the evaluation context.
|
||||
*/
|
||||
public static StandardEvaluationContext createStandardEvaluationContext() {
|
||||
return createStandardEvaluationContext(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link StandardEvaluationContext} with a {@link MapAccessor} in its
|
||||
* property accessor property and the supplied {@link BeanResolver} in its
|
||||
* beanResolver property.
|
||||
* @param beanResolver the bean resolver.
|
||||
* @return the evaluation context.
|
||||
*/
|
||||
public static StandardEvaluationContext createStandardEvaluationContext(BeanResolver beanResolver) {
|
||||
return createStandardEvaluationContext(beanResolver, null);
|
||||
}
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ExpressionUtils.class);
|
||||
/**
|
||||
* Create a {@link StandardEvaluationContext} with a {@link MapAccessor} in its
|
||||
* property accessor property and the supplied {@link ConversionService} in its
|
||||
@@ -63,26 +45,9 @@ public abstract class ExpressionUtils {
|
||||
* @param conversionService the conversion service.
|
||||
* @return the evaluation context.
|
||||
*/
|
||||
public static StandardEvaluationContext createStandardEvaluationContext(ConversionService conversionService) {
|
||||
return createStandardEvaluationContext(null, conversionService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link StandardEvaluationContext} with a {@link MapAccessor} in its
|
||||
* property accessor property, the supplied {@link BeanResolver} in its
|
||||
* beanResolver property, and the supplied {@link ConversionService} in its
|
||||
* conversionService property.
|
||||
* @param beanResolver the bean resolver.
|
||||
* @param conversionService the conversion service.
|
||||
* @return the evaluation context.
|
||||
*/
|
||||
public static StandardEvaluationContext createStandardEvaluationContext(BeanResolver beanResolver,
|
||||
ConversionService conversionService) {
|
||||
private static StandardEvaluationContext createStandardEvaluationContext(ConversionService conversionService) {
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
evaluationContext.addPropertyAccessor(new MapAccessor());
|
||||
if (beanResolver != null) {
|
||||
evaluationContext.setBeanResolver(beanResolver);
|
||||
}
|
||||
if (conversionService != null) {
|
||||
evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService));
|
||||
}
|
||||
@@ -90,14 +55,39 @@ public abstract class ExpressionUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link BeanFactoryResolver}, extracts {@link ConversionService} and delegates to
|
||||
* {@link #createStandardEvaluationContext(BeanResolver, ConversionService)}
|
||||
*
|
||||
* @param beanFactory the beanFactory.
|
||||
* @return the evaluation context.
|
||||
* Used to create a context with no BeanFactory, usually in tests.
|
||||
* @return The evaluation context.
|
||||
*/
|
||||
public static StandardEvaluationContext createStandardEvaluationContext() {
|
||||
return doCreateContext(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the context from the beanFactory if not null; emits a warning if the beanFactory
|
||||
* is null.
|
||||
* @param beanFactory
|
||||
* @return The evaluation context.
|
||||
*/
|
||||
public static StandardEvaluationContext createStandardEvaluationContext(BeanFactory beanFactory) {
|
||||
return createStandardEvaluationContext(new BeanFactoryResolver(beanFactory),
|
||||
IntegrationContextUtils.getConversionService(beanFactory));
|
||||
if (beanFactory == null) {
|
||||
logger.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanfactory"));
|
||||
}
|
||||
return doCreateContext(beanFactory);
|
||||
}
|
||||
|
||||
private static StandardEvaluationContext doCreateContext(BeanFactory beanFactory) {
|
||||
ConversionService conversionService = null;
|
||||
StandardEvaluationContext evaluationContext = null;
|
||||
if (beanFactory != null) {
|
||||
evaluationContext = IntegrationContextUtils.getEvaluationContext(beanFactory);
|
||||
}
|
||||
if (evaluationContext == null) {
|
||||
if (beanFactory != null) {
|
||||
conversionService = IntegrationContextUtils.getConversionService(beanFactory);
|
||||
}
|
||||
evaluationContext = createStandardEvaluationContext(conversionService);
|
||||
}
|
||||
return evaluationContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2013 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.expression;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface IntegrationEvaluationContextAware {
|
||||
|
||||
void setIntegrationEvaluationContext(EvaluationContext evaluationContext);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013 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.expression;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
* @since 3.0
|
||||
*/
|
||||
public class IntegrationEvaluationContextAwareBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
public IntegrationEvaluationContextAwareBeanPostProcessor(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof IntegrationEvaluationContextAware) {
|
||||
StandardEvaluationContext evaluationContext = IntegrationContextUtils.getEvaluationContext(this.beanFactory);
|
||||
((IntegrationEvaluationContextAware) bean).setIntegrationEvaluationContext(evaluationContext);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
@@ -28,11 +28,9 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.BeanResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
@@ -42,6 +40,7 @@ import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.annotation.Header;
|
||||
import org.springframework.integration.annotation.Headers;
|
||||
import org.springframework.integration.annotation.Payload;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.mapping.InboundMessageMapper;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -87,9 +86,9 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
|
||||
private final Map<String, Expression> parameterPayloadExpressions = new HashMap<String, Expression>();
|
||||
|
||||
private final StandardEvaluationContext staticEvaluationContext = new StandardEvaluationContext();
|
||||
private volatile StandardEvaluationContext payloadExpressionEvaluationContext;
|
||||
|
||||
private volatile BeanResolver beanResolver;
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
|
||||
public GatewayMethodInboundMessageMapper(Method method) {
|
||||
@@ -111,8 +110,8 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
|
||||
public void setBeanFactory(final BeanFactory beanFactory) {
|
||||
if (beanFactory != null) {
|
||||
this.beanResolver = new BeanFactoryResolver(beanFactory);
|
||||
this.staticEvaluationContext.setBeanResolver(beanResolver);
|
||||
this.beanFactory = beanFactory;
|
||||
this.payloadExpressionEvaluationContext = ExpressionUtils.createStandardEvaluationContext(beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,12 +208,9 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
}
|
||||
|
||||
private StandardEvaluationContext createMethodInvocationEvaluationContext(Object[] arguments) {
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
StandardEvaluationContext context = ExpressionUtils.createStandardEvaluationContext(this.beanFactory);
|
||||
context.setVariable("args", arguments);
|
||||
context.setVariable("method", this.method.getName());
|
||||
if (this.beanResolver != null) {
|
||||
context.setBeanResolver(this.beanResolver);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -224,7 +220,7 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
expression = PARSER.parseExpression(expressionString);
|
||||
this.parameterPayloadExpressions.put(expressionString, expression);
|
||||
}
|
||||
return expression.getValue(this.staticEvaluationContext, argumentValue);
|
||||
return expression.getValue(this.payloadExpressionEvaluationContext, argumentValue);
|
||||
}
|
||||
|
||||
private Annotation findMappingAnnotation(Annotation[] annotations) {
|
||||
|
||||
@@ -210,12 +210,7 @@ public class DelayHandler extends AbstractReplyProducingMessageHandler implement
|
||||
this.delayExpression = expressionParser.parseExpression("headers['" + this.delayHeaderName + "']");
|
||||
}
|
||||
}
|
||||
if (this.getBeanFactory() != null) {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
}
|
||||
else {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext();
|
||||
}
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
this.releaseHandler = this.createReleaseMessageTask();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ import java.io.StringWriter;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.dispatcher.AggregateMessageDeliveryException;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class LoggingHandler extends AbstractMessageHandler {
|
||||
|
||||
private volatile Level level;
|
||||
|
||||
private final EvaluationContext evaluationContext;
|
||||
private volatile EvaluationContext evaluationContext;
|
||||
|
||||
private volatile Log messageLogger = this.logger;
|
||||
|
||||
@@ -74,9 +74,7 @@ public class LoggingHandler extends AbstractMessageHandler {
|
||||
+ "'. The (case-insensitive) supported values are: "
|
||||
+ StringUtils.arrayToCommaDelimitedString(Level.values()));
|
||||
}
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
evaluationContext.addPropertyAccessor(new MapAccessor());
|
||||
this.evaluationContext = evaluationContext;
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext();
|
||||
this.expression = EXPRESSION_PARSER.parseExpression("payload");
|
||||
}
|
||||
|
||||
@@ -123,6 +121,12 @@ public class LoggingHandler extends AbstractMessageHandler {
|
||||
return "logging-channel-adapter";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() throws Exception {
|
||||
super.onInit();
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleMessageInternal(Message<?> message) throws Exception {
|
||||
switch (this.level) {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.integration.handler.advice;
|
||||
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
@@ -172,13 +171,7 @@ public class ExpressionEvaluatingRequestHandlerAdvice extends AbstractRequestHan
|
||||
}
|
||||
|
||||
protected StandardEvaluationContext createEvaluationContext(){
|
||||
if (this.getBeanFactory() != null) {
|
||||
return ExpressionUtils.createStandardEvaluationContext(new BeanFactoryResolver(this.getBeanFactory()),
|
||||
this.getConversionService());
|
||||
}
|
||||
else {
|
||||
return ExpressionUtils.createStandardEvaluationContext(this.getConversionService());
|
||||
}
|
||||
return ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -19,7 +19,6 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.classify.Classifier;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
@@ -37,7 +36,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class SpelExpressionRetryStateGenerator implements RetryStateGenerator, BeanFactoryAware {
|
||||
|
||||
private final StandardEvaluationContext evaluationContext;
|
||||
private volatile StandardEvaluationContext evaluationContext;
|
||||
|
||||
private final Expression keyExpression;
|
||||
|
||||
@@ -62,7 +61,7 @@ public class SpelExpressionRetryStateGenerator implements RetryStateGenerator, B
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(beanFactory);
|
||||
}
|
||||
|
||||
public void setClassifier(Classifier<? super Throwable, Boolean> classifier) {
|
||||
|
||||
@@ -14,7 +14,6 @@ package org.springframework.integration.transaction;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.Message;
|
||||
@@ -180,13 +179,7 @@ public class ExpressionEvaluatingTransactionSynchronizationProcessor extends Int
|
||||
return evaluationContextToUse;
|
||||
}
|
||||
|
||||
protected StandardEvaluationContext createEvaluationContext(){
|
||||
if (this.getBeanFactory() != null) {
|
||||
return ExpressionUtils.createStandardEvaluationContext(new BeanFactoryResolver(this.getBeanFactory()),
|
||||
this.getConversionService());
|
||||
}
|
||||
else {
|
||||
return ExpressionUtils.createStandardEvaluationContext(this.getConversionService());
|
||||
}
|
||||
protected StandardEvaluationContext createEvaluationContext() {
|
||||
return ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -20,10 +20,8 @@ import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.SpelParserConfiguration;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
@@ -31,6 +29,8 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.expression.IntegrationEvaluationContextAware;
|
||||
import org.springframework.integration.gateway.MessagingGatewaySupport;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
@@ -46,17 +46,18 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @author Mark Fisher
|
||||
* @author Gunnar Hillert
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
* @since 2.1
|
||||
*/
|
||||
public class ContentEnricher extends AbstractReplyProducingMessageHandler implements Lifecycle {
|
||||
public class ContentEnricher extends AbstractReplyProducingMessageHandler implements Lifecycle, IntegrationEvaluationContextAware {
|
||||
|
||||
private final Map<Expression, Expression> propertyExpressions = new HashMap<Expression, Expression>();
|
||||
|
||||
private final SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
|
||||
|
||||
private final StandardEvaluationContext sourceEvaluationContext = new StandardEvaluationContext();
|
||||
private EvaluationContext sourceEvaluationContext;
|
||||
|
||||
private final StandardEvaluationContext targetEvaluationContext = new StandardEvaluationContext();
|
||||
private EvaluationContext targetEvaluationContext;
|
||||
|
||||
private volatile boolean shouldClonePayload = false;
|
||||
|
||||
@@ -69,7 +70,7 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
|
||||
private volatile Gateway gateway = null;
|
||||
|
||||
private volatile Long requestTimeout;
|
||||
|
||||
|
||||
private volatile Long replyTimeout;
|
||||
|
||||
/**
|
||||
@@ -111,20 +112,20 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timeout value for sending request messages. If not explicitly
|
||||
* Set the timeout value for sending request messages. If not explicitly
|
||||
* configured, the default is one second.
|
||||
*
|
||||
*
|
||||
* @param requestTimeout the timeout value in milliseconds. Must not be null.
|
||||
*/
|
||||
public void setRequestTimeout(Long requestTimeout) {
|
||||
Assert.notNull(requestTimeout, "requestTimeout must not be null");
|
||||
this.requestTimeout = requestTimeout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the timeout value for receiving reply messages. If not explicitly
|
||||
* Set the timeout value for receiving reply messages. If not explicitly
|
||||
* configured, the default is one second.
|
||||
*
|
||||
*
|
||||
* @param replyTimeout the timeout value in milliseconds. Must not be null.
|
||||
*/
|
||||
public void setReplyTimeout(Long replyTimeout) {
|
||||
@@ -168,6 +169,10 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
|
||||
this.shouldClonePayload = shouldClonePayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntegrationEvaluationContext(EvaluationContext evaluationContext) {
|
||||
this.sourceEvaluationContext = evaluationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Content Enricher. Will instantiate an internal Gateway if
|
||||
@@ -182,29 +187,34 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
|
||||
if (this.requestChannel != null) {
|
||||
this.gateway = new Gateway();
|
||||
this.gateway.setRequestChannel(requestChannel);
|
||||
|
||||
|
||||
if (this.requestTimeout != null) {
|
||||
this.gateway.setRequestTimeout(this.requestTimeout);
|
||||
}
|
||||
|
||||
|
||||
if (this.replyTimeout != null) {
|
||||
this.gateway.setReplyTimeout(this.replyTimeout);
|
||||
}
|
||||
|
||||
|
||||
if (replyChannel != null) {
|
||||
this.gateway.setReplyChannel(replyChannel);
|
||||
}
|
||||
|
||||
|
||||
this.gateway.afterPropertiesSet();
|
||||
}
|
||||
this.sourceEvaluationContext.addPropertyAccessor(new MapAccessor());
|
||||
this.targetEvaluationContext.addPropertyAccessor(new MapAccessor());
|
||||
BeanFactory beanFactory = this.getBeanFactory();
|
||||
if (beanFactory != null) {
|
||||
this.sourceEvaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
|
||||
|
||||
if (this.sourceEvaluationContext == null) {
|
||||
this.sourceEvaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
}
|
||||
|
||||
StandardEvaluationContext targetContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
// bean resolution is NOT allowed for the target of the enrichment
|
||||
targetContext.setBeanResolver(null);
|
||||
this.targetEvaluationContext = targetContext;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
final Object requestPayload = requestMessage.getPayload();
|
||||
@@ -249,7 +259,6 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
|
||||
return targetPayload;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lifecycle implementation. If no requestChannel is defined, this method
|
||||
* has no effect as in that case no Gateway is initialized.
|
||||
@@ -283,7 +292,6 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal gateway implementation for request/reply handling.
|
||||
* Simply exposes the sendAndReceiveMessage method.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -18,10 +18,9 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
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;
|
||||
@@ -29,47 +28,41 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Dave Syer
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractExpressionEvaluator implements BeanFactoryAware {
|
||||
|
||||
public abstract class AbstractExpressionEvaluator implements BeanFactoryAware, InitializingBean {
|
||||
|
||||
private final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private final StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
private volatile StandardEvaluationContext evaluationContext;
|
||||
|
||||
private final ExpressionParser expressionParser = new SpelExpressionParser();
|
||||
|
||||
private final BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter();
|
||||
|
||||
private volatile BeanResolver beanResolver;
|
||||
|
||||
public AbstractExpressionEvaluator() {
|
||||
this.evaluationContext.setTypeConverter(this.typeConverter);
|
||||
this.evaluationContext.addPropertyAccessor(new MapAccessor());
|
||||
}
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Specify a BeanFactory in order to enable resolution via <code>@beanName</code> in the expression.
|
||||
*/
|
||||
public void setBeanFactory(final BeanFactory beanFactory) {
|
||||
if (beanFactory != null) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.typeConverter.setBeanFactory(beanFactory);
|
||||
if (beanResolver == null) {
|
||||
if (this.evaluationContext != null && this.evaluationContext.getBeanResolver() == 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) {
|
||||
@@ -77,7 +70,32 @@ public abstract class AbstractExpressionEvaluator implements BeanFactoryAware {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
getEvaluationContext();
|
||||
}
|
||||
|
||||
protected StandardEvaluationContext getEvaluationContext() {
|
||||
return this.getEvaluationContext(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a WARN log if the beanFactory field is null, unless the argument is false.
|
||||
* @param beanFactoryRequired set to false to suppress the warning.
|
||||
* @return The evaluation context.
|
||||
*/
|
||||
protected final StandardEvaluationContext getEvaluationContext(boolean beanFactoryRequired) {
|
||||
if (this.evaluationContext == null) {
|
||||
if (this.beanFactory == null && !beanFactoryRequired) {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext();
|
||||
}
|
||||
else {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.beanFactory);
|
||||
}
|
||||
if (this.typeConverter != null) {
|
||||
this.evaluationContext.setTypeConverter(this.typeConverter);
|
||||
}
|
||||
}
|
||||
return this.evaluationContext;
|
||||
}
|
||||
|
||||
@@ -107,7 +125,7 @@ public abstract class AbstractExpressionEvaluator implements BeanFactoryAware {
|
||||
}
|
||||
|
||||
protected <T> T evaluateExpression(String expression, Object input, Class<T> expectedType) {
|
||||
return this.expressionParser.parseExpression(expression).getValue(this.evaluationContext, input, expectedType);
|
||||
return this.expressionParser.parseExpression(expression).getValue(this.getEvaluationContext(), input, expectedType);
|
||||
}
|
||||
|
||||
protected Object evaluateExpression(Expression expression, Object input) {
|
||||
@@ -115,15 +133,15 @@ public abstract class AbstractExpressionEvaluator implements BeanFactoryAware {
|
||||
}
|
||||
|
||||
protected <T> T evaluateExpression(Expression expression, Class<T> expectedType) {
|
||||
return expression.getValue(this.evaluationContext, expectedType);
|
||||
return expression.getValue(this.getEvaluationContext(), expectedType);
|
||||
}
|
||||
|
||||
protected Object evaluateExpression(Expression expression) {
|
||||
return expression.getValue(this.evaluationContext);
|
||||
return expression.getValue(this.getEvaluationContext());
|
||||
}
|
||||
|
||||
protected <T> T evaluateExpression(Expression expression, Object input, Class<T> expectedType) {
|
||||
return expression.getValue(this.evaluationContext, input, expectedType);
|
||||
return expression.getValue(this.getEvaluationContext(), input, expectedType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
@@ -158,7 +159,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
this.targetObject = targetObject;
|
||||
this.handlerMethods = Collections.<Class<?>, HandlerMethod> singletonMap(handlerMethod.getTargetParameterType()
|
||||
.getObjectType(), handlerMethod);
|
||||
this.prepareEvaluationContext(this.getEvaluationContext(), method, annotationType);
|
||||
this.prepareEvaluationContext(this.getEvaluationContext(false), method, annotationType);
|
||||
this.setDisplayString(targetObject, method);
|
||||
}
|
||||
|
||||
@@ -170,7 +171,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
this.targetObject = targetObject;
|
||||
this.requiresReply = expectedType != null;
|
||||
this.handlerMethods = this.findHandlerMethodsForTarget(targetObject, annotationType, methodName, requiresReply);
|
||||
this.prepareEvaluationContext(this.getEvaluationContext(), methodName, annotationType);
|
||||
this.prepareEvaluationContext(this.getEvaluationContext(false), methodName, annotationType);
|
||||
this.setDisplayString(targetObject, methodName);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -24,14 +24,18 @@ import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.annotation.Header;
|
||||
import org.springframework.integration.annotation.Payload;
|
||||
import org.springframework.integration.annotation.Publisher;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PublisherExpressionTests {
|
||||
@@ -40,8 +44,14 @@ public class PublisherExpressionTests {
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
public void setup() throws Exception {
|
||||
context.registerSingleton("testChannel", QueueChannel.class);
|
||||
IntegrationEvaluationContextFactoryBean factory = new IntegrationEvaluationContextFactoryBean();
|
||||
factory.setBeanFactory(context);
|
||||
factory.afterPropertiesSet();
|
||||
EvaluationContext ec = factory.getObject();
|
||||
context.getBeanFactory().registerSingleton(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME, ec);
|
||||
context.getBeanFactory().registerSingleton("foo", "foo");
|
||||
}
|
||||
|
||||
|
||||
@@ -56,8 +66,8 @@ public class PublisherExpressionTests {
|
||||
TestBean proxy = (TestBean) pf.getProxy();
|
||||
proxy.test("123");
|
||||
Message<?> message = testChannel.receive(0);
|
||||
assertNotNull(message);
|
||||
assertEquals("hello", message.getPayload());
|
||||
assertNotNull(message);
|
||||
assertEquals("hellofoo", message.getPayload());
|
||||
assertEquals("123", message.getHeaders().get("foo"));
|
||||
}
|
||||
|
||||
@@ -70,7 +80,7 @@ public class PublisherExpressionTests {
|
||||
static class TestBeanImpl implements TestBean {
|
||||
|
||||
@Publisher
|
||||
@Payload("#return")
|
||||
@Payload("#return + @foo")
|
||||
public String test(@Header("foo") String foo) {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -17,11 +17,13 @@
|
||||
package org.springframework.integration.config.xml;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
@@ -67,6 +69,7 @@ public class LoggingChannelAdapterParserTests {
|
||||
assertEquals(Ordered.LOWEST_PRECEDENCE, TestUtils.getPropertyValue(loggingHandler, "order"));
|
||||
assertEquals("INFO", TestUtils.getPropertyValue(loggingHandler, "level").toString());
|
||||
assertEquals("payload.foo", TestUtils.getPropertyValue(loggingHandler, "expression.expression"));
|
||||
assertNotNull(TestUtils.getPropertyValue(loggingHandler, "evaluationContext.beanResolver"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2013 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.expression;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.support.ConversionServiceFactoryBean;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 3.0
|
||||
*
|
||||
*/
|
||||
public class ExpressionUtilsTests {
|
||||
|
||||
@Test
|
||||
public void testEvaluationContext() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
|
||||
new RootBeanDefinition(IntegrationEvaluationContextFactoryBean.class));
|
||||
context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_CONVERSION_SERVICE_BEAN_NAME,
|
||||
new RootBeanDefinition(ConversionServiceFactoryBean.class));
|
||||
context.refresh();
|
||||
StandardEvaluationContext evalContext = ExpressionUtils.createStandardEvaluationContext(context);
|
||||
assertNotNull(evalContext.getBeanResolver());
|
||||
assertNotNull(evalContext.getTypeConverter());
|
||||
IntegrationEvaluationContextFactoryBean factory = context.getBean("&" + IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
|
||||
IntegrationEvaluationContextFactoryBean.class);
|
||||
assertSame(evalContext.getTypeConverter(), TestUtils.getPropertyValue(factory, "typeConverter"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEvaluationContextDefaultTypeConverter() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
|
||||
new RootBeanDefinition(IntegrationEvaluationContextFactoryBean.class));
|
||||
context.refresh();
|
||||
StandardEvaluationContext evalContext = ExpressionUtils.createStandardEvaluationContext(context);
|
||||
assertNotNull(evalContext.getBeanResolver());
|
||||
TypeConverter typeConverter = evalContext.getTypeConverter();
|
||||
assertNotNull(typeConverter);
|
||||
assertSame(TestUtils.getPropertyValue(typeConverter, "defaultConversionService"), TestUtils.getPropertyValue(typeConverter, "conversionService"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluationContextNoFactoryBean() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_CONVERSION_SERVICE_BEAN_NAME,
|
||||
new RootBeanDefinition(ConversionServiceFactoryBean.class));
|
||||
context.refresh();
|
||||
StandardEvaluationContext evalContext = ExpressionUtils.createStandardEvaluationContext(context);
|
||||
assertNull(evalContext.getBeanResolver());
|
||||
TypeConverter typeConverter = evalContext.getTypeConverter();
|
||||
assertNotNull(typeConverter);
|
||||
assertNotSame(TestUtils.getPropertyValue(typeConverter, "defaultConversionService"),
|
||||
TestUtils.getPropertyValue(typeConverter, "conversionService"));
|
||||
assertSame(context.getBean(IntegrationContextUtils.INTEGRATION_CONVERSION_SERVICE_BEAN_NAME),
|
||||
TestUtils.getPropertyValue(typeConverter, "conversionService"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluationContextNoBeanFactory() {
|
||||
StandardEvaluationContext evalContext = ExpressionUtils.createStandardEvaluationContext();
|
||||
assertNull(evalContext.getBeanResolver());
|
||||
TypeConverter typeConverter = evalContext.getTypeConverter();
|
||||
assertNotNull(typeConverter);
|
||||
assertSame(TestUtils.getPropertyValue(typeConverter, "defaultConversionService"),
|
||||
TestUtils.getPropertyValue(typeConverter, "conversionService"));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -34,9 +34,12 @@ import org.springframework.integration.annotation.Header;
|
||||
import org.springframework.integration.annotation.Headers;
|
||||
import org.springframework.integration.annotation.Payload;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*/
|
||||
public class GatewayProxyMessageMappingTests {
|
||||
@@ -52,6 +55,11 @@ public class GatewayProxyMessageMappingTests {
|
||||
factoryBean.setServiceInterface(TestGateway.class);
|
||||
factoryBean.setDefaultRequestChannel(channel);
|
||||
factoryBean.setBeanName("testGateway");
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
|
||||
new RootBeanDefinition(IntegrationEvaluationContextFactoryBean.class));
|
||||
context.refresh();
|
||||
factoryBean.setBeanFactory(context);
|
||||
factoryBean.afterPropertiesSet();
|
||||
this.gateway = (TestGateway) factoryBean.getObject();
|
||||
}
|
||||
@@ -136,6 +144,8 @@ public class GatewayProxyMessageMappingTests {
|
||||
gatewayDefinition.getPropertyValues().add("serviceInterface", TestGateway.class);
|
||||
context.registerBeanDefinition("testGateway", gatewayDefinition);
|
||||
context.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
|
||||
new RootBeanDefinition(IntegrationEvaluationContextFactoryBean.class));
|
||||
context.refresh();
|
||||
TestGateway gateway = context.getBean("testGateway", TestGateway.class);
|
||||
gateway.payloadAnnotationAtMethodLevelUsingBeanResolver("foo");
|
||||
@@ -160,6 +170,8 @@ public class GatewayProxyMessageMappingTests {
|
||||
gatewayDefinition.getPropertyValues().add("serviceInterface", TestGateway.class);
|
||||
context.registerBeanDefinition("testGateway", gatewayDefinition);
|
||||
context.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
|
||||
new RootBeanDefinition(IntegrationEvaluationContextFactoryBean.class));
|
||||
context.refresh();
|
||||
TestGateway gateway = context.getBean("testGateway", TestGateway.class);
|
||||
gateway.payloadAnnotationWithExpressionUsingBeanResolver("foo");
|
||||
|
||||
@@ -21,12 +21,13 @@ import java.util.Arrays;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
@@ -38,6 +39,8 @@ import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.SpelParserConfiguration;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
@@ -69,7 +72,7 @@ public class ExpressionEvaluatingMessageProcessorTests {
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Test
|
||||
public void testProcessMessageWithParameterCoercion() {
|
||||
public void testProcessMessageWithParameterCoercion() throws Exception {
|
||||
@SuppressWarnings("unused")
|
||||
class TestTarget {
|
||||
public String stringify(int number) {
|
||||
@@ -78,6 +81,7 @@ public class ExpressionEvaluatingMessageProcessorTests {
|
||||
}
|
||||
Expression expression = expressionParser.parseExpression("#target.stringify(payload)");
|
||||
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression);
|
||||
processor.afterPropertiesSet();
|
||||
EvaluationContext evaluationContext = TestUtils.getPropertyValue(processor, "evaluationContext", EvaluationContext.class);
|
||||
evaluationContext.setVariable("target", new TestTarget());
|
||||
assertEquals("2", processor.processMessage(new GenericMessage<String>("2")));
|
||||
@@ -85,7 +89,7 @@ public class ExpressionEvaluatingMessageProcessorTests {
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Test
|
||||
public void testProcessMessageWithVoidResult() {
|
||||
public void testProcessMessageWithVoidResult() throws Exception {
|
||||
@SuppressWarnings("unused")
|
||||
class TestTarget {
|
||||
public void ping(String input) {
|
||||
@@ -93,6 +97,7 @@ public class ExpressionEvaluatingMessageProcessorTests {
|
||||
}
|
||||
Expression expression = expressionParser.parseExpression("#target.ping(payload)");
|
||||
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression);
|
||||
processor.afterPropertiesSet();
|
||||
EvaluationContext evaluationContext = TestUtils.getPropertyValue(processor, "evaluationContext", EvaluationContext.class);
|
||||
evaluationContext.setVariable("target", new TestTarget());
|
||||
assertEquals(null, processor.processMessage(new GenericMessage<String>("2")));
|
||||
@@ -100,7 +105,7 @@ public class ExpressionEvaluatingMessageProcessorTests {
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Test
|
||||
public void testProcessMessageWithParameterCoercionToNonPrimitive() {
|
||||
public void testProcessMessageWithParameterCoercionToNonPrimitive() throws Exception {
|
||||
class TestTarget {
|
||||
@SuppressWarnings("unused")
|
||||
public String find(Resource[] resources) {
|
||||
@@ -110,7 +115,13 @@ public class ExpressionEvaluatingMessageProcessorTests {
|
||||
}
|
||||
Expression expression = expressionParser.parseExpression("#target.find(payload)");
|
||||
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression);
|
||||
processor.setBeanFactory(new GenericApplicationContext().getBeanFactory());
|
||||
ConfigurableListableBeanFactory beanFactory = new GenericApplicationContext().getBeanFactory();
|
||||
processor.setBeanFactory(beanFactory);
|
||||
IntegrationEvaluationContextFactoryBean factoryBean = new IntegrationEvaluationContextFactoryBean();
|
||||
factoryBean.setBeanFactory(beanFactory);
|
||||
beanFactory.registerSingleton(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
|
||||
factoryBean.getObject());
|
||||
processor.afterPropertiesSet();
|
||||
EvaluationContext evaluationContext = TestUtils.getPropertyValue(processor, "evaluationContext", EvaluationContext.class);
|
||||
evaluationContext.setVariable("target", new TestTarget());
|
||||
String result = (String) processor.processMessage(new GenericMessage<String>("classpath*:*.properties"));
|
||||
@@ -146,28 +157,34 @@ public class ExpressionEvaluatingMessageProcessorTests {
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Test
|
||||
public void testProcessMessageWithBeanAsMethodArgument() {
|
||||
public void testProcessMessageWithBeanAsMethodArgument() throws Exception {
|
||||
StaticApplicationContext context = new StaticApplicationContext();
|
||||
BeanDefinition beanDefinition = new RootBeanDefinition(String.class);
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("bar");
|
||||
context.registerBeanDefinition("testString", beanDefinition);
|
||||
context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
|
||||
new RootBeanDefinition(IntegrationEvaluationContextFactoryBean.class));
|
||||
Expression expression = expressionParser.parseExpression("payload.concat(@testString)");
|
||||
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression);
|
||||
processor.setBeanFactory(context);
|
||||
processor.afterPropertiesSet();
|
||||
GenericMessage<String> message = new GenericMessage<String>("foo");
|
||||
assertEquals("foobar", processor.processMessage(message));
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Test
|
||||
public void testProcessMessageWithMethodCallOnBean() {
|
||||
public void testProcessMessageWithMethodCallOnBean() throws Exception {
|
||||
StaticApplicationContext context = new StaticApplicationContext();
|
||||
BeanDefinition beanDefinition = new RootBeanDefinition(String.class);
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("bar");
|
||||
context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
|
||||
new RootBeanDefinition(IntegrationEvaluationContextFactoryBean.class));
|
||||
context.registerBeanDefinition("testString", beanDefinition);
|
||||
Expression expression = expressionParser.parseExpression("@testString.concat(payload)");
|
||||
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression);
|
||||
processor.setBeanFactory(context);
|
||||
processor.afterPropertiesSet();
|
||||
GenericMessage<String> message = new GenericMessage<String>("foo");
|
||||
assertEquals("barfoo", processor.processMessage(message));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -29,6 +29,7 @@ import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
@@ -52,28 +53,29 @@ import org.springframework.scheduling.support.PeriodicTrigger;
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Gunnar Hillert
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public class ContentEnricherTests {
|
||||
|
||||
private ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
|
||||
|
||||
private final ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
taskScheduler.setPoolSize(2);
|
||||
taskScheduler.afterPropertiesSet();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* In this test a {@link Target} message is passed into an {@link ContentEnricher}.
|
||||
* The Enricher passes the message to a "request-channel" that is backed by a
|
||||
* {@link QueueChannel}. The consumer of the "request-channel" takes a long
|
||||
* time to execute, longer actually than the specified "replyTimeout" set on
|
||||
* In this test a {@link Target} message is passed into a {@link ContentEnricher}.
|
||||
* The Enricher passes the message to a "request-channel" that is backed by a
|
||||
* {@link QueueChannel}. The consumer of the "request-channel" takes a long
|
||||
* time to execute, longer actually than the specified "replyTimeout" set on
|
||||
* the {@link ContentEnricher}.
|
||||
*
|
||||
*
|
||||
* Due to the occurring replyTimeout, a Null replyMessage is returned and because
|
||||
* "requiresReply" is set to "true" on the {@link ContentEnricher}, a
|
||||
* "requiresReply" is set to "true" on the {@link ContentEnricher}, a
|
||||
* {@link ReplyRequiredException} is raised.
|
||||
*/
|
||||
@Test
|
||||
@@ -81,26 +83,26 @@ public class ContentEnricherTests {
|
||||
|
||||
final long requestTimeout = 500L;
|
||||
final long replyTimeout = 700L;
|
||||
|
||||
|
||||
final DirectChannel replyChannel = new DirectChannel();
|
||||
final QueueChannel requestChannel = new QueueChannel(1);
|
||||
|
||||
|
||||
final ContentEnricher enricher = new ContentEnricher();
|
||||
enricher.setRequestChannel(requestChannel);
|
||||
enricher.setReplyChannel(replyChannel);
|
||||
|
||||
enricher.setOutputChannel(new NullChannel());
|
||||
|
||||
enricher.setOutputChannel(new NullChannel());
|
||||
enricher.setRequestTimeout(requestTimeout);
|
||||
enricher.setReplyTimeout(replyTimeout);
|
||||
|
||||
|
||||
final ExpressionFactoryBean expressionFactoryBean = new ExpressionFactoryBean("payload");
|
||||
expressionFactoryBean.setSingleton(false);
|
||||
expressionFactoryBean.afterPropertiesSet();
|
||||
|
||||
|
||||
final Map<String, Expression> expressions = new HashMap<String, Expression>();
|
||||
expressions.put("name", new LiteralExpression("cartman"));
|
||||
expressions.put("child.name", expressionFactoryBean.getObject());
|
||||
|
||||
|
||||
enricher.setPropertyExpressions(expressions);
|
||||
enricher.setRequiresReply(true);
|
||||
enricher.setBeanName("Enricher");
|
||||
@@ -117,45 +119,45 @@ public class ContentEnricherTests {
|
||||
}
|
||||
return new Target("child");
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
|
||||
final PollingConsumer consumer = new PollingConsumer(requestChannel, handler);
|
||||
final TestErrorHandler errorHandler = new TestErrorHandler();
|
||||
|
||||
|
||||
consumer.setTrigger(new PeriodicTrigger(0));
|
||||
consumer.setErrorHandler(errorHandler);
|
||||
consumer.setTaskScheduler(taskScheduler);
|
||||
consumer.setBeanFactory(mock(BeanFactory.class));
|
||||
consumer.afterPropertiesSet();
|
||||
consumer.start();
|
||||
|
||||
|
||||
final Target target = new Target("replace me");
|
||||
Message<?> requestMessage = MessageBuilder.withPayload(target).setReplyChannel(replyChannel).build();
|
||||
|
||||
|
||||
try {
|
||||
enricher.handleMessage(requestMessage);
|
||||
} catch (ReplyRequiredException e) {
|
||||
assertEquals("No reply produced by handler 'Enricher', and its 'requiresReply' property is set to true.", e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
fail("ReplyRequiredException expected.");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void requestChannelSendTimingOut() {
|
||||
|
||||
|
||||
final String requestChannelName = "Request_Channel";
|
||||
final long requestTimeout = 200L;
|
||||
|
||||
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
QueueChannel requestChannel = new RendezvousChannel();
|
||||
requestChannel.setBeanName(requestChannelName);
|
||||
|
||||
|
||||
ContentEnricher enricher = new ContentEnricher();
|
||||
enricher.setRequestChannel(requestChannel);
|
||||
enricher.setRequestTimeout(requestTimeout);
|
||||
@@ -163,17 +165,17 @@ public class ContentEnricherTests {
|
||||
|
||||
Target target = new Target("replace me");
|
||||
Message<?> requestMessage = MessageBuilder.withPayload(target).setReplyChannel(replyChannel).build();
|
||||
|
||||
|
||||
try {
|
||||
enricher.handleMessage(requestMessage);
|
||||
} catch (MessageDeliveryException e) {
|
||||
assertEquals("failed to send message to channel '" + requestChannelName
|
||||
assertEquals("failed to send message to channel '" + requestChannelName
|
||||
+ "' within timeout: " + requestTimeout, e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void simpleProperty() {
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
@@ -203,52 +205,52 @@ public class ContentEnricherTests {
|
||||
|
||||
@Test
|
||||
public void setReplyChannelWithoutRequestChannel() {
|
||||
|
||||
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
|
||||
|
||||
ContentEnricher enricher = new ContentEnricher();
|
||||
enricher.setReplyChannel(replyChannel);
|
||||
|
||||
try {
|
||||
|
||||
try {
|
||||
enricher.afterPropertiesSet();
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("If the replyChannel is set, then the requestChannel must not be null", e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
fail("Expected an exception.");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void setNullReplyTimeout() {
|
||||
|
||||
|
||||
ContentEnricher enricher = new ContentEnricher();
|
||||
|
||||
|
||||
try {
|
||||
enricher.setReplyTimeout(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("replyTimeout must not be null", e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
fail("Expected an exception.");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void setNullRequestTimeout() {
|
||||
|
||||
|
||||
ContentEnricher enricher = new ContentEnricher();
|
||||
|
||||
|
||||
try {
|
||||
enricher.setRequestTimeout(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("requestTimeout must not be null", e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
fail("Expected an exception.");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimplePropertyWithoutUsingRequestChannel() {
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
@@ -257,6 +259,7 @@ public class ContentEnricherTests {
|
||||
Map<String, Expression> propertyExpressions = new HashMap<String, Expression>();
|
||||
propertyExpressions.put("name", parser.parseExpression("'just a static string'"));
|
||||
enricher.setPropertyExpressions(propertyExpressions);
|
||||
enricher.afterPropertiesSet();
|
||||
Target target = new Target("replace me");
|
||||
Message<?> requestMessage = MessageBuilder.withPayload(target).setReplyChannel(replyChannel).build();
|
||||
enricher.handleMessage(requestMessage);
|
||||
@@ -490,6 +493,7 @@ public class ContentEnricherTests {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
Target clone = new Target(this.name);
|
||||
clone.setChild(this.child);
|
||||
@@ -531,9 +535,10 @@ public class ContentEnricherTests {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
throw new IllegalStateException("Cloning not possible");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
|
||||
|
||||
<channel id="output">
|
||||
<queue/>
|
||||
@@ -21,4 +21,23 @@
|
||||
<transformer expression="null"/>
|
||||
</chain>
|
||||
|
||||
<beans:bean id="integrationEvaluationContext" class="org.springframework.integration.config.IntegrationEvaluationContextFactoryBean">
|
||||
<beans:property name="propertyAccessors">
|
||||
<util:list>
|
||||
<beans:bean class="org.springframework.integration.transformer.SpelTransformerIntegrationTests$FooAccessor"/>
|
||||
</util:list>
|
||||
</beans:property>
|
||||
<beans:property name="functions">
|
||||
<util:map>
|
||||
<beans:entry key="bar"
|
||||
value="#{T(org.springframework.integration.transformer.SpelTransformerIntegrationTests$BarFunction).getMethod('bar', T(org.springframework.integration.Message))}"/>
|
||||
</util:map>
|
||||
</beans:property>
|
||||
</beans:bean>
|
||||
|
||||
<channel id="fooin" />
|
||||
<transformer id="foo" input-channel="fooin" expression="payload.bar" />
|
||||
|
||||
<channel id="functionIn" />
|
||||
<transformer id="bar" input-channel="functionIn" expression="#bar(#root)" />
|
||||
</beans:beans>
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package org.springframework.integration.transformer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
@@ -25,14 +27,22 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.PollableChannel;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.integration.handler.ReplyRequiredException;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -54,6 +64,12 @@ public class SpelTransformerIntegrationTests {
|
||||
@Autowired
|
||||
private MessageChannel transformerChainInput;
|
||||
|
||||
@Autowired @Qualifier("foo.handler")
|
||||
private AbstractReplyProducingMessageHandler fooHandler;
|
||||
|
||||
@Autowired @Qualifier("bar.handler")
|
||||
private AbstractReplyProducingMessageHandler barHandler;
|
||||
|
||||
|
||||
@Test
|
||||
public void simple() {
|
||||
@@ -81,12 +97,90 @@ public class SpelTransformerIntegrationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomAccessor() {
|
||||
QueueChannel outputChannel = new QueueChannel();
|
||||
fooHandler.setOutputChannel(outputChannel);
|
||||
Foo foo = new Foo("baz");
|
||||
fooHandler.handleMessage(new GenericMessage<Foo>(foo));
|
||||
Message<?> reply = outputChannel.receive(0);
|
||||
assertNotNull(reply);
|
||||
assertTrue(reply.getPayload() instanceof String);
|
||||
assertEquals("baz", reply.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomFunction() {
|
||||
QueueChannel outputChannel = new QueueChannel();
|
||||
barHandler.setOutputChannel(outputChannel);
|
||||
barHandler.handleMessage(new GenericMessage<String>("foo"));
|
||||
Message<?> reply = outputChannel.receive(0);
|
||||
assertNotNull(reply);
|
||||
assertEquals("bar", reply.getPayload());
|
||||
}
|
||||
|
||||
static class TestBean {
|
||||
|
||||
public String getFoo() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Foo {
|
||||
private String bar;
|
||||
|
||||
public Foo(String bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
|
||||
public String obtainBar() {
|
||||
return bar;
|
||||
}
|
||||
|
||||
public void updateBar(String bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class FooAccessor implements PropertyAccessor {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getSpecificTargetClasses() {
|
||||
return new Class[] {Foo.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return "bar".equals(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
Assert.isInstanceOf(Foo.class, target);
|
||||
return new TypedValue(((Foo) target).obtainBar(), TypeDescriptor.valueOf(String.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return "bar".equals(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(EvaluationContext context, Object target, String name, Object newValue)
|
||||
throws AccessException {
|
||||
Assert.isInstanceOf(Foo.class, target);
|
||||
Assert.isInstanceOf(String.class, newValue);
|
||||
((Foo) target).updateBar((String) newValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class BarFunction {
|
||||
|
||||
public static String bar(Message<?> message) {
|
||||
return "bar";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user