diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/AbstractInnerDefinitionAwareEndpointParser.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/AbstractInnerDefinitionAwareEndpointParser.java
new file mode 100644
index 0000000000..e5a2d1052d
--- /dev/null
+++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/AbstractInnerDefinitionAwareEndpointParser.java
@@ -0,0 +1,68 @@
+/*
+ * 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.config.xml;
+
+import java.util.List;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+import org.springframework.util.xml.DomUtils;
+import org.w3c.dom.Element;
+/**
+ * Abstract Parser for any consumers that require capabilities to define
+ * its handler implementation as inner bean.
+ * For example:
+ *
+ * <transformer id="testTransformer" input-channel="inChannel" output-channel="outChannel">
+ * <beans:bean class="org.bar.TestTransformer"/>
+ * </transformer>
+ *
+ *
+ * @author Oleg Zhurakousky
+ * @since 1.0.3
+ */
+public abstract class AbstractInnerDefinitionAwareEndpointParser extends AbstractConsumerEndpointParser {
+
+ @Override
+ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
+ // parses out inner bean definition for concrete implementation if defined
+ List childElements = DomUtils.getChildElementsByTagName(element, "bean");
+ BeanDefinition innerDefinition = null;
+ if (childElements != null && childElements.size() == 1){
+ Element beanElement = childElements.get(0);
+ BeanDefinitionParserDelegate delegate = parserContext.getDelegate();
+ innerDefinition = delegate.parseBeanDefinitionElement(beanElement).getBeanDefinition();
+ }
+
+ String ref = element.getAttribute(REF_ATTRIBUTE);
+ Assert.isTrue(!(StringUtils.hasText(ref) && innerDefinition != null), "Ambiguous definition. Inner bean " +
+ (innerDefinition == null ? innerDefinition : innerDefinition.getBeanClassName()) + " declaration and \"ref\" " + ref +
+ " are not allowed together.");
+ return this.parseEndpoint(element, parserContext, innerDefinition);
+ }
+ /**
+ *
+ * @param element
+ * @param parserContext
+ * @param innerDefinition
+ * @return
+ */
+ protected abstract BeanDefinitionBuilder parseEndpoint(Element element, ParserContext parserContext, BeanDefinition innerDefinition);
+}
diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/SplitterParser.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/SplitterParser.java
index e545260727..e6ee0d38cd 100644
--- a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/SplitterParser.java
+++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/SplitterParser.java
@@ -18,6 +18,7 @@ package org.springframework.integration.config.xml;
import org.w3c.dom.Element;
+import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
@@ -26,14 +27,17 @@ import org.springframework.util.StringUtils;
* Parser for the <splitter/> element.
*
* @author Mark Fisher
+ * @author Oleg Zhurakousky
*/
-public class SplitterParser extends AbstractConsumerEndpointParser {
+public class SplitterParser extends AbstractInnerDefinitionAwareEndpointParser {
@Override
- protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
+ protected BeanDefinitionBuilder parseEndpoint(Element element, ParserContext parserContext, BeanDefinition innerDefinition) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".config.SplitterFactoryBean");
- if (element.hasAttribute(REF_ATTRIBUTE)) {
+ if (innerDefinition != null){
+ builder.addPropertyValue("targetObject", innerDefinition);
+ } else if (element.hasAttribute(REF_ATTRIBUTE)) {
String ref = element.getAttribute(REF_ATTRIBUTE);
builder.addPropertyReference("targetObject", ref);
if (StringUtils.hasText(element.getAttribute(METHOD_ATTRIBUTE))) {
diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/TransformerParser.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/TransformerParser.java
index 7758f98299..cc98b85c7b 100644
--- a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/TransformerParser.java
+++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/TransformerParser.java
@@ -16,34 +16,41 @@
package org.springframework.integration.config.xml;
-import org.w3c.dom.Element;
-
+import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
/**
* Parser for the <transformer/> element.
*
* @author Mark Fisher
+ * @author Oleg Zhurakousky
*/
-public class TransformerParser extends AbstractConsumerEndpointParser {
+public class TransformerParser extends AbstractInnerDefinitionAwareEndpointParser {
@Override
- protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
+ protected BeanDefinitionBuilder parseEndpoint(Element element, ParserContext parserContext, BeanDefinition innerDefinition) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".config.TransformerFactoryBean");
- String ref = element.getAttribute(REF_ATTRIBUTE);
- if (!StringUtils.hasText(ref)) {
- parserContext.getReaderContext().error("The 'ref' attribute is required.", element);
- return null;
- }
- builder.addPropertyReference("targetObject", ref);
+
+ if (innerDefinition != null){
+ builder.addPropertyValue("targetObject", innerDefinition);
+ } else {
+ String ref = element.getAttribute(REF_ATTRIBUTE);
+ if (!StringUtils.hasText(ref)) {
+ parserContext.getReaderContext().error("Either \"ref\" attribute or inner bean () definition of concrete implementation of " +
+ "this Transformer is required.", element);
+ return null;
+ }
+ builder.addPropertyReference("targetObject", ref);
+ }
+
String method = element.getAttribute(METHOD_ATTRIBUTE);
if (StringUtils.hasText(method)) {
builder.addPropertyValue("targetMethodName", method);
}
return builder;
}
-
}
diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd
index 45705168a9..a7367127fa 100644
--- a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd
+++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd
@@ -82,7 +82,8 @@
specified, it will be a
bounded queue.
- A custom Queue implementation can be
+ A custom Queue implementation
+ can be
injected using the 'ref' attribute.
@@ -776,7 +777,7 @@
-
+
Defines a Transformer.
@@ -843,12 +844,12 @@
-
+
-
-
-
+
+
+
@@ -873,12 +874,12 @@
-
+
-
-
-
+
+
+
@@ -900,12 +901,12 @@
-
+
-
+
@@ -924,14 +925,15 @@
-
-
-
+
+
+
-
+
Defines a Splitter.
@@ -1010,7 +1012,8 @@
-
+
@@ -1164,4 +1167,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/InnerDefinitionAwareEndpointParserTests-context.xml b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/InnerDefinitionAwareEndpointParserTests-context.xml
new file mode 100644
index 0000000000..2ddb3cd25a
--- /dev/null
+++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/InnerDefinitionAwareEndpointParserTests-context.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/InnerDefinitionAwareEndpointParserTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/InnerDefinitionAwareEndpointParserTests.java
new file mode 100644
index 0000000000..d371aceb4d
--- /dev/null
+++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/InnerDefinitionAwareEndpointParserTests.java
@@ -0,0 +1,140 @@
+/*
+ * 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.config.xml;
+
+import java.io.ByteArrayInputStream;
+import java.util.Collection;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
+import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.integration.channel.DirectChannel;
+import org.springframework.integration.channel.PollableChannel;
+import org.springframework.integration.core.Message;
+import org.springframework.integration.endpoint.EventDrivenConsumer;
+import org.springframework.integration.message.MessageBuilder;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+/**
+ *
+ * @author Oleg Zhurakousky
+ *
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+public class InnerDefinitionAwareEndpointParserTests {
+
+ @Autowired
+ private Properties testConfigurations;
+
+ @Test
+ public void testInnerSplitterDefinitionSuccess(){
+ String configProperty = testConfigurations.getProperty("splitter-inner-success");
+ this.testSplitterDefinitionSuccess(configProperty);
+ }
+ @Test
+ public void testRefSplitterDefinitionSuccess(){
+ String configProperty = testConfigurations.getProperty("splitter-ref-success");
+ this.testSplitterDefinitionSuccess(configProperty);
+ }
+ @Test(expected=BeanDefinitionStoreException.class)
+ public void testInnerSplitterDefinitionFailureRefAndInner(){
+ String xmlConfig = testConfigurations.getProperty("splitter-failure-refAndBean");
+ ByteArrayInputStream stream = new ByteArrayInputStream(xmlConfig.getBytes());
+ GenericApplicationContext ac = new GenericApplicationContext();
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(ac);
+ reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
+ reader.loadBeanDefinitions(new InputStreamResource(stream));
+ }
+
+ @Test
+ public void testInnerTransformerDefinitionSuccess(){
+ String configProperty = testConfigurations.getProperty("transformer-inner-success");
+ this.testTransformerDefinitionSuccess(configProperty);
+ }
+ @Test
+ public void testRefTransformerDefinitionSuccess(){
+ String configProperty = testConfigurations.getProperty("transformer-ref-success");
+ this.testTransformerDefinitionSuccess(configProperty);
+ }
+
+ @Test(expected=BeanDefinitionStoreException.class)
+ public void testInnerTransformerDefinitionFailureRefAndInner(){
+ String xmlConfig = testConfigurations.getProperty("transformer-failure-refAndBean");
+ ByteArrayInputStream stream = new ByteArrayInputStream(xmlConfig.getBytes());
+ GenericApplicationContext ac = new GenericApplicationContext();
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(ac);
+ reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
+ reader.loadBeanDefinitions(new InputStreamResource(stream));
+ }
+
+ private void testSplitterDefinitionSuccess(String configProperty){
+ ByteArrayInputStream stream = new ByteArrayInputStream(configProperty.getBytes());
+ GenericApplicationContext ac = new GenericApplicationContext();
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(ac);
+ reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
+ reader.loadBeanDefinitions(new InputStreamResource(stream));
+ EventDrivenConsumer splitter = (EventDrivenConsumer) ac.getBean("testSplitter");
+ Assert.assertNotNull(splitter);
+ MessageBuilder inChannelMessageBuilder = MessageBuilder.withPayload(new String[]{"One","Two"});
+ Message inMessage = inChannelMessageBuilder.build();
+ DirectChannel inChannel = (DirectChannel) ac.getBean("inChannel");
+ inChannel.send(inMessage);
+ PollableChannel outChannel = (PollableChannel) ac.getBean("outChannel");
+ Assert.assertTrue(outChannel.receive().getPayload() instanceof String);
+ outChannel = (PollableChannel) ac.getBean("outChannel");
+ Assert.assertTrue(outChannel.receive().getPayload() instanceof String);
+ }
+
+ private void testTransformerDefinitionSuccess(String configProperty){
+ ByteArrayInputStream stream = new ByteArrayInputStream(configProperty.getBytes());
+ GenericApplicationContext ac = new GenericApplicationContext();
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(ac);
+ reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
+ reader.loadBeanDefinitions(new InputStreamResource(stream));
+ EventDrivenConsumer transformer = (EventDrivenConsumer) ac.getBean("testTransformer");
+ Assert.assertNotNull(transformer);
+ MessageBuilder inChannelMessageBuilder = MessageBuilder.withPayload(new String[]{"One","Two"});
+ Message inMessage = inChannelMessageBuilder.build();
+ DirectChannel inChannel = (DirectChannel) ac.getBean("inChannel");
+ inChannel.send(inMessage);
+ PollableChannel outChannel = (PollableChannel) ac.getBean("outChannel");
+ String payload = (String) outChannel.receive().getPayload();
+ Assert.assertTrue(payload.equals("One,Two"));
+ }
+
+ public static class TestSplitter{
+ public Collection split(String[] payload){
+ return CollectionUtils.arrayToList(payload);
+ }
+ }
+
+ public static class TestTransformer{
+ public String split(String[] payload){
+ return StringUtils.arrayToDelimitedString(payload, ",");
+ }
+ }
+
+}
diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/innerdefaware.properties b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/innerdefaware.properties
new file mode 100644
index 0000000000..33009dd3ae
--- /dev/null
+++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/innerdefaware.properties
@@ -0,0 +1,96 @@
+splitter-inner-success=\
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+
+splitter-ref-success=\
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+
+splitter-failure-refAndBean=\
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+
+transformer-inner-success=\
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+
+transformer-ref-success=\
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+
+transformer-failure-refAndBean=\
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+
\ No newline at end of file