diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractCorrelatingMessageHandlerParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractCorrelatingMessageHandlerParser.java
index 171dbad037..d069d28484 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractCorrelatingMessageHandlerParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractCorrelatingMessageHandlerParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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
@@ -10,18 +10,16 @@
* 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 org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler;
-import org.springframework.integration.config.IntegrationConfigUtils;
-import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
/**
@@ -30,8 +28,9 @@ import org.springframework.util.xml.DomUtils;
* @author Oleg Zhurakousky
* @author Stefan Ferstl
* @author Artem Bilan
- * @since 2.1
+ * @author Gary Russell
*
+ * @since 2.1
*/
public abstract class AbstractCorrelatingMessageHandlerParser extends AbstractConsumerEndpointParser {
@@ -62,11 +61,11 @@ public abstract class AbstractCorrelatingMessageHandlerParser extends AbstractCo
private static final String EXPIRE_GROUPS_UPON_TIMEOUT = "expire-groups-upon-timeout";
protected void doParse(BeanDefinitionBuilder builder, Element element, BeanMetadataElement processor,
- ParserContext parserContext) {
- this.injectPropertyWithAdapter(CORRELATION_STRATEGY_REF_ATTRIBUTE, CORRELATION_STRATEGY_METHOD_ATTRIBUTE,
+ ParserContext parserContext) {
+ IntegrationNamespaceUtils.injectPropertyWithAdapter(CORRELATION_STRATEGY_REF_ATTRIBUTE, CORRELATION_STRATEGY_METHOD_ATTRIBUTE,
CORRELATION_STRATEGY_EXPRESSION_ATTRIBUTE, CORRELATION_STRATEGY_PROPERTY, "CorrelationStrategy",
element, builder, processor, parserContext);
- this.injectPropertyWithAdapter(RELEASE_STRATEGY_REF_ATTRIBUTE, RELEASE_STRATEGY_METHOD_ATTRIBUTE,
+ IntegrationNamespaceUtils.injectPropertyWithAdapter(RELEASE_STRATEGY_REF_ATTRIBUTE, RELEASE_STRATEGY_METHOD_ATTRIBUTE,
RELEASE_STRATEGY_EXPRESSION_ATTRIBUTE, RELEASE_STRATEGY_PROPERTY, "ReleaseStrategy",
element, builder, processor, parserContext);
@@ -93,51 +92,4 @@ public abstract class AbstractCorrelatingMessageHandlerParser extends AbstractCo
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, EXPIRE_GROUPS_UPON_TIMEOUT);
}
- protected void injectPropertyWithAdapter(String beanRefAttribute, String methodRefAttribute,
- String expressionAttribute, String beanProperty, String adapterClass, Element element,
- BeanDefinitionBuilder builder, BeanMetadataElement processor, ParserContext parserContext) {
-
- final String beanRef = element.getAttribute(beanRefAttribute);
- final String beanMethod = element.getAttribute(methodRefAttribute);
- final String expression = element.getAttribute(expressionAttribute);
-
- final boolean hasBeanRef = StringUtils.hasText(beanRef);
- final boolean hasExpression = StringUtils.hasText(expression);
-
- if (hasBeanRef && hasExpression) {
- parserContext.getReaderContext().error("Exactly one of the '" + beanRefAttribute + "' or '"
- + expressionAttribute + "' attribute is allowed.", element);
- }
-
- BeanMetadataElement adapter = null;
- if (hasBeanRef) {
- adapter = this.createAdapter(new RuntimeBeanReference(beanRef), beanMethod, adapterClass);
- }
- else if (hasExpression) {
- BeanDefinitionBuilder adapterBuilder = BeanDefinitionBuilder
- .genericBeanDefinition(IntegrationConfigUtils.BASE_PACKAGE + ".aggregator.ExpressionEvaluating"
- + adapterClass);
- adapterBuilder.addConstructorArgValue(expression);
- adapter = adapterBuilder.getBeanDefinition();
- }
- else if (processor != null) {
- adapter = this.createAdapter(processor, beanMethod, adapterClass);
- }
- else {
- adapter = this.createAdapter(null, beanMethod, adapterClass);
- }
- builder.addPropertyValue(beanProperty, adapter);
- }
-
- private BeanMetadataElement createAdapter(BeanMetadataElement ref, String method, String unqualifiedClassName) {
- BeanDefinitionBuilder builder = BeanDefinitionBuilder
- .genericBeanDefinition(IntegrationConfigUtils.BASE_PACKAGE + ".config." + unqualifiedClassName
- + "FactoryBean");
- builder.addConstructorArgValue(ref);
- if (StringUtils.hasText(method)) {
- builder.addConstructorArgValue(method);
- }
- return builder.getBeanDefinition();
- }
-
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/BarrierParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/BarrierParser.java
new file mode 100644
index 0000000000..94e4756e58
--- /dev/null
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/BarrierParser.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015 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 org.w3c.dom.Element;
+
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.integration.handler.BarrierMessageHandler;
+import org.springframework.util.StringUtils;
+
+/**
+ * Parser for {@code }.
+ *
+ * @author Gary Russell
+ *
+ * @since 4.2
+ */
+public class BarrierParser extends AbstractConsumerEndpointParser {
+
+ @Override
+ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
+ BeanDefinitionBuilder handlerBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(BarrierMessageHandler.class);
+ handlerBuilder.addConstructorArgValue(element.getAttribute("timeout"));
+ String processor = element.getAttribute("output-processor");
+ if (StringUtils.hasText(processor)) {
+ handlerBuilder.addConstructorArgReference(processor);
+ }
+ IntegrationNamespaceUtils.injectConstructorWithAdapter("correlation-strategy",
+ "correlation-strategy-method", "correlation-strategy-expression",
+ "CorrelationStrategy", element, handlerBuilder, null, parserContext);
+ return handlerBuilder;
+ }
+
+}
+
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java
index 8b2a631c94..a84063e30c 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java
@@ -84,6 +84,7 @@ public class IntegrationNamespaceHandler extends AbstractIntegrationNamespaceHan
registerBeanDefinitionParser("scatter-gather", new ScatterGatherParser());
registerBeanDefinitionParser("idempotent-receiver", new IdempotentReceiverInterceptorParser());
registerBeanDefinitionParser("management", new IntegrationManagementParser());
+ registerBeanDefinitionParser("barrier", new BarrierParser());
}
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java
index 8578147998..f95bfc3c54 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java
@@ -22,6 +22,7 @@ import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanReference;
@@ -564,4 +565,66 @@ public abstract class IntegrationNamespaceUtils {
lifecycles.add(new RuntimeBeanReference(beanName));
}
+ public static void injectPropertyWithAdapter(String beanRefAttribute, String methodRefAttribute,
+ String expressionAttribute, String beanProperty, String adapterClass, Element element,
+ BeanDefinitionBuilder builder, BeanMetadataElement processor, ParserContext parserContext) {
+ BeanMetadataElement adapter = constructAdapter(beanRefAttribute, methodRefAttribute, expressionAttribute,
+ adapterClass, element, processor, parserContext);
+ builder.addPropertyValue(beanProperty, adapter);
+ }
+
+ public static void injectConstructorWithAdapter(String beanRefAttribute, String methodRefAttribute,
+ String expressionAttribute, String adapterClass, Element element,
+ BeanDefinitionBuilder builder, BeanMetadataElement processor, ParserContext parserContext) {
+ BeanMetadataElement adapter = constructAdapter(beanRefAttribute, methodRefAttribute, expressionAttribute,
+ adapterClass, element, processor, parserContext);
+ builder.addConstructorArgValue(adapter);
+ }
+
+ private static BeanMetadataElement constructAdapter(String beanRefAttribute, String methodRefAttribute,
+ String expressionAttribute, String adapterClass, Element element, BeanMetadataElement processor,
+ ParserContext parserContext) {
+ final String beanRef = element.getAttribute(beanRefAttribute);
+ final String beanMethod = element.getAttribute(methodRefAttribute);
+ final String expression = element.getAttribute(expressionAttribute);
+
+ final boolean hasBeanRef = StringUtils.hasText(beanRef);
+ final boolean hasExpression = StringUtils.hasText(expression);
+
+ if (hasBeanRef && hasExpression) {
+ parserContext.getReaderContext().error("Exactly one of the '" + beanRefAttribute + "' or '"
+ + expressionAttribute + "' attribute is allowed.", element);
+ }
+
+ BeanMetadataElement adapter = null;
+ if (hasBeanRef) {
+ adapter = createAdapter(new RuntimeBeanReference(beanRef), beanMethod, adapterClass);
+ }
+ else if (hasExpression) {
+ BeanDefinitionBuilder adapterBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(IntegrationConfigUtils.BASE_PACKAGE + ".aggregator.ExpressionEvaluating"
+ + adapterClass);
+ adapterBuilder.addConstructorArgValue(expression);
+ adapter = adapterBuilder.getBeanDefinition();
+ }
+ else if (processor != null) {
+ adapter = createAdapter(processor, beanMethod, adapterClass);
+ }
+ else {
+ adapter = createAdapter(null, beanMethod, adapterClass);
+ }
+ return adapter;
+ }
+
+ private static BeanMetadataElement createAdapter(BeanMetadataElement ref, String method, String unqualifiedClassName) {
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder
+ .genericBeanDefinition(IntegrationConfigUtils.BASE_PACKAGE + ".config." + unqualifiedClassName
+ + "FactoryBean");
+ builder.addConstructorArgValue(ref);
+ if (StringUtils.hasText(method)) {
+ builder.addConstructorArgValue(method);
+ }
+ return builder.getBeanDefinition();
+ }
+
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/BarrierMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/BarrierMessageHandler.java
new file mode 100644
index 0000000000..24d50eeaa5
--- /dev/null
+++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/BarrierMessageHandler.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2015 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.handler;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.springframework.integration.IntegrationMessageHeaderAccessor;
+import org.springframework.integration.aggregator.CorrelationStrategy;
+import org.springframework.integration.aggregator.DefaultAggregatingMessageGroupProcessor;
+import org.springframework.integration.aggregator.HeaderAttributeCorrelationStrategy;
+import org.springframework.integration.aggregator.MessageGroupProcessor;
+import org.springframework.integration.store.SimpleMessageGroup;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageHandlingException;
+import org.springframework.messaging.MessagingException;
+import org.springframework.util.Assert;
+
+/**
+ * A message handler that suspends the thread until a message with corresponding
+ * correlation is passed into the {@link #trigger(Message) trigger} method or
+ * the timeout occurs. Only one thread with a particular correlation (result of invoking
+ * the {@link CorrelationStrategy}) can be suspended at a time. If the inbound thread does
+ * not arrive before the trigger thread, the latter is suspended until it does, or the
+ * timeout occurs.
+ *
+ * The default {@link CorrelationStrategy} is a {@link HeaderAttributeCorrelationStrategy}.
+ *
+ * The default output processor is a {@link DefaultAggregatingMessageGroupProcessor}.
+ *
+ * @author Gary Russell
+ *
+ * @since 4.2
+ */
+public class BarrierMessageHandler extends AbstractReplyProducingMessageHandler implements MessageTriggerAction {
+
+ private final ConcurrentMap