From 1d57b284ebfc6d311bddd80e698971efaf48938c Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Fri, 9 Oct 2009 00:04:31 +0000 Subject: [PATCH] INT-814, INT-839 Added PublisherAnnotationBeanPostProcessor, added tests for documenting usage of @Publisher annotation and AOP-based MessagePublisherInterceptor --- .../PublisherAnnotationBeanPostProcessor.java | 108 ++++++++++++++++++ ...ePublishingAnnotationUsageTest-context.xml | 19 +++ .../MessagePublishingAnnotationUsageTest.java | 56 +++++++++ .../MessagePublishingInterceptorTests.java | 32 +++++- ...PublishingInterceptorUsageTest-context.xml | 55 +++++++++ ...MessagePublishingInterceptorUsageTest.java | 56 +++++++++ 6 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 org.springframework.integration/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java create mode 100644 org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTest-context.xml create mode 100644 org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTest.java create mode 100644 org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorUsageTest-context.xml create mode 100644 org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorUsageTest.java diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java b/org.springframework.integration/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java new file mode 100644 index 0000000000..503dd5dce9 --- /dev/null +++ b/org.springframework.integration/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2008 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 org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.integration.core.MessageChannel; + +/** + * Will post process beans that contain @{@link Publisher} annotation. + * + * @author Oleg Zhurakousky + * @since 2.0 + * + */ +public class PublisherAnnotationBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware, InitializingBean { + + private BeanFactory beanFactory; + private MessageChannel defaultChannel; + private PublisherAnnotationAdvisor advisor; + /** + * + */ + public PublisherAnnotationBeanPostProcessor(){} + /** + * + * @param defaultChannel + */ + public PublisherAnnotationBeanPostProcessor(MessageChannel defaultChannel){ + this.defaultChannel = defaultChannel; + } + /** + * + */ + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + if (this.containsPublisherAnnotations(bean)){ + ProxyFactory pf = new ProxyFactory(bean); + pf.addAdvisor(advisor); + bean = pf.getProxy(); + } + return bean; + } + /** + * + */ + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + /** + * + * @return + */ + public BeanFactory getBeanFactory() { + return beanFactory; + } + /** + * + */ + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + /** + * + */ + public void afterPropertiesSet(){ + advisor = new PublisherAnnotationAdvisor(); + advisor.setBeanFactory(beanFactory); + advisor.setDefaultChannel(defaultChannel); + } + /** + * + * @param bean + * @return + */ + private boolean containsPublisherAnnotations(Object bean){ + Method[] methods = bean.getClass().getMethods(); + for (Method method : methods) { + Annotation publisher = AnnotationUtils.findAnnotation(method, Publisher.class); + if (publisher != null){ + return true; + } + } + return false; + } +} diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTest-context.xml b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTest-context.xml new file mode 100644 index 0000000000..9deece9d0c --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTest-context.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTest.java b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTest.java new file mode 100644 index 0000000000..52abdf2058 --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2008 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 junit.framework.Assert; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.core.Message; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Oleg Zhurakousky + * @since 2.0 + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class MessagePublishingAnnotationUsageTest { + @Autowired + private TestBean testBean; + @Autowired + private QueueChannel channel; + @Test + public void demoMessagePublishingInterceptor(){ + String name = testBean.setName("John", "Doe"); + Assert.assertNotNull(name); + Message message = channel.receive(); + Assert.assertNotNull(message); + Assert.assertEquals("John Doe", message.getPayload()); + Assert.assertEquals("123", message.getHeaders().get("bar")); + } + + + public static class TestBean{ + @Publisher(value="#return", channel="testChannel", headers="bar='123'") + public String setName(String fname, String lname){ + return fname + " " + lname; + } + } +} diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorTests.java index 685335ec62..c07dfcf921 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorTests.java +++ b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorTests.java @@ -21,6 +21,8 @@ import static org.junit.Assert.assertNotNull; import java.lang.reflect.Method; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.junit.Before; import org.junit.Test; @@ -32,6 +34,7 @@ import org.springframework.integration.core.Message; /** * @author Mark Fisher + * @author Oleg Zhurakousky * @since 2.0 */ public class MessagePublishingInterceptorTests { @@ -60,6 +63,32 @@ public class MessagePublishingInterceptorTests { assertNotNull(message); assertEquals("foo", message.getPayload()); } + @Test + public void demoMethodNameMappingExpressionSource() { + Map expressionMap = new HashMap(); + expressionMap.put("test", "#return"); + MethodNameMappingExpressionSource source = new MethodNameMappingExpressionSource(expressionMap); + Map channelMap = new HashMap(); + channelMap.put("test", "c"); + source.setChannelMap(channelMap); + + Map headerExpressionMap = new HashMap(); + headerExpressionMap.put("test", new String[]{"bar=#return","name='oleg'"}); + source.setHeaderExpressionMap(headerExpressionMap); + + + 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()); + assertEquals("foo", message.getHeaders().get("bar")); + assertEquals("oleg", message.getHeaders().get("name")); + } static interface TestBean { @@ -77,7 +106,6 @@ public class MessagePublishingInterceptorTests { } - private static class TestExpressionSource implements ExpressionSource { public String getArgumentMapName(Method method) { @@ -85,7 +113,7 @@ public class MessagePublishingInterceptorTests { } public String[] getArgumentNames(Method method) { - return new String[] { "a1", "a2" }; + return new String[] { "a1", "a2"}; } public String getReturnValueName(Method method) { diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorUsageTest-context.xml b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorUsageTest-context.xml new file mode 100644 index 0000000000..e8b36ef8de --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorUsageTest-context.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorUsageTest.java b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorUsageTest.java new file mode 100644 index 0000000000..9d921dca00 --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/aop/MessagePublishingInterceptorUsageTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2008 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 junit.framework.Assert; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.core.Message; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Oleg Zhurakousky + * @since 2.0 + * + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class MessagePublishingInterceptorUsageTest { + @Autowired + private TestBean testBean; + @Autowired + private QueueChannel channel; + @Test + public void demoMessagePublishingInterceptor(){ + String name = testBean.setName("John", "Doe"); + Assert.assertNotNull(name); + Message message = channel.receive(); + Assert.assertNotNull(message); + Assert.assertEquals("John Doe", message.getPayload()); + Assert.assertEquals("bar", message.getHeaders().get("foo")); + } + + + public static class TestBean{ + public String setName(String fname, String lname){ + return fname + " " + lname; + } + } +}