INT-28 Initial commit of (new in 2.0) MessagePublishingInterceptor. An AOP interceptor that uses EL to construct a Message payload and then publishes it.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.aop;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that provides the variable names to use when constructing the
|
||||
* evaluation context for a MessagePublishingInterceptor.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExpressionBinding {
|
||||
|
||||
/**
|
||||
* Names of the arguments as a comma-separated list. If not provided, the
|
||||
* names will be discovered automatically if enabled by the compiler settings.
|
||||
* These names will be used as the keys in the argument Map.
|
||||
*/
|
||||
String argNames() default "";
|
||||
|
||||
/**
|
||||
* Name of the variable in the context that refers to the Map of arguments.
|
||||
* <p>The default is "args".
|
||||
*/
|
||||
String argumentMapName() default ExpressionSource.DEFAULT_ARGUMENT_MAP_NAME;
|
||||
|
||||
/**
|
||||
* Name of the variable in the context that refers to the return value, if any.
|
||||
* <p>The default is "return".
|
||||
*/
|
||||
String returnValueName() default ExpressionSource.DEFAULT_RETURN_VALUE_NAME;
|
||||
|
||||
/**
|
||||
* Name of the variable in the context that refers to any exception thrown
|
||||
* by the method invocation that is being intercepted.
|
||||
* <p>The default is "exception".
|
||||
*/
|
||||
String exceptionName() default ExpressionSource.DEFAULT_EXCEPTION_NAME;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.aop;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Strategy for determining the expression string and evaluation context
|
||||
* variable names from a Method.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
interface ExpressionSource {
|
||||
|
||||
static final String DEFAULT_ARGUMENT_MAP_NAME = "args";
|
||||
|
||||
static final String DEFAULT_RETURN_VALUE_NAME = "return";
|
||||
|
||||
static final String DEFAULT_EXCEPTION_NAME = "exception";
|
||||
|
||||
|
||||
/**
|
||||
* Returns the expression string to be evaluated.
|
||||
*/
|
||||
String getExpressionString(Method method);
|
||||
|
||||
/**
|
||||
* Returns the variable names to be associated with the intercepted method
|
||||
* invocation's argument array.
|
||||
*/
|
||||
String[] getArgumentNames(Method method);
|
||||
|
||||
/**
|
||||
* Returns the variable name to use in the evaluation context for the Map
|
||||
* of arguments. The keys in this map will be determined by the result of
|
||||
* the {@link #getArgumentNames(Method)} method.
|
||||
*/
|
||||
String getArgumentMapName(Method method);
|
||||
|
||||
/**
|
||||
* Returns the variable name to use in the evaluation context for any
|
||||
* return value resulting from the method invocation.
|
||||
*/
|
||||
String getReturnValueName(Method method);
|
||||
|
||||
/**
|
||||
* Returns the variable name to use in the evaluation context for any
|
||||
* exception thrown from the method invocation.
|
||||
*/
|
||||
String getExceptionName(Method method);
|
||||
|
||||
/**
|
||||
* Returns the channel name to which Messages should be published
|
||||
* for this particular method invocation.
|
||||
*/
|
||||
String getChannelName(Method method);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.aop;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.SpelExpressionParserFactory;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.channel.ChannelResolver;
|
||||
import org.springframework.integration.channel.MessageChannelTemplate;
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.gateway.SimpleMessageMapper;
|
||||
import org.springframework.integration.message.InboundMessageMapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link MethodInterceptor} that publishes Messages to a channel. The
|
||||
* 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 ExpressionSource.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MessagePublishingInterceptor implements MethodInterceptor {
|
||||
|
||||
private final MessageChannelTemplate channelTemplate = new MessageChannelTemplate();
|
||||
|
||||
private final ExpressionSource expressionSource;
|
||||
|
||||
private final ExpressionParser parser = SpelExpressionParserFactory.getParser();
|
||||
|
||||
private final InboundMessageMapper<Object> messageMapper = new SimpleMessageMapper();
|
||||
|
||||
private volatile ChannelResolver channelResolver;
|
||||
|
||||
|
||||
public MessagePublishingInterceptor(ExpressionSource expressionSource) {
|
||||
Assert.notNull(expressionSource, "expressionSource must not be null");
|
||||
this.expressionSource = expressionSource;
|
||||
}
|
||||
|
||||
|
||||
public void setDefaultChannel(MessageChannel defaultChannel) {
|
||||
this.channelTemplate.setDefaultChannel(defaultChannel);
|
||||
}
|
||||
|
||||
public void setChannelResolver(ChannelResolver channelResolver) {
|
||||
this.channelResolver = channelResolver;
|
||||
}
|
||||
|
||||
public final Object invoke(final MethodInvocation invocation) throws Throwable {
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
context.addPropertyAccessor(new MapAccessor());
|
||||
Class<?> targetClass = AopUtils.getTargetClass(invocation.getThis());
|
||||
Method method = AopUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
|
||||
String[] argumentNames = this.expressionSource.getArgumentNames(method);
|
||||
if (invocation.getArguments().length > 0 && argumentNames != null) {
|
||||
int index = 0;
|
||||
Map<String, Object> argumentMap = new HashMap<String, Object>();
|
||||
for (String argumentName : argumentNames) {
|
||||
if (invocation.getArguments().length <= ++index) {
|
||||
break;
|
||||
}
|
||||
argumentMap.put(argumentName, invocation.getArguments()[index]);
|
||||
}
|
||||
context.setVariable(this.expressionSource.getArgumentMapName(method), argumentMap);
|
||||
}
|
||||
try {
|
||||
Object returnValue = invocation.proceed();
|
||||
context.setVariable(this.expressionSource.getReturnValueName(method), returnValue);
|
||||
return returnValue;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
context.setVariable(this.expressionSource.getExceptionName(method), t);
|
||||
throw t;
|
||||
}
|
||||
finally {
|
||||
publishMessage(method, context);
|
||||
}
|
||||
}
|
||||
|
||||
private void publishMessage(Method method, EvaluationContext context) throws Exception {
|
||||
String expressionString = this.expressionSource.getExpressionString(method);
|
||||
if (expressionString != null) {
|
||||
Expression expression = this.parser.parseExpression(expressionString);
|
||||
Object result = expression.getValue(context);
|
||||
if (result != null) {
|
||||
Message<?> message = this.messageMapper.toMessage(result);
|
||||
String channelName = this.expressionSource.getChannelName(method);
|
||||
MessageChannel channel = null;
|
||||
if (channelName != null) {
|
||||
Assert.state(this.channelResolver != null, "ChannelResolver is required to resolve channel names.");
|
||||
channel = this.channelResolver.resolveChannelName(channelName);
|
||||
}
|
||||
if (channel != null) {
|
||||
this.channelTemplate.send(message, channel);
|
||||
}
|
||||
else {
|
||||
this.channelTemplate.send(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.aop;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* An {@link ExpressionSource} implementation that retrieves the expression
|
||||
* string and evaluation context variable names from an annotation.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MethodAnnotationExpressionSource implements ExpressionSource {
|
||||
|
||||
private final Set<Class<? extends Annotation>> annotationTypes;
|
||||
|
||||
private volatile String channelAttributeName = "channel";
|
||||
|
||||
private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
|
||||
public MethodAnnotationExpressionSource() {
|
||||
this(Collections.<Class<? extends Annotation>>singleton(Publisher.class));
|
||||
}
|
||||
|
||||
public MethodAnnotationExpressionSource(Set<Class<? extends Annotation>> annotationTypes) {
|
||||
Assert.notEmpty(annotationTypes, "annotationTypes must not be empty");
|
||||
this.annotationTypes = annotationTypes;
|
||||
}
|
||||
|
||||
|
||||
public void setChannelAttributeName(String channelAttributeName) {
|
||||
Assert.hasText(channelAttributeName, "channelAttributeName must not be empty");
|
||||
this.channelAttributeName = channelAttributeName;
|
||||
}
|
||||
|
||||
public String getExpressionString(Method method) {
|
||||
return this.getAnnotationValue(method, null, String.class);
|
||||
}
|
||||
|
||||
public String[] getArgumentNames(Method method) {
|
||||
ExpressionBinding annotation = AnnotationUtils.findAnnotation(method, ExpressionBinding.class);
|
||||
if (annotation != null) {
|
||||
String name = annotation.argNames();
|
||||
if (StringUtils.hasText(name)) {
|
||||
return StringUtils.tokenizeToStringArray(name, ",");
|
||||
}
|
||||
}
|
||||
return this.parameterNameDiscoverer.getParameterNames(method);
|
||||
}
|
||||
|
||||
public String getArgumentMapName(Method method) {
|
||||
ExpressionBinding annotation = AnnotationUtils.findAnnotation(method, ExpressionBinding.class);
|
||||
if (annotation != null) {
|
||||
return annotation.argumentMapName();
|
||||
}
|
||||
return ExpressionSource.DEFAULT_ARGUMENT_MAP_NAME;
|
||||
}
|
||||
|
||||
public String getReturnValueName(Method method) {
|
||||
ExpressionBinding annotation = AnnotationUtils.findAnnotation(method, ExpressionBinding.class);
|
||||
if (annotation != null) {
|
||||
return annotation.returnValueName();
|
||||
}
|
||||
return ExpressionSource.DEFAULT_RETURN_VALUE_NAME;
|
||||
}
|
||||
|
||||
public String getExceptionName(Method method) {
|
||||
ExpressionBinding annotation = AnnotationUtils.findAnnotation(method, ExpressionBinding.class);
|
||||
if (annotation != null) {
|
||||
return annotation.exceptionName();
|
||||
}
|
||||
return ExpressionSource.DEFAULT_EXCEPTION_NAME;
|
||||
}
|
||||
|
||||
public String getChannelName(Method method) {
|
||||
String channelName = this.getAnnotationValue(method, this.channelAttributeName, String.class);
|
||||
return (StringUtils.hasText(channelName) ? channelName : null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T getAnnotationValue(Method method, String attributeName, Class<T> expectedType) {
|
||||
T value = null;
|
||||
for (Class<? extends Annotation> annotationType : this.annotationTypes) {
|
||||
Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType);
|
||||
if (annotation != null) {
|
||||
if (value != null) {
|
||||
throw new IllegalStateException(
|
||||
"method [" + method + "] contains more than one publisher annotation");
|
||||
}
|
||||
Object valueAsObject = (attributeName == null) ? AnnotationUtils.getValue(annotation)
|
||||
: AnnotationUtils.getValue(annotation, attributeName);
|
||||
if (valueAsObject != null) {
|
||||
if (expectedType.isAssignableFrom(valueAsObject.getClass())) {
|
||||
value = (T) valueAsObject;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("expected type [" + expectedType.getName() +
|
||||
"] for attribute '" + attributeName + "' on publisher annotation [" +
|
||||
annotationType + "], but actual type was [" + valueAsObject.getClass() + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.aop;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to indicate that a method, or all public methods if applied at
|
||||
* class-level, should publish Messages whose payloads will be determined by
|
||||
* the provided EL expression.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Publisher {
|
||||
|
||||
/**
|
||||
* String representation of a Spel Expression. Required.
|
||||
*/
|
||||
String value();
|
||||
|
||||
/**
|
||||
* Name of the Message Channel to which Messages will be published.
|
||||
*/
|
||||
String channel() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.aop;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractPointcutAdvisor;
|
||||
import org.springframework.aop.support.ComposablePointcut;
|
||||
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.integration.channel.BeanFactoryChannelResolver;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
|
||||
/**
|
||||
* An advisor that will apply the {@link MessagePublishingInterceptor} to any
|
||||
* methods containing the provided annotations. If no annotations are provided,
|
||||
* the default will be {@link Publisher @Publisher}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class PublisherAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
|
||||
|
||||
private final Set<Class<? extends Annotation>> publisherAnnotationTypes;
|
||||
|
||||
private final MessagePublishingInterceptor interceptor;
|
||||
|
||||
|
||||
public PublisherAnnotationAdvisor(Class<? extends Annotation> ... publisherAnnotationTypes) {
|
||||
this.publisherAnnotationTypes = new HashSet<Class<? extends Annotation>>(Arrays.asList(publisherAnnotationTypes));
|
||||
ExpressionSource source = new MethodAnnotationExpressionSource(this.publisherAnnotationTypes);
|
||||
this.interceptor = new MessagePublishingInterceptor(source);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public PublisherAnnotationAdvisor() {
|
||||
this(Publisher.class);
|
||||
}
|
||||
|
||||
|
||||
public void setDefaultChannel(MessageChannel defaultChannel) {
|
||||
this.interceptor.setDefaultChannel(defaultChannel);
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.interceptor.setChannelResolver(new BeanFactoryChannelResolver(beanFactory));
|
||||
}
|
||||
|
||||
public Advice getAdvice() {
|
||||
return this.interceptor;
|
||||
}
|
||||
|
||||
public Pointcut getPointcut() {
|
||||
return this.buildPointcut();
|
||||
}
|
||||
|
||||
private Pointcut buildPointcut() {
|
||||
ComposablePointcut result = null;
|
||||
for (Class<? extends Annotation> publisherAnnotationType : this.publisherAnnotationTypes) {
|
||||
Pointcut cpc = new AnnotationMatchingPointcut(publisherAnnotationType, true);
|
||||
Pointcut mpc = new AnnotationMatchingPointcut(null, publisherAnnotationType);
|
||||
if (result == null) {
|
||||
result = new ComposablePointcut(cpc).union(mpc);
|
||||
}
|
||||
else {
|
||||
result.union(cpc).union(mpc);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.aop;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.integration.channel.MapBasedChannelResolver;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.Message;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MessagePublishingInterceptorTests {
|
||||
|
||||
private final ExpressionSource source = new TestExpressionSource();
|
||||
|
||||
private final MapBasedChannelResolver channelResolver = new MapBasedChannelResolver();
|
||||
|
||||
private final QueueChannel testChannel = new QueueChannel();
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
channelResolver.setChannelMap(Collections.singletonMap("c", testChannel));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnValue() {
|
||||
MessagePublishingInterceptor interceptor = new MessagePublishingInterceptor(source);
|
||||
interceptor.setChannelResolver(channelResolver);
|
||||
ProxyFactory pf = new ProxyFactory(new TestBeanImpl());
|
||||
pf.addAdvice(interceptor);
|
||||
TestBean proxy = (TestBean) pf.getProxy();
|
||||
proxy.test();
|
||||
Message<?> message = testChannel.receive(0);
|
||||
assertNotNull(message);
|
||||
assertEquals("foo", message.getPayload());
|
||||
}
|
||||
|
||||
|
||||
static interface TestBean {
|
||||
|
||||
String test();
|
||||
|
||||
}
|
||||
|
||||
|
||||
static class TestBeanImpl implements TestBean {
|
||||
|
||||
public String test() {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class TestExpressionSource implements ExpressionSource {
|
||||
|
||||
public String getArgumentMapName(Method method) {
|
||||
return "m";
|
||||
}
|
||||
|
||||
public String[] getArgumentNames(Method method) {
|
||||
return new String[] { "a1", "a2" };
|
||||
}
|
||||
|
||||
public String getChannelName(Method method) {
|
||||
return "c";
|
||||
}
|
||||
|
||||
public String getExceptionName(Method method) {
|
||||
return "x";
|
||||
}
|
||||
|
||||
public String getExpressionString(Method method) {
|
||||
return "#r";
|
||||
}
|
||||
|
||||
public String getReturnValueName(Method method) {
|
||||
return "r";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.aop;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MethodAnnotationExpressionSourceTests {
|
||||
|
||||
private final MethodAnnotationExpressionSource source = new MethodAnnotationExpressionSource();
|
||||
|
||||
@Test
|
||||
public void defaultBindings() {
|
||||
Method method = getMethod("methodWithExpressionAnnotationOnly", String.class, int.class);
|
||||
String expressionString = source.getExpressionString(method);
|
||||
assertEquals("testExpression1", expressionString);
|
||||
assertEquals(2, source.getArgumentNames(method).length);
|
||||
assertEquals("arg1", source.getArgumentNames(method)[0]);
|
||||
assertEquals("arg2", source.getArgumentNames(method)[1]);
|
||||
assertEquals(ExpressionSource.DEFAULT_ARGUMENT_MAP_NAME, source.getArgumentMapName(method));
|
||||
assertEquals(ExpressionSource.DEFAULT_EXCEPTION_NAME, source.getExceptionName(method));
|
||||
assertEquals(ExpressionSource.DEFAULT_RETURN_VALUE_NAME, source.getReturnValueName(method));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void annotationBindings() {
|
||||
Method method = getMethod("methodWithExpressionBinding", String.class, int.class);
|
||||
String expressionString = source.getExpressionString(method);
|
||||
assertEquals("testExpression2", expressionString);
|
||||
assertEquals(2, source.getArgumentNames(method).length);
|
||||
assertEquals("s", source.getArgumentNames(method)[0]);
|
||||
assertEquals("i", source.getArgumentNames(method)[1]);
|
||||
assertEquals("argz", source.getArgumentMapName(method));
|
||||
assertEquals("x", source.getExceptionName(method));
|
||||
assertEquals("result", source.getReturnValueName(method));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void channelName() {
|
||||
Method method = getMethod("methodWithChannelAndReturnAsPayload");
|
||||
String channelName = source.getChannelName(method);
|
||||
assertEquals("foo", channelName);
|
||||
}
|
||||
|
||||
|
||||
private static Method getMethod(String name, Class<?> ... params) {
|
||||
try {
|
||||
return MethodAnnotationExpressionSourceTests.class.getMethod(name, params);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("failed to resolve method", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Publisher("testExpression1")
|
||||
public void methodWithExpressionAnnotationOnly(String arg1, int arg2) {
|
||||
}
|
||||
|
||||
@Publisher(value="#return", channel="foo")
|
||||
public void methodWithChannelAndReturnAsPayload() {
|
||||
}
|
||||
|
||||
@Publisher("testExpression2")
|
||||
@ExpressionBinding(argNames="s, i", argumentMapName="argz", exceptionName="x", returnValueName="result")
|
||||
public void methodWithExpressionBinding(String arg1, int arg2) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.aop;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.Message;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PublisherAnnotationAdvisorTests {
|
||||
|
||||
private final StaticApplicationContext context = new StaticApplicationContext();
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
context.registerSingleton("testChannel", QueueChannel.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnValue() {
|
||||
PublisherAnnotationAdvisor advisor = new PublisherAnnotationAdvisor();
|
||||
advisor.setBeanFactory(context);
|
||||
QueueChannel testChannel = context.getBean("testChannel", QueueChannel.class);
|
||||
advisor.setDefaultChannel(testChannel);
|
||||
ProxyFactory pf = new ProxyFactory(new TestBeanImpl());
|
||||
pf.addAdvisor(advisor);
|
||||
TestBean proxy = (TestBean) pf.getProxy();
|
||||
proxy.test();
|
||||
Message<?> message = testChannel.receive(0);
|
||||
assertNotNull(message);
|
||||
assertEquals("foo", message.getPayload());
|
||||
}
|
||||
|
||||
|
||||
static interface TestBean {
|
||||
|
||||
String test();
|
||||
|
||||
}
|
||||
|
||||
|
||||
static class TestBeanImpl implements TestBean {
|
||||
|
||||
@Publisher("#return")
|
||||
public String test() {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user