diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/AbstractConsumerFactoryBean.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/AbstractConsumerFactoryBean.java new file mode 100644 index 0000000000..91707c43d6 --- /dev/null +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/AbstractConsumerFactoryBean.java @@ -0,0 +1,95 @@ +/* + * 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.config; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.integration.channel.MessageChannel; +import org.springframework.integration.endpoint.AbstractReplyProducingMessageConsumer; +import org.springframework.integration.message.MessageConsumer; +import org.springframework.util.Assert; + +/** + * Base class for FactoryBeans that create MessageConsumer instances. + * + * @author Mark Fisher + */ +public abstract class AbstractConsumerFactoryBean implements FactoryBean { + + private volatile MessageConsumer consumer; + + private volatile Object targetObject; + + private volatile String targetMethodName; + + private volatile MessageChannel outputChannel; + + private volatile boolean initialized; + + private final Object initializationMonitor = new Object(); + + + public void setTargetObject(Object targetObject) { + this.targetObject = targetObject; + } + + public void setTargetMethodName(String targetMethodName) { + this.targetMethodName = targetMethodName; + } + + public void setOutputChannel(MessageChannel outputChannel) { + this.outputChannel = outputChannel; + } + + public Object getObject() throws Exception { + if (this.consumer == null) { + this.initializeConsumer(); + Assert.notNull(this.consumer, "failed to create MessageConsumer"); + if (this.outputChannel != null + && this.consumer instanceof AbstractReplyProducingMessageConsumer) { + ((AbstractReplyProducingMessageConsumer) this.consumer).setOutputChannel(this.outputChannel); + } + } + return this.consumer; + } + + public Class getObjectType() { + if (this.consumer != null) { + return this.consumer.getClass(); + } + return MessageConsumer.class; + } + + public boolean isSingleton() { + return true; + } + + private void initializeConsumer() { + synchronized (this.initializationMonitor) { + if (this.initialized) { + return; + } + this.consumer = this.createConsumer(this.targetObject, this.targetMethodName); + this.initialized = true; + } + } + + /** + * Subclasses must implement this method to create the MessageConsumer. + */ + protected abstract MessageConsumer createConsumer(Object targetObject, String targetMethodName); + +} diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java new file mode 100644 index 0000000000..48e62049b8 --- /dev/null +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java @@ -0,0 +1,48 @@ +/* + * 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.config; + +import org.springframework.integration.message.MessageConsumer; +import org.springframework.integration.splitter.AbstractMessageSplitter; +import org.springframework.integration.splitter.DefaultMessageSplitter; +import org.springframework.integration.splitter.MethodInvokingSplitter; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Factory bean for creating a Message Splitter. + * + * @author Mark Fisher + */ +public class SplitterFactoryBean extends AbstractConsumerFactoryBean { + + @Override + protected MessageConsumer createConsumer(Object targetObject, String targetMethodName) { + if (targetObject == null) { + Assert.isTrue(!StringUtils.hasText(targetMethodName), + "'method' should only be provided when 'ref' is also provided"); + return new DefaultMessageSplitter(); + } + if (targetObject instanceof AbstractMessageSplitter) { + return (AbstractMessageSplitter) targetObject; + } + return (StringUtils.hasText(targetMethodName)) + ? new MethodInvokingSplitter(targetObject, targetMethodName) + : new MethodInvokingSplitter(targetObject); + } + +} diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/SplitterParser.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/SplitterParser.java index 89f0a79073..a5277c4ab9 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/config/SplitterParser.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/SplitterParser.java @@ -20,8 +20,6 @@ import org.w3c.dom.Element; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.integration.splitter.DefaultMessageSplitter; -import org.springframework.integration.splitter.MethodInvokingSplitter; import org.springframework.util.StringUtils; /** @@ -33,17 +31,16 @@ public class SplitterParser extends AbstractConsumerEndpointParser { @Override protected BeanDefinitionBuilder parseConsumer(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SplitterFactoryBean.class); if (element.hasAttribute(REF_ATTRIBUTE)) { String ref = element.getAttribute(REF_ATTRIBUTE); - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MethodInvokingSplitter.class); - builder.addConstructorArgReference(ref); + builder.addPropertyReference("targetObject", ref); if (StringUtils.hasText(element.getAttribute(METHOD_ATTRIBUTE))) { String method = element.getAttribute(METHOD_ATTRIBUTE); - builder.addConstructorArgValue(method); + builder.addPropertyValue("targetMethodName", method); } - return builder; } - return BeanDefinitionBuilder.genericBeanDefinition(DefaultMessageSplitter.class); + return builder; } } diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/router/config/SplitterParserTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/router/config/SplitterParserTests.java index 2c2f6fcd94..c328c9d658 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/router/config/SplitterParserTests.java +++ b/org.springframework.integration/src/test/java/org/springframework/integration/router/config/SplitterParserTests.java @@ -33,22 +33,60 @@ import org.springframework.integration.message.StringMessage; public class SplitterParserTests { @Test - public void testSplitter() { + public void splitterAdapterWithRefAndMethod() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "splitterParserTests.xml", this.getClass()); context.start(); - MessageChannel channel1 = (MessageChannel) context.getBean("channel1"); - PollableChannel channel2 = (PollableChannel) context.getBean("channel2"); - channel1.send(new StringMessage("this.is.a.test")); - Message result1 = channel2.receive(1000); + MessageChannel input = (MessageChannel) context.getBean("splitterAdapterWithRefAndMethodInput"); + PollableChannel output = (PollableChannel) context.getBean("output"); + input.send(new StringMessage("this.is.a.test")); + Message result1 = output.receive(1000); assertEquals("this", result1.getPayload()); - Message result2 = channel2.receive(1000); + Message result2 = output.receive(1000); assertEquals("is", result2.getPayload()); - Message result3 = channel2.receive(1000); + Message result3 = output.receive(1000); assertEquals("a", result3.getPayload()); - Message result4 = channel2.receive(1000); + Message result4 = output.receive(1000); assertEquals("test", result4.getPayload()); - assertNull(channel2.receive(0)); + assertNull(output.receive(0)); + } + + @Test + public void splitterAdapterWithRefOnly() { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "splitterParserTests.xml", this.getClass()); + context.start(); + MessageChannel input = (MessageChannel) context.getBean("splitterAdapterWithRefOnlyInput"); + PollableChannel output = (PollableChannel) context.getBean("output"); + input.send(new StringMessage("this.is.a.test")); + Message result1 = output.receive(1000); + assertEquals("this", result1.getPayload()); + Message result2 = output.receive(1000); + assertEquals("is", result2.getPayload()); + Message result3 = output.receive(1000); + assertEquals("a", result3.getPayload()); + Message result4 = output.receive(1000); + assertEquals("test", result4.getPayload()); + assertNull(output.receive(0)); + } + + @Test + public void splitterImplementation() { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "splitterParserTests.xml", this.getClass()); + context.start(); + MessageChannel input = (MessageChannel) context.getBean("splitterImplementationInput"); + PollableChannel output = (PollableChannel) context.getBean("output"); + input.send(new StringMessage("this.is.a.test")); + Message result1 = output.receive(1000); + assertEquals("this", result1.getPayload()); + Message result2 = output.receive(1000); + assertEquals("is", result2.getPayload()); + Message result3 = output.receive(1000); + assertEquals("a", result3.getPayload()); + Message result4 = output.receive(1000); + assertEquals("test", result4.getPayload()); + assertNull(output.receive(0)); } } diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/router/config/TestSplitter.java b/org.springframework.integration/src/test/java/org/springframework/integration/router/config/TestSplitterBean.java similarity index 96% rename from org.springframework.integration/src/test/java/org/springframework/integration/router/config/TestSplitter.java rename to org.springframework.integration/src/test/java/org/springframework/integration/router/config/TestSplitterBean.java index c8d004e255..a9ec4e943c 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/router/config/TestSplitter.java +++ b/org.springframework.integration/src/test/java/org/springframework/integration/router/config/TestSplitterBean.java @@ -19,7 +19,7 @@ package org.springframework.integration.router.config; /** * @author Mark Fisher */ -public class TestSplitter { +public class TestSplitterBean { public String[] split(String input) { return input.split("\\."); diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/router/config/TestSplitterImpl.java b/org.springframework.integration/src/test/java/org/springframework/integration/router/config/TestSplitterImpl.java new file mode 100644 index 0000000000..501b55733a --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/router/config/TestSplitterImpl.java @@ -0,0 +1,33 @@ +/* + * 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.router.config; + +import org.springframework.integration.message.Message; +import org.springframework.integration.splitter.AbstractMessageSplitter; + +/** + * @author Mark Fisher + */ +public class TestSplitterImpl extends AbstractMessageSplitter { + + + @Override + protected Object splitMessage(Message message) { + return message.getPayload().toString().split("\\."); + } + +} diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/router/config/splitterParserTests.xml b/org.springframework.integration/src/test/java/org/springframework/integration/router/config/splitterParserTests.xml index 308d6151b8..bbd4ddd42a 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/router/config/splitterParserTests.xml +++ b/org.springframework.integration/src/test/java/org/springframework/integration/router/config/splitterParserTests.xml @@ -9,15 +9,28 @@ - - - - + + - + - + + + + + + +