INT-720 Added support for the "dispatcher" sub-element within a "channel". This is now where the failover, load-balancer, and task-executor attributes are to be configured.

This commit is contained in:
Mark Fisher
2009-07-12 00:24:55 +00:00
parent ab773b5935
commit 2de0d5381c
5 changed files with 307 additions and 45 deletions

View File

@@ -16,6 +16,8 @@
package org.springframework.integration.config.xml;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -37,6 +39,9 @@ public class PointToPointChannelParser extends AbstractChannelParser {
private static final String DISPATCHER_PACKAGE = IntegrationNamespaceUtils.BASE_PACKAGE + ".dispatcher";
private final Log logger = LogFactory.getLog(this.getClass());
@Override
protected BeanDefinitionBuilder buildBeanDefinition(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = null;
@@ -64,16 +69,53 @@ public class PointToPointChannelParser extends AbstractChannelParser {
builder = BeanDefinitionBuilder.genericBeanDefinition(CHANNEL_PACKAGE + ".RendezvousChannel");
}
// verify that the 'task-executor' is not provided if a queue sub-element exists
String taskExecutor = element.getAttribute("task-executor");
if (queueElement != null && StringUtils.hasText(taskExecutor)) {
parserContext.getReaderContext().error("The 'task-executor' attribute " +
Element dispatcherElement = DomUtils.getChildElementByTagName(element, "dispatcher");
// check for the dispatcher attribute (deprecated)
String dispatcherAttribute = element.getAttribute("dispatcher");
boolean hasDispatcherAttribute = StringUtils.hasText(dispatcherAttribute);
if (hasDispatcherAttribute && logger.isWarnEnabled()) {
logger.warn("The 'dispatcher' attribute on the 'channel' element is deprecated. " +
"Please use the 'dispatcher' sub-element instead.");
}
// verify that a dispatcher is not provided if a queue sub-element exists
if (queueElement != null && (dispatcherElement != null || hasDispatcherAttribute)) {
parserContext.getReaderContext().error("The 'dispatcher' attribute or sub-element " +
"and any queue sub-element are mutually exclusive.", element);
return null;
}
if (builder == null) {
if (queueElement != null) {
return builder;
}
if (dispatcherElement != null && hasDispatcherAttribute) {
parserContext.getReaderContext().error("The 'dispatcher' attribute and 'dispatcher' " +
"sub-element are mutually exclusive. NOTE: the attribute is DEPRECATED. " +
"Please use the dispatcher sub-element instead.", element);
return null;
}
if (hasDispatcherAttribute) {
// this attribute is deprecated, but if set, we need to create a DirectChannel
// without any LoadBalancerStrategy and the failover flag set to true (default).
builder = BeanDefinitionBuilder.genericBeanDefinition(CHANNEL_PACKAGE + ".DirectChannel");
if (!"failover".equals(dispatcherAttribute)) {
// round-robin dispatcher is used by default, the "failover" value simply disables it
builder.addConstructorArgValue(new RootBeanDefinition(
DISPATCHER_PACKAGE + ".RoundRobinLoadBalancingStrategy", null, null));
}
}
else if (dispatcherElement == null) {
// configure the default DirectChannel with a RoundRobinLoadBalancingStrategy
builder = BeanDefinitionBuilder.genericBeanDefinition(CHANNEL_PACKAGE + ".DirectChannel");
builder.addConstructorArgValue(new RootBeanDefinition(
DISPATCHER_PACKAGE + ".RoundRobinLoadBalancingStrategy", null, null));
}
else {
// configure either an ExecutorChannel or DirectChannel based on existence of 'task-executor'
String taskExecutor = dispatcherElement.getAttribute("task-executor");
if (StringUtils.hasText(taskExecutor)) {
builder = BeanDefinitionBuilder.genericBeanDefinition(CHANNEL_PACKAGE + ".ExecutorChannel");
builder.addConstructorArgReference(taskExecutor);
@@ -81,15 +123,15 @@ public class PointToPointChannelParser extends AbstractChannelParser {
else {
builder = BeanDefinitionBuilder.genericBeanDefinition(CHANNEL_PACKAGE + ".DirectChannel");
}
// this attribute is deprecated, but if set, we need to create a UnicastingDispatcher
// without any LoadBalancerStrategy and the failover flag set to true (default).
String dispatcherAttribute = element.getAttribute("dispatcher");
if (!"failover".equals(dispatcherAttribute)) {
// round-robin dispatcher by default, but TODO first we need to check for the dispatcher element.
// unless the 'load-balancer' attribute is explicitly set to 'none',
// configure the default RoundRobinLoadBalancingStrategy
String loadBalancer = dispatcherElement.getAttribute("load-balancer");
if (!"none".equals(loadBalancer)) {
builder.addConstructorArgValue(new RootBeanDefinition(
DISPATCHER_PACKAGE + ".RoundRobinLoadBalancingStrategy", null, null));
}
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, dispatcherElement, "failover");
}
return builder;
}

View File

@@ -64,25 +64,11 @@
<xsd:element name="queue" type="queueType" />
<xsd:element name="priority-queue" type="priorityQueueType" />
<xsd:element name="rendezvous-queue" type="rendezvousQueueType" />
<xsd:element name="dispatcher" type="dispatcherType" />
</xsd:choice>
<xsd:element name="interceptors" type="channelInterceptorsType"
minOccurs="0" maxOccurs="1" />
</xsd:sequence>
<xsd:attribute name="task-executor" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Provide a TaskExecutor to use when dispatching Messages to this channel's subscribers. This is
mutually exclusive with any of the queue sub-elements. Also, when using a TaskExecutor, keep in
mind that any transaction active for the sender will NOT propagate to the handler invocation
since the TaskExecutor dispatches to the handler on a separate Thread.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.core.task.TaskExecutor" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
@@ -133,6 +119,73 @@
</xsd:annotation>
</xsd:complexType>
<xsd:complexType name="dispatcherType">
<xsd:annotation>
<xsd:documentation>
Defines the dispatching configuration for a non-buffering channel
(i.e. one without a queue).
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="load-balancer">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
Defines a load-balancing strategy for the channel's dispatcher.
The default is a round-robin load balancer.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="round-robin">
<xsd:annotation>
<xsd:documentation>
[DEFAULT] Defines a Round Robin dispatching strategy which allows for
load balancing of messages between multiple Message Handlers. Which message
handler receives the message first is determined by the 'order' attribute
of such Message Handler.
</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="none">
<xsd:annotation>
<xsd:documentation>
No LoadBalancingStrategy will be used.
</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="failover" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Specifies whether this dispatcher has failover enabled. By default,
failover will be enabled. Set this to 'false' to disable it.
When enabled and message delivery to the primary Message Handler fails,
an attempt will be made to deliver the message to the next handler and so on...
Primary, secondary etc... is determined by the load-balancing strategy in use
(e.g. round-robin). If no load-balancer strategy is configured, the order will
be fixed in a sequence determined by the 'order' attribute on the Message Handlers
(or the @Ordered annotation on adapted methods).
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="task-executor" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Provide a TaskExecutor to use when dispatching Messages to this channel's subscribers. This is
mutually exclusive with any of the queue sub-elements. Also, when using a TaskExecutor, keep in
mind that any transaction active for the sender will NOT propagate to the handler invocation
since the TaskExecutor dispatches to the handler on a separate Thread.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.core.task.TaskExecutor" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:element name="publish-subscribe-channel">
<xsd:annotation>
<xsd:documentation>
@@ -215,31 +268,15 @@
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
Defines a dispatching strategy for the channel.
The default is a round
robin load balancer. In case of a publish
subscribe channel this
attribute will be ignored.
This attribute is DEPRECATED. Please use the dispatcher sub-element instead.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="failover">
<xsd:annotation>
<xsd:documentation>
Defines a fail over dispatching strategy.
If message delivery to the primary Message Handler failed an
attempt will be made to deliver the message to the secondary and so on...
Primary, secondary etc... is determined by the 'order' attribute on the Message Handlers.
</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="round-robin">
<xsd:annotation>
<xsd:documentation>
[DEFAULT] Defines a Round Robin dispatching strategy which allows for
load balancing of messages between multiple Message Handlers. Which message
handler receives the message first is determined by the 'order' attribute
of such Message Handler.
Enables failover, but disables load-balancing.
See the dispatcher sub-element for more information.
</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>