INT-2998: Channel Adapters' Lifecycle Refactoring

* Add XSD attributeGroup `smartLifeCycleAttributeGroup`
* Use it for all adapters tags
* Refactoring `AbstractChannelAdapterParser` hierarchy
* Refactoring some `MessageHandler`'s that should not have `autoStartup` & `phase`.
    It is the responsibility of `AbstrctEndpoint`
* Polishing some tests according new logic

JIRA: https://jira.springsource.org/browse/INT-2998

INT-2998: Polishing

Polishing

 - Reformat schemas where indentation changed
 - Add SLC to the UDP inbound adapter
This commit is contained in:
Artem Bilan
2013-09-23 16:09:53 +03:00
committed by Gary Russell
parent e8ecbac7fd
commit f3d3f4ee4b
46 changed files with 757 additions and 1187 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -18,8 +18,10 @@ package org.springframework.integration.config.xml;
import org.w3c.dom.Element;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
@@ -30,7 +32,7 @@ import org.springframework.util.StringUtils;
/**
* Base parser for Channel Adapters.
*
* <p/>
* Includes logic to determine {@link org.springframework.integration.MessageChannel}:
* if 'channel' attribute is defined - uses its value as 'channelName';
* if 'id' attribute is defined - creates {@link DirectChannel} at runtime and uses id's value as 'channelName';
@@ -63,7 +65,17 @@ public abstract class AbstractChannelAdapterParser extends AbstractBeanDefinitio
if (!StringUtils.hasText(channelName)) {
channelName = this.createDirectChannel(element, parserContext);
}
return doParse(element, parserContext, channelName);
AbstractBeanDefinition beanDefinition = doParse(element, parserContext, channelName);
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
String autoStartup = element.getAttribute(IntegrationNamespaceUtils.AUTO_STARTUP);
if (StringUtils.hasText(autoStartup)) {
propertyValues.add("autoStartup", new TypedStringValue(autoStartup));
}
String phase = element.getAttribute(IntegrationNamespaceUtils.PHASE);
if (StringUtils.hasText(phase)) {
propertyValues.add("phase", new TypedStringValue(phase));
}
return beanDefinition;
}
private String createDirectChannel(Element element, ParserContext parserContext) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -19,6 +19,8 @@ package org.springframework.integration.config.xml;
import java.util.Collection;
import java.util.List;
import org.w3c.dom.Element;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
@@ -34,7 +36,6 @@ import org.springframework.integration.config.ConsumerEndpointFactoryBean;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Base class parser for elements that create Message Endpoints.
@@ -96,7 +97,8 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
+ elementDescription + ".", element);
}
return handlerBeanDefinition;
} else {
}
else {
if (!hasInputChannelAttribute) {
String elementDescription = IntegrationNamespaceUtils.createElementDescription(element);
parserContext.getReaderContext().error("The '" + inputChannelAttributeName
@@ -115,18 +117,18 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
String inputChannelName = element.getAttribute(inputChannelAttributeName);
if (!parserContext.getRegistry().containsBeanDefinition(inputChannelName)){
if (parserContext.getRegistry().containsBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME)){
if (!parserContext.getRegistry().containsBeanDefinition(inputChannelName)) {
if (parserContext.getRegistry().containsBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME)) {
BeanDefinition channelRegistry = parserContext.getRegistry().
getBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
ConstructorArgumentValues caValues = channelRegistry.getConstructorArgumentValues();
ValueHolder vh = caValues.getArgumentValue(0, Collection.class);
if (vh == null){ //although it should never happen if it does we can fix it
if (vh == null) { //although it should never happen if it does we can fix it
caValues.addIndexedArgumentValue(0, new ManagedSet<String>());
}
@SuppressWarnings("unchecked")
Collection<String> channelCandidateNames = (Collection<String>) caValues.getArgumentValue(0, Collection.class).getValue();
Collection<String> channelCandidateNames = (Collection<String>) caValues.getArgumentValue(0, Collection.class).getValue();
channelCandidateNames.add(inputChannelName);
}
else {
@@ -144,7 +146,8 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
}
IntegrationNamespaceUtils.configurePollerMetadata(pollerElementList.get(0), builder, parserContext);
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.AUTO_STARTUP);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.PHASE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
String beanName = this.resolveId(element, beanDefinition, parserContext);
parserContext.registerBeanComponent(new BeanComponentDefinition(beanDefinition, beanName));

View File

@@ -71,8 +71,6 @@ public abstract class AbstractOutboundChannelAdapterParser extends AbstractChann
IntegrationNamespaceUtils.configurePollerMetadata(pollerElement, builder, parserContext);
}
builder.addPropertyValue("inputChannelName", channelName);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "phase");
this.configureRequestHandlerAdviceChain(element, parserContext, handlerBeanComponentDefinition.getBeanDefinition(), builder);

View File

@@ -49,8 +49,6 @@ public abstract class AbstractPollingInboundChannelAdapterParser extends Abstrac
if (pollerElement != null) {
IntegrationNamespaceUtils.configurePollerMetadata(pollerElement, adapterBuilder, parserContext);
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(adapterBuilder, element, "auto-startup");
IntegrationNamespaceUtils.setValueIfAttributeDefined(adapterBuilder, element, "phase");
return adapterBuilder.getBeanDefinition();
}

View File

@@ -99,8 +99,6 @@ public class ChainParser extends AbstractConsumerEndpointParser {
}
builder.addPropertyValue("handlers", handlerList);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-timeout");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "phase");
return builder;
}

View File

@@ -65,6 +65,8 @@ public abstract class IntegrationNamespaceUtils {
static final String EXPRESSION_ATTRIBUTE = "expression";
public static final String HANDLER_ALIAS_SUFFIX = ".handler";
public static final String REQUEST_HANDLER_ADVICE_CHAIN = "request-handler-advice-chain";
public static final String AUTO_STARTUP = "auto-startup";
public static final String PHASE = "phase";
/**
* Property name on ChannelInitializer used to configure the default max subscribers for

View File

@@ -22,7 +22,7 @@ import java.util.concurrent.locks.ReentrantLock;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.Lifecycle;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.MessageHandlingException;
@@ -66,7 +66,7 @@ import org.springframework.util.Assert;
* @author Gary Russell
* @author Artem Bilan
*/
public class MessageHandlerChain extends AbstractMessageHandler implements MessageProducer, SmartLifecycle {
public class MessageHandlerChain extends AbstractMessageHandler implements MessageProducer, Lifecycle {
private volatile List<MessageHandler> handlers;
@@ -85,10 +85,6 @@ public class MessageHandlerChain extends AbstractMessageHandler implements Messa
private final Object initializationMonitor = new Object();
private volatile boolean autoStartup = true;
private volatile int phase = Integer.MAX_VALUE;
private volatile boolean running;
private final ReentrantLock lifecycleLock = new ReentrantLock();
@@ -176,14 +172,6 @@ public class MessageHandlerChain extends AbstractMessageHandler implements Messa
* SmartLifecycle implementation (delegates to the {@link #handlers})
*/
public final boolean isAutoStartup() {
return this.autoStartup;
}
public final int getPhase() {
return this.phase;
}
public final boolean isRunning() {
this.lifecycleLock.lock();
try {
@@ -237,26 +225,18 @@ public class MessageHandlerChain extends AbstractMessageHandler implements Messa
}
}
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
public void setPhase(int phase) {
this.phase = phase;
}
private void doStop() {
for (MessageHandler handler : this.handlers) {
if (handler instanceof SmartLifecycle) {
((SmartLifecycle) handler).stop();
if (handler instanceof Lifecycle) {
((Lifecycle) handler).stop();
}
}
}
private void doStart() {
for (MessageHandler handler : this.handlers) {
if (handler instanceof SmartLifecycle) {
((SmartLifecycle) handler).start();
if (handler instanceof Lifecycle) {
((Lifecycle) handler).start();
}
}
}

View File

@@ -877,13 +877,6 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-startup" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Lifecycle attribute signaling if this component should be started during Application Context startup.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="pattern" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
@@ -907,6 +900,7 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attributeGroup ref="smartLifeCycleAttributeGroup"/>
</xsd:complexType>
</xsd:element>
@@ -1041,23 +1035,7 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-startup" type="xsd:string" default="true">
<xsd:annotation>
<xsd:documentation>
Lifecycle attribute signaling if this component should be started during Application Context startup.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="phase" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation>
The Lifecycle attribute determining the start/stop order
of the underlying MessageHandlerChain.
</xsd:documentation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attributeGroup ref="smartLifeCycleAttributeGroup"/>
</xsd:attributeGroup>
<xsd:complexType name="methodInvokingChannelAdapterType">
@@ -1552,16 +1530,6 @@
<xsd:group ref="chain-elements-group" maxOccurs="unbounded"/>
</xsd:choice>
<xsd:attributeGroup ref="inputOutputChannelGroup" />
<xsd:attribute name="phase" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation>
The Lifecycle attribute determining the start/stop order
of the underlying MessageHandlerChain.
</xsd:documentation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="id" type="xsd:string" />
</xsd:complexType>
</xsd:element>
@@ -3066,17 +3034,6 @@
-->
<xsd:attributeGroup name="topLevelRouterAttributeGroup">
<xsd:attribute name="auto-startup" default="true">
<xsd:annotation>
<xsd:documentation>
Lifecycle attribute signaling if this component should be
started during Application Context startup. Defaults to true.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="input-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
@@ -3099,6 +3056,7 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attributeGroup ref="smartLifeCycleAttributeGroup"/>
</xsd:attributeGroup>
<!--
@@ -4025,17 +3983,7 @@ endpoint itself is a Polling Consumer for a channel with a queue.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-startup" default="true">
<xsd:annotation>
<xsd:documentation>
Lifecycle attribute signaling if this component should be
started during Application Context startup. Defaults to true.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attributeGroup ref="smartLifeCycleAttributeGroup"/>
</xsd:attributeGroup>
<xsd:attributeGroup name="subscribersAttributeGroup">
@@ -4117,4 +4065,24 @@ endpoint itself is a Polling Consumer for a channel with a queue.
</xsd:annotation>
</xsd:attribute>
</xsd:attributeGroup>
<xsd:attributeGroup name="smartLifeCycleAttributeGroup">
<xsd:attribute name="auto-startup" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Boolean value indicating whether this endpoint should start automatically.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="phase" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The lifecycle phase within which this endpoint should start and stop.
The lower the value the earlier this endpoint will start and the later it will stop. The
default is 0. Values can be negative. See SmartLifeCycle.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:attributeGroup>
</xsd:schema>

View File

@@ -53,6 +53,7 @@ import org.springframework.integration.MessageChannel;
import org.springframework.integration.MessageRejectedException;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.handler.LoggingHandler;
@@ -335,9 +336,11 @@ public class ChainParserTests {
@Test //INT-2605
public void checkSmartLifecycleConfig() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("ChainParserSmartLifecycleAttributesTest.xml", this.getClass());
MessageHandlerChain handlerChain = ctx.getBean(MessageHandlerChain.class);
assertEquals(false, handlerChain.isAutoStartup());
assertEquals(256, handlerChain.getPhase());
AbstractEndpoint chainEndpoint = ctx.getBean("chain", AbstractEndpoint.class);
assertEquals(false, chainEndpoint.isAutoStartup());
assertEquals(256, chainEndpoint.getPhase());
MessageHandlerChain handlerChain = ctx.getBean("chain.handler", MessageHandlerChain.class);
assertEquals(3000L, TestUtils.getPropertyValue(handlerChain, "sendTimeout"));
assertEquals(false, TestUtils.getPropertyValue(handlerChain, "running"));
//INT-3108